I think the interpreter is done, barring any bugs which may pop up later, as more code gets run through it.
Unsigned divide, remainder, and comparisons were added per Eric Smith's recommendation.
This interpreter leaves cog registers $000..$0BF free for user programs, while $0C0..$0DF is a buffer that only gets disturbed by MOVExxxx/FILLxxxx/STRSIZE/STRCOMP instructions, but might serve as local-variable copies for in-line PASM code.
To execute a PASM program, you just do this in Spin2:
EXEC(@pasm_program)
Here is how you write the PASM code for this usage (2-byte header tells org/length):
DAT
pasm_program byte $000,3-1 'PASM loads/executes at $000 and is 3 instructions long
org $000 'set origin to load/execute address
xor outa,#$FF 'initially executes
_ret_ xor outb,#$FF '...then returns to execute next bytecode
tognib _ret_ xor outb,#$0F 'can be called
PASM programs can be terminate-stay-resident and use interrupts, if you want.
To call PASM code that is already loaded into $000..$0BF from Spin2:
CALL(tognib)
There will be some automation of the 2-byte header generation for in-line PASM, as well as local variable referencing.
I like the EXEC / CALL idea, Chip. Thanks for putting it in! A few questions:
(1) How can we pass values to the PASM code and get results back? It seems a common use case would be to use PASM to accelerate some frequently used functions, e.g. for floating point. It looks like we can almost pass things on the ptra stack, but I think the top of stack is kept in "x". Maybe that could be located in a known fixed location (like $1DC)?
(2) We can HUBEXEC via EXEC of a JMP instruction, but I wonder if that's a common enough use case to warrant its own instruction? It's not a big deal either way: once we can get into PASM we can do anything
LOL, have to agree with Roy and potatohead even though I find this to bee hilarious.
CORE is a better choice, not because it provides a better or more accurate description than COG does, but because it gives the folks who are familiar with the term CORE some idea of what the P1/P2 is.
Maybe hub addresses $00 to $7f can be reserved for this purpose.
For each cog we have 4 longs representing count_out,address,count_in,address
for example
to_pasm cogid ptra
shl ptra,#4 'calc address of pointers for cog
wrlong count,ptra[0] 'number of variables passed to pasm
wrlong addr,ptra[1] 'address of variable list
..
back2spin2 cogid ptra
shl ptra,#4 'calc address of pointers for cog
rdlong count,ptra[2] 'number of returned variables to spin2
rdlong addr,ptra[3] 'address of returned varaiables
Maybe hub addresses $00 to $7f can be reserved for this purpose.
For each cog we have 4 longs representing count_out,address,count_in,address
for example
to_pasm cogid ptra
shl ptra,#4 'calc address of pointers for cog
wrlong count,ptra[0] 'number of variables passed to pasm
wrlong addr,ptra[1] 'address of variable list
..
back2spin2 cogid ptra
shl ptra,#4 'calc address of pointers for cog
rdlong count,ptra[2] 'number of returned variables to spin2
rdlong addr,ptra[3] 'address of returned varaiables
Yes, there needs to be something like that, where the local variables will be copied into some registers for the PASM code and then restored to hub RAM on exit. Registers $0C0-$0DF can serve this purpose. This way, inline PASM code can use the local variables by name, as registers.
Chip
Can I make a suggestion for an addition to Pnut.
Two new directives for generating bytes for use with the RFVAR/RFVARS instructions.
Maybe somethng like
Chip
Can I make a suggestion for an addition to Pnut.
Two new directives for generating bytes for use with the RFVAR/RFVARS instructions.
Maybe somethng like
pgm byte 0,1,2,3
fvar 1234
fvars -2468
Yes, I was just thinking about that today. There is a problem, though, in that the assembler is only two-pass. We'd need more passes to resolve cases where the data are forward addresses, so that their sizes are not known on the first pass. We'd need more passes to resolve their sizes. It would take some brain power to improve the assembler. One clunky way around the problem is to have var7/var14/var21/var29 and vars7/vars14/vars21/vars29, where the data size is stated and then the data is qualified. That's probably what I'll do for now.
Yes, I was just thinking about that today. There is a problem, though, in that the assembler is only two-pass. We'd need more passes to resolve cases where the data are forward addresses, so that their sizes are not known on the first pass. We'd need more passes to resolve their sizes. It would take some brain power to improve the assembler. One clunky way around the problem is to have var7/var14/var21/var29 and vars7/vars14/vars21/vars29, where the data size is stated and then the data is qualified. That's probably what I'll do for now.
Yikes!
I hadn't thought about the extra passes needed. That adds a bit of complexity.
And of course the SPIN2 component suffers the same issue.
I think the interpreter is done, though I need to test it with compiled code.
Here is what inline PASM will look like:
PRI doit(b,c,d) : a | e, f, g
spin2_code_here_if_wanted
---
add a,b 'assembles from $000..$0BF
sub c,a 'a,b,c,d,e,f,g,... at $0C0..$0DF
mul a,b
xor d,a
---
spin2_code_here_if_wanted
You can do labels and byte/word/long declarations, as well.
Here is the interpreter code that executes an inline PASM routine:
'
'
' In-line PASM
'
inline rfvar y 'get address of pasm code
add y,pbase
rfbyte z 'get length of pasm code
setq z 'load pasm code starting at register 0
rdlong 0,y
rfbyte y 'get local variable count
setq y 'load local variables from hub into buff
rdlong buff,dbase
call #0 'call pasm code
setq y 'store local variables in buff back to hub
wrlong buff,dbase
_ret_ rdfast #0,pb 'restart bytecode stream, in case FIFO disrupted
Does the pasm have to have that --- before and after it?
If so, then it should be something like a PASM keyword at the start and then indent the actual pasm lines. That would fit the language syntax better and not use --- as a keyword which i think is awful.
Does the pasm have to have that --- before and after it?
If so, then it should be something like a PASM keyword at the start and then indent the actual pasm lines. That would fit the language syntax better and not use --- as a keyword which i think is awful.
I agree with you about --- as a keyword, but indentation alone won't cut it if the inline assembly can contain labels (which won't be indented). In fastspin I used asm / endasm to delimit the inline assembly block.
Chip
I've been running the SPIN2 interpreter through my debugger and it's running great!
Here's the current bytecodes isolated to their final sequences for verification.
ersmith
Yeah, you are right. Although, there's nothing really that couldn't stop it from having the labels indented that I can think of right now.
I prefer the ASM/ENDASM keywords though to allow for nicer formatting of the PASM code inside.
Comments
Mike
https://darpa.mil/program/hierarchical-identify-verify-exploit
Unsigned divide, remainder, and comparisons were added per Eric Smith's recommendation.
This interpreter leaves cog registers $000..$0BF free for user programs, while $0C0..$0DF is a buffer that only gets disturbed by MOVExxxx/FILLxxxx/STRSIZE/STRCOMP instructions, but might serve as local-variable copies for in-line PASM code.
To execute a PASM program, you just do this in Spin2:
EXEC(@pasm_program)
Here is how you write the PASM code for this usage (2-byte header tells org/length):
PASM programs can be terminate-stay-resident and use interrupts, if you want.
To call PASM code that is already loaded into $000..$0BF from Spin2:
CALL(tognib)
There will be some automation of the 2-byte header generation for in-line PASM, as well as local variable referencing.
https://www.rt.com/news/438298-python-master-slave-code/
I really like the mix of spin2 and pasm inside a single cog. Its going to be great.
(1) How can we pass values to the PASM code and get results back? It seems a common use case would be to use PASM to accelerate some frequently used functions, e.g. for floating point. It looks like we can almost pass things on the ptra stack, but I think the top of stack is kept in "x". Maybe that could be located in a known fixed location (like $1DC)?
(2) We can HUBEXEC via EXEC of a JMP instruction, but I wonder if that's a common enough use case to warrant its own instruction? It's not a big deal either way: once we can get into PASM we can do anything
CORE is a better choice, not because it provides a better or more accurate description than COG does, but because it gives the folks who are familiar with the term CORE some idea of what the P1/P2 is.
Maybe hub addresses $00 to $7f can be reserved for this purpose.
For each cog we have 4 longs representing count_out,address,count_in,address
for example
Yes, there needs to be something like that, where the local variables will be copied into some registers for the PASM code and then restored to hub RAM on exit. Registers $0C0-$0DF can serve this purpose. This way, inline PASM code can use the local variables by name, as registers.
Mike
Can I make a suggestion for an addition to Pnut.
Two new directives for generating bytes for use with the RFVAR/RFVARS instructions.
Maybe somethng like
Yes, I was just thinking about that today. There is a problem, though, in that the assembler is only two-pass. We'd need more passes to resolve cases where the data are forward addresses, so that their sizes are not known on the first pass. We'd need more passes to resolve their sizes. It would take some brain power to improve the assembler. One clunky way around the problem is to have var7/var14/var21/var29 and vars7/vars14/vars21/vars29, where the data size is stated and then the data is qualified. That's probably what I'll do for now.
Yikes!
I hadn't thought about the extra passes needed. That adds a bit of complexity.
And of course the SPIN2 component suffers the same issue.
That's a relief.
Here is what inline PASM will look like:
You can do labels and byte/word/long declarations, as well.
Here is the interpreter code that executes an inline PASM routine:
If so, then it should be something like a PASM keyword at the start and then indent the actual pasm lines. That would fit the language syntax better and not use --- as a keyword which i think is awful.
I agree with you about --- as a keyword, but indentation alone won't cut it if the inline assembly can contain labels (which won't be indented). In fastspin I used asm / endasm to delimit the inline assembly block.
I've been running the SPIN2 interpreter through my debugger and it's running great!
Here's the current bytecodes isolated to their final sequences for verification.
Yeah, you are right. Although, there's nothing really that couldn't stop it from having the labels indented that I can think of right now.
I prefer the ASM/ENDASM keywords though to allow for nicer formatting of the PASM code inside.