P1 Spin Interpreter for P2

I started from scratch again in converting my faster P1 spin interpreter to run on P2.
What i am after is to run P1 compiled spin on the P2. There will be some things it cannot do such as videeo (waitvid) and some of the timer hardware differences, but overall most code should work.
So, let’s look at the makeup of hub code for the P1 object... (P1 spin on P2 will only use the bottom 64KB of HUB)
$0000(4) clockfreq - initially jump over spin code then updated to clockfreq
$0004(1) clockmode - not used
$0005(1) checksum - not used
$0006(...) spin code - same
* My P2 interpreter uses COG & LUT for extra speed
* PTRA & PTRB are used for pcurr and dcurr respectively
Currently how this works is P1 compiled spin bytecode is copied into the P2 source as bytes with the first 4 bytes replaced with a jump over the bytecode. The bottom 64KB will be reserved for P1 spin bytecode and interpreter.
What i am after is to run P1 compiled spin on the P2. There will be some things it cannot do such as videeo (waitvid) and some of the timer hardware differences, but overall most code should work.
So, let’s look at the makeup of hub code for the P1 object... (P1 spin on P2 will only use the bottom 64KB of HUB)
$0000(4) clockfreq - initially jump over spin code then updated to clockfreq
$0004(1) clockmode - not used
$0005(1) checksum - not used
$0006(...) spin code - same
* My P2 interpreter uses COG & LUT for extra speed
* PTRA & PTRB are used for pcurr and dcurr respectively
Currently how this works is P1 compiled spin bytecode is copied into the P2 source as bytes with the first 4 bytes replaced with a jump over the bytecode. The bottom 64KB will be reserved for P1 spin bytecode and interpreter.
Comments
How were you going to handle PASM? Were you going to translate that from P1 to P2 in your compiler? And which compiler were you going to use?
Just out of curiousity, are you doing this for fun (totally understandable) and/or "because it's there", or do you have a specific use case in mind? If the latter, have you looked at fastspin? It can already compile most P1 Spin programs (the Spin part, that is; I don't try to translate PASM). If we combined that with a P1 PASM to P2 PASM translator would that do everything you want?
Regards,
Eric
2. Because i can run P1 spin code
I am using pre-compiled P1 binaries. I’ve converted my P1 PASM (my Interpreter) to P2. So I am not using any new compilers for the P1 spin.
However, maybe I should take a look at fastspin. Might be fun too
Ah, so your pre-compiled P1 binaries do not have any PASM baked into their DAT sections? Then I guess you should be good to go, once the interpreter is up. Have fun!
(And if you do want to try out fastspin on your Spin code, there are options to compile the binaries to run at different base addresses, so that one program can load another. IIRC one of your use-cases was a small operating system that loads programs from disk, so that might be a way to achieve that.)
I can (and have) put debug code into the interpreter to output (using the ROM Monitor) to display variables etc at certain points in the interpreter.
It’s amazing how much code space i saved when converting pasm from p1 to p2. Those ptra++ and —ptrb save quite a bit on their own
And yes, another reason is for my OS on SD
I translated the DIRx/OUTx/INx registers and implemented PAR and CNT. The pin registers work for both ports A and B.
I rewrote FILL/MOVE bytecodes using REP.
I rewrote the maths routines to use skipf. Wow, what a boost this will be, and much less code too. Its not tested yet though.
BTW we have an extra bytecode available since we don’t have WAITVID, and $3C was unused too.
I looked at XBYTE but not for me just yet anyway.
Might be worth taking a look at openspin with a view to changing the DIR/OUT/IN register addresses, and removing CTR/FRQ/PHS/VID registers and WAITVID to output compiled spin1 for P2. Probably a minor change to highlight errors. I wonder if P2ASM could co-exist with OpenSpin?
Actually I am debugging it with calls inserted into the spin interpreter to output serial messages using the ROM Monitor. Some of those messages pause for serial entry (just a cr) and I also call the monitor too, and return.
I haven't played with the inbuilt debugger on the P2 yet.
I keep finding new instruction toys in P2
I used skip in the ROM SD so I have coded the maths ops in the interpreter to use these extensively.
write down some simple example how to use Monitor/Debugger.
Mike
Have a look at this thread
https://forums.parallax.com/discussion/169842/fun-with-the-p2-rom#latest
They are currently untested. If you see any holes/bugs please comment
Just realised there is an error in some skipf values. The top 1's need to be 0's once all required instructions are skipped
Here are the VAR bytecodes
' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ' % $40..7F Variable operation % ' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% '---------------------------------------------------------------------------------------------------------------------------- ' .---v---v---v---v---v---v---v---. These opcodes allow fast access by making long access '$40-7F Fast access VAR, LOC | 0 1 | w | v v v | o o | to the first few long entries in the variable space ' `---^---^---^---^---^---^---^---' or stack a single byte opcode. The single byte opcodes ' | | | are effectively expanded within the interpreter... ' 0= VAR Address 00= PUSH Read - push result in stack ' 1= LOC (adr = v*4) 01= POP Write - pop value from stack ' | | 10= USING 2nd opcode (assignment) executed, result in target ' | | 11= PUSH # Push address of destination into stack ' | `---------|------------------------. ' `-----------. | | ' \|/ \|/ \|/ ' .---v---v---v---v---v---v---v---. .---v---v---v---v---v---v---v---. ' | 1 | 1 0 | 0 | 1 w | o o | | 0 0 0 | v v v | 0 0 | ' `---^---^---^---^---^---^---^---' `---^---^---^---^---^---^---^---' '---------------------------------------------------------------------------------------------------------------------------- ' ADR ' VAR xxx PUSH $%00_0000_0000_1111_1100_1000 ' " " POP $%00_0000_0000_1111_0011_1000 ' " " ASGN $%00_0000_0000_1100_1111_1000 ?????????? ' " " PUSH# $%00_0000_0000_0011_1111_1000 ' ' LOC xxx PUSH $%00_0000_0000_1111_1100_0100 ' " " POP $%00_0000_0000_1111_0011_0100 ' " " ASGN $%00_0000_0000_1100_1111_0100 ?????????? ' " " PUSH# $%00_0000_0000_0011_1111_0100 'varop {adr} mov adr,op '\ isolate adr $%--_----_----_----_----_---0 and adr,#%00011100 '/ adr=n*4 $%--_----_----_----_----_--0- ' {+base} add adr,vbase ' VAR: +base $%--_----_----_----_----_-0-- add adr,dbase ' LOC: +base $%--_----_----_----_----_0--- ' {read var} rdlong x,adr '\ PUSH: read var $%--_----_----_----_---0_---- {push var} wrlong x,ptrb++ '/ & push $%--_----_----_----_--0-_---- ' {pop var} rdlong x,--ptrb '\ POP: pop var $%--_----_----_----_-0--_---- {write var} wrlong x,adr '/ & write $%--_----_----_----_0---_---- ' nop '\ ASGN: $%--_----_----_---0_----_---- ?????????? nop '/ $%--_----_----_--0-_----_---- ?????????? ' and x,maskword '\ PUSH#: mask adr $%--_----_----_-0--_----_---- {push adr} wrlong adr,ptrb++ '/ & push $%--_----_----_0---_----_---- ' jmp #loop ' '------------------------------------------------------------------------------------------------------------
and the table'---------------------------------------------------------------------------------------------------------------------------- long $%00_0000_0000_1111_1100_1000 <<10 +varop '$40 VAR PUSH addr=0*4= 00 long $%00_0000_0000_1111_0011_1000 <<10 +varop '$41 VAR POP addr=0*4= 00 long $%00_0000_0000_1100_1111_1000 <<10 +varop '$42 VAR USING addr=0*4= 00 long $%00_0000_0000_0011_1111_1000 <<10 +varop '$43 VAR PUSH # addr=0*4= 00 long $%00_0000_0000_1111_1100_1000 <<10 +varop '$44 VAR PUSH addr=1*4= 04 long $%00_0000_0000_1111_0011_1000 <<10 +varop '$45 VAR POP addr=1*4= 04 long $%00_0000_0000_1100_1111_1000 <<10 +varop '$46 VAR USING addr=1*4= 04 long $%00_0000_0000_0011_1111_1000 <<10 +varop '$47 VAR PUSH # addr=1*4= 04 long $%00_0000_0000_1111_1100_1000 <<10 +varop '$48 VAR PUSH addr=2*4= 08 long $%00_0000_0000_1111_0011_1000 <<10 +varop '$49 VAR POP addr=2*4= 08 long $%00_0000_0000_1100_1111_1000 <<10 +varop '$4A VAR USING addr=2*4= 08 long $%00_0000_0000_0011_1111_1000 <<10 +varop '$4B VAR PUSH # addr=2*4= 08 long $%00_0000_0000_1111_1100_1000 <<10 +varop '$4C VAR PUSH addr=3*4= 0C long $%00_0000_0000_1111_0011_1000 <<10 +varop '$4D VAR POP addr=3*4= 0C long $%00_0000_0000_1100_1111_1000 <<10 +varop '$4E VAR USING addr=3*4= 0C long $%00_0000_0000_0011_1111_1000 <<10 +varop '$4F VAR PUSH # addr=3*4= 0C long $%00_0000_0000_1111_1100_1000 <<10 +varop '$50 VAR PUSH addr=4*4= 10 long $%00_0000_0000_1111_0011_1000 <<10 +varop '$51 VAR POP addr=4*4= 10 long $%00_0000_0000_1100_1111_1000 <<10 +varop '$52 VAR USING addr=4*4= 10 long $%00_0000_0000_0011_1111_1000 <<10 +varop '$53 VAR PUSH # addr=4*4= 10 long $%00_0000_0000_1111_1100_1000 <<10 +varop '$54 VAR PUSH addr=5*4= 14 long $%00_0000_0000_1111_0011_1000 <<10 +varop '$55 VAR POP addr=5*4= 14 long $%00_0000_0000_1100_1111_1000 <<10 +varop '$56 VAR USING addr=5*4= 14 long $%00_0000_0000_0011_1111_1000 <<10 +varop '$57 VAR PUSH # addr=5*4= 14 long $%00_0000_0000_1111_1100_1000 <<10 +varop '$58 VAR PUSH addr=6*4= 18 long $%00_0000_0000_1111_0011_1000 <<10 +varop '$59 VAR POP addr=6*4= 18 long $%00_0000_0000_1100_1111_1000 <<10 +varop '$5A VAR USING addr=6*4= 18 long $%00_0000_0000_0011_1111_1000 <<10 +varop '$5B VAR PUSH # addr=6*4= 18 long $%00_0000_0000_1111_1100_1000 <<10 +varop '$5C VAR PUSH addr=7*4= 1C long $%00_0000_0000_1111_0011_1000 <<10 +varop '$5D VAR POP addr=7*4= 1C long $%00_0000_0000_1100_1111_1000 <<10 +varop '$5E VAR USING addr=7*4= 1C long $%00_0000_0000_0011_1111_1000 <<10 +varop '$5F VAR PUSH # addr=7*4= 1C long $%00_0000_0000_1111_1100_0100 <<10 +varop '$60 LOC PUSH addr=0*4= 00 long $%00_0000_0000_1111_0011_0100 <<10 +varop '$61 LOC POP addr=0*4= 00 long $%00_0000_0000_1100_1111_0100 <<10 +varop '$62 LOC USING addr=0*4= 00 long $%00_0000_0000_0011_1111_0100 <<10 +varop '$63 LOC PUSH # addr=0*4= 00 long $%00_0000_0000_1111_1100_0100 <<10 +varop '$64 LOC PUSH addr=1*4= 04 long $%00_0000_0000_1111_0011_0100 <<10 +varop '$65 LOC POP addr=1*4= 04 long $%00_0000_0000_1100_1111_0100 <<10 +varop '$66 LOC USING addr=1*4= 04 long $%00_0000_0000_0011_1111_0100 <<10 +varop '$67 LOC PUSH # addr=1*4= 04 long $%00_0000_0000_1111_1100_0100 <<10 +varop '$68 LOC PUSH addr=2*4= 08 long $%00_0000_0000_1111_0011_0100 <<10 +varop '$69 LOC POP addr=2*4= 08 long $%00_0000_0000_1100_1111_0100 <<10 +varop '$6A LOC USING addr=2*4= 08 long $%00_0000_0000_0011_1111_0100 <<10 +varop '$6B LOC PUSH # addr=2*4= 08 long $%00_0000_0000_1111_1100_0100 <<10 +varop '$6C LOC PUSH addr=3*4= 0C long $%00_0000_0000_1111_0011_0100 <<10 +varop '$6D LOC POP addr=3*4= 0C long $%00_0000_0000_1100_1111_0100 <<10 +varop '$6E LOC USING addr=3*4= 0C long $%00_0000_0000_0011_1111_0100 <<10 +varop '$6F LOC PUSH # addr=3*4= 0C long $%00_0000_0000_1111_1100_0100 <<10 +varop '$70 LOC PUSH addr=4*4= 10 long $%00_0000_0000_1111_0011_0100 <<10 +varop '$71 LOC POP addr=4*4= 10 long $%00_0000_0000_1100_1111_0100 <<10 +varop '$72 LOC USING addr=4*4= 10 long $%00_0000_0000_0011_1111_0100 <<10 +varop '$73 LOC PUSH # addr=4*4= 10 long $%00_0000_0000_1111_1100_0100 <<10 +varop '$74 LOC PUSH addr=5*4= 14 long $%00_0000_0000_1111_0011_0100 <<10 +varop '$75 LOC POP addr=5*4= 14 long $%00_0000_0000_1100_1111_0100 <<10 +varop '$76 LOC USING addr=5*4= 14 long $%00_0000_0000_0011_1111_0100 <<10 +varop '$77 LOC PUSH # addr=5*4= 14 long $%00_0000_0000_1111_1100_0100 <<10 +varop '$78 LOC PUSH addr=6*4= 18 long $%00_0000_0000_1111_0011_0100 <<10 +varop '$79 LOC POP addr=6*4= 18 long $%00_0000_0000_1100_1111_0100 <<10 +varop '$7A LOC USING addr=6*4= 18 long $%00_0000_0000_0011_1111_0100 <<10 +varop '$7B LOC PUSH # addr=6*4= 18 long $%00_0000_0000_1111_1100_0100 <<10 +varop '$7C LOC PUSH addr=7*4= 1C long $%00_0000_0000_1111_0011_0100 <<10 +varop '$7D LOC POP addr=7*4= 1C long $%00_0000_0000_1100_1111_0100 <<10 +varop '$7E LOC USING addr=7*4= 1C long $%00_0000_0000_0011_1111_0100 <<10 +varop '$7F LOC PUSH # addr=7*4= 1C '----------------------------------------------------------------------------------------------------------------------------
' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ' % $80-DF Memory operation % ' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% '---------------------------------------------------------------------------------------------------------------------------- ' .---v---v---v---v---v---v---v---. '$80-DF Access MEM, OBJ, | 1 | s s | i | w w | o o | (96 stack load / save opcodes) ' VAR and LOC `---^---^---^---^---^---^---^---' ' | | | | ' 00= Byte | | 00= PUSH Read - push result in stack ' 01= Word | | 01= POP Write - pop value from stack ' 10= Long | | 10= USING 2nd opcode (assignment) executed, result in target ' (11= mathop) | | 11= PUSH # Push address of destination into stack ' | 00= MEM base popped from stack, if i=1 add offset ' | 01= OBJ base is object base , if i=1 add offset ' | 10= VAR base is variable base , if i=1 add offset ' | 11= LOC base is stack base , if i=1 add offset ' 0= no offset ' 1=[]= add offset (indexed) '---------------------------------------------------------------------------------------------------------------------------- ' {+index} 'INDEX: pop/scale/+ $%--_----_----_----_--0-_-000 ' {pop adr} 'MEM: pop adr $%--_----_----_----_----_0--- ' {read adr} 'OBJ: read adr+pbase $%--_----_----_----_-0-0_---- ' {read adr} 'VAR: read adr+vbase $%--_----_----_----_0--0_---- ' {read adr} 'LOC: read adr+dbase $%--_----_----_---0_---0_---- ' {read var byte} 'PUSH: read byte $%--_----_----_--0-_----_---- ' {write var byte} 'POP: write byte $%--_----_-0--_----_----_---- ' {read var word} 'PUSH: read word $%--_----_----_-0--_----_---- ' {write var word} 'POP: write word $%--_----_0---_----_----_---- ' {read var long} 'PUSH: read long $%--_----_----_0---_----_---- ' {write var long} 'POP: write long $%--_---0_----_----_----_---- ' {assign} 'ASGN: $%--_-00-_----_----_----_---- ?????????? memop {pop index} rdlong x,--ptrb '\ INDEX: pop $%--_----_----_----_----_---0 { & scale} shl x,#1 '| & scale $%--_----_----_----_----_--0- shl x,#2 '/ $%--_----_----_----_----_-0-- {pop adr} rdlong adr,--ptrb 'MEM: pop adr $%--_----_----_----_----_0--- {read adr} call #\read_adr 'OBJ/VAR/LOC: read adr $%--_----_----_----_---0_---- {+index} add adr,x 'INDEX: +index $%--_----_----_----_--0-_---- {+base} add adr,pbase 'OBJ: +pbase $%--_----_----_----_-0--_---- add adr,vbase 'VAR: +vbase $%--_----_----_----_0---_---- add adr,dbase 'LOC: +dbase $%--_----_----_---0_----_---- {read var} rdbyte x,adr '\ PUSH: read byte $%--_----_----_--0-_----_---- rdword x,adr '| read word $%--_----_----_-0--_----_---- rdlong x,adr '| read long $%--_----_----_0---_----_---- {push var} wrlong x,ptrb++ '/ & push result $%--_----_---0_----_----_---- {pop var} rdlong x,--ptrb '\ POP: pop value $%--_----_--0-_----_----_---- {write var} wrbyte x,adr '| & write byte $%--_----_-0--_----_----_---- wrword x,adr '| write word $%--_----_0---_----_----_---- wrlong x,adr '/ write long $%--_---0_----_----_----_---- ' {assign} nop '\ ASGN: $%--_--0-_----_----_----_---- ?????????? nop '/ $%--_-0--_----_----_----_---- ?????????? {push address} and adr,maskword '\ PUSH#: mask $%--_0---_----_----_----_---- wrlong adr,ptrb++ '/ & push adr $%-0_----_----_----_----_---- jmp #loop '----------------------------------------------------------------------------------------------------------------------------
'---------------------------------------------------------------------------------------------------------------------------- long $%11_1111_1110_1101_1111_0111 <<10 +memop '$80 Byte MEM PUSH long $%11_1111_1001_1111_1111_0111 <<10 +memop '$81 Byte MEM POP long $%11_1001_1111_1111_1111_0111 <<10 +memop '$82 Byte MEM USING ?????????? long $%10_0111_1111_1111_1111_0111 <<10 +memop '$83 Byte MEM PUSH # long $%11_1111_1110_1101_1010_1111 <<10 +memop '$84 Byte OBJ PUSH long $%11_1111_1001_1111_1010_1111 <<10 +memop '$85 Byte OBJ POP long $%11_1001_1111_1111_1010_1111 <<10 +memop '$86 Byte OBJ USING ?????????? long $%10_0111_1111_1111_1010_1111 <<10 +memop '$87 Byte OBJ PUSH # long $%11_1111_1110_1101_0110_1111 <<10 +memop '$88 Byte VAR PUSH long $%11_1111_1001_1111_0110_1111 <<10 +memop '$89 Byte VAR POP long $%11_1001_1111_1111_0110_1111 <<10 +memop '$8A Byte VAR USING ?????????? long $%10_0111_1111_1111_0110_1111 <<10 +memop '$8B Byte VAR PUSH # long $%11_1111_1110_1100_1110_1111 <<10 +memop '$8C Byte LOC PUSH long $%11_1111_1001_1110_1110_1111 <<10 +memop '$8D Byte LOC POP long $%11_1001_1111_1110_1110_1111 <<10 +memop '$8E Byte LOC USING ?????????? long $%10_0111_1111_1110_1110_1111 <<10 +memop '$8F Byte LOC PUSH # long $%11_1111_1110_1101_1101_0000 <<10 +memop '$90 Byte [] MEM PUSH long $%11_1111_1001_1111_1101_0000 <<10 +memop '$91 Byte [] MEM POP long $%11_1001_1111_1111_1101_0000 <<10 +memop '$92 Byte [] MEM USING ?????????? long $%10_0111_1111_1111_1101_0000 <<10 +memop '$93 Byte [] MEM PUSH # long $%11_1111_1110_1101_1000_1000 <<10 +memop '$94 Byte [] OBJ PUSH long $%11_1111_1001_1111_1000_1000 <<10 +memop '$95 Byte [] OBJ POP long $%11_1001_1111_1111_1000_1000 <<10 +memop '$96 Byte [] OBJ USING ?????????? long $%10_0111_1111_1111_1000_1000 <<10 +memop '$97 Byte [] OBJ PUSH # long $%11_1111_1110_1101_0100_1000 <<10 +memop '$98 Byte [] VAR PUSH long $%11_1111_1001_1111_0100_1000 <<10 +memop '$99 Byte [] VAR POP long $%11_1001_1111_1111_0100_1000 <<10 +memop '$9A Byte [] VAR USING ?????????? long $%10_0111_1111_1111_0100_1000 <<10 +memop '$9B Byte [] VAR PUSH # long $%11_1111_1110_1100_1100_1000 <<10 +memop '$9C Byte [] LOC PUSH long $%11_1111_1001_1110_1100_1000 <<10 +memop '$9D Byte [] LOC POP long $%11_1001_1111_1110_1100_1000 <<10 +memop '$9E Byte [] LOC USING ?????????? long $%10_0111_1111_1110_1100_1000 <<10 +memop '$9F Byte [] LOC PUSH # long $%11_1111_1110_1011_1111_0111 <<10 +memop '$A0 Word MEM PUSH long $%11_1111_0101_1111_1111_0111 <<10 +memop '$A1 Word MEM POP long $%11_1001_1111_1111_1111_0111 <<10 +memop '$A2 Word MEM USING ?????????? long $%10_0111_1111_1111_1111_0111 <<10 +memop '$A3 Word MEM PUSH # long $%11_1111_1110_1011_1010_1111 <<10 +memop '$A4 Word OBJ PUSH long $%11_1111_0101_1111_1010_1111 <<10 +memop '$A5 Word OBJ POP long $%11_1001_1111_1111_1010_1111 <<10 +memop '$A6 Word OBJ USING ?????????? long $%10_0111_1111_1111_1010_1111 <<10 +memop '$A7 Word OBJ PUSH # long $%11_1111_1110_1011_0110_1111 <<10 +memop '$A8 Word VAR PUSH long $%11_1111_0101_1111_0110_1111 <<10 +memop '$A9 Word VAR POP long $%11_1001_1111_1111_0110_1111 <<10 +memop '$AA Word VAR USING ?????????? long $%10_0111_1111_1111_0110_1111 <<10 +memop '$AB Word VAR PUSH # long $%11_1111_1110_1010_1110_1111 <<10 +memop '$AC Word LOC PUSH long $%11_1111_0101_1110_1110_1111 <<10 +memop '$AD Word LOC POP long $%11_1001_1111_1110_1110_1111 <<10 +memop '$AE Word LOC USING ?????????? long $%10_0111_1111_1110_1110_1111 <<10 +memop '$AF Word LOC PUSH # long $%11_1111_1110_1111_1101_0000 <<10 +memop '$B0 Word [] MEM PUSH long $%11_1111_1101_1111_1101_0000 <<10 +memop '$B1 Word [] MEM POP long $%11_1001_1111_1111_1101_0000 <<10 +memop '$B2 Word [] MEM USING ?????????? long $%10_0111_1111_1111_1101_0000 <<10 +memop '$B3 Word [] MEM PUSH # long $%11_1111_1110_1111_1000_1000 <<10 +memop '$B4 Word [] OBJ PUSH long $%11_1111_1101_1111_1000_1000 <<10 +memop '$B5 Word [] OBJ POP long $%11_1001_1111_1111_1000_1000 <<10 +memop '$B6 Word [] OBJ USING ?????????? long $%10_0111_1111_1111_1000_1000 <<10 +memop '$B7 Word [] OBJ PUSH # long $%11_1111_1110_1111_0100_1000 <<10 +memop '$B8 Word [] VAR PUSH long $%11_1111_1101_1111_0100_1000 <<10 +memop '$B9 Word [] VAR POP long $%11_1001_1111_1111_0100_1000 <<10 +memop '$BA Word [] VAR USING ?????????? long $%10_0111_1111_1111_0100_1000 <<10 +memop '$BB Word [] VAR PUSH # long $%11_1111_1110_1110_1100_1000 <<10 +memop '$BC Word [] LOC PUSH long $%11_1111_1101_1110_1100_1000 <<10 +memop '$BD Word [] LOC POP long $%11_1001_1111_1110_1100_1000 <<10 +memop '$BE Word [] LOC USING ?????????? long $%10_0111_1111_1110_1100_1000 <<10 +memop '$BF Word [] LOC PUSH # long $%11_1111_1110_0111_1111_0111 <<10 +memop '$C0 Long MEM PUSH long $%11_1110_1101_1111_1111_0111 <<10 +memop '$C1 Long MEM POP long $%11_1001_1111_1111_1111_0111 <<10 +memop '$C2 Long MEM USING ?????????? long $%10_0111_1111_1111_1111_0111 <<10 +memop '$C3 Long MEM PUSH # long $%11_1111_1110_0111_1010_1111 <<10 +memop '$C4 Long OBJ PUSH long $%11_1110_1101_1111_1010_1111 <<10 +memop '$C5 Long OBJ POP long $%11_1001_1111_1111_1010_1111 <<10 +memop '$C6 Long OBJ USING ?????????? long $%10_0111_1111_1111_1010_1111 <<10 +memop '$C7 Long OBJ PUSH # long $%11_1111_1110_0111_0110_1111 <<10 +memop '$C8 Long VAR PUSH \ see also $40-7F bytecodes long $%11_1110_1101_1111_0110_1111 <<10 +memop '$C9 Long VAR POP | long $%11_1001_1111_1111_0110_1111 <<10 +memop '$CA Long VAR USING | ?????????? long $%10_0111_1111_1111_0110_1111 <<10 +memop '$CB Long VAR PUSH # | long $%11_1111_1110_0110_1110_1111 <<10 +memop '$CC Long LOC PUSH | long $%11_1110_1101_1110_1110_1111 <<10 +memop '$CD Long LOC POP | long $%11_1001_1111_1110_1110_1111 <<10 +memop '$CE Long LOC USING | ?????????? long $%10_0111_1111_1110_1110_1111 <<10 +memop '$CF Long LOC PUSH # / long $%11_1111_1110_0111_1101_0000 <<10 +memop '$D0 Long [] MEM PUSH long $%11_1110_1101_1111_1101_0000 <<10 +memop '$D1 Long [] MEM POP long $%11_1001_1111_1111_1101_0000 <<10 +memop '$D2 Long [] MEM USING ?????????? long $%10_0111_1111_1111_1101_0000 <<10 +memop '$D3 Long [] MEM PUSH # long $%11_1111_1110_0111_1000_1000 <<10 +memop '$D4 Long [] OBJ PUSH long $%11_1110_1101_1111_1000_1000 <<10 +memop '$D5 Long [] OBJ POP long $%11_1001_1111_1111_1000_1000 <<10 +memop '$D6 Long [] OBJ USING ?????????? long $%10_0111_1111_1111_1000_1000 <<10 +memop '$D7 Long [] OBJ PUSH # long $%11_1111_1110_0111_0100_1000 <<10 +memop '$D8 Long [] VAR PUSH long $%11_1110_1101_1111_0100_1000 <<10 +memop '$D9 Long [] VAR POP long $%11_1001_1111_1111_0100_1000 <<10 +memop '$DA Long [] VAR USING ?????????? long $%10_0111_1111_1111_0100_1000 <<10 +memop '$DB Long [] VAR PUSH # long $%11_1111_1110_0110_1100_1000 <<10 +memop '$DC Long [] LOC PUSH long $%11_1110_1101_1110_1100_1000 <<10 +memop '$DD Long [] LOC POP long $%11_1001_1111_1110_1100_1000 <<10 +memop '$DE Long [] LOC USING ?????????? long $%10_0111_1111_1110_1100_1000 <<10 +memop '$DF Long [] LOC PUSH # '----------------------------------------------------------------------------------------------------------------------------
Note the math_bin & math_un code is not currently in the code
' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ' % $E0..FF Math operation % ' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% '---------------------------------------------------------------------------------------------------------------------------- ' .---v---v---v---v---v---v---v---. '$E0-FF Math operation | 1 1 1 | o o o o o | (32 maths opcodes) ' `---^---^---^---^---^---^---^---' ' ' .---v---v---v---v---v---v---v---. ' Math Assignment (USING) | p 1 s | o o o o o | (32 maths opcodes) "op2" ' operation `---^---^---^---^---^---^---^---' ' | | ' | (!s) 0 = swap binary args ' | 1 = no swap ' (!p) 0 = push ' 1 = no push '---------------------------------------------------------------------------------------------------------------------------- math_bin test a,#%00100000 wz '!s=swap binary args (for assignment operator) '<<<<<<<<<<<<<<<<<<<< if_nz rdlong y,--ptrb 'if binary+!swap 1st into y rdlong x,--ptrb 'if binary+!swap 2nd into x, if binary+swap 1st into x if_nz jmp #math_EFx math_un rdlong y,--ptrb 'if unary 1st into y (i.e.swap), if binary+swap 2nd into y '<<<<<<<<<<<<<<<<<<<< math_EFx shr vtable,#9 'shift to 2nd vector sets vector,vtable '2nd vector (9bits) '<<<<<<<<<<<<<<<<<<<< jmp vector 'indirect jump to: math_E0...FF '------------------------------------------------------------------------------------------------------------ math_E0 '$F0=AND bool ' %11_1111_1110_1111_1111_0000 '$F2=OR bool ' %11_1111_1011_1111_1111_0000 .math_F0 CMP x,#0 wz ' * 'f=0,t=-1 MUXNZ x,masklong ' * CMP y,#0 wz ' * 'f=0,t=-1 MUXNZ y,masklong ' * .math_E0 ROR x,y '$E0=ROR ' %11_1111_1111_1111_1110_1111 ROL x,y '$E1=ROL ' %11_1111_1111_1111_1101_1111 SHR x,y '$E2=SHR ' %11_1111_1111_1111_1011_1111 SHL x,y '$E3=SHL ' %11_1111_1111_1111_0111_1111 FGES x,y '$E4=FGES ' %11_1111_1111_1110_1111_1111 FLES x,y '$E5=FLES ' %11_1111_1111_1101_1111_1111 NEG x '$E6=NEG un ' %11_1111_1111_1011_1111_1111 NOT x '$E7=NOT un ' %11_1111_1111_0111_1111_1111 AND x,y '$E8=AND ' %11_1111_1110_1111_1111_1111 ABS x '$E9=ABS un ' %11_1111_1101_1111_1111_1111 OR x,y '$EA=OR ' %11_1111_1011_1111_1111_1111 XOR x,y '$EB=XOR ' %11_1111_0111_1111_1111_1111 ADD x,y '$EC=ADD ' %11_1110_1111_1111_1111_1111 SUB x,y '$ED=SUB ' %11_1101_1111_1111_1111_1111 SAR x,y '$EE=SAR ' %11_1011_1111_1111_1111_1111 REV x '$EF=REV un ' %11_0111_1111_1111_1111_1111 *un ENCOD x '$F1=ENCOD un ' %10_1111_1111_1111_1111_1111 DECOD x '$F3=DECOD un ' %01_1111_1111_1111_1111_1111 jmp #pushr 'push result '------------------------------------------------------------------------------------------------------------ math_F4 getct c1 skipf skipover ' skip over instruction(s) ' skip skipover ' skip over instruction(s) '------------------------------------------------------------------------------------------------------------ QMUL x,y '$F4=MPY ' %00_0001_1111_1111_1111_1100 GETQX x ' ' * QMUL x,y '$F5=MPY_MSW ' %00_0001_1111_1111_1111_0011 GETQY x ' ' * QDIV x,y '$F6=DIV ' %00_0001_1111_1111_1100_1111 GETQX x ' ' * QDIV x,y '$F7=MOD ' %00_0001_1111_1111_0011_1111 GETQY x ' ' * QSQRT x,#0 '$F8=SQRT un ' %00_0001_1111_1100_1111_1111 *un GETQX x ' * '$F9..$FE=test signed LT/GT/NE/EQ/LE/GE '$F9..$FE ' %00_0000_1000_0011_1111_1111 'LT/GT/NE/EQ/LE/GE CMPS x,y wcz ' * 'tests if_z MOV x,#%100 ' * 'equal? if_nz MOV x,#%010 ' * 'above? if_c MOV x,#%001 ' * 'below? ANDN x,a wz ' * 'set t/f CMP y,#0 wz '$FF=NOT bool' %00_0000_0111_1111_1111_1111 '!t/f un pushtf MUXZ x,masklong ' * 'Z=true(-1)/false(0) pushr wrlong x,ptrb++ 'push result jmp pa 'indirect return ret <= PA=pushret=~#loop '????????? '------------------------------------------------------------------------------------------------------------
and the table' binary normal assign description '---------------------------------------------------------------------------------------------------------------------------- long %11_1111_1111_1111_1110_1111 <<10 +math_E0 '$E0 ROR 1st -> 2nd b -> ->= rotate right long %11_1111_1111_1111_1101_1111 <<10 +math_E0 '$E1 ROL 1st <- 2nd b <- <-= rotate left long %11_1111_1111_1111_1011_1111 <<10 +math_E0 '$E2 SHR 1st >> 2nd b >> >>= shift right long %11_1111_1111_1111_0111_1111 <<10 +math_E0 '$E3 SHL 1st << 2nd b << <<= shift left long %11_1111_1111_1110_1111_1111 <<10 +math_E0 '$E4 FGES 1st #> 2nd b #> #>= limit minimum (signed) long %11_1111_1111_1101_1111_1111 <<10 +math_E0 '$E5 FLES 1st <# 2nd b <# <#= limit maximum (signed) long %11_1111_1111_1011_1111_1111 <<10 +math_E0 '$E6 NEG - 1st unary - - negate long %11_1111_1111_0111_1111_1111 <<10 +math_E0 '$E7 NOT ! 1st unary ! ! bitwise not long %11_1111_1110_1111_1111_1111 <<10 +math_E0 '$E8 AND 1st & 2nd b & &= bitwise and long %11_1111_1101_1111_1111_1111 <<10 +math_E0 '$E9 ABS ABS( 1st ) unary || || absolute long %11_1111_1011_1111_1111_1111 <<10 +math_E0 '$EA OR 1st | 2nd b | |= bitwise or long %11_1111_0111_1111_1111_1111 <<10 +math_E0 '$EB XOR 1st ^ 2nd b ^ ^= bitwise xor long %11_1110_1111_1111_1111_1111 <<10 +math_E0 '$EC ADD 1st + 2nd b + += add long %11_1101_1111_1111_1111_1111 <<10 +math_E0 '$ED SUB 1st - 2nd b - -= subtract long %11_1011_1111_1111_1111_1111 <<10 +math_E0 '$EE SAR 1st ~> 2nd b ~> ~>= shift arithmetic right long %11_0111_1111_1111_1111_1111 <<10 +math_E0 '$EF REV 1st >< 2nd b >< ><= reverse bits (neg y first) long %11_1111_1110_1111_1111_0000 <<10 +math_E0 '$F0 AND bool 1st AND 2nd b AND boolean and long %10_1111_1111_1111_1111_1111 <<10 +math_E0 '$F1 ENCOD >| 1st unary >| >| encode (0-32) long %11_1111_1011_1111_1111_0000 <<10 +math_E0 '$F2 OR bool 1st OR 2nd b OR boolean or long %01_1111_1111_1111_1111_1111 <<10 +math_E0 '$F3 DECOD |< 1st unary |< |< decode '------------------------------------------------------------------ long %00_0001_1111_1111_1111_1100 <<10 +math_F4 '$F4 MPY 1st * 2nd b * *= multiply, return lower half (signed) long %00_0001_1111_1111_1111_0011 <<10 +math_F4 '$F5 MPY_MSW 1st ** 2nd b ** **= multiply, return upper half (signed) long %00_0001_1111_1111_1100_1111 <<10 +math_F4 '$F6 DIV 1st / 2nd b / /= divide, return quotient (signed) long %00_0001_1111_1111_0011_1111 <<10 +math_F4 '$F7 MOD 1st // 2nd b // //= divide, return remainder (signed) long %00_0001_1111_1100_1111_1111 <<10 +math_F4 '$F8 SQRT ^^ 1st unary ^^ ^^ square root long %00_0000_1000_0011_1111_1111 <<10 +math_F4 '$F9 LT 1st < 2nd b < test below (signed) long %00_0000_1000_0011_1111_1111 <<10 +math_F4 '$FA GT 1st > 2nd b > test above (signed) long %00_0000_1000_0011_1111_1111 <<10 +math_F4 '$FB NE 1st <> 2nd b <> test not equal long %00_0000_1000_0011_1111_1111 <<10 +math_F4 '$FC EQ 1st == 2nd b == test equal long %00_0000_1000_0011_1111_1111 <<10 +math_F4 '$FD LE 1st =< 2nd b =< test below or equal (signed) long %00_0000_1000_0011_1111_1111 <<10 +math_F4 '$FE GE 1st => 2nd b => test above or equal (signed) long %00_0000_0111_1111_1111_1111 <<10 +math_F4 '$FF NOT bool NOT 1st unary NOT NOT boolean not '----------------------------------------------------------------------------------------------------------------------------
I think this is very cool what you are doing there, sure we still have the problem with PASM1/PASM2 but you are opening up a lot of OBEX P1 stuff for the P2.
I really like fastspin, but it compiles to large binaries, and - yes - I am sure that 512kb will be small soon, needing RAM for HDMI or whatever.
Having a SPIN1 byte code interpreter on the P2 would be nice. @Chip has to come up with Spin2 yet (and hopefully follow @ersmith and his SPIN2 additions)
You said that you will implement port B, as far as I follow the forum, what about the memory size?
I guess 64kb will work with the current byte codes, but - hmm - basically spin bytecodes are relocatable so do you plan/think about/have a Idea for using more then 64kb?
just curious,
Mike
And yes, Ports A & B are supported
Saving a huge amount of clocks as the decode table removes most requirements for testing bytecode bits. This also saves instructions. Same goes for conditional instruction execution.
Also used some of the new instructions like SIGNX, ZEROX, and others.
I’ve been optimising for speed at some instruction code expense.
Been testing out some of the basics. Mathops all seem working fine. Basic repeats working. Register translation working. Waitcnt working. Some of the assignments are working, some not. Maths assignments not done yet - should just be a matter of calling the mathop routine.
It’s interesting to debug. I am displaying the registers, stack, and upcoming bytecode at each bytecode execution.
Yet to do COGINIT tho.
Nice, Cluso99!
How much is left to do Cluso, and what P1 Spin doesn't/can't work beyond WAITVID and the counter stuff in this P1 SPIN interpreter for P2?
Done & To do...
* Bytecodes $00-$3F have been coded. Most opcodes working, some have only rudimentary testing, and a few have not been tested at all. Most coding is done tho'.
- CALL, JMP, jump conditionals, DJNZ work.
- Repeat loops (no parameters) work, but Repeat with parameters (from, to, step) do not.
- COGINIT not coded
- LOCKs coded but untested
- WAITCNT works but actual time not validated
- WAITPEQ & WAITPNE coded but not validated
* Bytecodes VAR $40-$7F types PUSH & POP working, Mathop (Assign-Using) need matho as subroutine, PUSH# coded but not tested
* Bytecodes MEM $80-$DF types PUSH & POP working, Mathop (Assign-Using) need matho as subroutine, PUSH# coded but not tested
* Bytecodes MATHOPS $E0-$FF working, but the mathops being called as a routine needs doing ie the calls from other bytecodes.
* Tricks with the special registers $1F0-$1FF of P1.
- I trap PAR, CNT and read accordingly. I save PTR in a register for this case and GETCT is substituted.
- I translate DIRx/INx/OUTx to their new addresses (both A & B ports work correctly).
- The other special registers read 0 and ignore writes ie the VID & Counter registers. IIRC this works.
* Need to engage XBYTE - currently RDLUT & EXECF are used.
This is so I can debug at this specific point in the interpreter. I output...
- the x, y, a registers
- the bytecode address (pcurr=PTRA) and next 3 bytecodes
- the stack address (dcurr=PTRB) top 3 stack values
@Wuerfel_21 has mentioned the possibility of adding the spin1 interpreter to @ersmith 's flexspin.
To help, here is information that I did a few years ago in converting my P1 Faster Spin Interpreter over to P2.
I searched for the old threads but they appear to be MIA
My ideea was to be able to include P1 binaries as included "file" commands in the P2 source. Of course there are a few things that are not available such as waitvid and the counters.
Attached below is my P1 Spin1 Interpreter for both P1 and P2. I'm not sure how many bugs are in the P2 version.
Thanks, Ray. I hope to take a look at those over the weekend. If the P2 version of the interpreter works (at least partly) then it might be a quick route to getting bytecode working for P2.
The P2 interpreter doesn't compile, unfortunately... there were some missing single quotes on comments, and after I fixed those there were some additional errors:
ClusoInterpreterP2_306d.spin:817: error: Changing hub value for symbol j9_012:writer ClusoInterpreterP2_306d.spin:1614: error: Negative repeat count not allowed ClusoInterpreterP2_306d.spin:1615: error: fit 464 failed: pc is 486 ClusoInterpreterP2_306d.spin:1647: error: fit 480 failed: pc is 502
I guess something in there bit rotted? For now I guess it makes sense for us to look at the P1 interpreter first, although the P2 one has more bang for the buck in the sense that we already have a P1 bytecode back end so it's a quick path to getting bytecode on P2.
Incidentally, Ada's work on the Spin bytecodes has really come along -- she's done a great job. We can run some BASIC and C programs now, with floats and strings.
This bit might be handy for testing (from v305l)
I've posted v305l below as it was the last version that I compiled
' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ' % THE SPIN BYTECODE GOES HERE (starts at HUB $00004) % ' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% '----------------------------------------------------------------------------------------------- {{ +--------------------------------------------------------------------------+ CON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 PUB Main | x,y,z repeat x := 1 y := 3 z := x + y x~ y~~ |===========================================================================| Objects : - P1_spin_001e Object Address : 0010 : Object Name : P1_spin_001e Binary Image Information : PBASE : 0010 VBASE : 0028 DBASE : 0030 PCURR : 0018 DCURR : 0040 |===========================================================================| |===========================================================================| Object P1_spin_001e Object Base is 0010 |===========================================================================| Object Constants |===========================================================================| Constant _clkmode = 00000408 (1032) Constant _xinfreq = 004C4B40 (5000000) |===========================================================================| |===========================================================================| Spin Block Main with 0 Parameters and 3 Extra Stack Longs. Method 1 PUB Main | x,y,z Local Parameter DBASE:0000 - Result Local Variable DBASE:0004 - x Local Variable DBASE:0008 - y Local Variable DBASE:000C - z |===========================================================================| 12 repeat Addr : 0018: Label0002 13 x := 1 Addr : 0018: 36 : Constant 2 $00000001 Addr : 0019: 65 : Variable Operation Local Offset - 1 Write 14 y := 3 Addr : 001A: 37 21 : Constant Mask Y=33 Decrement 00000003 3 Addr : 001C: 69 : Variable Operation Local Offset - 2 Write 15 z := x + y Addr : 001D: 64 : Variable Operation Local Offset - 1 Read Addr : 001E: 68 : Variable Operation Local Offset - 2 Read Addr : 001F: EC : Math Op + Addr : 0020: 6D : Variable Operation Local Offset - 3 Write 16 x~ Addr : 0021: 66 18 : Variable Operation Local Offset - 1 Assign VAR~ Post-clear 17 y~~ Addr : 0023: 6A 1C : Variable Operation Local Offset - 2 Assign VAR~~ Post-set Addr : 0025: Label0003 Addr : 0025: JMP Label0002 Addr : 0025: 04 71 : Jmp 0018 -15 Addr : 0027: Label0004 Addr : 0027: 32 : Return +--------------------------------------------------------------------------+}} '----------------------------------------------------------------------------------------------- 'Offset(h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F '----------------------------------------------------------------------------------------------- {00000000} byte {$00, $B4, $C4, $04,}$6F, $0F, $10, $00, $28, $00, $30, $00, $18, $00, $40, $00 {00000010} byte $18, $00, $02, $00, $08, $00, $0C, $00, $36, $65, $37, $21, $69, $64, $68, $EC ''{00000020} byte $6D, $66, $18, $6A, $1C, $04, $71, $32, $FF, $FF, $F9, $FF, $FF, $FF, $F9, $FF {00000020} byte $6D, $66, $18, $6A, $1C, $04, $71, $32, $FF, $FF, $F9, $FF, $FF, $FF, $F9, $FF '-----------------------------------------------------------------------------------------------
Here is the spin bytecode source for the test in v306d
Note that I patched address $001D from $85 to $F5 for testing.
It may be better to start from v305l and implement the sections from v306d one at a time although I haven't looked closely enough to see if this way is possible.