How to use setq in the right way?
in Propeller 2
Hello everyone!
It has been quite a while since I last posted here in this forum.
Back then I was using the P1, now I got a P2 Eval Board for Christmas and I am trying to port programs and drivers from Spin1 / PASM to Spin2 / PASM2.
While doing this, I came across something, which don't really understand.
This code does not work correctly, as the "setq" instruction seems to be applied only to the "rdlong", but not to the "wrlong":
This code seems to work, but looks a little odd:
Is there a chance to do this in a more elegant way?
Why does the first mentioned code fail? Is the setq only valid for the very next instruction?
Wishing you all the best for 2021!
Patrick
It has been quite a while since I last posted here in this forum.
Back then I was using the P1, now I got a P2 Eval Board for Christmas and I am trying to port programs and drivers from Spin1 / PASM to Spin2 / PASM2.
While doing this, I came across something, which don't really understand.
This code does not work correctly, as the "setq" instruction seems to be applied only to the "rdlong", but not to the "wrlong":
hub_cog_transfer
rdlong buf_ptr,bufAdr
cmp transfermode, #1 wz
setq #128-1 ' setq to 128 longs to transfer
if_nz rdlong speed_buf,buf_ptr
if_z wrlong speed_buf,buf_ptr
hub_cog_transfer_ret
ret
This code seems to work, but looks a little odd:
hub_cog_transfer
rdlong buf_ptr,bufAdr
cmp transfermode, #1 wz
if_z setq #128-1 ' setq to 128 longs to transfer
if_z wrlong speed_buf,buf_ptr
if_nz setq #128-1 ' setq to 128 longs to transfer
if_nz rdlong speed_buf,buf_ptr
hub_cog_transfer_ret
ret
Is there a chance to do this in a more elegant way?
Why does the first mentioned code fail? Is the setq only valid for the very next instruction?
Wishing you all the best for 2021!
Patrick

Comments
That way, there would be not any "cancelled", nor decision-based-skipped instructions, in between SETQ and the RDLONG/WRLONG relying on Q's value, since the instruction pipeline would not be disturbed in any way.
It would look like the following:
hub_cog_transfer rdlong buf_ptr,bufAdr skipf transfermode ' transfermode would hold #%100 for a wrlong transfer, or #%010 for a rdlong one. setq #128-1 ' setq to 128 longs to transfer wrlong speed_buf,buf_ptr rdlong speed_buf,buf_ptr hub_cog_transfer_ret retJust in time: Happy New Year to you all!
An aside: The hidden Q register set by SETQ can be accessed independent of SETQ as well. MUXQ can read Q at any time. XORO32, RDLUT and GETXACC all write to Q. Some cordic ops and COGINIT clear Q by default. CRCNIB uses Q as a work register so needs IRQ shielded to prevent corruption.
or
hub_cog_transfer rdlong buf_ptr,bufAdr skipf transfermode ' transfermode = 0 for read, %10 for write setq #128-1 ' setq to 128 longs to transfer _ret_ rdlong speed_buf,buf_ptr _ret_ wrlong speed_buf,buf_ptrI tested both proposed variants and they work just as expected.
There is still a lot for me to learn and discover regarding the P2 programming, but I must admit, that the P2 is a very powerful chip.
To give you an example:
The above code replaces all this of the orginal P1 "mb_rawb_spi" code by Jonathan "lonesock" Dummer, which for the P1 was already an incrediby fast solution for the hub <-> cog transfer.
hub_cog_transfer ' setup for all 4 passes mov ctrb,clockXferMode mov frqb,#1 rdlong buf_ptr,bufAdr mov ops_left,#4 movd transfer_long,#speed_buf four_transfer_passes ' sync to the Hub RAM access rdlong tmp1,tmp1 ' how many long to move on this pass? (512 bytes / 4)longs / 4 passes mov tmp1,#(512 / 4 / 4) ' get my starting address right (phsb is incremented 1 per clock, so 16 each Hub access) mov phsb,buf_ptr ' write the longs, stride 4...low 2 bits of phsb are ignored transfer_long rdlong 0-0,phsb add transfer_long,incDest4 djnz tmp1,#transfer_long ' go back to where I started, but advanced 1 long sub transfer_long,decDestNminus1 ' offset my Hub pointer by one long per pass add buf_ptr,#4 ' do all 4 passes djnz ops_left,#four_transfer_passes ' restore the counter mode mov frqb,#0 mov ctrb,clockInMode hub_cog_transfer_ret retThere's Occam's Razor, shaving again!
I'm kind of anticipating (crystal ball lits on...): someday, somewhere, someone will be asking for just a few MORE instructions to be ADDED to any given snippet, in order to justify starting another COG... :LOL:
If there is a fixed difference between [bufAdr] and [buf_ptr], then the time between RDLONG and RDLONG/WRLONG can be determined and one or both of SKIPF and SETQ might be effectively "zero-cycle" instructions.
I don't like to see a RET if _RET_ will do. Sometimes, however, adding a RET can save code overall: