ALTB instruction gotcha/trap
ozpropdev
Posts: 2,792
in Propeller 2
From the P2 documentation:.
For accessing bit fields that span multiple registers, there is the ALTB instruction which sums D[13:5] and S/#[8:0] values to
compute an address which is substituted into the next instruction's D field. It can be used with and without S/#:
ALTB bitindex,#base 'set next D field to base+bitindex[13:5] BITC 0,bitindex 'write C to bit[bitindex[4:0]]
This won't work correctly as bitindexes > 31 will be interpreted as including bitfeild lengths too.
A alternate bitindex must be used containing the lower 5 bits for correct operation.
For example
MOV bitindex2,bitindex AND bitindex2,#$1f ALTB bitindex,#base BITC 0,bitindex2
Here's some test code showing the results in denug.
_clkfreq = 180_000_000 dat org asmclk altb bit,#r0 bith 0-0,bit debug(uhex(r0,r1,r2,r3)) mov r3,#0 mov bitx,bit and bitx,#$1f altb bit,#r0 bith 0-0,bitx debug(uhex(r0,r1,r2,r3)) jmp #$ bit long 120 bitx long 0 r0 long 0 r1 long 0 r2 long 0 r3 long 0
Results in:
Cog0 r0 = $0, r1 = $0, r2 = $0, r3 = $F00_0000
Cog0 r0 = $0, r1 = $0, r2 = $0, r3 = $100_0000
Comments
Thanks @ozpropdev , this is very interesting. Been a long while since I looked at this.
Found this in the silicon docs:
So, the original idea is to be able to access individual bits in a series of multiple longs in cog ram.
In principle, you could have an extremely large table of bits. Using half of cog ram (512/2 = 256 longs), you would have a 8192 bit table.
But, looks like when Chip added the "addpins" feature, to allow some commands to affect multiple bits, this got broke.
Perhaps the TESTB in the above example would still work, but the BITC could, probably unwantingly, affect multiple bits if "bitindex" is >31.
Should also work (not tested)
TESTB works as-is because it doesn't take a pinfield.
Diving a bit deeper...
The ALTB instruction is what allows us to address a series of longs as a bit table.
You would use the S field to specify the base address in cog ram of your table, could be from 0..511.
Use the D field to specify the bit you want to address, the index.
But, the ALTB only tells the next instruction what long to look at. Does this by dividing the index by 32, hence the bitindex[13:5]. Dropping bitindex[4:0] is effectively the same as dividing by 32.
You still need to use the bitindex in the next instruction, BITC, TESTB, etc. to say which particular bit in that long you want.
This was all fine, until Chip added the "addpins" feature. Now, the BITC like instructions will clobber multiple bits if bitindex>31.
The fix for this is relatively simple, as @ozpropdev shows.
Now, for the BITC like instructions, you must AND the bitindex with $1F before use, that is, make sure that the bitindex is not >31.
You need the original version of the bitindex for the ALTB instruction though.
@ozpropdev shows how to create a second version of the bitindex, "bitx", in his example that is anded with $1F and then used in the ALTB instruction.
Nice catch, @Wuerfel_21 . Docs do say "Prior SETQ overrides S[9:5]"
Maybe Chip added this feature precisely to counter the "addpins" effect?
I guess the value used with SETQ then says how many extra bits above the index to affect.
If the value is #0, then just the one bit in the index is affected.
If the value is >0 then multiple higher bits would also be affected.
Not clear this would be useful. Seems using it with #0 would be the most common usage.
Yes, SETQ overrides the span bits in any register-bit-write or pin-write instruction which supports bit spans.
And the SETQ+ALTB+BITC sequence will work.
Think I just proven the setq way to work, by modifying the @ozpropdev code like this:
Result attached.