Reduce a byte by percentage in fewest clocks in PASM
ke4pjw
Posts: 1,169
I need to reduce a byte by a percentage in the fewest clocks. Even if the percentage resolution was 5 or 10%, that would be "good enough".
Are there any tricks for doing such a thing?
Comments
MUL + SHR, the obvious 4 clocks
SCA / SCAS, 2 or 4 clocks depending what the next instruction is
MULPIX if you have a bunch of unsigned bytes
But the thing about all of these is they don't take 0-100 for the gain input.
The goal here is to stay within the 16x16 multiply that the P2 can do in 2 clocks.
328 = 2.56 * 128 + a round-up, so 255 input = 255 output
328 * 100 = 32800, ok for 16 bits
655 * 100 = 65500, ok for 16 bits, but 255 input is reduced to 254
656 * 100 = 65600, overflows 16 bits, max 65535
Is this for your lighting controller? If that's the case, isn't the level going to be expressed as 0..255 for 0..100%? If yes, this is in my pixel driver; you could remove the checks for < 0 or > 255 since the adjustment level is coming from a control device. This scales all three/four bytes in the pixel color with the mulpix instruction (as James suggested above).
Thanks guys. I didn't even realize we had a MUL instruction! I was looking for something as a shortcut, but apparently it can just be done in a strightforward manner. Most likely I will perform this operation on the input.
@JonnyMac Yes, this is for the light controller. Unfortunately, the data structure I use in my modified version of your driver is slightly different, as I don't support RGBW, just RGB. The reasoning is because at the time I was unsure how to fill the W in my E1.31 driver. Now I know how to, so that is some technical debt. The other was to save memory, as I wanted to scale to tens of thousands of pixels. Still unsure how I want to do this, but supporting RGBW would be nice. mulpix looks very interesting, but there is little to no documentation in the PASM manual. I may have a look at the hardware manual to see if I can find more detail.
I think Evan or one of the other PASM gurus suggested mulpix to me. The dest field is the value you want adjusted -- and it is adjusted byte-by-byte based on what's in the source field. Here's a simple Spin method that does the same thing:
In my code I use the movbyts instruction to copy the adjustment (0..255) to all four bytes of that long. This allows the level to be applied to all four bytes of the color.
Actually, it's
Also, instead of
you can use SETPIV and BLNPIX, with the caveat that the control goes the other way (255 means all black), but the advantage that you can use any color to fade toward instead of
#0
:or, if one really wants that 0 = black, MIXPIX
@JonnyMac I took a look at my modifications. I can absolutely do this in the pixel driver, as I only shift out bytes 0,1,2 and ignore byte 3. Thank you sir!
So dumb question. I walked through @SaucySoliton 's steps with a calculator, and indeed it is a percent reduction. ie 0% reduction of 255 returns 255. 100% reduction in 255 returns 0.
Does mulpix work the same way?
Also I assume mulpix performs the multiply and shift right on every byte in the long?
The mulpix instruction treats 255 like 1.0, so
...would set all the bytes in pixel to half of their present level. Honestly, I don't know what's happening at the microcode level, but the results match the description.
The silicon manual explains it:
(That also means the equivalent code above is wrong, for it fails to take the $FF bias into account. Didn't realize that was there)
I hopped on Discord and @Wuerfel_21 helped me understand what to do for this specific use case. The code in question is as follows:
And here is the result:
Thank you all so much!