Welcome to the Parallax Discussion Forums, sign-up to participate.
' ' Interpreter loop ' inst rfbyte p 'get bytecode rdlut x,p 'lookup long from lut alti x 'execute long as next instruction nop '(instruction placeholder) jmp #inst 'loop
' ' Bytecode-to-instruction lookup in LUT ' org $200 push neg1 'constant -1 pusha #0 'constant 0 pusha #1 'constant 1 pusha #2 'constant 2 pusha #3 'constant 3 pusha #4 'constant 4 pusha #7 'constant 7 pusha #8 'constant 8 pusha #15 'constant 15 pusha #16 'constant 16 pusha #31 'constant 31 pusha #32 'constant 32 call rd1xx 'read register $1xx call wr1xx 'write register $1xx ops call #op1 'unary operator NOT boolean not call #op1 'unary operator ! bitwise not call #op1 'unary operator - negate call #op1 'unary operator || absolute call #op1 'unary operator >| encode call #op1 'unary operator |< decode call #op1 'unary operator ~ sign extend byte call #op1 'unary operator ~~ sign extened word call #op2 'binary operator AND boolean and call #op2 'binary operator OR boolean or call #op2 'binary operator & bitwise and call #op2 'binary operator | bitwise or call #op2 'binary operator ^ bitwise xor call #op2 'binary operator >> shift right call #op2 'binary operator << shift left call #op2 'binary operator ~> arithmetic shift right call #op2 'binary operator <~ arithmetic shift left call #op2 'binary operator -> rotate right call #op2 'binary operator <- rotate left call #op2 'binary operator >< reverse LSBs call #op2 'binary operator #> limit minimum (signed) call #op2 'binary operator <# limit maximum (signed) call #op2 'binary operator + add call #op2 'binary operator - subtract call #op2 'binary operator * multiply (signed) call #op2 'binary operator / divide (signed) call #op2 'binary operator // remainder (signed) call #op2 'binary operator ** scale (unsigned) call #op2 'binary operator */ fraction (unsigned) call #op1 'SQRT(x) math terms, 1 result call #op1 'LOG(x) call #op1 'EXP(x) call #op2 'NEGBOOL(x,bool) call #op3 'MUXBOOL(x,mux,bool) call #op2 'POLCAR(r,t : x,y) math terms, 2 results call #op2 'CARPOL(x,y : r,t) call #op3 'ROTCAR(x,y,t : x,y)
' ' Math operators ' op3 popa z 'pop z op2 popa y 'pop y op1 popa x wc, wz 'pop x, set flags altd p,#.op - (ops & $FF) 'point next d to op instruction alti 0 'execute d as next instruction nop '(instruction executes here) _ret_ pusha x 'push x, return to bytecode loop .op call #.not 'NOT unaries not x '! neg x '- abs x '|| topone x '>| decod x '|< call #.sxb '~~ call #.sxw '~ call #.and 'AND binaries call #.or 'OR and x,y '& or x,y '| xor x,y '^ shr x,y '>> shl x,y '<< sar x,y '~> sal x,y '<~ ror x,y '-> rol x,y '<- call #.rev '>< mins x,y '#> maxs x,y '<# add x,y '+ sub x,y '- call #.mul '* call #.div '/ call #.rem '// call #.scl '** call #.fra '*/ call #.sqrt 'SQRT() 1 result call #.log 'LOG() call #.exp 'EXP() call #.negbool 'NEGBOOL(,) call #.muxbool 'MUXBOOL(,,) call #.polcar 'POLCAR(r,t : x,y) 2 results call #.carpol 'CARPOL(x,y : r,t) call #.rotcar 'ROTCAR(x,y,t : x,y) .not if_nz not x,#0 _ret_ not x,#0 .sxb shl x,#24 _ret_ sar x,#24 .sxw shl x,#16 _ret_ sar x,#16 .and if_nz cmp y,#0 wz if_nz not x,#0 ret .or if_z cmp y,#0 wz if_nz not x,#0 ret .rev rev x rol x,y rol x,#1 _ret_ triml x,y .mul testb y,#31 wz abs x abs y qmul x,y .mul2 getqx x if_c_eq_z neg x ret .div testb y,#31 wz abs x abs y qdiv x,y jmp #.mul2 .rem abs x abs y qdiv x,y getqy x if_c neg x ret .scl qmul x,y _ret_ getqy x .fra qfrac x,y _ret_ getqx x .sqrt qsqrt x _ret_ getqx x .log qlog x _ret_ getqx x .exp qexp x _ret_ getqx x .negbool cmp y,#0 wz _ret_ negnz x .muxbool cmp z,#0 wz _ret_ muxnz x,y .polcar qrotate x,y jmp #.results .carpol qvector x,y jmp #.results .rotcar setq y qrotate x,z .results getqy x pusha x _ret_ getqx x
' ' Subroutines ' blank call #hsync 'blank lines xcont m_vi,#0 _ret_ djnz x,#blank hsync xcont m_bs,#0 'horizontal sync xzero m_sn,#1 _ret_ xcont m_bv,#0
Comments
Seems like Spin2 is going to be a lot more capable than Spin1 was. I often resort to PASM to do most things on P1, might not need as much PASM on P2.
I like the "_ret_ " addition too.
Tachyon Forth - compact, fast, forthwright and interactive
--->CLICK THE LOGO for more links<---
P2 +++++ TAQOZ INTRO & LINKS +++++ P2 SHORTFORM DATASHEET
P1 +++++ Latest binary V5.4 includes EASYFILE +++++ Tachyon Forth News Blog
Brisbane, Australia
I was thinking 'WAITX #0'.
What about making blank Flash a NOP, which means 0xffffffff ?
That would be 'AUGD #all_ones'. This NOP thing is the biggest problem now.
What happens now, if an errant branch lands on a whole chain of 'AUGD #all_ones' ?
They pretty much are NOPs. The next instruction afterward, though, with a literal D would get the top 27 bits as highs. May or may not be a problem.
Here's the constant portion of the LUT table:
The most common constants are single instructions.
Don't be. Worth it. This exercise is important.
Parallax colors simplified: https://forums.parallax.com/discussion/123709/commented-graphics-demo-spin<br>
Or, don't bother re-arranging anything and just define NOP to be an alias for OR 0,0.
Hope you're not thinking about changing that...
That's an excellent point. Possibly better would be to trigger a debug interrupt. Instead of a debugger, startup code could set the debug interrupt to call cogstop or whatever other behavior is desirable (cogatn a watchdog cog, for instance).
At which point, yeah, just make NOP an alias for an existing instruction.
PS: Way to go Chip!!! W000000T!
Try the FTDI 245 and the FullDuplexParallel Object.
Check out my spin driver for the Parallax "96 x 64 Color OLED Display Module" Product ID: 28087
If your program is buggy and runs off into the weeds, those weeds are quite likely to be some other part of your code or your data somewhere, which it will then try to execute.
Could be fixed, but inconvenient...
One thing garryj did is load the top of his cog code with variables initialized to 0. As such, they are just NOPs and skipped over. Can't do this if NOP changes:
I did that once a couple of times, myself.
We just can't do that anymore.
Parallax colors simplified: https://forums.parallax.com/discussion/123709/commented-graphics-demo-spin<br>
It would have generated the same exact code, and wouldn't have broken when Chip made this change.
In any case, the changes to make it a non-issue are minimal.
_ret_ only works if the internal call-stackpointer is not at bottom, otherwise it's ignored and therfore a NOP.
So as long as you not have done a CALL in your code, the %0000 condition works as a NOP and only inside subroutines it is a _ret_.
Andy