Lets see if I have this straight, the interpreter lives in COG RAM, the main facilitator, your program is in HUB RAM which gets used in the COG RAM, as needed. Actually it looks like HUB RAM is just a temporary storage area, and all the action is done by the interpreter, which is in the COG RAM. Is the Spin code, which has to be converted to byte code? look different in the HUB RAM, from the PASM code, that is also held in the HUB RAM area? Right now when I look in the HUB RAM it looks like everything is in machine code, so you really can not tell what part is SPIN and what part is PASM.
You mention that PropellerGCC has always supported running code directly from COG RAM, but with only 512 bytes of work space, that really looks to be just a flashy example, and not something that you could do some "real world" programming with (I am thinking COG mode in SimpleIDE). Even if you somehow got to use the other 7 COGs COG RAM, still does not seem, at this point, a very beneficial thing.
jazzed thanks again for this Simulator program, I would never have gotten this deep into COG RAM, HUB RAM, interpreter stuff, specifically programming, without this. I suppose the Parallax Education dept. is looking very closely at this program. This is some good stuff!
Your questions are great and they make me want to stand up in front of a white board with a handful of colored markers. This understanding is such a fundamental to the Propeller world but really needs a "Chalk Talk". I wish I could figure out how to make a tutorial of all this. Maybe Steve's simulator is the missing key to this.
Lets see if I have this straight, the interpreter lives in COG RAM, the main facilitator, your program is in HUB RAM which gets used in the COG RAM, as needed. Actually it looks like HUB RAM is just a temporary storage area, and all the action is done by the interpreter, which is in the COG RAM. Is the Spin code, which has to be converted to byte code? look different in the HUB RAM, from the PASM code, that is also held in the HUB RAM area? Right now when I look in the HUB RAM it looks like everything is in machine code, so you really can not tell what part is SPIN and what part is PASM.
Ya, that's pretty much it except that HUB RAM keeps the SPIN or other bytecode/LMM program. Any PASM code in HUB is really wasting space after it gets started with cognew unless the area gets recycled. The colors in the map on the simulator HUB RAM tab show the different usage areas (there is more detail that is not discernable at the moment for multiple object programs).
You mention that PropellerGCC has always supported running code directly from COG RAM, but with only 512 bytes of work space, that really looks to be just a flashy example, and not something that you could do some "real world" programming with (I am thinking COG mode in SimpleIDE). Even if you somehow got to use the other 7 COGs COG RAM, still does not seem, at this point, a very beneficial thing.
This is the way Propeller works. The pong program is actually fairly substantial and it should be a good example or test case for anyone writing COGC code (or compiler models). It has VGA output, reads pins, generates VGA graphics, has game logic in it, and has access to all of hub ram except the part used for stack. For more substantial programs, some sort of HUB RAM convention must be used like storing byte-code or LMM code. What's more important about COGC code though is that you can write 7 different drivers in COGC mode and use those in your SimpleIDE programs. SimpleIDE can do lots of things that simple users never see.
This observation that COG is to small to be beneficial is consistent with why many people just skip over the Propeller. Clearly it is more capable than that, but it's hard to change anyone's mind once they have formed an opinion whether it is right or wrong. That is, you only get one chance for a good first impression.
jazzed thanks again for this Simulator program, I would never have gotten this deep into COG RAM, HUB RAM, interpreter stuff, specifically programming, without this. I suppose the Parallax Education dept. is looking very closely at this program. This is some good stuff!
Parallax Education is not interested in the simulator project. It's my own initiative.
Dave Hein's Simulator has been available for years, but it is limited to command line users - It's a great tool, and was used for writing PropellerGCC from the beginning.
There was also another GUI called GEAR that does simulation - it has advanced interface features like I plan to add. I could never understand how to use GEAR at all though.
Thinking more about the Simulator, using the PASM Toggle example, when there is a cognew used why doesn't it show in the COG[1] tab? I thought that when you use cognew, that was a way to start the use of a new COG, other than the main COG 0. And I would imagine that now, the HUB RAM would have some sort of code to associate it with the specific COG, since each COG gets to use some HUB RAM.
In the Simulator program, across the top, you have a selection called 'Clear', is it to clear the binary file that got loaded? I tried it a few times and nothing seemed to have changed or occurred.
Thinking more about the Simulator, using the PASM Toggle example, when there is a cognew used why doesn't it show in the COG[1] tab? I thought that when you use cognew, that was a way to start the use of a new COG, other than the main COG 0. And I would imagine that now, the HUB RAM would have some sort of code to associate it with the specific COG, since each COG gets to use some HUB RAM.
In the Simulator program, across the top, you have a selection called 'Clear', is it to clear the binary file that got loaded? I tried it a few times and nothing seemed to have changed or occurred.
Ray
Whenever a cognew is executed, a * is added to the COG[1] to show that code has been loaded. This only shows up in Debug mode. If you do Run, then Stop it won't show up until you do Step or Debug (Continue is like Debug and I'm considering removing that). I suppose at the end of Run a Step can be automatically executed to show the current state.
Sorry about the Clear button. Only Load can clear and restart a program. The Clear button clears any breakpoints set in the program. How to set a breakpoint? Just click on a line contents or the BP field in the COG display (not the line number). Break points do not work in Run mode ... that may change later.
And the adventure continues. I decided to use the PASM Toggle example code as a way to see what the Simulator program reveals. So, after loading, running and stopping the program, you now see that there is a *COG[0] and *COG[1]. After looking at both tab contents I made a general breakdown:
COG[0] : 496 lines of code <- HUB 72 bytes
COG[1] : 47 lines of code <- HUB 72 bytes
As it turns out the HUB data that is associated with COG[0] is the same as the HUB data that is associated with COG[1], as displayed by the Simulator. I was under the impression that each COG would have its own HUB RAM space, so in this case COG[0] HUB RAM space would be blank, right?
Now the interesting part, COG[1] RAM has 47 lines of code, and the first 6 lines reflects the 6 lines that are shown after the org 0 in your PASM Toggle program. In fact it is very easy to follow at this point. I tried a couple of different things, first I did a Run, which did nothing that I could see. Next I tried the Step, which actually did a step of the defined :loop. Now, when I did a Debug, it started to do a very fast stepping of the :loop, which also toggled Pin16. At this point I was expecting to see the toggle to be at 80_000_000, but it was going way faster than that, what am I really seeing here, the actual processor speed working the code or is it supposed to be the actual code at work with an 80_000_000 pause?
After this exercise I can see that, in fact, the PASM code gets loaded into COG RAM and executed. Do you have to have both the DAT and org 0 to make this happen. I know that a Spin program can have a DAT section, but where does that code go?
Some general questions, the COG[1] has 47 lines of code, what are the other 41 lines of code doing? HUB RAM has 72 bytes being used, is that what it takes to convey your last 3 lines of PASM program? And if you removed the cognew from the program would that program still run?
In my earlier post I posed the question about removal of the cognew from the PASM Toggle program, which I just did. I mainly use PropellerIDE for all the building of code, in these tests. With the removal of the cognew from the code, the program was built without any errors. After doing the Load,Run, and Stop, I now see *COG[0], *COG[1], *COG[2], *COG[3], and *COG[4], yes they all have lines of code. The COG[0] looks like it no longer has the correct interpreter code, but when you do a Debug, it does do a continuous Step as do the other COGs. Of course when you do a Run (COG[0]) it does not toggle the Pin16 anymore.
The PropellerIDE shows that the new build is: "Program size is 60 bytes". How much of the Propeller chip resources are actually being used, in terms of bytes, to run this 60 byte program?
Not sure if there is a problem with the Simulator, but when you Load, Run, Stop the program below, and then look at the COGS, all the COGs have an '*', plus they all have lines of code. I think before only COG[0] had the interpreter loaded in the COG[0].
Ray
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
PUB main
As explained before you need something in main that repeats.
Somewhere along the line I missed that explanation, that did take care of the problem though.
Below is a Spin version of the PASM Toggle, or at least as close as I could get it. PropellerIDE shows that this program comes in at 60 bytes, just like the PASM Toggle program. So, what do we have here, we only utilize COG[0], saving a COG, and that P16 does blink every 80_000_000. The HUB RAM comes in at 68 bytes while PASM Toggle comes in at 72 bytes of HUB RAM, plus it uses 47 lines of code in COG[1]. The Spin program exists within the interpreter or is the code that is in the HUB RAM the actual Spin program? If that is the case, trying to interpret the machine code could be a little time consuming. In the COG[0] I am still having a difficult time finding the code lines that actually reach out to the HUB RAM to run that code if in fact that is how it works.
Not sure if this is a fair comparison but it looks like the Spin program works as good as the PASM version, plus the Spin version would be more flexible in terms of having re-usable code in the form of a method(s). In terms of program size, the Spin program can be as large as the availability of HUB RAM exits. While the PASM version would be limited to the availability of COG RAM, of course there is some spill over to the HUB RAM for incidentals, but not for actual code lines.
Now if Spin had inline asm capabilities, would there be any major improvements in the usability of Spin? Or is there a way to call PASM code subs from methods? As an example something like a 'waitms' method, you could declare the wait length within a method call and the grunt work would be done in PASM.
Ray
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
'' Main
pub main
DIRA[16] := %1
repeat
waitcnt(80_000_000 + cnt)
OUTA[16] := 1
waitcnt(80_000_000 + cnt)
OUTA[16] := 0
Somewhere along the line I missed that explanation, that did take care of the problem though.
Below is a Spin version of the PASM Toggle, or at least as close as I could get it. PropellerIDE shows that this program comes in at 60 bytes, just like the PASM Toggle program. So, what do we have here, we only utilize COG[0], saving a COG, and that P16 does blink every 80_000_000. The HUB RAM comes in at 68 bytes while PASM Toggle comes in at 72 bytes of HUB RAM, plus it uses 47 lines of code in COG[1]. The Spin program exists within the interpreter or is the code that is in the HUB RAM the actual Spin program? If that is the case, trying to interpret the machine code could be a little time consuming. In the COG[0] I am still having a difficult time finding the code lines that actually reach out to the HUB RAM to run that code if in fact that is how it works.
I'm not sure where we are headed with this but it is a fun discussion.
PASM equivalent to your SPIN:
{ PASMToggle.spin }}
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
PUB Main
{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
The code above will use 1 cog and will take up 11 LONGs for instructions and data. You can see them right there in the listing (the beauty of PASM). It toggles the pin at the same rate as the Spin program.
The propeller processor (a COG) can only execute instructions from COG RAM. These instructions are 32 bits in length and certain bits mean certain things to the processor as it decodes the instruction. These instructions are coded as PASM to make them more readable. There are only 496 usable LONGs in a COG that can execute instructions - the remaining LONGs are reserved registers. That's all a COG can ever do is execute propeller instructions from COGRAM.
The Spin interpreter (or any interpreter or virtual machine for that matter) is a PASM program that executes in COGRAM that for all practical purposes is an implementation of a NEW processor - in this case, one that understands Spin byte codes as its instruction set. This Spin processor can only execute byte codes from HUBRAM. The interpreter will execute many, many PASM instructions for each Spin instruction. If you look at Steve's Spin trace above, you will see a series of RDBYTE instructions - each of those is the Spin interpreter fetching a Spin byte code or parameter from HUBRAM and processing it. If you look at my trace below, you will see a RDBYTE instruction fetching a Spin byte code and then all the PASM instruction that are executed to make that byte code do whatever it is supposed to do.
81904649 COG 0 PC 009 00bc0bee RDBYTE WC 0 WZ 0 WR 1 DST 005 00000037 SRC $1ee 00000029 C 1 Z 0 RESULT $03d <<SPIN>>
81904657 COG 0 PC 00a 80ffdc01 ADD WC 0 WZ 0 WR 1 DST 1ee 00000029 SRC #$001 C 0 Z 0 RESULT $02a
81904665 COG 0 PC 00b 857c0a40 CMP WC 1 WZ 0 WR 0 DST 005 0000003d SRC #$040 C 1 Z 0 RESULT $000
81904681 COG 0 PC 00d a0bc0605 MOV WC 0 WZ 0 WR 1 DST 003 000003a8 SRC $005 0000003d C 0 Z 0 RESULT $03d
81904689 COG 0 PC 00e 20fc0604 ROR WC 0 WZ 0 WR 1 DST 003 0000003d SRC #$004 C 1 Z 0 RESULT $d0000003
81904697 COG 0 PC 00f 80fc061a ADD WC 0 WZ 0 WR 1 DST 003 d0000003 SRC #$01a C 0 Z 0 RESULT $d000001d
81904705 COG 0 PC 010 50bc2603 MOVS WC 0 WZ 0 WR 1 DST 013 a0bc081d SRC $003 d000001d C 1 Z 0 RESULT $a0bc081d
81904713 COG 0 PC 011 24fc0602 ROL WC 0 WZ 0 WR 1 DST 003 d000001d SRC #$002 C 1 Z 0 RESULT $40000077
81904721 COG 0 PC 012 2cfc0603 SHL WC 0 WZ 0 WR 1 DST 003 40000077 SRC #$003 C 0 Z 0 RESULT $3b8
81904729 COG 0 PC 013 a0bc081d MOV WC 0 WZ 0 WR 1 DST 004 000000c4 SRC $01d d6cfc4b4 C 1 Z 0 RESULT $d6cfc4b4
81904737 COG 0 PC 014 28bc0803 SHR WC 0 WZ 0 WR 1 DST 004 d6cfc4b4 SRC $003 000003b8 C 0 Z 0 RESULT $0d6
81904745 COG 0 PC 015 60fc08ff AND WC 0 WZ 0 WR 1 DST 004 000000d6 SRC #$0ff C 1 Z 0 RESULT $0d6
81904753 COG 0 PC 016 50bc3204 MOVS WC 0 WZ 0 WR 1 DST 019 5c7c00c4 SRC $004 000000d6 C 0 Z 0 RESULT $5c7c00d6
81904761 COG 0 PC 017 627c0a01 TEST WC 0 WZ 1 WR 0 DST 005 0000003d SRC #$001 C 1 Z 0 RESULT $000
81904769 COG 0 PC 018 617c0a02 TEST WC 1 WZ 0 WR 0 DST 005 0000003d SRC #$002 C 0 Z 1 RESULT $000
81904777 COG 0 PC 019 5c7c00d6 JMP WC 0 WZ 0 WR 0 DST 000 00000000 SRC #$0d6 C 1 Z 0 RESULT $000
81904817 COG 0 PC 0d6 00bc01ee RDBYTE WC 0 WZ 0 WR 1 DST 000 00000000 SRC $1ee 0000002a C 0 Z 0 RESULT $0b4
81904825 COG 0 PC 0d7 80ffdc01 ADD WC 0 WZ 0 WR 1 DST 1ee 0000002a SRC #$001 C 0 Z 0 RESULT $02b
81904833 COG 0 PC 0d8 a0bc0a00 MOV WC 0 WZ 0 WR 1 DST 005 0000003d SRC $000 000000b4 C 0 Z 0 RESULT $0b4
81904841 COG 0 PC 0d9 28fc0a05 SHR WC 0 WZ 0 WR 1 DST 005 000000b4 SRC #$005 C 0 Z 0 RESULT $005
81904849 COG 0 PC 0da 68fc01e0 OR WC 0 WZ 0 WR 1 DST 000 000000b4 SRC #$1e0 C 0 Z 0 RESULT $1f4
81904857 COG 0 PC 0db 50bf8200 MOVS WC 0 WZ 0 WR 1 DST 1c1 608c05f1 SRC $000 000001f4 C 0 Z 0 RESULT $608c05f4
81904865 COG 0 PC 0dc 54bf8600 MOVD WC 0 WZ 0 WR 1 DST 1c3 a0bfe200 SRC $000 000001f4 C 0 Z 0 RESULT $a0bfe800
81904873 COG 0 PC 0dd 50bf9000 MOVS WC 0 WZ 0 WR 1 DST 1c8 a0bc01f1 SRC $000 000001f4 C 0 Z 0 RESULT $a0bc01f4
81904889 COG 0 PC 0df 5ccfbddc if_nc CALL WC 0 WZ 0 WR 1 DST 1de 5c7c0096 SRC #$1dc C 0 Z 0 RESULT $5c7c00e0
81904897 COG 0 PC 1dc 84ffde04 SUB WC 0 WZ 0 WR 1 DST 1ef 00000050 SRC #$004 C 0 Z 0 RESULT $04c
81904937 COG 0 PC 1dd 08bc01ef RDLONG WC 0 WZ 0 WR 1 DST 000 000001f4 SRC $1ef 0000004c C 0 Z 0 RESULT $010
81904945 COG 0 PC 1de 5c7c00e0 JMP WC 0 WZ 0 WR 0 DST 000 00000010 SRC #$0e0 C 1 Z 0 RESULT $000
81904953 COG 0 PC 0e0 a08c0200 if_nc MOV WC 0 WZ 0 WR 1 DST 001 00000003 SRC $000 00000010 C 0 Z 0 RESULT $010
81904969 COG 0 PC 0e2 60fc001f AND WC 0 WZ 0 WR 1 DST 000 00000010 SRC #$01f C 1 Z 0 RESULT $010
81904977 COG 0 PC 0e3 60fc021f AND WC 0 WZ 0 WR 1 DST 001 00000010 SRC #$01f C 1 Z 0 RESULT $010
81904985 COG 0 PC 0e4 a0bc0e00 MOV WC 0 WZ 0 WR 1 DST 007 ffffffff SRC $000 00000010 C 0 Z 0 RESULT $010
81904993 COG 0 PC 0e5 85bc0e01 SUB WC 1 WZ 0 WR 1 DST 007 00000010 SRC $001 00000010 C 0 Z 1 RESULT $000
81905001 COG 0 PC 0e6 acbc0e07 ABSNEG WC 0 WZ 0 WR 1 DST 007 00000000 SRC $007 00000000 C 0 Z 1 RESULT $000
81905009 COG 0 PC 0e7 84fc0e01 SUB WC 0 WZ 0 WR 1 DST 007 00000000 SRC #$001 C 1 Z 0 RESULT $ffffffff
81905017 COG 0 PC 0e8 a08fd001 if_nc MOV WC 0 WZ 0 WR 1 DST 1e8 00000010 SRC $001 00000010 C 0 Z 0 RESULT $010
81905033 COG 0 PC 0ea 74bf7fe7 MUXNC WC 0 WZ 0 WR 1 DST 1bf 3c8c0007 SRC $1e7 00800000 C 0 Z 0 RESULT $3c8c0007
81905041 COG 0 PC 0eb 74bf97e7 MUXNC WC 0 WZ 0 WR 1 DST 1cb 3c8c0007 SRC $1e7 00800000 C 0 Z 0 RESULT $3c8c0007
81905049 COG 0 PC 0ec 68fc0a0c OR WC 0 WZ 0 WR 1 DST 005 00000005 SRC #$00c C 1 Z 0 RESULT $00d
81905057 COG 0 PC 0ed 5c7c0179 JMP WC 0 WZ 0 WR 0 DST 000 00000010 SRC #$179 C 1 Z 0 RESULT $000
81905065 COG 0 PC 179 5cfc3217 CALL WC 0 WZ 0 WR 1 DST 019 5c7c00d6 SRC #$017 C 0 Z 0 RESULT $5c7c017a
81905073 COG 0 PC 017 627c0a01 TEST WC 0 WZ 1 WR 0 DST 005 0000000d SRC #$001 C 1 Z 0 RESULT $000
81905081 COG 0 PC 018 617c0a02 TEST WC 1 WZ 0 WR 0 DST 005 0000000d SRC #$002 C 0 Z 1 RESULT $000
81905089 COG 0 PC 019 5c7c017a JMP WC 0 WZ 0 WR 0 DST 000 00000010 SRC #$17a C 1 Z 0 RESULT $000
81905105 COG 0 PC 17b 5cc7bddc if_nc_and_nz CALL WC 0 WZ 0 WR 1 DST 1de 5c7c00e0 SRC #$1dc C 0 Z 0 RESULT $5c7c017c
81905113 COG 0 PC 1dc 84ffde04 SUB WC 0 WZ 0 WR 1 DST 1ef 0000004c SRC #$004 C 0 Z 0 RESULT $048
81905153 COG 0 PC 1dd 08bc01ef RDLONG WC 0 WZ 0 WR 1 DST 000 00000010 SRC $1ef 00000048 C 0 Z 0 RESULT $001
81905161 COG 0 PC 1de 5c7c017c JMP WC 0 WZ 0 WR 0 DST 000 00000001 SRC #$17c C 1 Z 0 RESULT $000
81905169 COG 0 PC 17c 5c4401b7 if_nc_and_nz JMP WC 0 WZ 0 WR 0 DST 000 00000001 SRC #$1b7 C 1 Z 0 RESULT $000
81905177 COG 0 PC 1b7 637c0a0c TEST WC 1 WZ 1 WR 0 DST 005 0000000d SRC #$00c C 0 Z 0 RESULT $000
81905233 COG 0 PC 1ba a4cc0401 if_nc NEG WC 0 WZ 0 WR 1 DST 002 00000101 SRC #$001 C 0 Z 0 RESULT $ffffffff
81905241 COG 0 PC 1bb 3c8c0407 if_nc REV WC 0 WZ 0 WR 1 DST 002 ffffffff SRC $007 ffffffff C 1 Z 0 RESULT $001
81905249 COG 0 PC 1bc 2c8c05e8 if_nc SHL WC 0 WZ 0 WR 1 DST 002 00000001 SRC $1e8 00000010 C 0 Z 0 RESULT $10000
81905257 COG 0 PC 1bd 6c8c05e5 if_nc XOR WC 0 WZ 0 WR 1 DST 002 00010000 SRC $1e5 ffffffff C 1 Z 0 RESULT $fffeffff
81905265 COG 0 PC 1be 3c8c0007 if_nc REV WC 0 WZ 0 WR 1 DST 000 00000001 SRC $007 ffffffff C 1 Z 0 RESULT $001
81905273 COG 0 PC 1bf 3c8c0007 if_nc REV WC 0 WZ 0 WR 1 DST 000 00000001 SRC $007 ffffffff C 1 Z 0 RESULT $001
81905281 COG 0 PC 1c0 2c8c01e8 if_nc SHL WC 0 WZ 0 WR 1 DST 000 00000001 SRC $1e8 00000010 C 0 Z 0 RESULT $10000
81905289 COG 0 PC 1c1 608c05f4 if_nc AND WC 0 WZ 0 WR 1 DST 002 fffeffff SRC $1f4 00000000 C 0 Z 1 RESULT $000
81905297 COG 0 PC 1c2 688c0002 if_nc OR WC 0 WZ 0 WR 1 DST 000 00010000 SRC $002 00000000 C 1 Z 0 RESULT $10000
81905305 COG 0 PC 1c3 a0bfe800 MOV WC 0 WZ 0 WR 1 DST 1f4 00000000 SRC $000 00010000 C 0 Z 0 RESULT $10000
81905313 COG 0 PC 1c4 5c7c0008 JMP WC 0 WZ 0 WR 0 DST 000 00010000 SRC #$008 C 0 Z 0 RESULT $000
81905321 COG 0 PC 008 a0fc0000 MOV WC 0 WZ 0 WR 1 DST 000 00010000 SRC #$000 C 0 Z 1 RESULT $000
81905361 COG 0 PC 009 00bc0bee RDBYTE WC 0 WZ 0 WR 1 DST 005 0000000d SRC $1ee 0000002b C 0 Z 0 RESULT $03b <<SPIN>>
There are around 60 PASM insturctions executed to do whatever that one Spin Byte code does. That's why PASM runs on average about 40 times faster than Spin.
The tradeoff as you mentioned is that you can write a Spin program that can be 32K bytes in size whereas your PASM program can never be larger than 496 longs (without getting really fancy). So there is your tradeoff - speed for program size. But, you can make a COG do a lot in 496 longs as far as soft peripheral and other helper type code goes. So it's really a good match - Spin for more complicated logic that can run slower (and is easier for the programmer to write and create more abstract ideas) and then PASM for when you need the speed.
Most high-level languages on the Propeller work in a similar manner.
Not sure if this is a fair comparison but it looks like the Spin program works as good as the PASM version, plus the Spin version would be more flexible in terms of having re-usable code in the form of a method(s). In terms of program size, the Spin program can be as large as the availability of HUB RAM exits. While the PASM version would be limited to the availability of COG RAM, of course there is some spill over to the HUB RAM for incidentals, but not for actual code lines.
I'm not sure there is anything to compare - this trivial example can be written in either and performs the same in either. It is easier to write in Apin but not that much more difficult to write in PASM. They are two different tools that you would normally use for different things in your program. As mentioned above, your Spin program can fill HUBRAm with byte code and your PASM program can only execute from COGRAM but you can use all of HUBRAM for data if you desire.
For non-trivial programs, the differences become apparent and the best uses for each will soon show themselves.
Now if Spin had inline asm capabilities, would there be any major improvements in the usability of Spin? Or is there a way to call PASM code subs from methods? As an example something like a 'waitms' method, you could declare the wait length within a method call and the grunt work would be done in PASM.
Ray
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
'' Main
pub main
DIRA[16] := %1
repeat
waitcnt(80_000_000 + cnt)
OUTA[16] := 1
waitcnt(80_000_000 + cnt)
OUTA[16] := 0
Inline PASM is talked about and would be an interesting feature in a Spin program. I'm sure once it shows up, there will be many intersting tricks the Propeller starts performing!
I call and raise you ... :-)
I just ran your PASM program through the Simulator -
Program size is 72 bytes.
HUB RAM 80 bytes
There is a match for COG use.
The programs being at this trivial size, having it coded in PASM is not that particularly important. Now if we were to switch gears and start doing FDS, then PASM starts to become a very necessary tool.
I am really impressed with the Simulator because now you can try out some programming ideas without having to have an actual Propeller board at hand. All you really need is PropellerIDE, MCU Simulator, and a programmers calculator on the computer. In fact how would this work out on a tablet? I wonder how far jazzed is going to take the Simulator program?
I guess now would be a good time to see how a PropellerGCC program, like maybe a Toggle program, would match up to the Spin and PASM programs. I am thinking a COG C Toggle program, that would be a good match, I think?
I guess now would be a good time to see how a PropellerGCC program, like maybe a Toggle program, would match up to the Spin and PASM programs. I am thinking a COG C Toggle program, that would be a good match, I think?
Ray
cog_c_toggle uses 2 COGs which the simulator didn't like when I tried it earlier. It will look a lot like the Spin example using the COGNEW since there is a COG running one of the C memory model VMs and then the COG you start to blink running the actual blinking code.
lmm_toggle will look a lot like your Spin program. One COG running through a BIG loop executing some sort of byte code (or actual instructions) from HUBRAM. Unless you can digest the byte code in HUBRAM, you won't see much interesting.
The other examples I looked at looked like they were multi-COG examples.
I am using the program example that mindrobots provided, coginit PASM Toggle. What I did was the following:
1. Load - loads the binary
2. Step - shows some code starting at $000, looks like the interpreter.
3. Debug - does a quick step until it hits a loop which is the PASM program code. The PASM code listing is now at $000. What just happened?
I am not sure what I am seeing here, it looks like the actual Propeller procedure is load the interpreter, then load the actual program, and run. When you do the normal Load, Run, and Stop, the COG[0] code listing looks like you have just been using the PASM code, but in fact you have missed the whole loading of the interpreter step. I got the misconception that you were really just using and running the PASM code, if this makes any sense at all.
It seems to me that it would be beneficial, to have a sequence, where you get to see the actual program run, starting at $000, stepping through the interpreter to a point where it starts too execute the PASM code. Right now you really do not get to see how the PASM code interacts or is being used by the interpreter or whatever that mechanism is called. Somebody brand new might start getting some wrong ideas as too how all this works when presented with some concept shortcuts. Just my two cents, I am just describing what my impressions are when I use the program.
Using the mindrobots coginit PASM program, it's time for a quiz. So get out a pencil and a sheet of paper ...
1. If you remove the CON block of code, will the program still run, and why?
2. If in fact, the program is running, will the P16 be toggling?
a. At what rate? Please show your work,
b. Can the rate be manipulated and how? Please show your work.
Bonus Question.
3. Can you start another toggling sequence, maybe P17, which will be active in its own cog? Please show your work.
I am using the program example that mindrobots provided, coginit PASM Toggle. What I did was the following:
1. Load - loads the binary
2. Step - shows some code starting at $000, looks like the interpreter.
3. Debug - does a quick step until it hits a loop which is the PASM program code. The PASM code listing is now at $000. What just happened?
I am not sure what I am seeing here, it looks like the actual Propeller procedure is load the interpreter, then load the actual program, and run. When you do the normal Load, Run, and Stop, the COG[0] code listing looks like you have just been using the PASM code, but in fact you have missed the whole loading of the interpreter step. I got the misconception that you were really just using and running the PASM code, if this makes any sense at all.
It seems to me that it would be beneficial, to have a sequence, where you get to see the actual program run, starting at $000, stepping through the interpreter to a point where it starts too execute the PASM code. Right now you really do not get to see how the PASM code interacts or is being used by the interpreter or whatever that mechanism is called. Somebody brand new might start getting some wrong ideas as too how all this works when presented with some concept shortcuts. Just my two cents, I am just describing what my impressions are when I use the program.
Ray
Propeller 101 -
(Your step #2) When the Prop 1 resets, the first progmatic thing it does is to load a copy of the Spin interpreter into COG0 and start executing it at COGRAM $000. Once the Spin interpreter gets initialized and running, the first thing it does is to execute the Spin byte code at $10 in HUBRAM (or wherever the Spin programs start - I forget). You will see all of this in the simulator if you wish to step through it.
(Your step #3a) The first Spin instruction is COGINIT, so the interpreter will read that bytecode from HUBRAM (RDBYTE) and start executing it....at some point in processing that byte code, it will execute the PASM instruction COGINIT - you can watch everything up to that point if you care to do a lot of stepping.
(Your step #3b) The PASM COGINIT instruction tells the COG to load a 496 long section of HUBRAM that it was passed a pointer to into the specified COG's RAM. In this case, the specified COG is COG0, so the PASM program will overlay the Spin interpreter that is currently in COGRAM. Once loaded, program execution starts at COGRAM $000 The simulator won't show you the details of the PASM COGINIT being executed because that is all being done inside the hardware by that one instruction (it's a software simulator, not a hardware simulator ) If you are watching this in DEBUG, then the COGRAM contents will appear to have magically changed from the Spin interpreter code to you PASM code.
If you start a PASM Trace (not a Spin Trace) of everything from the Load through to the point where you see the PASM program in COG, then you would have a list of all the steps and be able to see how the Spin interpreter does the COGINIT. This would give you the sequence you are asking for: from Spin $000 through to the PASM code executing.
Using the mindrobots coginit PASM program, it's time for a quiz. So get out a pencil and a sheet of paper ...
1. If you remove the CON block of code, will the program still run, and why?
2. If in fact, the program is running, will the P16 be toggling?
a. At what rate? Please show your work,
b. Can the rate be manipulated and how? Please show your work.
Bonus Question.
3. Can you start another toggling sequence, maybe P17, which will be active in its own cog? Please show your work.
Ray
I took your quiz about a week ago when I first started playing with the simulator. (I'd like to see your answers to compare! )
Bonus question puzzle:
Why does this code leave you with one blinking LED:
COGINIT(0, @TOGGLE16, 0)
COGINTI(1, @TOGGLE17, 0)
and this code leaves you with two blinking LEDs?
COGINIT(1, @TOGGLE16, 0)
COGINIT(0, @TOGGLE17, 0)
assuming that you have a TOGGLE16 block of PASM code that blinks pin 16 at some rate and a TOGGLE17 block of code that toggles pin 17 at some rate.
(I got myself with this while I was playing distractedly with multiple LEDs - DOH!)
Why does this code leave you with one blinking LED:
COGINIT(0, TOGGLE16, 0)
COGINTI(1, TOGGLE17, 0)
and this code leaves you with two blinking LEDs?
COGINIT(1, TOGGLE16, 0)
COGINIT(0, TOGGLE17, 0)
assuming that you have a TOGGLE16 block of PASM code that blinks pin 16 at some rate and a TOGGLE17 block of code that toggles pin 17 at some rate.
(I got myself with this while I was playing distractedly with multiple LEDs - DOH!)
As far as I know it's because the code that executes these commands are running in cog 0. In the first case you are loading the new code in the current running cog and as such, the second coginit is never reached.
In the second case, you start cog 1, and afterwards you load TOGGLE17 into the cog that starts all this. If you would put any code after this, it would not be executed.
1. If you remove the CON block of code, will the program still run, and why?
Yes, the Propeller chip has an internal RC Oscillator 12MHz or 20kHz. The processor starts at ~20kHz waits 50ms then switches to ~12MHz. So what is the math ~80_000_000 / 12_000_000? You can take the Propeller DIP chip, plug it into the breadboard, provide the necessary power and you can program it. The experiments that I did, I do not remember using the just mentioned setup, having a program that had the previously mentioned CON block code inserted, and would seeing if the program would compile let alone run correctly?
The reason this question came up is, I am making an assumption that the Simulator is simulating an external 5MHz crystal. So when you do have the CON block code inserted everything runs correctly. Which leads to another question, will the Simulator program be simulating an EEPROM?
Maybe we should step back and try a PASM Toggle program that would have P16 toggle at 250ms, 500ms, and 1000ms.
Using the mindrobots coginit PASM program, it's time for a quiz. So get out a pencil and a sheet of paper ...
1. If you remove the CON block of code, will the program still run, and why?
2. If in fact, the program is running, will the P16 be toggling?
a. At what rate? Please show your work,
b. Can the rate be manipulated and how? Please show your work.
Bonus Question.
3. Can you start another toggling sequence, maybe P17, which will be active in its own cog? Please show your work.
Ray
1. Yes. It will run with the default 12MHz propeller clock.
From PropellerManual v1.1: "RCFAST ... Internal fast oscillator (~12 MHz). May be 8 MHz to 20 MHz. (Default)"
2. Yes.
2.a. The simulated rate is wrong at the moment for some reason.
2.b. To change the rate, you must change the clock.
3. Yes, see @mindrobots and @Michel L answers.
I tried out the simulator under Windows and it's very nice. There does seem to be a problem with DJNZ. A single-line DJNZ, such as "djnz count, #$" would just exit the loop immediately. If I make the loop two lines by adding a NOP it worked better, but it didn't appear to loop the correct number of times in the RUN mode. In the STEP mode it would sit on the NOP for 4 clicks, and then execute the DJNZ. If I replace the loop with a SUB and conditional jump it works OK.
Here's a little program that blinks a bit from left to right while jumping up and down. The speed depends on the input bits.
con
_clkmode = xtal1+pll16x
_clkfreq = 80_000_000
pub main
coginit(0, @entry, 0)
dat
entry neg dira, #1
mov outa, #1
loop2 rol outa, #15
call #delay
ror outa, #17
call #delay
jmp #loop2
delay mov count, ina wz
if_z jmp delay_ret
{
nop
djnz count, #$-1
}
sub count, #1 wz
if_nz jmp #$-1
delay_ret ret
count res 1
Comments
You mention that PropellerGCC has always supported running code directly from COG RAM, but with only 512 bytes of work space, that really looks to be just a flashy example, and not something that you could do some "real world" programming with (I am thinking COG mode in SimpleIDE). Even if you somehow got to use the other 7 COGs COG RAM, still does not seem, at this point, a very beneficial thing.
jazzed thanks again for this Simulator program, I would never have gotten this deep into COG RAM, HUB RAM, interpreter stuff, specifically programming, without this. I suppose the Parallax Education dept. is looking very closely at this program. This is some good stuff!
Ray
Your questions are great and they make me want to stand up in front of a white board with a handful of colored markers. This understanding is such a fundamental to the Propeller world but really needs a "Chalk Talk". I wish I could figure out how to make a tutorial of all this. Maybe Steve's simulator is the missing key to this.
This observation that COG is to small to be beneficial is consistent with why many people just skip over the Propeller. Clearly it is more capable than that, but it's hard to change anyone's mind once they have formed an opinion whether it is right or wrong. That is, you only get one chance for a good first impression.
Dave Hein's Simulator has been available for years, but it is limited to command line users - It's a great tool, and was used for writing PropellerGCC from the beginning.
There was also another GUI called GEAR that does simulation - it has advanced interface features like I plan to add. I could never understand how to use GEAR at all though.
In the Simulator program, across the top, you have a selection called 'Clear', is it to clear the binary file that got loaded? I tried it a few times and nothing seemed to have changed or occurred.
Ray
Whenever a cognew is executed, a * is added to the COG[1] to show that code has been loaded. This only shows up in Debug mode. If you do Run, then Stop it won't show up until you do Step or Debug (Continue is like Debug and I'm considering removing that). I suppose at the end of Run a Step can be automatically executed to show the current state.
Sorry about the Clear button. Only Load can clear and restart a program. The Clear button clears any breakpoints set in the program. How to set a breakpoint? Just click on a line contents or the BP field in the COG display (not the line number). Break points do not work in Run mode ... that may change later.
COG[0] : 496 lines of code <- HUB 72 bytes
COG[1] : 47 lines of code <- HUB 72 bytes
As it turns out the HUB data that is associated with COG[0] is the same as the HUB data that is associated with COG[1], as displayed by the Simulator. I was under the impression that each COG would have its own HUB RAM space, so in this case COG[0] HUB RAM space would be blank, right?
Now the interesting part, COG[1] RAM has 47 lines of code, and the first 6 lines reflects the 6 lines that are shown after the org 0 in your PASM Toggle program. In fact it is very easy to follow at this point. I tried a couple of different things, first I did a Run, which did nothing that I could see. Next I tried the Step, which actually did a step of the defined :loop. Now, when I did a Debug, it started to do a very fast stepping of the :loop, which also toggled Pin16. At this point I was expecting to see the toggle to be at 80_000_000, but it was going way faster than that, what am I really seeing here, the actual processor speed working the code or is it supposed to be the actual code at work with an 80_000_000 pause?
After this exercise I can see that, in fact, the PASM code gets loaded into COG RAM and executed. Do you have to have both the DAT and org 0 to make this happen. I know that a Spin program can have a DAT section, but where does that code go?
Some general questions, the COG[1] has 47 lines of code, what are the other 41 lines of code doing? HUB RAM has 72 bytes being used, is that what it takes to convey your last 3 lines of PASM program? And if you removed the cognew from the program would that program still run?
Ray
The PropellerIDE shows that the new build is: "Program size is 60 bytes". How much of the Propeller chip resources are actually being used, in terms of bytes, to run this 60 byte program?
Ray
Ray
As explained before you need something in main that repeats.
I'll see what I can do, but my schedule is a little rough through Wednesday.
Below is a Spin version of the PASM Toggle, or at least as close as I could get it. PropellerIDE shows that this program comes in at 60 bytes, just like the PASM Toggle program. So, what do we have here, we only utilize COG[0], saving a COG, and that P16 does blink every 80_000_000. The HUB RAM comes in at 68 bytes while PASM Toggle comes in at 72 bytes of HUB RAM, plus it uses 47 lines of code in COG[1]. The Spin program exists within the interpreter or is the code that is in the HUB RAM the actual Spin program? If that is the case, trying to interpret the machine code could be a little time consuming. In the COG[0] I am still having a difficult time finding the code lines that actually reach out to the HUB RAM to run that code if in fact that is how it works.
Not sure if this is a fair comparison but it looks like the Spin program works as good as the PASM version, plus the Spin version would be more flexible in terms of having re-usable code in the form of a method(s). In terms of program size, the Spin program can be as large as the availability of HUB RAM exits. While the PASM version would be limited to the availability of COG RAM, of course there is some spill over to the HUB RAM for incidentals, but not for actual code lines.
Now if Spin had inline asm capabilities, would there be any major improvements in the usability of Spin? Or is there a way to call PASM code subs from methods? As an example something like a 'waitms' method, you could declare the wait length within a method call and the grunt work would be done in PASM.
Ray
PASM equivalent to your SPIN:
The code above will use 1 cog and will take up 11 LONGs for instructions and data. You can see them right there in the listing (the beauty of PASM). It toggles the pin at the same rate as the Spin program.
The propeller processor (a COG) can only execute instructions from COG RAM. These instructions are 32 bits in length and certain bits mean certain things to the processor as it decodes the instruction. These instructions are coded as PASM to make them more readable. There are only 496 usable LONGs in a COG that can execute instructions - the remaining LONGs are reserved registers. That's all a COG can ever do is execute propeller instructions from COGRAM.
The Spin interpreter (or any interpreter or virtual machine for that matter) is a PASM program that executes in COGRAM that for all practical purposes is an implementation of a NEW processor - in this case, one that understands Spin byte codes as its instruction set. This Spin processor can only execute byte codes from HUBRAM. The interpreter will execute many, many PASM instructions for each Spin instruction. If you look at Steve's Spin trace above, you will see a series of RDBYTE instructions - each of those is the Spin interpreter fetching a Spin byte code or parameter from HUBRAM and processing it. If you look at my trace below, you will see a RDBYTE instruction fetching a Spin byte code and then all the PASM instruction that are executed to make that byte code do whatever it is supposed to do.
There are around 60 PASM insturctions executed to do whatever that one Spin Byte code does. That's why PASM runs on average about 40 times faster than Spin.
The tradeoff as you mentioned is that you can write a Spin program that can be 32K bytes in size whereas your PASM program can never be larger than 496 longs (without getting really fancy). So there is your tradeoff - speed for program size. But, you can make a COG do a lot in 496 longs as far as soft peripheral and other helper type code goes. So it's really a good match - Spin for more complicated logic that can run slower (and is easier for the programmer to write and create more abstract ideas) and then PASM for when you need the speed.
Most high-level languages on the Propeller work in a similar manner.
I'm not sure there is anything to compare - this trivial example can be written in either and performs the same in either. It is easier to write in Apin but not that much more difficult to write in PASM. They are two different tools that you would normally use for different things in your program. As mentioned above, your Spin program can fill HUBRAm with byte code and your PASM program can only execute from COGRAM but you can use all of HUBRAM for data if you desire.
For non-trivial programs, the differences become apparent and the best uses for each will soon show themselves.
Inline PASM is talked about and would be an interesting feature in a Spin program. I'm sure once it shows up, there will be many intersting tricks the Propeller starts performing!
I just ran your PASM program through the Simulator -
Program size is 72 bytes.
HUB RAM 80 bytes
There is a match for COG use.
The programs being at this trivial size, having it coded in PASM is not that particularly important. Now if we were to switch gears and start doing FDS, then PASM starts to become a very necessary tool.
I am really impressed with the Simulator because now you can try out some programming ideas without having to have an actual Propeller board at hand. All you really need is PropellerIDE, MCU Simulator, and a programmers calculator on the computer. In fact how would this work out on a tablet? I wonder how far jazzed is going to take the Simulator program?
I guess now would be a good time to see how a PropellerGCC program, like maybe a Toggle program, would match up to the Spin and PASM programs. I am thinking a COG C Toggle program, that would be a good match, I think?
Ray
cog_c_toggle uses 2 COGs which the simulator didn't like when I tried it earlier. It will look a lot like the Spin example using the COGNEW since there is a COG running one of the C memory model VMs and then the COG you start to blink running the actual blinking code.
lmm_toggle will look a lot like your Spin program. One COG running through a BIG loop executing some sort of byte code (or actual instructions) from HUBRAM. Unless you can digest the byte code in HUBRAM, you won't see much interesting.
The other examples I looked at looked like they were multi-COG examples.
LM who? CM what??
I had two PASM cogs that it didn't like. I do need to update though, it's been 24 hours!!
What have you done? mcusimulator let out the blue smoke!!!
dgately
I put a little "twist" in the simulator today during lunch. It's all I had time to do.
I am using the program example that mindrobots provided, coginit PASM Toggle. What I did was the following:
1. Load - loads the binary
2. Step - shows some code starting at $000, looks like the interpreter.
3. Debug - does a quick step until it hits a loop which is the PASM program code. The PASM code listing is now at $000. What just happened?
I am not sure what I am seeing here, it looks like the actual Propeller procedure is load the interpreter, then load the actual program, and run. When you do the normal Load, Run, and Stop, the COG[0] code listing looks like you have just been using the PASM code, but in fact you have missed the whole loading of the interpreter step. I got the misconception that you were really just using and running the PASM code, if this makes any sense at all.
It seems to me that it would be beneficial, to have a sequence, where you get to see the actual program run, starting at $000, stepping through the interpreter to a point where it starts too execute the PASM code. Right now you really do not get to see how the PASM code interacts or is being used by the interpreter or whatever that mechanism is called. Somebody brand new might start getting some wrong ideas as too how all this works when presented with some concept shortcuts. Just my two cents, I am just describing what my impressions are when I use the program.
Ray
1. If you remove the CON block of code, will the program still run, and why?
2. If in fact, the program is running, will the P16 be toggling?
a. At what rate? Please show your work,
b. Can the rate be manipulated and how? Please show your work.
Bonus Question.
3. Can you start another toggling sequence, maybe P17, which will be active in its own cog? Please show your work.
Ray
Propeller 101 -
(Your step #2) When the Prop 1 resets, the first progmatic thing it does is to load a copy of the Spin interpreter into COG0 and start executing it at COGRAM $000. Once the Spin interpreter gets initialized and running, the first thing it does is to execute the Spin byte code at $10 in HUBRAM (or wherever the Spin programs start - I forget). You will see all of this in the simulator if you wish to step through it.
(Your step #3a) The first Spin instruction is COGINIT, so the interpreter will read that bytecode from HUBRAM (RDBYTE) and start executing it....at some point in processing that byte code, it will execute the PASM instruction COGINIT - you can watch everything up to that point if you care to do a lot of stepping.
(Your step #3b) The PASM COGINIT instruction tells the COG to load a 496 long section of HUBRAM that it was passed a pointer to into the specified COG's RAM. In this case, the specified COG is COG0, so the PASM program will overlay the Spin interpreter that is currently in COGRAM. Once loaded, program execution starts at COGRAM $000 The simulator won't show you the details of the PASM COGINIT being executed because that is all being done inside the hardware by that one instruction (it's a software simulator, not a hardware simulator ) If you are watching this in DEBUG, then the COGRAM contents will appear to have magically changed from the Spin interpreter code to you PASM code.
If you start a PASM Trace (not a Spin Trace) of everything from the Load through to the point where you see the PASM program in COG, then you would have a list of all the steps and be able to see how the Spin interpreter does the COGINIT. This would give you the sequence you are asking for: from Spin $000 through to the PASM code executing.
I took your quiz about a week ago when I first started playing with the simulator. (I'd like to see your answers to compare! )
Bonus question puzzle:
Why does this code leave you with one blinking LED: and this code leaves you with two blinking LEDs? assuming that you have a TOGGLE16 block of PASM code that blinks pin 16 at some rate and a TOGGLE17 block of code that toggles pin 17 at some rate.
(I got myself with this while I was playing distractedly with multiple LEDs - DOH!)
As far as I know it's because the code that executes these commands are running in cog 0. In the first case you are loading the new code in the current running cog and as such, the second coginit is never reached.
In the second case, you start cog 1, and afterwards you load TOGGLE17 into the cog that starts all this. If you would put any code after this, it would not be executed.
The reason this question came up is, I am making an assumption that the Simulator is simulating an external 5MHz crystal. So when you do have the CON block code inserted everything runs correctly. Which leads to another question, will the Simulator program be simulating an EEPROM?
Maybe we should step back and try a PASM Toggle program that would have P16 toggle at 250ms, 500ms, and 1000ms.
Ray
1. Yes. It will run with the default 12MHz propeller clock.
From PropellerManual v1.1: "RCFAST ... Internal fast oscillator (~12 MHz). May be 8 MHz to 20 MHz. (Default)"
2. Yes.
2.a. The simulated rate is wrong at the moment for some reason.
2.b. To change the rate, you must change the clock.
3. Yes, see @mindrobots and @Michel L answers.
Here's a little program that blinks a bit from left to right while jumping up and down. The speed depends on the input bits.
Thanks for testing this and providing a good example.
Let me know if you see other things.
The Run timing accuracy issue with different clock rates is in the queue too.