Today I decided to try out a toggle program that is done in PropellerGCC using SimpleIDE, in the default setup. Some general observations:
SimpleIDE -> Code Size 2,388 bytes (2,560 total)
Simulator -> COG RAM 496(Where did the 16 lines of COG RAM go?), HUB RAM 2396 bytes
What is now residing in the COG RAM, is it the standard interpreter or something else? Is the C toggle program being converted to PASM code and then run or is it the HUB RAM byte code method? When I do a Step, it seems like it is just looping between $002 and $006 lines.
Maybe a better thing to try would be toggle program that is done in a way that it could be run in 'COG Mode' instead of 'CMM Mode'. Now I am thinking what would the program look like in 'LMM Mode'.
Ray
/*
Blank Simple Project.c
http://learn.parallax.com/propeller-c-tutorials
*/
#include "simpletools.h" // Include simple tools
int main() // Main function
{
// Add startup code here.
while(1)
{
// Add main loop code here.
pause(1000);
high(16);
pause(1000);
low(16);
}
}
I thought I would do a 'COG Mode' version using SimpleIDE.
SimpleIDE -> Code Size 224 bytes (224 total)
Simulator -> COG RAM 496, HUB RAM 3840
PASM Toggle -> COG RAM 496, HUB RAM ~80
Now it looks like the C code(HUB RAM bytes?) gets translated to PASM and then run through the standard interpreter. If you compare the PASM Toggle numbers to this program numbers you get a feel for what the C overhead is, I think. Now I am not so sure if this C version is an apples to apples comparison, code wise, to the PASM Toggle program.
The one question that I do have is, is there a way to run the PASM code directly through the processor, without having a standard interpreter, and still have it work as expected? It seems like so far, the things that I have tried, the PASM code gets pushed through a standard interpreter that sits in the COG RAM. What does all this mean? :-)
Ray
/**
* This is the main SimTest2 program file.
*/
#include <propeller.h>
int main(void)
{
int mask = 1 << 16;
while(1)
{
OUTA |= mask;
DIRA |= mask;
waitcnt(80000000 + CNT);
OUTA &= ~mask;
DIRA |= mask;
waitcnt(80000000 + CNT);
}
return 0;
}
Every Propeller program starts life as a Spin program. It doesn't matter what language is used.
The loader inside the chip is a PASM program on COG 0 that reads Spin bytes from the serial port or the eeprom. Then, the loader starts the Spin interpreter on COG 0 to run the Spin program. The simulator skips the first step (no pesky loader issues!)
In Propeller GCC, there are various "interpreters" that run CMM, LMM, or XMM programs. The only C programs not interpreted are built and run with COGC mode, but it still needs to be booted up by Spin.
A COGC program completely replaces the Spin interpreter with itself, so that the only thing running on the Propeller is PASM.
Yes, that helps. What I was waiting for is for someone to explain the actual procedure in some precise verbiage for the viewing audience. That should work for everybody.
Now onto some PASM stuff. Below is a program that does not really do what I was expecting, separate COGs toggling a specified pin. Instead what I am getting is P16 toggling, and P3,P4,P5 toggling, at different rates. I am doing a cognew(@Toggle1,0), I was expecting to see a *COG[1] when the program got loaded, but everything is in *COG[0].
Ray
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
PUB Main
cognew(@Toggle1,0)
{Launch cog to toggle P16 endlessly}
coginit(0,@Toggle, 0)
DAT
{Toggle P16}
org 0
Toggle mov dira, Pin
mov Time, cnt
add Time, Delay
:loop waitcnt Time, Delay
xor outa, Pin
waitcnt Time, Delay
xor outa, Pin
jmp #:loop
Toggle1 mov dira, Pin1
mov Time1,cnt
add Time1, Delay1
:loop waitcnt Time1,Delay1
xor outa, Pin1
waitcnt Time1,Delay1
xor outa,Pin1
jmp #:loop
Pin long |< 16
Delay long 80_000_000
Time res 1
Pin1 long |< 17
Delay1 long 80_000_000
Time1 res 1
The main problem with your program is that (most likely because I haven't tested it) Toggle1 needs to have ORG in the same way that Toggle does. The ORG directive sets the internal register addressing.
Btw, I've found in brief testing that the simulator is still having trouble with waitcnt (oyvey!) even if the clock is set to 80MHz. One example of this is if Delay in your example is set to 80_000_000/4. I'm not sure when I'll have time to address that.
Once you put the ORG in for the second COGs code, you need to move the data for the first COG under its ORG and keep the data for the second COG where it is.
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
PUB Main
cognew(@Toggle1,0)
{Launch cog to toggle P16 endlessly}
coginit(0,@Toggle, 0)
DAT
{Toggle P16}
org 0
Toggle mov dira, Pin
mov Time, cnt
add Time, Delay
:loop waitcnt Time, Delay
xor outa, Pin
waitcnt Time, Delay
xor outa, Pin
jmp #:loop
Pin long |< 16
Delay long 80_000_000
Time res 1
org 0
Toggle1 mov dira, Pin1
mov Time1,cnt
add Time1, Delay1
:loop waitcnt Time1,Delay1
xor outa, Pin1
waitcnt Time1,Delay1
xor outa,Pin1
jmp #:loop
Pin1 long |< 17
Delay1 long 80_000_000
Time1 res 1
Basically, what will be loaded into a COG is from ORG to ORG (or end of source code) starting from the label you put in the COGNEW or COGINIT. The PASM instructions and any defined data need related to one COG to be under the same ORG. Anything defined with a RES should be at the end of the ORG section. Page 341 of the V1.2 Propeller Manual explains this very well.
With these changes, your program runs on a real Propeller just fine. It actually runs in the simulator with both COGs running the PASM code as expected. The only simulator issue I see is the waitcnt problem in DEBUG mode that Steve mentioned above. RUN mode is pretty close to proper timing.
With these changes, your program runs on a real Propeller just fine. It actually runs in the simulator with both COGs running the PASM code as expected. The only simulator issue I see is the waitcnt problem in DEBUG mode that Steve mentioned above. RUN mode is pretty close to proper timing.
Actually I have no plan to change the DEBUG mode because it should be "cycle accurate" (at some point) to allow counting. Traditionally waitcnt in DEBUG mode have resulted in horrible hangs, and I don't want that.
I would like to see RUN behave correctly, just like a clock down to millisecond resolution (although not completely deterministic because of PC multitasking).
Actually I have no plan to change the DEBUG mode because it should be "cycle accurate" (at some point) to allow counting. Traditionally waitcnt in DEBUG mode have resulted in horrible hangs, and I don't want that.
I would like to see RUN behave correctly, just like a clock down to millisecond resolution (although not completely deterministic because of PC multitasking).
I don't have a problem with DEBUG timings/operations the way they are. I think it would get pretty bazaar, trying to keep WAITCNT accurate with different clockrates to simulate plus figuring in the delay factor. I misunderstood your WAITCNT statement above.
I'm just having fun playing with the simulator and think it's a great learning/teaching/testing tool to add to the arsenal. I'd like to say it will increase my Propeller productivity! (I'd like to say I just won a Lottery too!!)
I verified that the program below works as expected on my QS board, both P17 and P16 toggling at the same time.
On the Simulator I was expecting to see P17 and P16 toggling at the same time, but it seems that P17 toggles first, then P16 toggles, and so on. Having looked at the Simulator, can I make the assumption that COG[0] RAM has an interpreter running the Toggle 16 code, and that COG[1] RAM has its own interpreter running the Toggle 17 code? How do you now how much COG RAM space you have left to work with?
Is there such a thing as having global variable(s) in the PASM realm? I mean could you, for instance, turn off the toggling of P17 from some code in P16, without resorting too stopping and starting COG[1]?
Ray
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
PUB Main
{Launch COG 1, in this setup, to toggle P17 enslessly }
cognew(@Toggle1,0)
{Launch cog to toggle P16 endlessly}
coginit(0,@Toggle, 0)
DAT
{Toggle P16}
org 0
Toggle mov dira, Pin
mov Time, cnt
add Time, Delay
:loop waitcnt Time, Delay
xor outa, Pin
waitcnt Time, Delay
xor outa, Pin
jmp #:loop
Pin long |< 16
Delay long 80_000_000
Time res 1
{ Toggle P17 }
org 0
Toggle1 mov dira, Pin1
mov Time1, cnt
add Time1, Delay1
:loop waitcnt Time1, Delay1
xor outa, Pin1
waitcnt Time1, Delay1
xor outa, Pin1
jmp #:loop
Pin1 long |< 17
Delay1 long 80_000_000
Time1 res 1
The P17 toggler started first, so it should blink first by a little at least.
Yes, there are globals ... it's called HUB RAM. Use rdlong wrlong (rdword, rdbyte, etc...) to access them. Usually globals are defined in VAR or DAT sections and can be set by Spin code. Read the book for the syntax.
The simulator itself interprets the COG programs, but the PASM you've shown doesn't use an interpreter once COG 0 is replaced. If you cognew a spin function there will be a new spin interpreter.
{{ PASM_IO.spin }}
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
PUB Main
' Make Pin#16 high/low depending if switch on Pin#0 is high/low
' will not work on a Quickstart using keypad - you need a
' real switch on Pin#0
'
' Replace the Spin interpreter on COG0 with your PASM code
coginit(0,@Toggle,0)
DAT
{Toggle P16}
org 0
Toggle mov dira, Pin ' make pin an output
:loop mov outa, #0 ' make all outputs low
mov temp, ina ' grab the inputs
and temp, #1 ' mask out all but P#0
tjz temp, #:loop ' loop if the input pin is low
mov outa, Pin ' else set output pin high
jmp #:loop ' and then loop
Pin long |< 16
temp res 1
Load it into the simulator and "Run" - you can check the box next to P0 on and off and watch P16 follow it. Go into DEBUG to watch the code run.
Ray, this is PASM, once it is loaded, NO INTERPRETERS are involved!
Steve, my employer thanks you for keeping me out of trouble at work for the good part of ANOTHER day!! (at least I imagine they would if they knew)
Ray, this is PASM, once it is loaded, NO INTERPRETERS are involved!
One of these days it will stick in brain.
The PASM_IO.spin program needs the driver for the touch pads to be included, for the program to work with the QS board, correct? That would be a good example, have the program functional with the Simulator and be able to work with the QS board, using the touch pads. Would be a good lesson in how to deal with drivers also.
The PASM_IO.spin program needs the driver for the touch pads to be included, for the program to work with the QS board, correct? That would be a good example, have the program functional with the Simulator and be able to work with the QS board, using the touch pads. Would be a good lesson in how to deal with drivers also.
Ray
A push button and a resistor was a lot easier to code for!
The problem is that the simulator probably won't work with the QS touch pad code because the simulator just simulates a simple push button or switch (as it should!) - it will be difficult to make it simulate the capacitive(?) buttons on the QS.
OK, maybe I should ask the question this way, if there was a PASM program in existence, that worked the pads on the QS board, what would be occurring if it were run on the Simulator? If I recall didn't somebody write a C program for that purpose, maybe if shows up it could be run in the Simulator.
From the software side, my guess is since reading the touch pads is timing sensitive, it may (probably would) have issues in RUN, would certainly have issues in DEBUG or STEP. It also works by "charging" the pads and then "discharging" them to determine they've been touched. There is no way to simulate that, it's a function of the physical hardware. A push button (or more correctly a toggle switch) is the modeled hardware in the simulator program.
Whie I was playing with this more today....I mean conducting important global business on conference calls,
I was thinking, "Gee, it would be neat to be able to somehow set a break point at PC = $000 for the PASM program you are playing with. Well, that's kinda hard to do since it isn't loaded yet. Steve could add somethign to the simulated COGxxxx instructions so it would stop after it loads the COG but before is starts running, but he has enough to do.
So, I used my meager PASM skill sand added this code to the front of my program:
Toggle mov temp, ina
and temp, #%10
tjz temp, #Toggle
Yes, this uses 4 longs but it does allow you to sit at the top of your code until you toggle an I/O pin (in this case, Pin#1).
To use it, you just put the code at the front of your COG code (among with a temp register), LOAD your program, make sure your input box is NOT checked, hit RUN...wait a while for all the loading to take place and then hit STOP. At this point, if you switch to your COG, you should see your PASM code with the PC on one of the first 3 instructions. Click your I/O box (Pin#1 in my example) and then step through your program until you are past the TJZ instruction. At this point, you are at the start of your REAL PASM code and can see what it does from the start. Clear your Input checkbox and you are ready to DEBUG, TRACE STEP or whatever through your code.
There's probably a cool PASM trick to do this in fewer instructions.
You can probably set a breakpoint on the instruction after the TJZ and set your Input checkbox and just DEBUG or RUN to the breakpoint but I haven't tried that yet. I just did the breakpoint thing - it works REALLY WELL!! But the above steps lets you see each step so you understand the process.
{{ PASM_IO.spin }}
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
PUB Main
' Make Pin#16 high/low depending if switch on Pin#0 is high/low
' will not work on a Quickstart using keypad - you need a
' real switch on Pin#0
'
' Replace the Spin interpreter on COG0 with your PASM code
coginit(0,@Toggle,0)
DAT
{Toggle P16}
org 0
Toggle waitpeq temp, #
mov dira, Pin ' make pin an output
:loop mov outa, #0 ' make all outputs low
mov temp, ina ' grab the inputs
and temp, #1 ' mask out all but P#0
tjz temp, #:loop ' loop if the input pin is low
mov outa, Pin ' else set output pin high
jmp #:loop ' and then loop
Pin long |< 16
temp long 0
This runs as expected on real hardware (DUH!)
When I simulate it, I LOAD and RUN with the Input checkbox cleared and STOP it. I go into my COG and I'm sitting on the WAITPEQ. I check the input box and set a breakpoint and hit debug. The CNT starts running but I still sit there - to RESULT field never changes even though my INA on the side panel shows $00000002. No combination of STOP, STEP or anything else I've tried gets it to read INA inside the WAITPEQ instruction.
If I set Input 1 immediately after the load, it of course, blows right through the WAITPEQ.
Haven't tried a WAITPNE but I assume it will be the same. No rechecking the INA register once inside the WAITPxx instruction??
EDIT: Just tried WAITPNE - results are similar (but inverted! )
My eyes started bleeding with any computer stuff once I crossed the 200 pound mark in 1999. Went north from there to 250 ... LOL. Now I'm only 220-ish.
I may have time to look at improvements again tomorrow.
Ray, I'll leave the C version of the button test to you...to paraphrase a popular forumite, "my eyes bleed when I read C"
Yes I can do the testing but I cannot remember where I saw that program, I do not think it was in the OBEX. I am wondering if there was a Spin program for that, maybe that would be good enough to run. But then if it is a Spin program, then you have byte code to worry about and at this point, the Simulator would not give any insight into PASM code aspect of the Spin program.
Yes I can do the testing but I cannot remember where I saw that program, I do not think it was in the OBEX. I am wondering if there was a Spin program for that, maybe that would be good enough to run. But then if it is a Spin program, then you have byte code to worry about and at this point, the Simulator would not give any insight into PASM code aspect of the Spin program.
Ray
The C code is right here where Steve said it was:
Try this program in the SimpleIDE workspace: SimpleIDE\Propeller GCC Demos\QuickStart\Whack-a-mole\qswam.side
OK, Ray, here's your quiz:
This is the QS button code from the Whack-a-mole program:
/*
* Get all buttons at once
* Run this function from HUB if compiled for LMM.
*/
int getButtons()
{
int n = 16;
int result = -1;
int reading = 0;
int pins = 0xFF;
OUTA |= pins; //output high to buttons
while(n--)
{
DIRA |= pins; //output high to buttons
DIRA ^= pins; //switch to input
reading = pins;
msleep(2); //wait for RC time
reading &= INA; //return button states
result &= reading;
}
result = ~result & 0xFF;
return result;
}
It's all C, and it's LMM, so what does that mean as far as what you will see in the simulator?
There may or may not be a PASM version, I'll look. There are several Spin versions. It will be interesting to see what all/any of these will do in the simulator versus real life. There's also a Forth version but I get scolded when I mention that!
At some point, it would be really cool to be able to simulate all the quirky hardware so someone could sit down with a QuickStart and the simulator and run on hardware and then on simulator and play and learn.
I took the Whack-a-mole program and compiled it, then I loaded into to Simulator, I loaded up the QS board and tried to compare would was flashing on the Simulator and on the QS board. The two where out of sink but it seemed like the Simulator was working just like the QS board. If the WAM program could be slowed down to where you could actually hit a button, of course in the Simulator you would have to have a quick mouse to work with, this could be an interesting way to kill some time.
The next step will be to look at what the Simulator reveals in terms of code, I hope it is not all in the HUB RAM. The SimpleIDE shows - Code Size 3,220 bytes (3,388 total), so it is not a small program.
It probably compiled in LMM, so what will be running in COG (after the inintial Spin interpreter loads and turns things over to PropGCC, of course) and what will be in HUBRAM? (In general terms, not specifically, long by long)
I decided to try some more basic stuff. The program below sort of works as expected, until it gets to the point where the pin is supposed too turn off. The program turns P16 on, but it does not turn P16 off, I thought that 'xor outa, Pin' was supposed to do that. When run on the QS board it works the same, P16 turns on, but not off. Is the program stuck at the waitcnt or do I have some concepts screwed up?
Ray
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
PUB Main
coginit(0,@Start,0)
DAT
org 0
Start
mov dira, Pin ' make pin an output
mov Time, cnt ' Calculate delay time
add Time, Delay
mov outa, Pin ' set output pin high
waitcnt Time, Delay ' Wait
xor outa, Pin ' make pin low?
Pin long |< 16
temp res 1
Delay long 80_000_000
Time res 1
1) all the RES need to be at the end of the code for a COG (after all the code and longs)
2) what did you expect the program to do after the XOR? It IS doing exactly what you told it to do....continuing to execute instructions. It see everything in the COG as an instruction and executes it. Most of the COG is filled with NOPs if you look in the simulator.
Here's the updated code with a "JMP #$" after the XOR - this will effectively halt the COG by making it execute that one instruction repeatedly.
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
PUB Main
coginit(0,@Start,0)
DAT
org 0
Start
mov dira, Pin ' make pin an output
mov Time, cnt ' Calculate delay time
add Time, Delay
mov outa, Pin ' set output pin high
waitcnt Time, Delay ' Wait
xor outa, Pin ' make pin low?
jmp #$ ' will halt a REAL COG
' jmp #$+1 ' uncomment this and next and comment out the above jmp to
' jmp #$-1 ' halt the simulator
Pin long |< 16
Delay long 80_000_000
Time res 1
temp res 1
I think you helped find a bug in the simulator, though.
When you run the above program in the simulator, it treats the JMP #$ as a JMP #$+1.
It appears to simulate a JMP #$-1 correctly and a JMP #$-1 correctly but stumbles on a JMP #$. It appears to have already incremented the PC so it jumps to the $+1 location instead of $.
So, if you want to halt the simulator, you just do this:
jmp #$+1
jmp #$-1
and it just sits and executes those two instruction back and forth....and back and forth....
Did not know about the RES having to be the last items, I thought they could be intermixed willy nilly, I hope you like my technical terms. I had completely forgotten that the processor keeps going and going, from the code start to code end, code start to code end ... I tried to put in a loop at the end, but my loop code did not work. It is a good reminder to know that you need a code loop for the processor, and a separate code loop for the Simulator. The original program, if you did a Load, Step, and then a Debug, you can see the processor loop that it is doing. Make sure you have your Delay set to ~250ms.
Another thing that I would like to know is how many different ways are there too set 'outa' to 0 and then back to1? Lets say you wanted to make two subroutines of code, one to set 'outa' to 0, and the other subroutine to set 'outa' to 1. I guess this would translate to pressing the touch pad on the QS board to turn on an LED and pressing it again to turn the LED off, of course this would show up in the Simulator as checking the box to keep the LED on in a constant state and unchecking to turn it off.
Here is my latest program which does not do what is expected. Even the Simulator Debug is not showing what I would expect, the P16 to go on/off. I tried to use 'flashon' and 'flashoff' as subroutines, but for some reason the 'ret' is not doing what I thought it should do. I was relying on the Simulator to give some clues as to what the problem is, but ...
Ray
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
PUB Main
coginit(0,@Start,0)
DAT
org 0
Start
mov dira, Pin ' make pin an output
mov Time, cnt ' Calculate delay time
add Time, Delay
:Main
waitcnt Time, Delay ' Wait
jmp :flashon
waitcnt Time, Delay ' Wait
jmp :flashoff
jmp :Main
:flashon mov outa, Pin ' set output pin high
ret
' waitcnt Time, Delay ' Wait
:flashoff xor outa, Pin ' make pin low?
ret
' waitcnt Time, Delay ' Wait
' jmp :flash
' Just in case
jmp #$ ' end processor loop
jmp #$+1 ' end Simulator loop
jmp #$-1
Pin long |< 16
Delay long 80_000_000
Time res 1
temp res 1
I have some updates to push, but I just haven't had time to finish testing. Maybe I can push them tonight.
Here are some highlights:
The spiral is being replaced with an analog and digital clock display.
The jmp #$ thing is fixed.
Instructions waitpne and waitpeq work (need to set WR).
The djnz issue works much better, but it still isn't perfect.
Stopping Run will update the HUB and COG displays.
Different clock frequencies can be used at startup.
Thinking that break on coginit thing can be an optio Rick ... not ready yet.
Comments
SimpleIDE -> Code Size 2,388 bytes (2,560 total)
Simulator -> COG RAM 496(Where did the 16 lines of COG RAM go?), HUB RAM 2396 bytes
What is now residing in the COG RAM, is it the standard interpreter or something else? Is the C toggle program being converted to PASM code and then run or is it the HUB RAM byte code method? When I do a Step, it seems like it is just looping between $002 and $006 lines.
Maybe a better thing to try would be toggle program that is done in a way that it could be run in 'COG Mode' instead of 'CMM Mode'. Now I am thinking what would the program look like in 'LMM Mode'.
Ray
SimpleIDE -> Code Size 224 bytes (224 total)
Simulator -> COG RAM 496, HUB RAM 3840
PASM Toggle -> COG RAM 496, HUB RAM ~80
Now it looks like the C code(HUB RAM bytes?) gets translated to PASM and then run through the standard interpreter. If you compare the PASM Toggle numbers to this program numbers you get a feel for what the C overhead is, I think. Now I am not so sure if this C version is an apples to apples comparison, code wise, to the PASM Toggle program.
The one question that I do have is, is there a way to run the PASM code directly through the processor, without having a standard interpreter, and still have it work as expected? It seems like so far, the things that I have tried, the PASM code gets pushed through a standard interpreter that sits in the COG RAM. What does all this mean? :-)
Ray
Every Propeller program starts life as a Spin program. It doesn't matter what language is used.
The loader inside the chip is a PASM program on COG 0 that reads Spin bytes from the serial port or the eeprom. Then, the loader starts the Spin interpreter on COG 0 to run the Spin program. The simulator skips the first step (no pesky loader issues!)
In Propeller GCC, there are various "interpreters" that run CMM, LMM, or XMM programs. The only C programs not interpreted are built and run with COGC mode, but it still needs to be booted up by Spin.
A COGC program completely replaces the Spin interpreter with itself, so that the only thing running on the Propeller is PASM.
Hope that helps.
Now onto some PASM stuff. Below is a program that does not really do what I was expecting, separate COGs toggling a specified pin. Instead what I am getting is P16 toggling, and P3,P4,P5 toggling, at different rates. I am doing a cognew(@Toggle1,0), I was expecting to see a *COG[1] when the program got loaded, but everything is in *COG[0].
Ray
The main problem with your program is that (most likely because I haven't tested it) Toggle1 needs to have ORG in the same way that Toggle does. The ORG directive sets the internal register addressing.
Btw, I've found in brief testing that the simulator is still having trouble with waitcnt (oyvey!) even if the clock is set to 80MHz. One example of this is if Delay in your example is set to 80_000_000/4. I'm not sure when I'll have time to address that.
A few other PASM gotchas:
Steve mentioned the ORG issue.
Once you put the ORG in for the second COGs code, you need to move the data for the first COG under its ORG and keep the data for the second COG where it is.
Basically, what will be loaded into a COG is from ORG to ORG (or end of source code) starting from the label you put in the COGNEW or COGINIT. The PASM instructions and any defined data need related to one COG to be under the same ORG. Anything defined with a RES should be at the end of the ORG section. Page 341 of the V1.2 Propeller Manual explains this very well.
With these changes, your program runs on a real Propeller just fine. It actually runs in the simulator with both COGs running the PASM code as expected. The only simulator issue I see is the waitcnt problem in DEBUG mode that Steve mentioned above. RUN mode is pretty close to proper timing.
Thanks Rick. PASM has too many caveats for one person to remember in less than 5 seconds. It's almost as bad as C++ LOL ;-)
Actually I have no plan to change the DEBUG mode because it should be "cycle accurate" (at some point) to allow counting. Traditionally waitcnt in DEBUG mode have resulted in horrible hangs, and I don't want that.
I would like to see RUN behave correctly, just like a clock down to millisecond resolution (although not completely deterministic because of PC multitasking).
I don't have a problem with DEBUG timings/operations the way they are. I think it would get pretty bazaar, trying to keep WAITCNT accurate with different clockrates to simulate plus figuring in the delay factor. I misunderstood your WAITCNT statement above.
I'm just having fun playing with the simulator and think it's a great learning/teaching/testing tool to add to the arsenal. I'd like to say it will increase my Propeller productivity! (I'd like to say I just won a Lottery too!!)
Need more coffee ....
On the Simulator I was expecting to see P17 and P16 toggling at the same time, but it seems that P17 toggles first, then P16 toggles, and so on. Having looked at the Simulator, can I make the assumption that COG[0] RAM has an interpreter running the Toggle 16 code, and that COG[1] RAM has its own interpreter running the Toggle 17 code? How do you now how much COG RAM space you have left to work with?
Is there such a thing as having global variable(s) in the PASM realm? I mean could you, for instance, turn off the toggling of P17 from some code in P16, without resorting too stopping and starting COG[1]?
Ray
The P17 toggler started first, so it should blink first by a little at least.
Yes, there are globals ... it's called HUB RAM. Use rdlong wrlong (rdword, rdbyte, etc...) to access them. Usually globals are defined in VAR or DAT sections and can be set by Spin code. Read the book for the syntax.
The simulator itself interprets the COG programs, but the PASM you've shown doesn't use an interpreter once COG 0 is replaced. If you cognew a spin function there will be a new spin interpreter.
I wanted to play with the input checkboxes.
Load it into the simulator and "Run" - you can check the box next to P0 on and off and watch P16 follow it. Go into DEBUG to watch the code run.
Ray, this is PASM, once it is loaded, NO INTERPRETERS are involved!
Steve, my employer thanks you for keeping me out of trouble at work for the good part of ANOTHER day!! (at least I imagine they would if they knew)
The PASM_IO.spin program needs the driver for the touch pads to be included, for the program to work with the QS board, correct? That would be a good example, have the program functional with the Simulator and be able to work with the QS board, using the touch pads. Would be a good lesson in how to deal with drivers also.
Ray
A push button and a resistor was a lot easier to code for!
The problem is that the simulator probably won't work with the QS touch pad code because the simulator just simulates a simple push button or switch (as it should!) - it will be difficult to make it simulate the capacitive(?) buttons on the QS.
Ray
I was thinking, "Gee, it would be neat to be able to somehow set a break point at PC = $000 for the PASM program you are playing with. Well, that's kinda hard to do since it isn't loaded yet. Steve could add somethign to the simulated COGxxxx instructions so it would stop after it loads the COG but before is starts running, but he has enough to do.
So, I used my meager PASM skill sand added this code to the front of my program: Yes, this uses 4 longs but it does allow you to sit at the top of your code until you toggle an I/O pin (in this case, Pin#1).
To use it, you just put the code at the front of your COG code (among with a temp register), LOAD your program, make sure your input box is NOT checked, hit RUN...wait a while for all the loading to take place and then hit STOP. At this point, if you switch to your COG, you should see your PASM code with the PC on one of the first 3 instructions. Click your I/O box (Pin#1 in my example) and then step through your program until you are past the TJZ instruction. At this point, you are at the start of your REAL PASM code and can see what it does from the start. Clear your Input checkbox and you are ready to DEBUG, TRACE STEP or whatever through your code.
There's probably a cool PASM trick to do this in fewer instructions.
You can probably set a breakpoint on the instruction after the TJZ and set your Input checkbox and just DEBUG or RUN to the breakpoint but I haven't tried that yet. I just did the breakpoint thing - it works REALLY WELL!! But the above steps lets you see each step so you understand the process.
This is getting better and better!!!
Try this program in the SimpleIDE workspace: SimpleIDE\Propeller GCC Demos\QuickStart\Whack-a-mole\qswam.side
@Rick, try waitpne or waitpeq next ;-)
(Lab rat warning ... I haven't tested them).
I did say
Ray, I'll leave the C version of the button test to you...to paraphrase a popular forumite, "my eyes bleed when I read C"
Time to pull, update and build..... YAY!!
EDIT: Nevermind, they were there all along!
This runs as expected on real hardware (DUH!)
When I simulate it, I LOAD and RUN with the Input checkbox cleared and STOP it. I go into my COG and I'm sitting on the WAITPEQ. I check the input box and set a breakpoint and hit debug. The CNT starts running but I still sit there - to RESULT field never changes even though my INA on the side panel shows $00000002. No combination of STOP, STEP or anything else I've tried gets it to read INA inside the WAITPEQ instruction.
If I set Input 1 immediately after the load, it of course, blows right through the WAITPEQ.
Haven't tried a WAITPNE but I assume it will be the same. No rechecking the INA register once inside the WAITPxx instruction??
EDIT: Just tried WAITPNE - results are similar (but inverted! )
My eyes started bleeding with any computer stuff once I crossed the 200 pound mark in 1999. Went north from there to 250 ... LOL. Now I'm only 220-ish.
I may have time to look at improvements again tomorrow.
Ray
The C code is right here where Steve said it was:
OK, Ray, here's your quiz:
This is the QS button code from the Whack-a-mole program:
It's all C, and it's LMM, so what does that mean as far as what you will see in the simulator?
There may or may not be a PASM version, I'll look. There are several Spin versions. It will be interesting to see what all/any of these will do in the simulator versus real life. There's also a Forth version but I get scolded when I mention that!
At some point, it would be really cool to be able to simulate all the quirky hardware so someone could sit down with a QuickStart and the simulator and run on hardware and then on simulator and play and learn.
The next step will be to look at what the Simulator reveals in terms of code, I hope it is not all in the HUB RAM. The SimpleIDE shows - Code Size 3,220 bytes (3,388 total), so it is not a small program.
Ray
Ray
A couple things in your code.
1) all the RES need to be at the end of the code for a COG (after all the code and longs)
2) what did you expect the program to do after the XOR? It IS doing exactly what you told it to do....continuing to execute instructions. It see everything in the COG as an instruction and executes it. Most of the COG is filled with NOPs if you look in the simulator.
Here's the updated code with a "JMP #$" after the XOR - this will effectively halt the COG by making it execute that one instruction repeatedly.
I think you helped find a bug in the simulator, though.
When you run the above program in the simulator, it treats the JMP #$ as a JMP #$+1.
It appears to simulate a JMP #$-1 correctly and a JMP #$-1 correctly but stumbles on a JMP #$. It appears to have already incremented the PC so it jumps to the $+1 location instead of $.
So, if you want to halt the simulator, you just do this:
and it just sits and executes those two instruction back and forth....and back and forth....
Another thing that I would like to know is how many different ways are there too set 'outa' to 0 and then back to1? Lets say you wanted to make two subroutines of code, one to set 'outa' to 0, and the other subroutine to set 'outa' to 1. I guess this would translate to pressing the touch pad on the QS board to turn on an LED and pressing it again to turn the LED off, of course this would show up in the Simulator as checking the box to keep the LED on in a constant state and unchecking to turn it off.
Ray
Ray
I have some updates to push, but I just haven't had time to finish testing. Maybe I can push them tonight.
Here are some highlights:
The spiral is being replaced with an analog and digital clock display.
The jmp #$ thing is fixed.
Instructions waitpne and waitpeq work (need to set WR).
The djnz issue works much better, but it still isn't perfect.
Stopping Run will update the HUB and COG displays.
Different clock frequencies can be used at startup.
Thinking that break on coginit thing can be an optio Rick ... not ready yet.