Shop OBEX P1 Docs P2 Docs Learn Events
ALTB instruction gotcha/trap — Parallax Forums

ALTB instruction gotcha/trap

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

  • RaymanRayman Posts: 14,640

    Thanks @ozpropdev , this is very interesting. Been a long while since I looked at this.

    Found this in the silicon docs:

     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]]
    
    ALTB    bitindex        'set next D field to bitindex[13:5]
    TESTB   0,bitindex  WC  'read bit[bitindex[4:0]] into C
    

    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)

       SETQ #0
       ALTB bitindex,#base
       BITC 0,bitindex
    

    TESTB works as-is because it doesn't take a pinfield.

  • RaymanRayman Posts: 14,640

    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.

  • RaymanRayman Posts: 14,640
    edited 2022-08-25 16:12

    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.

  • cgraceycgracey Posts: 14,151

    @Wuerfel_21 said:
    Should also work (not tested)

       SETQ #0
       ALTB bitindex,#base
       BITC 0,bitindex
    

    TESTB works as-is because it doesn't take a pinfield.

    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.

  • RaymanRayman Posts: 14,640

    Think I just proven the setq way to work, by modifying the @ozpropdev code like this:

      _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))
    
                  mov       r3,#0
                  setq      #0
                  altb      bit,#r0
                  bith      0-0,bit
                  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
    

    Result attached.

    344 x 222 - 4K
Sign In or Register to comment.