Welcome to the Parallax Discussion Forums, sign-up to participate.

# Question of Shifts in SPIN

Posts: 1,542
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

• Posts: 3,036
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

• Posts: 3,036
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
• Posts: 1,542
So it looks like it may be simpler to write a PASM routine to carry out (pun purely unintended) the rotate the array?
• Posts: 22,524
In Spin, you can always just test the bit that's shifted out before you do the shift.

-Phil
• Posts: 3,820
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.)

• Posts: 134
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
```
• Posts: 22,524
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
• Posts: 3,820
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
```
• Posts: 1,542
edited 2019-07-21 - 06:14:23
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

```
• Posts: 264
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.
• Posts: 1,542
edited 2019-07-23 - 06:39:03
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.....

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