Byte Array In Cog
JonnyMac
Posts: 9,556
I have a PASM driver that I'd like to add a buffer to. In short, I'd like to create a block of longs but access it as an array of bytes. I'm sure I could work out the read/write access code myself, but on the chance someone else has tackled this task, I'd love to see it.

Comments
http://code.google.com/p/spinneret-web-server/source/browse/trunk/MultiSocketServer_MikeG/StringMethods.spin
Click the "View raw file" link in the File Info box on the right side of the page.
While this is possible, I recommend storing the bytes in the hub - as packing/unpacking bytes would be more complicated.
Using the hub would also be faster...
I think very highly of your opinion, Bill, so I'm going to go with the hub.
@Mike: I'm still going to have a look at your code as I think the exercise may be worthwhile, anyway; even if I don't use it on this particular project.
Read routine
' Read byte from cog array ' -- "cbidx" is byte index to read from, 0 to 63 ' -- "bval" is byte read read mov t1, #cbuf ' point to cbuf[0] mov t2, cbidx ' make copy of byte index shr t2, #2 ' convert to long index add t1, t2 ' convert to array address movs :rdcell, t1 ' fix mov instruction nop :rdcell mov bval, 0-0 ' read long holding byte mov t2, cbidx ' make copy of byte index and t2, #%11 ' convert to byte pos in long shl t2, #3 ' convert to bit count shr bval, t2 ' move target to lsb and bval, #$FF ' clean up read_ret retWrite routine
' Write byte to cog array ' -- "cbidx" is byte index to write to, 0 to 63 ' -- "bval" is byte written write mov t1, #cbuf ' point to cbuf[0] mov t2, cbidx ' make copy of byte index shr t2, #2 ' convert to long index add t1, t2 ' convert to array address movs :rdcell, t1 ' fix mov instruction nop :rdcell mov t3, 0-0 ' read long holding byte mov t2, cbidx ' make copy of byte index and t2, #%11 ' convert to byte pos in long shl t2, #3 ' convert to bit count mov t4, #$FF ' create bit mask shl t4, t2 ' align with target byte andn t3, t4 ' clear old byte and bval, #$FF ' clean up shl bval, t2 ' adjust target to byte position or bval, t3 ' put into long cell movd :wrcell, t1 ' fix move instruction nop :wrcell mov 0-0, bval ' update array write_ret retOnce it's fully tested I'll do speed tests to compare using a byte array in the hub.
Does this mean that extracting a byte from a long taken from Cog-RAM needs more clock-cycles because you have to use more commands than retrieving the byte from HUB-RAM, ?
best regards
Stefan
Even if I want it as a PASM subroutine, reading a byte from hub ram is far easier than extracting from a cog long as I did above.
read mov t1, bufpntr ' point to hub buf[0] add t1, bidx ' point to hub buf[bidx] rdbyte bval, t1 ' bval := buf[bidx] read_ret retStill, I think there must be some cases where having the bytes in the COG would be faster...
I do have a code where I had an array of words starting at cog address 0.
Starting from address 0 saves an instruction or two when accessing...
But, I didn't try to have 2 words in each long, so it wasn't compacted.
So, if you can't have one long for every byte in your array, then Bill is probably right.
Your code is absolute correct - and faster than using cog longs
A small modification makes it potentially faster for subsequent reads:
read mov t1, bufpntr ' point to hub buf[0] add t1, bidx ' point to hub buf[bidx] read_next rdbyte bval, t1 ' bval := buf[bidx] add t1,#1 read_next_ret read_ret retThis way, you call "read" to get the first byte, and "read_next" to get following bytes.
Here's a mod that tightens up your original read code a bit:
rd_byte mov t1,index ror t1,#2 add t1,#byte_buf movs load_long,t1 rol t1,#5 load_long mov value,0-0 shr value,t1 and value,#$ff rd_byte_ret ret byte_buf res 32 t1 res 1 index res 1 value res 1BTW, if index can be volatile, you can just use it instead of t1 to eliminate one more instruction.
-Phil
rd_byte call #access and rd_value,#$ff rd_byte_ret ret wr_byte call #access andn rd_value,#$ff or rd_value,wr_value movd store_long,load_long rol rd_value,t1 store_long mov 0-0,rd_value wr_byte_ret ret access mov t1,index ror t1,#2 add t1,#byte_buf movs load_long,t1 rol t1,#5 load_long mov rd_value,0-0 ror rd_value,t1 access_ret ret byte_buf res 32 t1 res 1 index res 1 rd_value res 1 wr_value res 1-Phil
http://forums.parallax.com/showthread.php?132672-my-call-rutine-of-getting-single-byte-from-cog-ram-long
Exactly, it is because it takes more instructions. To be faster, you'd have to be able to read a byte (or write one) from/to a long in the cog in less than 20-22 cycles (less than 5 regular instructions)
loop call #rd_byte call #wr_byte jmp #loop rd_byte call #access and rd_value,#$ff rd_byte_ret ret wr_byte call #access andn rd_value,#$ff or rd_value,wr_value movd store_long,load_long rol rd_value,t1 store_long mov 0-0,rd_value wr_byte_ret ret access mov t1,index ror t1,#2 add t1,#byte_buf movs load_long,t1 rol t1,#5 load_long mov rd_value,0-0 ror rd_value,t1 access_ret ret byte_buf res 32 t1 res 1 index res 1 rd_value res 1 wr_value res 1I am trying to understand the tricks used in this bit of code and have a couple of questions:
1) I understand < movs load_long, t1 > but I do not understand < movd store_long, load_long >. How does the index address get properly loaded for the write function?
2) I tried to use PASD to look at register values during these code moves but get stymied when looking at the self-modifying code because PASD does not breakout the 9 bit literal values very readily. Is there any suggestion to help understanding how to better use the debugger to interpret self-modified instructions.
This has been a good tutorial for me.
Regards,
sm
Thank you.
sm