Use of PASM res statement
David Betz
Posts: 14,530
Will the following code work? I have a feeling that someone once told me that I had to put all of my "res" statements at the end of my PASM code. Should I change all of the "res 1" statements to "long 0"?
'' Modified for use with PropGCC by David Betz
'' Derived from:
'' File....... jm_ws2812.spin
'' Purpose.... 800kHz driver for WS2812 LEDs
'' Author..... Jon "JonnyMac" McPhalen
'' Copyright (c) 2013 Jon McPhalen
pub driver
return @ws2812
dat
org 0
ws2812 jmp #ws2812_cont
txpin res 1 ' tx pin #
ledcount res 1 ' # of rgb leds in chain
resettix res 1 ' frame reset timing
bit0hi res 1 ' bit0 high timing
bit0lo res 1 ' bit0 low timing
bit1hi res 1 ' bit1 high timing
bit1lo res 1 ' bit1 low timing
hubpntr res 1 ' pointer to rgb array
ws2812_cont mov txmask, #1 ' create mask for tx
shl txmask, txpin
andn outa, txmask ' set to output low
or dira, txmask

Comments
CON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 VAR long LED_pin long rate PUB Main LED_pin := 16 rate := clkfreq / 10 cognew(@pasm,@LED_pin) DAT PASM t1 res 1 LED_mask res 1 t2 res 1 delay_time res 1 org _1 mov t1,par ' This line overwrites itself _2 mov LED_mask,#1 ' as does this one _3 rdlong t2,t1 ' and this one _4 shl LED_mask,t2 add t1,#4 rdlong delay_time,t1 ' This line overwrites _4 or dira,LED_mask mov cnt,delay_time add cnt,cnt :loop waitcnt cnt,delay_time xor outa,LED_mask jmp #:loop {{ If the res's are located at the bottom, _1 through _4 contain: _1 %10100000101111000111011111110000 _2 %10100000111111000111100000000001 _3 %00001000101111000111101000111011 _4 %00101100101111000111100000111101 With the res's located above the org, _1 %00000000000000000000000011111100 _2 %00000000000000010000000000000000 _3 %00000000000000000000000000010000 _4 %00000000011110100001001000000000 }}It might be useful for saving cog memory by overwriting one-time instructions.Dunno if I'd ever use it simply due to how unreadable / unmaintainable it could make the code if used for anything more complicated.
Having all RES at the end is the simplest to make it always work.
But if you know what you do, then you can use it for some tricks like in the code snippet you posted. Here the RES is used to give CogReg1 ..8 alternative names, to use it later as variables that overlay the Init code, which is only used once at startup of the cog.
( I think thats the case here, but without seeing the whole code I can't tell for sure).
Andy
Edit: Looking again at the code, this only would work if there is another ORG 1 before the Init code.
'' Modified for use with PropGCC by David Betz '' Derived from: '' File....... jm_ws2812.spin '' Purpose.... 800kHz driver for WS2812 LEDs '' Author..... Jon "JonnyMac" McPhalen '' Copyright (c) 2013 Jon McPhalen {{ // parameter structure typedef struct { uint32_t pin; uint32_t *colors; uint32_t count; } ws2812_params; // driver header structure typedef struct { uint32_t jmp_inst; uint32_t resettix; uint32_t bit0hi; uint32_t bit0lo; uint32_t bit1hi; uint32_t bit1lo; } ws2812_hdr; }} pub driver return @ws2812 dat org 0 ws2812 jmp #ws2812_cont resettix long 0 ' frame reset timing bit0hi long 0 ' bit0 high timing bit0lo long 0 ' bit0 low timing bit1hi long 0 ' bit1 high timing bit1lo long 0 ' bit1 low timing ws2812_cont mov t1, par ' get the pin number rdlong t2, t1 mov txmask, #1 ' create mask for tx shl txmask, t2 andn outa, txmask ' set to output low or dira, txmask add t1, #4 rdlong hubpntr, t1 ' get the buffer address add t1, #4 rdlong ledcount, t1 ' get the led count mov t2, #0 ' init is done wrlong t2, t1 rgbmain mov bittimer, resettix ' set reset timing add bittimer, cnt ' sync timer waitcnt bittimer, #0 ' let timer expire mov addr, hubpntr ' point to rgbbuf[0] mov nleds, ledcount ' set # active leds frameloop rdlong colorbits, addr ' read a channel add addr, #4 ' point to next ' Shifts long in colorbits to WS2812 chain ' ' WS2812 Timing (slot is 1.25us for 800kHz) ' ' 0  0.35us / 0.80us ' 1  0.70us / 0.60us ' ' At least 50us (reset) between frames ' ' This routine manipulates the value in colorbits so that elements are ' transmitted GRB as required by the WS2812. Rearrange-on-the-fly code ' trick by TonyP12 in the Propeller forum. ' ' Entry $00_RR_GG_BB ' Step 1 $BB_00_RR_GG ' Step 2-24 $GG_BB_00_RR - when nbits == 24 ' $BB_00_RR_GG - after sending GG ' Step 2-16 $RR_GG_BB_00 - when nbits == 16 ' $GG_BB_00_RR - after sending RR ' Step 2-8 $BB_00_RR_GG - when nbits == 8 shiftout ror colorbits, #8 ' {1} to offset the rol 24 below mov nbits, #24 ' shift 24 bits (3 x 8) :loop test nbits, #%111 wz ' {2} nbits at 24, 16 or 8? if_z rol colorbits, nbits ' if yes, modify colorbits rol colorbits, #1 wc ' msb --> C if_c mov bittimer, bit1hi ' set bit timing if_nc mov bittimer, bit0hi or outa, txmask ' tx line 1 add bittimer, cnt ' sync bit timer if_c waitcnt bittimer, bit1lo if_nc waitcnt bittimer, bit0lo andn outa, txmask ' tx line 0 waitcnt bittimer, #0 ' hold while low djnz nbits, #:loop ' next bit djnz nleds, #frameloop ' done with all leds? jmp #rgbmain ' back to top ' -------------------------------------------------------------------------------------------------- hubpntr res 1 ' pointer to rgb array ledcount res 1 ' # of rgb leds in chain txmask res 1 ' mask for tx output bittimer res 1 ' timer for reset/bit addr res 1 ' address of current rgb bit nleds res 1 ' # of channels to process colorbits res 1 ' rgb for current channel nbits res 1 ' # of bits to process t1 res 1 ' work vars t2 res 1 fit 496 {{ Terms of Use: MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. }}The idea is that the C code that loads this driver will overwrite the variable in right after the initial jmp instruction with values it computes for the protocol timing. This eliminates having to pass each of these as parameters to the COG code and then fetch them to store them into local registers. It's how a number of the PropGCC drivers are written. So overlaying instructions won't really work here. To get around that problem I've changed all of the "res 1" statements to "long 0".By the way, thanks JonnyMac for your elegant code!
BTW, and it's noted in the code, I got a great assist from TonyP12 with rearranging the RGB long to GRB.
Just last night a friend pointed out that Adafruit has a link to my WS2812 object in ObEx. As a community, we could probably do more to show them that the Arduino, while the most popular kid in school right now, isn't necessarily the smartest. With the popularity of WS2812 LED strips and modules, your project in C could well be an invitation for those struggling to get more performance out of their Arduinos.