The Propeller Tool hasn't been updated for 7 years, so I doubt that it will support P2 Spin. SimpleIDE, and then later, PropellerIDE were developed to support the P1. The PropellerIDE may be updated to support P2 Spin, or maybe a whole new IDE will be developed.
It is possible to run P1 Spin on the P2. I got that working a few years ago for P2-Hot. So in that way it would be possible to use the 7-year old version of the Propeller Tool to write and run Spin programs on the P2.
How would you load the programs? Does your P1 emulator for P2 contain a P1-compatible loader?
Digging up the Propeller Tool for the P2 seems like a waste. It's closed source, single platform, does not run anywhere useful.
Please, not "a whole new IDE", doesn't the world have enough IDE's already ?!
Getting P2 support into PropellerIDE sounds like a better idea. Better yet might be a plugin for P2 support in VS Code.
Sadly I don't have the skills or time to tackle any of this.
Before adding P2 support to PropellerIDE I would think it would be necessary to find someone new to take over PropellerIDE. It seems to be unsupported at present.
I can't help feeling that a whole new IDE would suffer the same fate.
Surely a plugin for an existing IDE would be a lot easier, quicker, cheaper and require less support in the years ahead?
Not IntelliJ though. That is comlex and clunky to use, takes ages to start up and uses ridiculous amounts of RAM. What with being written in Java. I'm having to use it now for my SpinalHDL RISC V project.
Not Eclipse. That is comlex and clunky to use, takes ages to start up and uses ridiculous amounts of RAM. What with being written in Java.
VS Code seems to be the best of the bunch. Starts quickly making it natural to use for even simple things. Open Source, cross-platform. Has excellent C/C++ support. Lots of plugins, that are easy to install, for almost anything you want to do.
The Propeller Tool hasn't been updated for 7 years, so I doubt that it will support P2 Spin. SimpleIDE, and then later, PropellerIDE were developed to support the P1. The PropellerIDE may be updated to support P2 Spin, or maybe a whole new IDE will be developed.
It is possible to run P1 Spin on the P2. I got that working a few years ago for P2-Hot. So in that way it would be possible to use the 7-year old version of the Propeller Tool to write and run Spin programs on the P2.
How would you load the programs? Does your P1 emulator for P2 contain a P1-compatible loader?
David,
The answers to your questions are:
- Include a P1-compatible loader with the P1 emulator.
and
- Not yet.
Of course, it would be better to just use fastspin and run the code without an emulator.
The Propeller Tool hasn't been updated for 7 years, so I doubt that it will support P2 Spin. SimpleIDE, and then later, PropellerIDE were developed to support the P1. The PropellerIDE may be updated to support P2 Spin, or maybe a whole new IDE will be developed.
It is possible to run P1 Spin on the P2. I got that working a few years ago for P2-Hot. So in that way it would be possible to use the 7-year old version of the Propeller Tool to write and run Spin programs on the P2.
How would you load the programs? Does your P1 emulator for P2 contain a P1-compatible loader?
David,
The answers to your questions are:
- Include a P1-compatible loader with the P1 emulator.
and
- Not yet.
Of course, it would be better to just use fastspin and run the code without an emulator.
I figured you'd need to emulate the P1 loader. However, I agree that using fastspin or Chips spin2 when it becomes available would make more sense. Still, your P1 emulator is pretty cool!
It is possible to run P1 Spin on the P2. I got that working a few years ago for P2-Hot. So in that way it would be possible to use the 7-year old version of the Propeller Tool to write and run Spin programs on the P2.
? but P2 has very different timers, and no video, so any P1 code using that hardware, will not run ?
jmg,
P2 does NTSC and VGA video just fine. It's just done differently, but still assisted by instructions so not pure bit bang.
Also, I assume he's talking about Spin and not PASM, and probably isn't able to do the Spin stuff that deals with the timers (or only handles some cases?).
Yes, the Spin1 emulator only handles the P1 Spin bytecodes. It doesn't execute P1 PASM code. The INA, INB, OUTA, OUTB, DIRA and DIRB registers are handled by re-mapping from the P1 I/O register addresses to the P2 addresses. The address for the P1 CNT register is detected, and reads are done using GETCT. All other special P1 registers are not supported.
There are probably some P1 features that could be supported using SmartPins, but I haven't done anything with SmartPins yet. The worked on the P1 Spin emulator was done a few years ago with P2-Hot. It executed the more frequently used bytecodes from cog memory, and the less frequently used bytecodes were implemented in hubexec. With the addition of the XBYTE feature, the P1 bytecode interpreter should be very efficient, and should fit entirely in cog memory.
Well, most of the code out there either expects a static tile / bitmap, with optional VBLANK flag, or a video driver that is triggering things by scanline.
The P1 video engine will not work, and will need a rewrite. But, other parts may not need much, if they are SPIN, or if PASM, a lighter adjustment. A good example might be seen in Chips graphics demo. The video COG needs to be done P2 style. We could just do the same tiles and color mapping.
The graphics cog needs P1 to P2 PASM translation.
The Spin program should work almost completely unchanged.
So long as the sweep frequencies are the same, a whole lot can be made to work. Replace the video COG, and then evaluate what the others are doing and how they are triggered, communicated with.
Some of the more software video drivers may not be optimal done on a P2. However, many of those were about cloning old display means and methods, or about doing more than a P1 was designed for. The P2 basics are so much more capable as to render most of that unnecessary.
Probably easier to closely emulate the screen map, and call it good, just using palettes to match colors and such up, if needed.
Again, with graphics demo, maybe adding to it makes sense. Do a linear 16 color display, maybe 8 bit color, and the graphics COG gets much simpler. The SPIN program would work with some minor league changes.
@potatohead : I agree completely -- a lot of the Spin framework around drivers should be portable pretty much as-is, once the PASM has been translated to P2 code. And as you say, the P2 is so much more capable than P1 that it may even be feasible to write the low level drivers in Spin, particularly since with the extra RAM the size overhead of compiling to PASM with fastspin is not so onerous.
I've updated the top post with a new version. That new version is also available in GUI form at the spin2gui GitHub repo. The official release is WIndows only, but spin2gui is written in Tcl/Tk so should be trivial to get running on other platforms (I've run it on Linux myself).
The GUI is very basic, but it does make it easy to do an edit/compile/run of a Spin program for P2. If you get a chance please try it out and let me know what you think.
may even be feasible to write the low level drivers in Spin,
Yes. I need to try that. Agreed. Nice work here, BTW.
Really appreciate how you did inline PASM. Thank you.
Thanks! The inline PASM still needs some work (it's got limitations that are a bit of a pain) but it does make some things easy. For example, I was curious about the speed of the Cordic multiply versus using the mul instruction to synthesize one. It turns out Cordic is easier, but mul is faster. Cordic takes 66 cycles, whereas mul takes 44 for the full 32x32 -> 64 bit multiply (and if you don't need the upper 32 bits it could be even faster).
Here's my test code. It also illustrates the new multiple assignment feature supported by fastspin (the multiply functions return 3 values, the lo 32 bits, hi 32 bits, and time taken).
'''' program to test multiply''OBJ
ser: "SimpleSerial"PUB main | a,b
ser.start(115_200)
ser.str(string("Multiply test...", 13, 10))
try(1, 1)
try($7fffffff, $ffffffff)
try($ffff, $ffff)
PUBtry(a, b) | t, lo, hi
(lo,hi,t) := cordicmul(a, b)
report(string("cordic"), lo, hi, t)
(lo,hi,t) := hwmul(a, b)
report(string("mul16"), lo, hi, t)
PUBreport(msg, x, y, t)
ser.str(msg)
ser.str(string(" gives "))
ser.hex(x, 8)
ser.tx(",")
ser.hex(y, 8)
ser.str(string( " in "))
ser.dec(t)
ser.str(string(" cycles.", 13, 10))
PUBcordicmul(a, b) : lo, hi, t | m1, m2
t := CNT
asm
qmul a, b
getqx lo
getqy hi
endasm
t := CNT - t
PUBhwmul(a, b) : lo, hi, t | ahi, bhi
t := CNT
ahi := a>>16
bhi := b>>16
asm
mov lo, a
mov hi, ahi
mul lo, b
mul hi, bhi
mul ahi, b
mul bhi, a
mov a, ahi
shl a, #16shr ahi, #16mov b, bhi
shl b, #16shr bhi, #16add lo, a wcaddx hi, ahi
add lo, b wcaddx hi, bhi
endasm
t := CNT - t
Funny thing about the multiply timings -- I went to some effort to port the multiply routines to COG memory (basically I got fastspin -w to work properly with multiple return values; I'll be posting the updated fastspin soon) only to find out that the COG execution times and hubexec execution times are the same. I shouldn't have been surprised, I guess -- in both cases we're just running straightline code with no branches and no HUB accesses, so hubexec gets to run at full speed. It's something to keep in mind, though -- for simple functions hubexec is just as fast as COG or LUT exec!
I've updated the top post again. The multiple assignment syntax has been loosened up so that:
a,b := b,a
works (no parentheses required). I also fixed a really stupid bug where if there was no Spin code the DAT section would be optimized away, which meant that compiling Chip's .spin2 files didn't work right with fastspin. (I had been testing PNut compatibility, but I was testing it with the -c flag which explicitly asked for just the DAT section, rather than doing a regular compile). At this point I think fastspin should work the same as PNut when there's just a DAT.
I'll also mention https://github.com/totalspectrum/spin2gui/releases, a simple GUI for doing Spin programming on the P2. It's not fancy (not up to Propeller Tool level) but it does make compiling and running simple Spin programs very straightforward. It uses fastspin to compile Spin and Dave Hein's very nice loadp2 to load the binary files into the P2. If you add David Betz's propeller-load you could also use spin2gui for P1 programming, but I haven't really focused on that.
...
I'll also mention https://github.com/totalspectrum/spin2gui/releases, a simple GUI for doing Spin programming on the P2. It's not fancy (not up to Propeller Tool level) but it does make compiling and running simple Spin programs very straightforward. It uses fastspin to compile Spin and Dave Hein's very nice loadp2 to load the binary files into the P2. If you add David Betz's propeller-load you could also use spin2gui for P1 programming, but I haven't really focused on that.
Sounds good
If it is easy to add David Betz's propeller-load , sounds like that would make for a nice dual-chip design flow, which is going to help ramp P2 usage.
Someone can start now using P1, and know the environment will not change. They can check compile on P2 anytime they like.
Probably been asked before, but does your Spin support conditional compile, so those areas where P1 <> P2 can be 'user managed' ?
If it is easy to add David Betz's propeller-load , sounds like that would make for a nice dual-chip design flow, which is going to help ramp P2 usage.
Someone can start now using P1, and know the environment will not change. They can check compile on P2 anytime they like.
Well, the P2 hardware is pretty different from the P1. For simple Spin only programs it doesn't matter, but once you start using PASM it will matter a lot.
Probably been asked before, but does your Spin support conditional compile, so those areas where P1 <> P2 can be 'user managed' ?
Yes, absolutely. For example the SimpleSerial.spin file from the spin2gui library works on both P1 and P2, and it looks like:
'''' serial port definitions'''' this is for a very simple serial port'' (transmit only, and only on the default pin for now)''
#ifdef __P2__
#define OUT OUTB
#define DIR DIRB
#else
#define OUT OUTA
#define DIR DIRA
#endifCON
txpin = 30VARlong bitcycles
PUBstart(baudrate)
bitcycles := clkfreq / baudrate
return1PUBtx(c) | val, nextcnt
OUT[txpin] := 1
DIR[txpin] := 1
val := (c | 256) << 1
nextcnt := CNTrepeat10waitcnt(nextcnt += bitcycles)
OUT[txpin] := val
val >>= 1PUBstr(s) | cREPEATWHILE ((c := byte[s++]) <> 0)
tx(c)
Note that this isn't a very good way to write a serial port for P2 (you'd really want to use the smartpins) but it is quick and dirty and easy to make P1 compatible.
I've fixed a number of bugs that showed up in compiling ROM_137PBJ.spin2, so there's a new version 3.8.1. Please get it from https://github.com/totalspectrum/spin2cpp/releases This version also adds a -l flag for producing a listing file, as suggested by @jmg. To create a listing from foo.spin2, do:
fastspin -2 -l foo.spin2
This produces a file foo.lst which looks like:
00000 |
00000 | dat00000 | orgh 000000 | '00000 | ' Launch cogs 15..0 with blink program.00000 | ' Cogs that don't exist won't blink.00000 | '00000000 | org00000000 |
0000000000000000 0C04E4FC | .loop coginit cognum,#@blink 'last iteration relaunches cog 000004001 FE057CFB | djnf cognum,#.loop
00008002 |
0000800200008002 0F000000 | cognum long15
0000c 003 | '
0000c 003 | ' blink
0000c 003 | '
0000c 000 | org
0000c 000 |
0000c 000
0000c 000 010C60FD | blink cogid x 'which cog am I, 0..15?00010001 200C04F1 | add x,#32'add 32 to get pin 32..4700014002 5F0C60FD | drvnot x 'output and flip that pin00018003 100C64F0 | shl x,#16'shift up to make it big
0001c 004 1F0C60FD | waitx x 'wait that many clocks00020005 E8FF9FFD | jmp #blink 'do it again00024006 |
0002400600024006 | x res1
Only the DAT section appears in the listing, for now, so it's mainly useful for tracking down issues with assembly code. You can get a listing for the compiled Spin code, but you'll have to run fastspin twice:
ROM_137PBJ.spin2 is a good test case for an assembler. I also found several bugs in p2asm when trying to assemble that file. The unaligned data and instructions uncovered some bugs, and also using _ret_ with an instruction that used ## to include a 32-bit value. I'm impressed that PNut correctly handled the interesting conditions contained in ROM_137PBJ.spin2.
ROM_137PBJ.spin2 is a good test case for an assembler. I also found several bugs in p2asm when trying to assemble that file. The unaligned data and instructions uncovered some bugs, and also using _ret_ with an instruction that used ## to include a 32-bit value. I'm impressed that PNut correctly handled the interesting conditions contained in ROM_137PBJ.spin2.
ooh! never thought about those _ret_ issues. Pleased they worked.
ROM_137PBJ.spin2 is a good test case for an assembler. I also found several bugs in p2asm when trying to assemble that file. The unaligned data and instructions uncovered some bugs, and also using _ret_ with an instruction that used ## to include a 32-bit value. I'm impressed that PNut correctly handled the interesting conditions contained in ROM_137PBJ.spin2.
I was also bitten by the _ret_ with ##... that's a tricky one
It is useful that we have 3 mostly independent assemblers now -- hopefully we won't all make the same mistakes!
ROM_137PBJ.spin2 is a good test case for an assembler. I also found several bugs in p2asm when trying to assemble that file. The unaligned data and instructions uncovered some bugs, and also using _ret_ with an instruction that used ## to include a 32-bit value. I'm impressed that PNut correctly handled the interesting conditions contained in ROM_137PBJ.spin2.
I was also bitten by the _ret_ with ##... that's a tricky one
It is useful that we have 3 mostly independent assemblers now -- hopefully we won't all make the same mistakes!
That IS good. I see that OnSemi always validates its work from at least two different competitive tools to serve as a reality-check before it fabricates anything.
There are new releases of fastspin and spin2gui. There are a bunch of bugfixes, and some improvments:
(a) You can now pass the multiple return values from a function as parameters to another function:
' function to double a 64 bit numberPUBdbl64(ahi, alo): bhi, blo
bhi := ahi
blo := alo
asm
add blo, blo wcaddx bhi, bhi
endasm
' function to quadruple a 64 bit numberPUBquad64(ahi, alo)return dbl64( dbl64(ahi, alo) )
(b) Parameters may be given default values:
PUBincr(n = 1)
a += n
calling just plain "incr" is the same as "incr(1)". The default values must be constant (the prevents name conflicts when expanding them... I'm looking into ways to relax this).
(c) Some more Spin2 operators are supported, such as "a\b" for "use a, then set a to b".
I've published another release of spin2gui and fastspin. This has a number of bug releases for P2 (including getting coginit of Spin methods to work properly on P2) and a changed listing file format which works with the generated Spin code.
spin2gui now supports opening a listing file to view alongside the original source, if you're curious about how the compiler is converting Spin to PASM2. You can also control the optimization levels from the GUI. For example, consider the simple Spin program:
CON
ASIZE = 10VARlong a[ASIZE]
PUBdemo | irepeat i from0to ASIZE-1
a[i] := 100*i
spin2gui now has a somewhat improved interface (multiple tabs so that you can keep multiple Spin files open at the same time) and an updated fastspin with some bug fixes.
The compiler has been upgraded to use the "rep" instruction for some loops, so the example above now compiles to:
Comments
Please, not "a whole new IDE", doesn't the world have enough IDE's already ?!
Getting P2 support into PropellerIDE sounds like a better idea. Better yet might be a plugin for P2 support in VS Code.
Sadly I don't have the skills or time to tackle any of this.
I can't help feeling that a whole new IDE would suffer the same fate.
Surely a plugin for an existing IDE would be a lot easier, quicker, cheaper and require less support in the years ahead?
Not IntelliJ though. That is comlex and clunky to use, takes ages to start up and uses ridiculous amounts of RAM. What with being written in Java. I'm having to use it now for my SpinalHDL RISC V project.
Not Eclipse. That is comlex and clunky to use, takes ages to start up and uses ridiculous amounts of RAM. What with being written in Java.
VS Code seems to be the best of the bunch. Starts quickly making it natural to use for even simple things. Open Source, cross-platform. Has excellent C/C++ support. Lots of plugins, that are easy to install, for almost anything you want to do.
Hey, look at me, I'm praising an MS product!
The answers to your questions are:
- Include a P1-compatible loader with the P1 emulator.
and
- Not yet.
Of course, it would be better to just use fastspin and run the code without an emulator.
I figured you'd need to emulate the P1 loader. However, I agree that using fastspin or Chips spin2 when it becomes available would make more sense. Still, your P1 emulator is pretty cool!
? but P2 has very different timers, and no video, so any P1 code using that hardware, will not run ?
P2 does NTSC and VGA video just fine. It's just done differently, but still assisted by instructions so not pure bit bang.
Also, I assume he's talking about Spin and not PASM, and probably isn't able to do the Spin stuff that deals with the timers (or only handles some cases?).
There are probably some P1 features that could be supported using SmartPins, but I haven't done anything with SmartPins yet. The worked on the P1 Spin emulator was done a few years ago with P2-Hot. It executed the more frequently used bytecodes from cog memory, and the less frequently used bytecodes were implemented in hubexec. With the addition of the XBYTE feature, the P1 bytecode interpreter should be very efficient, and should fit entirely in cog memory.
Well, most of the code out there either expects a static tile / bitmap, with optional VBLANK flag, or a video driver that is triggering things by scanline.
The P1 video engine will not work, and will need a rewrite. But, other parts may not need much, if they are SPIN, or if PASM, a lighter adjustment. A good example might be seen in Chips graphics demo. The video COG needs to be done P2 style. We could just do the same tiles and color mapping.
The graphics cog needs P1 to P2 PASM translation.
The Spin program should work almost completely unchanged.
So long as the sweep frequencies are the same, a whole lot can be made to work. Replace the video COG, and then evaluate what the others are doing and how they are triggered, communicated with.
Some of the more software video drivers may not be optimal done on a P2. However, many of those were about cloning old display means and methods, or about doing more than a P1 was designed for. The P2 basics are so much more capable as to render most of that unnecessary.
Probably easier to closely emulate the screen map, and call it good, just using palettes to match colors and such up, if needed.
Again, with graphics demo, maybe adding to it makes sense. Do a linear 16 color display, maybe 8 bit color, and the graphics COG gets much simpler. The SPIN program would work with some minor league changes.
Eric
Yes. I need to try that. Agreed. Nice work here, BTW.
Really appreciate how you did inline PASM. Thank you.
The GUI is very basic, but it does make it easy to do an edit/compile/run of a Spin program for P2. If you get a chance please try it out and let me know what you think.
Eric
Thanks! The inline PASM still needs some work (it's got limitations that are a bit of a pain) but it does make some things easy. For example, I was curious about the speed of the Cordic multiply versus using the mul instruction to synthesize one. It turns out Cordic is easier, but mul is faster. Cordic takes 66 cycles, whereas mul takes 44 for the full 32x32 -> 64 bit multiply (and if you don't need the upper 32 bits it could be even faster).
Here's my test code. It also illustrates the new multiple assignment feature supported by fastspin (the multiply functions return 3 values, the lo 32 bits, hi 32 bits, and time taken).
'' '' program to test multiply '' OBJ ser: "SimpleSerial" PUB main | a,b ser.start(115_200) ser.str(string("Multiply test...", 13, 10)) try(1, 1) try($7fffffff, $ffffffff) try($ffff, $ffff) PUB try(a, b) | t, lo, hi (lo,hi,t) := cordicmul(a, b) report(string("cordic"), lo, hi, t) (lo,hi,t) := hwmul(a, b) report(string("mul16"), lo, hi, t) PUB report(msg, x, y, t) ser.str(msg) ser.str(string(" gives ")) ser.hex(x, 8) ser.tx(",") ser.hex(y, 8) ser.str(string( " in ")) ser.dec(t) ser.str(string(" cycles.", 13, 10)) PUB cordicmul(a, b) : lo, hi, t | m1, m2 t := CNT asm qmul a, b getqx lo getqy hi endasm t := CNT - t PUB hwmul(a, b) : lo, hi, t | ahi, bhi t := CNT ahi := a>>16 bhi := b>>16 asm mov lo, a mov hi, ahi mul lo, b mul hi, bhi mul ahi, b mul bhi, a mov a, ahi shl a, #16 shr ahi, #16 mov b, bhi shl b, #16 shr bhi, #16 add lo, a wc addx hi, ahi add lo, b wc addx hi, bhi endasm t := CNT - t
Thanks again. I'll be giving this a go.
cool,
Mike
I'll also mention https://github.com/totalspectrum/spin2gui/releases, a simple GUI for doing Spin programming on the P2. It's not fancy (not up to Propeller Tool level) but it does make compiling and running simple Spin programs very straightforward. It uses fastspin to compile Spin and Dave Hein's very nice loadp2 to load the binary files into the P2. If you add David Betz's propeller-load you could also use spin2gui for P1 programming, but I haven't really focused on that.
Sounds good
If it is easy to add David Betz's propeller-load , sounds like that would make for a nice dual-chip design flow, which is going to help ramp P2 usage.
Someone can start now using P1, and know the environment will not change. They can check compile on P2 anytime they like.
Probably been asked before, but does your Spin support conditional compile, so those areas where P1 <> P2 can be 'user managed' ?
Yes, absolutely. For example the SimpleSerial.spin file from the spin2gui library works on both P1 and P2, and it looks like:
'' '' serial port definitions '' '' this is for a very simple serial port '' (transmit only, and only on the default pin for now) '' #ifdef __P2__ #define OUT OUTB #define DIR DIRB #else #define OUT OUTA #define DIR DIRA #endif CON txpin = 30 VAR long bitcycles PUB start(baudrate) bitcycles := clkfreq / baudrate return 1 PUB tx(c) | val, nextcnt OUT[txpin] := 1 DIR[txpin] := 1 val := (c | 256) << 1 nextcnt := CNT repeat 10 waitcnt(nextcnt += bitcycles) OUT[txpin] := val val >>= 1 PUB str(s) | c REPEAT WHILE ((c := byte[s++]) <> 0) tx(c)
Note that this isn't a very good way to write a serial port for P2 (you'd really want to use the smartpins) but it is quick and dirty and easy to make P1 compatible.
fastspin -2 -l foo.spin2
This produces a file foo.lst which looks like:00000 | 00000 | dat 00000 | orgh 0 00000 | ' 00000 | ' Launch cogs 15..0 with blink program. 00000 | ' Cogs that don't exist won't blink. 00000 | ' 00000 000 | org 00000 000 | 00000 000 00000 000 0C04E4FC | .loop coginit cognum,#@blink 'last iteration relaunches cog 0 00004 001 FE057CFB | djnf cognum,#.loop 00008 002 | 00008 002 00008 002 0F000000 | cognum long 15 0000c 003 | ' 0000c 003 | ' blink 0000c 003 | ' 0000c 000 | org 0000c 000 | 0000c 000 0000c 000 010C60FD | blink cogid x 'which cog am I, 0..15? 00010 001 200C04F1 | add x,#32 'add 32 to get pin 32..47 00014 002 5F0C60FD | drvnot x 'output and flip that pin 00018 003 100C64F0 | shl x,#16 'shift up to make it big 0001c 004 1F0C60FD | waitx x 'wait that many clocks 00020 005 E8FF9FFD | jmp #blink 'do it again 00024 006 | 00024 006 00024 006 | x res 1
Only the DAT section appears in the listing, for now, so it's mainly useful for tracking down issues with assembly code. You can get a listing for the compiled Spin code, but you'll have to run fastspin twice:
fastspin -2 myspinprog.spin2 fastspin -2 -l myspinprog.p2asm
(fastspin always produces a .p2asm file with the compiled Spin code, and you can run fastspin over that to get a listing)ooh! never thought about those _ret_ issues. Pleased they worked.
I was also bitten by the _ret_ with ##... that's a tricky one
It is useful that we have 3 mostly independent assemblers now -- hopefully we won't all make the same mistakes!
That IS good. I see that OnSemi always validates its work from at least two different competitive tools to serve as a reality-check before it fabricates anything.
(a) You can now pass the multiple return values from a function as parameters to another function:
' function to double a 64 bit number PUB dbl64(ahi, alo): bhi, blo bhi := ahi blo := alo asm add blo, blo wc addx bhi, bhi endasm ' function to quadruple a 64 bit number PUB quad64(ahi, alo) return dbl64( dbl64(ahi, alo) )
(b) Parameters may be given default values:
PUB incr(n = 1) a += n
calling just plain "incr" is the same as "incr(1)". The default values must be constant (the prevents name conflicts when expanding them... I'm looking into ways to relax this).(c) Some more Spin2 operators are supported, such as "a\b" for "use a, then set a to b".
spin2gui now supports opening a listing file to view alongside the original source, if you're curious about how the compiler is converting Spin to PASM2. You can also control the optimization levels from the GUI. For example, consider the simple Spin program:
CON ASIZE = 10 VAR long a[ASIZE] PUB demo | i repeat i from 0 to ASIZE-1 a[i] := 100*i
With no optimizations this produces:00408 | _Demo 00408 | ' repeat i from 0 to ASIZE-1 00408 004804F6 | mov _var_01, #0 0040c 0040c | L__0001 0040c | ' a[i] := 100*i 0040c 244200F6 | mov _tmp001_, _var_01 00410 024264F0 | shl _tmp001_, #2 00414 1E4400F6 | mov _tmp002_, objptr 00418 224200F1 | add _tmp001_, _tmp002_ 0041c 245400F6 | mov muldiva_, _var_01 00420 645604F6 | mov muldivb_, #100 00424 0800C0FD | calla #multiply_ 00428 2A4600F6 | mov _tmp003_, muldiva_ 0042c 214660FC | wrlong _tmp003_, _tmp001_ 00430 244200F6 | mov _tmp001_, _var_01 00434 244400F6 | mov _tmp002_, _var_01 00438 014404F1 | add _tmp002_, #1 0043c 224800F6 | mov _var_01, _tmp002_ 00440 0A485CF2 | cmps _var_01, #10 wcz 00444 C4FF9FCD | if_b jmp #@L__0001 00448 00448 | _Demo_ret 00448 2E0064FD | reta
With full optimizations this comes down to:00408 | _Demo 00408 001804F6 | mov _var_02, #0 0040c 081A00F6 | mov _var_03, objptr 00410 0A1604F6 | mov _var_01, #10 00414 00414 | L__0003 00414 | ' a[i] := 100*i 00414 0D1860FC | wrlong _var_02, _var_03 00418 641804F1 | add _var_02, #100 0041c 041A04F1 | add _var_03, #4 00420 FC176CFB | djnz _var_01, #@L__0003 00424 00424 | _Demo_ret 00424 2E0064FD | reta
The compiler has been upgraded to use the "rep" instruction for some loops, so the example above now compiles to:
00408 | _Demo 00408 002004F6 | mov _var_02, #0 0040c 0C2200F6 | mov _var_03, objptr 00410 0A1E04F6 | mov _var_01, #10 00414 0A06DCFC | rep @L__0006, #10 00418 00418 | L__0003 00418 | ' a[i] := 100*i 00418 112060FC | wrlong _var_02, _var_03 0041c 642004F1 | add _var_02, #100 00420 042204F1 | add _var_03, #4 00424 00424 | L__0006 00424 00424 | _Demo_ret 00424 2E0064FD | reta
I'm eager to give it a proper go.