Shop OBEX P1 Docs P2 Docs Learn Events
Question of Shifts in SPIN — Parallax Forums

Question of Shifts in SPIN

Most likely I have missed something in the PROP manual, but my question regards shifts in SPIN and if there is a carry in/out test than can be done. Easy enough in PASM, but the spin descriptions are not as clear to me. Given an array of 12 bit words, I would like to unwind them into another array of words by shifting left or right and using the carry out of SourceVar(m) as the bit to shift into the DestVar(n) of the destination array (think rotate the array 90 degrees). Has anyone used the SPIN shift instructions to set or clear a bit in a word depending on the carry out value?

Thanks for any ideas.

FF

Comments

  • the problem is 12-bit, what you need is a 4-bitmove

    mask out 4-bit of fromarray with and
    or 4-bit into toarray

    I would use a pointer to the from byte
    and then split into 3 variations
    just first 4 bit
    just last 4 bits
    both (all) 8 bits

    and a pointer to the tobyte also 3 variations
    first 4
    last4
    both 8 bit

    You could check first if both arrays are at 0bit position in the start byte and 7bit on the end byte, special case, then you can use bytemove…

    but c out of << I don't know.

    Enjoy!

    Mike



  • Another idea

    use bytearrays,
    if shift left check if source byte is negative -> your carry
    if shift right check if byte bit 0 is set - your carry
    the you can use << or >> on bytes

    but that still leaves the half byte problem of 12 bit

    Mike
  • So it looks like it may be simpler to write a PASM routine to carry out (pun purely unintended) the rotate the array?
  • In Spin, you can always just test the bit that's shifted out before you do the shift.

    -Phil
  • Spin doesn't save the carry, so you have to test for it explicitly (as Phil said). In some cases a clever compiler can optimize the test and shift into a shift with carry. fastspin will do this in a few cases, but probably not for your particular use case. (it does work for shifting out to a pin though.)

  • I use shift in this way.
    PUB spiOut(out) : in | y
    
        out ><= 8               ' reverse byte
        repeat y from 0 to 7
            outa[clkPin]~~      ' clk pin high
            outa[mosiPin]:= out ' data bit out
            out /= 2            ' rotate right 1
            'waitcnt(cnt + 1000)
            outa[clkPin]~       ' clk pin low
            in *= 2             ' rotate left 1
            in |= ina[misoPin]  ' data bit in
    
  • Also, in PASM, be aware that the carry flag contains the first bit shifted out, not the last one. The Propeller uses a "barrel shifter" wherein the bits are not shifted incrementally but all at once. And there's no logic to reach into the source register beforehand to test the "last" bit to be shifted out -- only bit 0 or bit 31, depending upon the direction of the shift.

    -Phil
  • frida wrote: »
    I use shift in this way.
    PUB spiOut(out) : in | y
    
        out ><= 8               ' reverse byte
        repeat y from 0 to 7
            outa[clkPin]~~      ' clk pin high
            outa[mosiPin]:= out ' data bit out
            out /= 2            ' rotate right 1
            'waitcnt(cnt + 1000)
            outa[clkPin]~       ' clk pin low
            in *= 2             ' rotate left 1
            in |= ina[misoPin]  ' data bit in
    

    I think much better to use shifts instead of multiply and divide. A simple compiler (like the default Spin compiler) will just blindly translate that code and will actually do multiply and divide, which are very slow. fastspin will try to use shifts automatically, but the "out /= 2" actually requires some tricky handling because in Spin variables are signed and a signed divide by 2 is not the same as a logical shift right, so it has to check for the "out" variable being negative (if fastspin were a bit smarter perhaps it could conclude that it cannot be negative because of the reverse at the top, but it's not that clever).

    For
        outa[mosiPin] := out
        out >>= 1
    
    fastspin does do something like:
       shr   arg01, #1 wc
       muxc  outa, #2 ' assuming mosiPin is pin 1
    
  • frank freedmanfrank freedman Posts: 1,974
    edited 2019-07-21 06:14
    Well, I still like PASM better than SPIN, though learning more SPIN now. Pretty much bypassed most of it for PASM. Anyway, I found a way around my question of rotating an array of n samples from m channels into m channels of n bits. An example would be an group of 4 12 bit ADCs sampling at the same time. The result is an array of 12 bytes with the 4LSBs of each byte containing bit 2^n for each channel (up to 8 in byte, 16 if word used instead). Call it with the address of the sample array and bit count and the channel array address and channel count, If the input array was fed from a 24bit ADC, then change the channel array to long.

    Definitely a 0.01 version, so if anyone sees another way, chime in. It does work as expected.

    @Phil, did end up doing a bit test and shift.....

    FF
    
    
    BitSort ( @ADCBits, BitCnt, @ADCChans, Chans)       ' Rotate input sample array into the output channel array
    
    
    
    PUB BitSort ( SampleBits, Bits, Channel, ChanCnt) | Selector, ChanSel, n, m
    
       Bits--                                           ' set to bits - 1 set for correct bit count so ADC bits goes 2^0-2^n-1 for n bits
       ChanCnt--                                        ' same for channel count for ch 0 - channel m-1
       ' start decode of bit words to channel words
       repeat n from 0 to Bits                          ' start looping to get the bit snaps to rotate to channel values 
            selector :=  |< 0                           ' set channel bit selector to first input channel        
            ChanSel := Channel                          ' set channel array address to  channel 0
            repeat m from 0 to (ChanCnt)                ' unwind the bits for each channel
             word[(ChanSel)] <<= 1                      ' shift word for next value
              if (byte[SampleBits] & Selector )         ' is bit 2^n set for channel m
                  word[ChanSel]++                       ' if true +1 then
             Selector <<= 1                              ' Shift to next channel, shift not increment
             ChanSel+= 2                                 'point to next channel  
          SampleBits += 1
        
    
  • See if this'll suit your needs:
    PUB BitSort(SampleBits,Bits,Channel,ChanCnt) | n, m
    
      repeat n from 0 to bits - 1
        repeat m from 0 to ChanCnt - 1
          word[Channel][m] := word[Channel][m] <<= 1        
          word[Channel][m] |= word[SampleBits][n] >> m & 1  
    
    I tried something similar in PASM for a LTC2348 18-bit 8-channel adc that is able to be read in parallel. After much tweaking it was only slightly faster, and far more complicated, than simply reading all 8 channels serially.
  • frank freedmanfrank freedman Posts: 1,974
    edited 2019-07-23 06:39
    Made one change to your posted code, that being changing the line:
    word[Channel][m] |= word[SampleBits][n] >> m & 1 to
    word[Channel][m] |= byte[SampleBits][n] >> m & 1 since the sample bits array is a byte wide sample for up to 8 channels.

    it worked perfectly. Nice......


    '8channels 12 bit converter sample for testing
    ' channel: 76543210
    Test11 = %01011010 'bit 2^11 snapshot
    Test10 = %01011100 'bit 2^10 snapshot
    Test9 = %10011010 'bit 2^9 snapshot
    Test8 = %10011100 'bit 2^8 snapshot
    Test7 = %01101010 'bit 2^7 snapshot
    Test6 = %01101100 'bit 2^6 snapshot
    Test5 = %10101010 'bit 2^5 snapshot
    Test4 = %10101100 'bit 2^4 snapshot
    Test3 = %01011010 'bit 2^3 snapshot
    Test2 = %01011100 'bit 2^2 snapshot
    Test1 = %10011010 'bit 2^1 snapshot
    Test0 = %10011100 'bit 2^0 snapshot



    FF routine.....

    What Output array addx 050C
    number of channels 8
    Channel 0 addx 050C binary 000000000000
    Channel 1 addx 050E binary 101010101010
    Channel 2 addx 0510 binary 010101010101
    Channel 3 addx 0512 binary 111111111111
    Channel 4 addx 0514 binary 111100001111
    Channel 5 addx 0516 binary 000011110000
    Channel 6 addx 0518 binary 110011001100
    Channel 7 addx 051A binary 001100110011


    Chris' routine

    What Output array addx 0500
    number of channels 8
    Channel 0 addx 0500 binary 000000000000
    Channel 1 addx 0502 binary 101010101010
    Channel 2 addx 0504 binary 010101010101
    Channel 3 addx 0506 binary 111111111111
    Channel 4 addx 0508 binary 111100001111
    Channel 5 addx 050A binary 000011110000
    Channel 6 addx 050C binary 110011001100
    Channel 7 addx 050E binary 001100110011

Sign In or Register to comment.