Passing a Long in Prop Assembly
I've read the pertinent manual sections repeatedly, and have done a search on the forum, but I still can't get this to work.
The intention of the code is something very simple, to take a variable from Hub RAM, do something to it, and then return it to Hub RAM. In this case, I'm just taking the baby-step of just adding 1 to a variable from Hub RAM, but all I get returned is the ADDR of the variable. I need some way to de-reference the MEM variable.
Any suggestions?
I'm using the PASD debugger, so I can see what it's doing. That part of the code I've deleted because it's just so much noise.
Basically the code should take X0, add one to it, and then put it back in the X0 location in main memory. Instead, it puts the address value of X0 and adds one to it and then puts that into main hub RAM.
It's the whole issue of pointers/dereferencing, just like in C++.
The intention of the code is something very simple, to take a variable from Hub RAM, do something to it, and then return it to Hub RAM. In this case, I'm just taking the baby-step of just adding 1 to a variable from Hub RAM, but all I get returned is the ADDR of the variable. I need some way to de-reference the MEM variable.
Any suggestions?
I'm using the PASD debugger, so I can see what it's doing. That part of the code I've deleted because it's just so much noise.
Basically the code should take X0, add one to it, and then put it back in the X0 location in main memory. Instead, it puts the address value of X0 and adds one to it and then puts that into main hub RAM.
It's the whole issue of pointers/dereferencing, just like in C++.
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
VAR
long x0
OBJ
PUB TestMessages
repeat
x0 :=5
cognew(@entry, @x0) 'Launch assy, pass Shared addr
Repeat
waitcnt(clkfreq + cnt)
DAT
org 0
entry
mov Mem, PAR 'Retrieve shared memory addr and put it in Mem
mov ValReg, #0 'Clear value in ValReg
mov ValReg, Mem ' Move Mem to ValReg. This is the mistake, I want the value held in Mem, not the address of Mem
add ValReg, #1
wrlong ValReg, Mem 'Move ValReg value to Shared
:endless jmp #:endless
Mem res 1
ValReg res 1

Comments
To read the value at the address, "5" in this case, you need to use "rdlong ValReg, Mem"
Delete your second and third "mov" commands and use the "rdlong" command instead.
BTW, JonnyMac has several good SpinZone articles on using PASM. The light bulb finally went on for me while working through one of his examples. There's a link to his articles in post #3 of my index (see signature).
Corrected code for future reference:
VAR long x0 OBJ PUB TestMessages repeat x0 :=5 cognew(@entry, @x0) 'Launch assy, pass Shared addr repeat waitcnt(clkfreq + cnt) DAT org 0 entry mov Mem, PAR 'Retrieve shared memory addr and put it in Mem rdlong ValReg, Mem add ValReg, #1 wrlong ValReg, Mem 'Move ValReg value to Shared :endless jmp #:endless Mem res 1 ValReg res 1Maybe it'd be nice to see something a bit more elaborate in the Prop manua under PAR, distinguishing between pointers and contents for this operation. All I saw was this, which leaves out that important line:
VAR long Shared 'Shared variable (Spin & Assy) PUB Main | Temp cognew(@Process, @Shared) 'Launch assy, pass Shared addr repeat <do something with Shared vars> DAT org 0 Process mov Mem, PAR 'Retrieve shared memory addr :loop <do something> wrlong ValReg, Mem 'Move ValReg value to Shared jmp #:loop Mem res 1 ValReg res 1I tag this onto a spin program for development, then trim and move to its own file if what I do is useful as a stand-alone object.
var long cog long cmd long value pri start stop ' stop if running cog := cognew(@entry, @cmd) + 1 ' lauch the cog return cog ' return load status pri stop if (cog) ' if running cogstop(cog - 1) ' stop cog := 0 ' mark stopped longfill(@cmd, 0, 2) pri run_command(c, v, wait) repeat while (cmd) ' let previous command finish value := v ' setup value (do this first!) cmd := c ' enable pasm cog if (wait) repeat while (cmd) return value dat { pasm code } org 0 entry mov r1, #0 wrlong r1, par ' clear cmd get_cmd rdlong r1, par wz ' look for command if_z jmp #get_cmd ' if 0, try again mov r2, par ' r2 = hub address of cmd add r2, #4 ' r2 = hub address of value rdlong r2, r2 ' r2 = value cmp r1, #1 wz ' cmd == 1? if_e jmp #cmd1 cmp r1, #2 wz if_e jmp #cmd2 cmp r1, #3 wz if_e jmp #cmd3 bad_cmd jmp #entry cmd1 ' do something with value in r2 shl r2, #1 ' multiply by 2 jmp #cmd_exit cmd2 ' do something with value in r2 sar r2, #1 ' signed divide by 2 jmp #cmd_exit cmd3 ' do something with value in r2 adds r2, #3 ' add 3 jmp #cmd_exit cmd_exit mov r1, par ' point to cmd add r1, #4 ' advance pointer to value wrlong r2, r1 ' write r2 to value jmp #entry ' -------------------------------------------------------------------------------------------------- r1 res 1 r2 res 1 fit 496I'm going to try that out.
Link: http://classic.parallax.com/downloads/propeller-spin-zone-articles-and-code
BTW, it seems that the PASM takes a #4 jump in memory to just go one more memory location, huh? Intuition would tell me it would be just as simple as adding 1, but apparently you have to add 4 to move one.
H
Note that PASM sees the cog as an array of longs, so you would use 1 when advancing an address within the cog. Here's an example from an LED driver I wrote.
dat { single-shot ws2812 driver } org 0 ws2812ss rdlong r1, par ' hub address of parameters -> r1 movd :read, #resettix ' location of cog parameters -> :read(dest) mov r2, #6 ' get 6 parameters :read rdlong 0-0, r1 ' copy parameter from hub to cog add r1, #4 ' next hub element add :read, INC_DEST ' next cog element djnz r2, #:read ' done?The value in INC_DEST is 1 shifted left by nine bits to put it into the destination field of the instruction (INC_DEST is for increment destination).
What I'm looking for is a trick to basically get the timing right. I'm having the assembly program do the Bresenham algorithm and then send the results to the hub, but only at the right time, after each calculation. The problem is that the timing isn't right. I want to do it sort of like a DataReady bit in a serial protocol, where the cog tells the the hub another piece of data is ready, and to output the data to Parallax Serial Terminal. The Brensenham is lightning fast, so I wanted to the cog to say, "Data is ready" and the hub to say "I'm done outputting the data, it's OK to proceed with another calculation." In this sample, I eliminated all the irrelevant stuff. Instead of a Bresenham, I'm just adding 5 to a counter and uploading it to the hub.
I'd like to use assembly in the Hub, but I know that's not permitted.
CON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 VAR long Cog, TestVar long x0 long TxControl long x_value_from_cog OBJ pst: "Parallax Serial Terminal" ' dbg : "PASDebug" '<---- Add for Debugger PUB TestMessages ''Send test messages to Parallax Serial Terminal. pst.Start(57_600) x0 :=5 TxControl:=0 'When TxControl is 0, sending data to PST is disabled cognew(@entry, @x0) 'Launch assy, pass Shared addr repeat 'Blocking function, waiting for TxControl to if TxControl==0 'equal 1. When it is 1, do the output to next 'the terminal Pst.NewLine pst.Str(String(pst#NL, "Inside SpinLoop")) pst.Dec(x_value_from_cog) TxControl :=0 'Tell the cog it's done with output to PST, and proceed DAT org 0 entry mov X0Pntr, PAR 'Retrieve shared memory addr and put it in X0Pntr rdlong X0cog, X0Pntr 'Retrieve X0 loop add X0cog, #10 'just something simple like adding 10 to a number cmp X0cog, #120 wc 'the real code would have the Bresenham here. if_nc jmp done mov X0Pntr, PAR 'Get to memory location of x_value_tx add X0Pntr, #8 mov Output_X, X0cog 'and move Output_X into it wrlong Output_X , X0Pntr Update_Data_Flag mov X0Pntr, PAR 'Get to memory location of TxControl add X0Pntr, #4 'and set it to 1, so that Spin section knows mov temp, #1 'that data is ready wrlong temp, X0Pntr Wait_Until_Main_Done rdlong temp, X0Pntr 'delay so that MainCog has time to send data to PST rdlong Delay, #0 'Get clock frequency shr Delay, #2 'Divide by 4 mov Time, cnt 'Get current time add Time, Delay 'Adjust by 1/4 second waitcnt Time, Delay 'Wait for 1/4 second cmp temp, #1 wz if_nz jmp Wait_Until_Main_Done jmp loop done jmp done X0Pntr res 1 'X0Pntr points to MainCogRam memory X0cog res 1 temp res 1 Delay res 1 Time res 1 Output_X res 1label ... jmp #labelThen there is something wrong with the wait for the Flag from Spin: You set the TxControl to 1 in PASM and wait then until it is 1. So you don't wait - you need to wait until Spin sets it to zero. Then you don't need the 250ms delay anymore.Andy
OK, I'll try that tonight. I had a weird error where the compiler said basically that the label doesn't exist, but it did. I took out the : or the # (can't remember) and then it compiled OK.
I was trying various options with the delay, etc. Assembly is very, very fast, so I put that delay in. Thanks, btw.
' Send test messages to Parallax Serial Terminal. ' to show how a cog can get data from the MAIN hub, ' do something to it using lightning-fast assembly, ' and then send it back up to the MAIN hub to be used as needed. CON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 VAR long Cog, TestVar 'Don't change the order of the variables. Pointers in use! long x0 long TxControl long x_value_from_cog OBJ pst: "Parallax Serial Terminal" PUB TestMessages pst.Start(57_600) x0 :=5 TxControl:=0 'When TxControl is 0, sending data to PST is disabled cognew(@entry, @x0) 'Launch assy, pass Shared addr repeat 'Blocking function, waiting for TxControl to if TxControl==0 'equal 1. When it is 1, do the output to next 'the terminal Pst.NewLine pst.Str(String(pst#NL, "Inside SpinLoop")) pst.Dec(x_value_from_cog) TxControl :=0 'set it back equal to 0 to tell the cog assembly OK to cont.' DAT org 0 entry mov X0Pntr, PAR 'Retrieve shared memory addr and put it in X0Pntr rdlong X0cog, X0Pntr 'Retrieve X0 using the pointer loop add X0cog, #10 'Do something pretty useless, just to do something in cmp X0cog, #120 wc 'CogRAM if_nc jmp #done mov X0Pntr, PAR 'Get to memory location of x_value_tx add X0Pntr, #8 mov Output_X, X0cog 'and move Output_X into it wrlong Output_X , X0Pntr Update_Data_Flag mov X0Pntr, PAR 'Get to memory location of TxControl add X0Pntr, #4 'and set it to 1, so that Spin section knows mov temp, #1 'that data is ready wrlong temp, X0Pntr Wait_Until_Main_Done rdlong temp, X0Pntr cmp temp, #1 wz if_z jmp #Wait_Until_Main_Done jmp #loop done jmp #done X0Pntr res 1 'X0Pntr points to MainCogRam memory X0cog res 1 temp res 1 Output_X res 1BTW, what does "0-0" do in Johnny Mac's code? I'm not sure if that's a number, or a calculation, or maybe just trying to say, "put your variable here".
The 0-0 indicates that the data there is modified by some other code in the program.