'****************************************************************************** ' P1 Spin Interpreter for P2 ' ' Copyright (c) 2014, Dave Hein ' See end of file for terms of use. '****************************************************************************** CON _clkmode = xtal1+pll16x _clkfreq = 80_000_000 DAT orgh $380 org ' Add address offset to Spin header startup mov temp1, ptestprog add temp1, #6 mov temp3, #5 :loop rdword temp2, temp1 add temp2, ptestprog wrword temp2, temp1 add temp1, #2 djnz temp3, @:loop ' Clear VAR area mov temp1, ptestprog add temp1, #8 ' Get address of vbase rdword temp2, temp1 ' Get vbase add temp1, #2 ' Get address of dbase rdword temp3, temp1 ' Get dbase sub temp3, temp2 ' Compute number of bytes shr temp3, #2 ' Compute number of longs mov temp4, #0 :loop1 wrlong temp4, temp2 add temp2, #4 djnz temp3, @:loop1 ' Initialize stack frame and result variable mov temp1, ptestprog add temp1, #10 ' Get address of dbase rdword temp1, temp1 ' Get dbase mov temp2, #0 wrlong temp2, temp1 ' Initialize result to zero sub temp1, #2 wrword pexitcode, temp1 ' Set return address to exit code sub temp1, #6 mov temp2, #2 wrword temp2, temp1 ' Write first word of stack frame ' Start the Spin interpreter mov temp1, pinterp mov temp2, ptestprog add temp2, #4 coginit temp1, temp2, #0 temp1 long 0 temp2 long 0 temp3 long 0 temp4 long 0 pinterp long @interp ptestprog long @testprog ppbase long @pbase pexitcode long @exitcode orgh DAT ' This table decodes the Spin bytecode. jump_table ' 0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F word {00} ldfrmr, ldfrmr, ldfrmr, ldfrmr, _jmp, _call, callobj,callobx word {08} _tjz, _djnz, _jz, _jnz, casedon,caseval,caseran,lookdon word {10} lookupv,lookdnv,lookupr,lookdnr,_pop, _run, _strsiz,_strcmp word {18} _bytefl,_wordfl,_longfl,_waitpe,_bytemv,_wordmv,_longmv,_waitpn word {20} _clkset,cogstp, lckret, _waitcn,rwregx, rwregx, rwregx, _waitvi word {28} _cogini,lcknewr,lcksetr,lckclrr,_cogini,lcknew, lckset, lckclr word {30} _abort, abrtval,_ret, retval, ldlix, ldlix, ldlix, ldlip word {38} ldbi, ldwi, ldmi, ldli, unsupp, rwregb, rwregbs,rwreg word {40} ldlvc, stlvc, exlvc, lalvc, ldlvc, stlvc, exlvc, lalvc word {48} ldlvc, stlvc, exlvc, lalvc, ldlvc, stlvc, exlvc, lalvc word {50} ldlvc, stlvc, exlvc, lalvc, ldlvc, stlvc, exlvc, lalvc word {58} ldlvc, stlvc, exlvc, lalvc, ldlvc, stlvc, exlvc, lalvc word {60} ldllc, stllc, exllc, lallc, ldllc, stllc, exllc, lallc word {68} ldllc, stllc, exllc, lallc, ldllc, stllc, exllc, lallc word {70} ldllc, stllc, exllc, lallc, ldllc, stllc, exllc, lallc word {78} ldllc, stllc, exllc, lallc, ldllc, stllc, exllc, lallc word {80} ldba, stba, exba, la_a, ldbo, stbo, exbo, la_o word {88} ldbv, stbv, exbv, la_v, ldbl, stbl, exwl, la_l word {90} ldbax, stbax, exbax, labax, ldbox, stbox, exbox, labox word {98} ldbvx, stbvx, exbvx, labvx, ldblx, stblx, exblx, lablx word {A0} ldwa, stwa, exwa, la_a, ldwo, stwo, exwo, la_o word {A8} ldwv, stwv, exwv, la_v, ldwl, stwl, exwl, la_l word {B0} ldwax, stwax, exwax, lawax, ldwox, stwox, exwox, lawox word {B8} ldwvx, stwvx, exwvx, lawvx, ldwlx, stwlx, exwlx, lawlx word {C0} ldla, stla, exla, la_a, ldlo, stlo, exlo, la_o word {C8} ldlv, stlv, exlv, la_v, ldll, stll, exll, la_l word {D0} ldlax, stlax, exlax, lalax, ldlox, stlox, exlox, lalox word {D8} ldlvx, stlvx, exlvx, lalvx, ldllx, stllx, exllx, lallx word {E0} _ror, _rol, _shr, _shl, _min, _max, _neg, _com word {E8} _and, _abs, _or, _xor, _add, _sub, _sar, _rev word {F0} _andl, encode, _orl, decode, _mul, _mulh, _div, _mod word {F8} _sqrt, _cmplt, _cmpgt, _cmpne, _cmpeq, _cmple, _cmpge, _notl ' This table decodes the extra byte that is used to perform extended operations. jump_table_ex ' 0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F word {00} store, unsupx, repeatx,unsupx, unsupx, unsupx, repeats,unsupx word {08} randf, unsupx, unsupx, unsupx, randr, unsupx, unsupx, unsupx word {10} sexb, unsupx, unsupx, unsupx, sexw, unsupx, unsupx, unsupx word {18} postclr,unsupx, unsupx, unsupx, postset,unsupx, unsupx, unsupx word {20} unsupx, unsupx, unsupx, unsupx, unsupx, unsupx, preinc, unsupx word {28} unsupx, unsupx, unsupx, unsupx, unsupx, unsupx, postinc,unsupx word {30} unsupx, unsupx, unsupx, unsupx, unsupx, unsupx, predec, unsupx word {38} unsupx, unsupx, unsupx, unsupx, unsupx, unsupx, postdec,unsupx word {40} _rorx, _rolx, _shrx, _shlx, _minx, _maxx, _negx, _comx word {48} _andx, _absx, _orx, _xorx, _addx, _subx, _sarx, _revx word {50} _andlx, encodex,_orlx, decodex,_mulx, _mulhx, _divx, _modx word {58} _sqrtx, _cmpltx,_cmpgtx,_cmpnex,_cmpeqx,_cmplex,_cmpgex,_notlx word {60} unsupx, unsupx, unsupx, unsupx, unsupx, unsupx, unsupx, unsupx word {68} unsupx, unsupx, unsupx, unsupx, unsupx, unsupx, unsupx, unsupx word {70} unsupx, unsupx, unsupx, unsupx, unsupx, unsupx, unsupx, unsupx word {78} unsupx, unsupx, unsupx, unsupx, unsupx, unsupx, unsupx, unsupx ' Bytecodes for cogstop(cogid) exitcode byte $3f, $89, $21 org 0 '*********************************************************************** ' Copy 5 Spin state variable to registers '*********************************************************************** interp setinda #pbase reps #5, #1 cogid id rdword inda++,++ptra jmp #loop long 0[3] '*********************************************************************** ' Push x to the stack '*********************************************************************** pushx1 wrlong x, dcurr add dcurr, #4 '*********************************************************************** ' This is the main loop that fetches bytecodes and executes them '*********************************************************************** loop mov t1, jumps rdbyte op,pcurr 'get opcode add pcurr,#1 add t1, op add t1, op rdword t2, t1 jmp t2 '*********************************************************************** ' This code handles extended operators, such as ++ and += '*********************************************************************** exoplong add adr, op2 exoplong1 rdlong x, adr mov savex, #exoplong2 jmp #exop1 exopword add adr, op2 exopword1 rdword x, adr mov savex, #exopword2 jmp #exop1 exopbyte add adr, op2 exopbyte1 rdbyte x, adr mov savex, #exopbyte2 exop1 rdbyte op2,pcurr mov t1, op2 and t1, #$7f shl t1, #1 add t1, jumpx rdword t2, t1 add pcurr,#1 jmp t2 '*********************************************************************** ' This code saves the result from the extended operation '*********************************************************************** postsave add savex, #1 jmp savex exopbyte2 mov y, x postbyte wrbyte y, adr and x, #$ff jmp #exopdone exopword2 mov y, x postword wrword y, adr and x, maskword jmp #exopdone exoplong2 mov y, x postlong wrlong y, adr exopdone test op2, #$80 wc 'check for load bit mov savex, #pushx1 if_c jmp #pushx1 if_nc jmp #loop '*********************************************************************** ' Load Immediate Instructions '*********************************************************************** ' ' Load Long Immediate 1, 0 and -1 ldlix sub op, #$35 mov x, op jmp #pushx1 ' Load Long Immediate Packed ldlip mov x, #2 rdbyte y,pcurr 'constant mask, get data byte add pcurr,#1 rol x,y 'decode, x = 2 before test y,#%001_00000 wc 'decrement? if_c sub x,#1 test y,#%010_00000 wc 'not? if_c xor x,masklong jmp #pushx1 ' Load Byte Immediate ldbi call #fetchbyte jmp #pushx1 ' Load Word Immediate ldli call #fetchbyte mov a, #3 jmp #addbytes ' Load Word Immediate ldmi call #fetchbyte mov a, #2 jmp #addbytes ' Load Word Immediate ldwi call #fetchbyte mov a, #1 addbytes shl x, #8 rdbyte y, pcurr add pcurr, #1 or x, y djnz a, @addbytes jmp #pushx1 '*********************************************************************** ' Compact Local Variable Instructions '*********************************************************************** ' Load Long Local Compact ldllc mov op2, dbase mov adr, op and adr, #$1c ldlong add adr, op2 rdlong x, adr jmp #pushx1 ' Store Long Local Compact stllc mov adr, op and adr, #$1c mov op2, dbase stlong add adr, op2 call #popx1 wrlong x, adr jmp #loop ' Execute Long Local Compact exllc mov adr, op and adr, #$1c mov op2, dbase jmp #exoplong ' Load Address Long Local Compact lallc and op, #$1c add op, dbase mov x, op jmp #pushx1 '*********************************************************************** ' DAT Variable Instructions '*********************************************************************** ' Load Long Object ldlo call #getadrz mov adr, pbase jmp #ldlong ' Store Long Object stlo call #getadrz mov adr, pbase jmp #stlong ' Execute Long Object exlo call #getadrz mov adr, pbase jmp #exoplong ' Load Address Object la_o call #getadrz mov x, op2 add x, pbase jmp #pushx1 '*********************************************************************** ' Indexed DAT Variable Instructions '*********************************************************************** ' Load Byte Object with Index ldbox call #getadrz call #pop_adr add adr, pbase jmp #ldbyte ldbyte add adr, op2 rdbyte x, adr jmp #pushx1 ldword add adr, op2 rdword x, adr jmp #pushx1 ' Store Byte Object with Index stbox call #getadrz call #pop_adr add adr, pbase jmp #stbyte stbyte add adr, op2 call #popx1 wrbyte x, adr jmp #loop stword add adr, op2 call #popx1 wrword x, adr jmp #loop ' Load Address Byte Object with Index labox call #getadrz call #popx1 add x, op2 add x, pbase jmp #pushx1 '*********************************************************************** ' Absolute Address Instructions '*********************************************************************** ' Load Byte Absolute ldba call #popy1 jmp #ldba1 ' Load Word Absolute ldwa call #popy1 jmp #ldwa1 ' Load Long Absolute ldla call #popy1 if_z jmp #ldclkfreq jmp #ldla1 ldbax call #popay add y, a ldba1 rdbyte x, y jmp #pushx1 ' Load Word Absolute with Index ldwax call #popay shl a, #1 add y, a ldwa1 rdword x, y jmp #pushx1 ' Load Long Absolute with Index ldlax call #popay shl a, #2 add y, a ldla1 rdlong x, y jmp #pushx1 '*********************************************************************** ' Jump Instructions '*********************************************************************** ' Test and Jump on Zero _tjz call #getadrs call #popx1 if_nz add dcurr, #4 jmp #_jz1 ' Jump on Zero _jz call #getadrs call #popx1 _jz1 if_z add pcurr, op2 jmp #loop ' Decrement and Jump on NonZero _djnz call #getadrs call #popx1 sub x, #1 wz if_nz add pcurr, op2 if_nz jmp #pushx1 jmp #loop ' Jump on NonZero _jnz call #getadrs call #popx1 if_nz add pcurr, op2 jmp #loop ' Jump _jmp call #getadrs add pcurr, op2 jmp #loop '*********************************************************************** ' Math Instructions '*********************************************************************** _shr call #popyx shr x, y jmp savex _shl call #popyx shl x, y jmp savex _ror call #popyx rol x, y jmp savex _rol call #popyx rol x, y jmp savex ' Complement _com call #popx1 xor x, masklong jmp savex _and call #popyx and x, y jmp savex ' Absolute _abs call #popx1 abs x, x jmp savex _or call #popyx or x, y jmp savex ' Add _add call #popyx add x, y jmp savex ' Subtract _sub call #popyx sub x, y jmp savex _neg call #popx1 neg x, x jmp savex _xor call #popyx xor x, y jmp savex _sar call #popyx sar x, y jmp savex ' Or Logical _orl call #popx1 if_nz neg x, #1 call #popy1 if_nz neg x, #1 jmp savex _andl call #popx1 if_nz neg x, #1 call #popy1 if_z mov x, #0 jmp savex _notl call #popx1 muxz x, masklong jmp savex _mul call #popyx mul32 x, y getmull x jmp savex _mulh call #popyx mul32 x, y getmulh x jmp savex _div call #popyx div32 x, y getdivq x jmp savex _mod call #popyx div32 x, y getdivr x jmp savex ' Compare if Less Than _cmplt call #popyx cmps x, y wz, wc muxc x, masklong jmp savex ' Compare if Greater Than _cmpgt call #popyx cmps x, y wz, wc if_nz_and_nc neg x, #1 if_z_or_c mov x, #0 jmp savex ' Compare if Less than or Equal _cmple call #popyx cmps x, y wz, wc if_nz_and_nc mov x, #0 if_z_or_c neg x, #1 jmp savex ' Compare if Not Equal _cmpne call #popyx sub x, y wz if_nz neg x, #1 jmp savex ' Compare if Equal _cmpeq call #popyx sub x, y wz jmp #_notlx ' Compare if Greater than or Equal _cmpge call #popyx cmps x, y wz, wc muxnc x, masklong jmp savex retval call #popx1 jmp #_ret1 _ret rdlong x,dbase _ret1 call #return1 pushz if_z jmp #pushx1 if_nz jmp #loop '*********************************************************************** ' Calling and Return Instructions '*********************************************************************** return1 mov dcurr,dbase 'restore dcurr sub dcurr,#2 'pop pcurr rdword pcurr,dcurr sub dcurr,#2 'pop dbase rdword dbase,dcurr sub dcurr,#2 'pop vbase rdword vbase,dcurr sub dcurr,#2 'pop pbase (and flags) rdword pbase,dcurr test pbase,#%01 wz 'get push flag test pbase,#%10 wc 'get abort flag and pbase,maskpar 'trim pbase ret ' Load Stack Frame ldfrmr ldfrm ldfrmar ldfrma jmp #loadframe callobj mov a, #0 callobj1 call #getcallparms add pbase, x add vbase, y _call mov a, #0 call #getcallparms jmp #callmethod ' Read values from the Method Table getcallparms rdbyte y,pcurr 'get method table entry number add pcurr,#1 add y,a 'add index shl y,#2 'lookup words from table add y,pbase rdlong y,y mov x,y 'get low word and x,maskword shr y,#16 'get high word ret ' Call Method callmethod mov dbase,dcall 'get new dcall rdword dcall,dcall 'set old dcall wrword pcurr,dbase 'set return pcurr add dbase,#2 'set call dbase add dcurr,y 'set call dcurr mov pcurr,pbase 'set call pcurr add pcurr,x jmp #loop loadframe or op,pbase 'add pbase into flags wrword op,dcurr 'push pbase plus flags add dcurr,#2 wrword vbase,dcurr 'push vbase add dcurr,#2 wrword dbase,dcurr 'push dbase add dcurr,#2 wrword dcall,dcurr 'push dcall mov dcall,dcurr 'set new dcall add dcurr,#2 mov x, #0 'init result to 0 jmp #pushx1 _cogini1 coginit y, a, #0 jmp #pushz '*********************************************************************** ' Helper Functions '*********************************************************************** ' Get Unsigned Address getadrz rdbyte op2,pcurr test op2,#$80 wc and op2,#$7F jmp #getadr2 ' Get Signed Address getadrs rdbyte op2,pcurr test op2,#$80 wc shl op2,#25 sar op2,#25 getadr2 add pcurr,#1 if_nc ret rdbyte t2,pcurr add pcurr,#1 shl op2,#8 or op2,t2 ret ' Fetch a bytecode fetchbyte rdbyte x, pcurr add pcurr, #1 ret ' Pop a from the stack popayx sub dcurr,#4 rdlong a,dcurr ' Pop y from the stack popyx sub dcurr,#4 rdlong y,dcurr ' Pop x from the stack popx1 sub dcurr,#4 rdlong x,dcurr wz ret ' Pop a from the stack popay sub dcurr,#4 rdlong a,dcurr ' Pop y from the stack popy1 sub dcurr, #4 rdlong y, dcurr wz ret ' Pop adr from the stack pop_adr sub dcurr,#4 rdlong adr,dcurr ret '*********************************************************************** ' Extended Instructions '*********************************************************************** store call #popx1 jmp savex postclr mov y, #0 jmp #postsave postset neg y, #1 jmp #postsave postinc mov y, x add y, #1 jmp #postsave postdec mov y, x sub y, #1 jmp #postsave _rolx call #popy1 rol x, y jmp savex _shlx call #popy1 shl x, y jmp savex _divx call #popy1 jmp #_div+1 _modx call #popy1 jmp #_mod+1 _notlx muxz x, masklong jmp savex _rorx call #popy1 ror x, y jmp savex _shrx call #popy1 shr x, y jmp savex _andx call #popy1 and x, y jmp savex _absx abs x, x jmp savex _negx neg x, x jmp savex _comx xor x, masklong jmp savex _orx call #popy1 or x, y jmp savex '*********************************************************************** ' Read/Write Register Instructions '*********************************************************************** rwreg0 rdbyte op, pcurr add pcurr, #1 mov adr, op rwreg1 and adr, #$1f add adr, #$1e0 call #mapreg mov regrevflag, #0 mov reglsb, t1 mov regnbits, t2 sub regnbits,reglsb wc if_c neg regnbits, regnbits if_c mov reglsb, t2 if_c mov regrevflag, #1 xor regnbits, #31 neg regmask, #1 shr regmask, regnbits test op, #$20 wz if_z jmp #ldreg streg sets streg1, adr setd streg2, adr call #popx1 and x, regmask cmp regrevflag, #0 wz if_nz rev x, regnbits shl regmask, reglsb streg1 mov y, 0-0 andn y, regmask shl x, reglsb or y, x streg2 mov 0-0, y jmp #loop ldreg sets ldreg1, adr nop cmp adr, #$1f1 wz if_z getcnt x ldreg1 if_nz mov x, 0-0 mov regsave, x shr x, reglsb and x, regmask cmp regrevflag, #0 wz if_nz rev x, regnbits test op, #$40 wz if_z jmp #pushx1 mov savex, #exopreg2 jmp #exop1 exopreg2 mov y, x postreg setd exopreg3, adr and x, regmask and y, regmask cmp regrevflag, #0 wz if_nz rev y, regnbits shl y, reglsb shl regmask, reglsb andn regsave, regmask or y, regsave exopreg3 mov 0-0, y jmp #exopdone ' Mapping for port A mapreg cmp adr, #$1f2 wz 'P1 INA if_z mov adr, #$1f4 'P2 PINA if_z ret cmp adr, #$1f4 wz 'P1 OUTA if_z mov adr, #$1f8 'P2 OUTA if_z ret cmp adr, #$1f6 wz 'P1 DIRA if_z mov adr, #$1fc 'P2 DIRA ret { ' Mapping for port C mapreg cmp adr, #$1f2 wz 'P1 INA if_z mov adr, #$1f6 'P2 PINC if_z ret cmp adr, #$1f4 wz 'P1 OUTA if_z mov adr, #$1fa 'P2 OUTC if_z ret cmp adr, #$1f6 wz 'P1 DIRA if_z mov adr, #$1fe 'P2 DIRC ret } regrevflag long 0 reglsb long 0 regmask long 0 regnbits long 0 regsave long 0 '*********************************************************************** ' Constants and Variables '*********************************************************************** bitcycles long 80000000 / 115200 jumps long @jump_table jumpx long @jump_table_ex savex long pushx1 masklong long $FFFFFFFF maskword long $FFFF maskpar long $0000FFFC fit $1E9 org $1E9 id res 1 dcall res 1 pbase res 1 vbase res 1 dbase res 1 pcurr res 1 dcurr res 1 fit $1F0 org 0 x res 1 y res 1 a res 1 t1 res 1 t2 res 1 op res 1 op2 res 1 adr res 1 '*********************************************************************** ' These instructions execute from hub memory '*********************************************************************** orgh ' casedone casedon sub dcurr, #8 rdlong pcurr, dcurr add pcurr, pbase jmp #loop ' casevalue caseval call #getadrs call #popyx add dcurr, #4 cmp x, y wz if_z add pcurr, op2 jmp #loop ' caserange caseran call #getadrs call #popayx add dcurr, #4 cmps a, y wz, wc if_nz_and_nc jmp #caseran1 cmps a, x wz, wc if_nz_and_nc jmp #loop cmps x, y wz, wc if_nz_and_nc jmp #loop add pcurr, op2 jmp #loop caseran1 cmps y, x wz, wc if_nz_and_nc jmp #loop cmps x, a wz, wc if_nz_and_nc jmp #loop add pcurr, op2 jmp #loop ' lookdone lookdon sub dcurr, #12 mov x, #0 jmp #pushx1 ' lookupval lookupv call #pop_adr call #popayx add dcurr, #12 cmps a, x wz, wc if_c jmp #lookupv1 if_z jmp #lookupv2 add x, #1 sub dcurr, #12 wrlong x, dcurr add dcurr, #12 jmp #loop lookupv1 mov pcurr, y add pcurr, pbase sub dcurr, #12 mov x, #0 jmp #pushx1 lookupv2 mov pcurr, y add pcurr, pbase sub dcurr, #12 mov x, adr jmp #pushx1 ' lookdnval lookdnv call #popyx add dcurr, #4 cmp x, y wz if_nz jmp #lookdnv1 sub dcurr, #8 rdlong pcurr, dcurr add pcurr, pbase jmp #loop lookdnv1 sub dcurr, #12 rdlong x, dcurr add x, #1 wrlong x, dcurr add dcurr, #12 jmp #loop ' lookuprange lookupr call #popyx mov t1, y mov t2, x call #popayx add dcurr, #12 mov adr, t1 sub adr, t2 abs adr, adr sub a, x wc if_c jmp #lookupr1 cmp a, adr wc, wz if_c_or_z jmp #lookupr2 add x, adr add x, #1 sub dcurr, #12 wrlong x, dcurr add dcurr, #12 jmp #loop lookupr1 sub dcurr, #12 mov pcurr, y add pcurr, pbase mov x, #0 jmp #pushx1 lookupr2 sub dcurr, #12 mov pcurr, y add pcurr, pbase cmp t2, t1 wc, wz mov x, t2 if_c_or_z add x, a if_nc_and_nz sub x, a jmp #pushx1 ' lookdnrange lookdnr call #popayx add dcurr, #4 mov t1, a mov t2, y max t1, y ' Get minimum min t2, a ' Get maximum cmps x, t1 wc if_c jmp #lookdnr1 cmps t2, x wc if_c jmp #lookdnr1 sub dcurr, #8 rdlong pcurr, dcurr add pcurr, pbase call #pop_adr cmps y, a wc sub x, y if_nc neg x, x add x, adr jmp #pushx1 lookdnr1 sub dcurr, #12 rdlong x, dcurr add x, #1 add x, t2 sub x, t1 wrlong x, dcurr add dcurr, #12 jmp #loop _waitcn call #popx1 waitcnt x, #0 jmp #loop _waitpe call #popayx test a, #1 wz getcnt t1 ' Port A and B :loop if_nz waitpeq x, y, #1 wc if_z waitpeq x, y, #0 wc { ' Port C and D :loop if_nz waitpeq x, y, #3 wc if_z waitpeq x, y, #2 wc } if_c jmp #:loop jmp #loop _waitpn call #popayx test a, #1 wz getcnt t1 :loop if_z waitpne x, y, #1 wc if_nz waitpne x, y, #0 wc if_c jmp #:loop jmp #loop cogstp call #popx1 cogstop x jmp #loop _cogini call #popayx 'coginit, pop parameters test x, #8 wc and x, #7 setnib _cogini1, x, #6 test op,#%100 wz 'push result? if_nc jmp #_cogini1 cognew y, a wc if_c neg x, #1 '-1 if c, else 0..7 if_nc mov x, y '-1 if c, else 0..7 jmp #pushz callobx call #popx1 mov a, x jmp #callobj1 _pop call #popx1 sub dcurr, x jmp #loop abrtval call #popx1 jmp #_abort1 _abort rdlong x,dbase _abort1 call #return1 if_nc jmp #_abort1 jmp #pushz rwreg mov t2, #31 mov t1, #0 jmp #rwreg0 rwregb call #popx1 and x, #31 mov t2, x mov t1, x jmp #rwreg0 rwregbs call #popyx and x, #31 and y, #31 mov t2, x mov t1, y jmp #rwreg0 rwregx call #pop_adr or adr, #$10 shl op, #5 jmp #rwreg1 '*********************************************************************** ' Prepare to start a Spin cog '*********************************************************************** 'run(metindex, stackaddr) _run call #popyx 'stackptr := (metindex >> 8) << 2 mov adr, x shr adr, #8 shl adr, #2 wz 'metindex := ((metindex & 255) << 2) + PBASE and x, #255 shl x, #2 add x, pbase 'skip bytemove if no parms if_z jmp #_run1 't2 := stackaddr + 12 mov t2, y add t2, #12 't1 := DCURR - stackptr mov t1, dcurr sub t1, adr 'a := stackptr mov a, adr 'bytemove(t2, t1, a) :loop rdbyte op2, t1 add t1, #1 wrbyte op2, t2 add t2, #1 djnz a, @:loop 'pop(stackptr) sub dcurr, adr 'long[stackaddr] := -1 _run1 neg t1, #1 wrlong t1, y add y, #4 'long[stackaddr][1] := (@exitcode << 16) mov t1, ##@exitcode shl t1, #16 wrlong t1, y add y, #4 'word[stackaddr][2] := 0 mov t1, #0 wrlong t1, y 'stackptr += stackaddr + 12 add adr, y add adr, #4 'word[stackptr][1] := pbase add adr, #2 wrword pbase, adr 'word[stackptr][2] := vbase add adr, #2 wrword vbase, adr 'word[stackptr][3] := stackaddr + 8 add adr, #2 wrword y, adr 'word[stackptr][4] := word[metindex] + PBASE add adr, #2 rdword t1, x add t1, pbase wrword t1, adr 'word[stackptr][5] := word[metindex][1] + stackptr add adr, #2 add x, #2 rdword t1, x add t1, adr sub t1, #10 wrword t1, adr sub adr, #10 '(-1, @interp, stackptr) neg t1, #1 wrlong t1, dcurr add dcurr, #4 mov t1, ##@interp wrlong t1, dcurr add dcurr, #4 wrlong adr, dcurr add dcurr, #4 jmp #loop '*********************************************************************** ' String, Block Move and Block Fill Instructions '*********************************************************************** ' strsize _strsiz call #popx1 mov y, x :loop rdbyte a, x wz if_nz add x, #1 if_nz jmp #:loop sub x, y jmp #pushx1 ' strcomp _strcmp call #popyx :loop rdbyte t1, x wz add x, #1 if_z jmp #_strcmp1 rdbyte t2, y wz add y, #1 if_z jmp #_strcmp2 cmp t1, t2 wz if_z jmp #:loop _strcmp2 mov x, #0 jmp #pushx1 _strcmp1 rdbyte t2, y wz jmp #_notlx ' longfill _longfl call #popayx :loop wrlong y, x add x, #4 djnz a, @:loop jmp #loop ' wordfill _wordfl call #popayx :loop wrword y, x add x, #2 djnz a, @:loop jmp #loop ' bytefill _bytefl call #popayx :loop wrbyte y, x add x, #1 djnz a, @:loop jmp #loop ' longmove _longmv call #popayx :loop rdlong t1, y add y, #4 wrlong t1, x add x, #4 djnz a, @:loop jmp #loop ' wordmove _wordmv call #popayx :loop rdword t1, y add y, #2 wrword t1, x add x, #2 djnz a, @:loop jmp #loop ' bytemove _bytemv call #popayx :loop rdbyte t1, y add y, #1 wrbyte t1, x add x, #1 djnz a, @:loop jmp #loop '*********************************************************************** ' Lock instructions '*********************************************************************** lcknewr locknew x wc if_c neg x, #1 jmp #pushx1 lcksetr call #popx1 lockset x wc if_c neg x, #1 if_nc mov x, #0 jmp #pushx1 lckclrr call #popx1 lockclr x wc if_c neg x, #1 if_nc mov x, #0 jmp #pushx1 lcknew locknew x jmp #loop lckset call #popx1 lockset x jmp #loop lckclr call #popx1 lockclr x jmp #loop lckret call #popx1 lockret x jmp #loop '*********************************************************************** ' Local Variable Instructions '*********************************************************************** ' Load Long Var ldll call #getadrz mov adr, dbase jmp #ldlong ' Store Long Var stll call #getadrz mov adr, dbase jmp #stlong ' Execute Long Var exll call #getadrz mov adr, dbase jmp #exoplong ' Load Address Var la_l call #getadrz mov x, op2 add x, dbase jmp #pushx1 ' Load Word Var ldwl call #getadrz mov adr, dbase jmp #ldword ' Store Word Var stwl call #getadrz mov adr, dbase jmp #stword ' Execute Word Var exwl call #getadrz mov adr, dbase jmp #exopword ' Load Byte Var ldbl call #getadrz mov adr, dbase jmp #ldbyte ' Store Byte Var stbl call #getadrz mov adr, dbase jmp #stbyte ' Execute Byte Var exbl call #getadrz mov adr, dbase jmp #exopbyte '*********************************************************************** ' Compact VAR Variable Instructions '*********************************************************************** ' Load Long Local Compact ldlvc mov op2, vbase mov adr, op and adr, #$1c jmp #ldlong ' Store Long Local Compact stlvc mov adr, op and adr, #$1c mov op2, vbase jmp #stlong ' Execute Long Local Compact exlvc mov adr, op and adr, #$1c mov op2, vbase jmp #exoplong ' Load Address Long Local Compact lalvc and op, #$1c add op, vbase mov x, op jmp #pushx1 '*********************************************************************** ' VAR Variable Instructions '*********************************************************************** ' Load Long Var ldlv call #getadrz mov adr, vbase jmp #ldlong ' Store Long Var stlv call #getadrz mov adr, vbase jmp #stlong ' Load Word Var ldwv call #getadrz mov adr, vbase jmp #ldword ' Store Word Var stwv call #getadrz mov adr, vbase jmp #stword ' Load Byte Var ldbv call #getadrz mov adr, vbase jmp #ldbyte ' Store Byte Var stbv call #getadrz mov adr, vbase jmp #stbyte ' Execute Long Var exlv call #getadrz mov adr, vbase jmp #exoplong ' Execute Word Var exwv call #getadrz mov adr, vbase jmp #exopword ' Execute Byte Var exbv call #getadrz mov adr, vbase jmp #exopbyte ' Load Address Var la_v call #getadrz mov x, op2 add x, vbase jmp #pushx1 '*********************************************************************** ' Indexed Local Variable Instructions '*********************************************************************** ' Load Long Local with Index ldllx call #getadrz call #pop_adr shl adr, #2 add adr, dbase jmp #ldlong ' Store Long Local with Index stllx call #getadrz call #pop_adr shl adr, #2 add adr, dbase jmp #stlong ' Execute Long Local with Index exllx call #getadrz call #pop_adr shl adr, #2 add adr, dbase jmp #exoplong ' Load Address Long Local with Index lallx call #getadrz call #popx1 shl x, #2 add x, op2 add x, dbase jmp #pushx1 ' Load Word Local with Index ldwlx call #getadrz call #pop_adr shl adr, #1 add adr, dbase jmp #ldword ' Store Word Local with Index stwlx call #getadrz call #pop_adr shl adr, #1 add adr, dbase jmp #stword ' Execute Word Local with Index exwlx call #getadrz call #pop_adr shl adr, #1 add adr, dbase jmp #exopword ' Load Address Word Local with Index lawlx call #getadrz call #popx1 shl x, #1 add x, op2 add x, dbase jmp #pushx1 ' Load Byte Local with Index ldblx call #getadrz call #pop_adr add adr, dbase jmp #ldbyte ' Store Byte Local with Index stblx call #getadrz call #pop_adr add adr, dbase jmp #stbyte ' Execute Byte Local with Index exblx call #getadrz call #pop_adr add adr, dbase jmp #exopbyte ' Load Address Byte Local with Index lablx call #getadrz call #popx1 add x, op2 add x, dbase jmp #pushx1 '*********************************************************************** ' Indexed VAR Variable Instructions '*********************************************************************** ' Load Long VAR with Index ldlvx call #getadrz call #pop_adr shl adr, #2 add adr, vbase jmp #ldlong ' Store Long VAR with Index stlvx call #getadrz call #pop_adr shl adr, #2 add adr, vbase jmp #stlong ' Execute Long VAR with Index exlvx call #getadrz call #pop_adr shl adr, #2 add adr, vbase jmp #exoplong ' Load Address Long VAR with Index lalvx call #getadrz call #popx1 shl x, #2 add x, op2 add x, vbase jmp #pushx1 ' Load Word VAR with Index ldwvx call #getadrz call #pop_adr shl adr, #1 add adr, vbase jmp #ldword ' Store Word VAR with Index stwvx call #getadrz call #pop_adr shl adr, #1 add adr, vbase jmp #stword ' Execute Word VAR with Index exwvx call #getadrz call #pop_adr shl adr, #1 add adr, vbase jmp #exopword ' Load Address Word VAR with Index lawvx call #getadrz call #popx1 shl x, #1 add x, op2 add x, vbase jmp #pushx1 ' Load Byte VAR with Index ldbvx call #getadrz call #pop_adr add adr, vbase jmp #ldbyte ' Store Byte VAR with Index stbvx call #getadrz call #pop_adr add adr, vbase jmp #stbyte ' Execute Byte VAR with Index exbvx call #getadrz call #pop_adr add adr, vbase jmp #exopbyte ' Load Address Byte VAR with Index labvx call #getadrz call #popx1 add x, op2 add x, vbase jmp #pushx1 '*********************************************************************** ' DAT Variable Instructions '*********************************************************************** ' Load Word Object ldwo call #getadrz mov adr, pbase jmp #ldword ' Store Word Object stwo call #getadrz mov adr, pbase jmp #stword ' Execute Word Object exwo call #getadrz mov adr, pbase jmp #exopword ' Load Byte Object ldbo call #getadrz mov adr, pbase jmp #ldbyte ' Store Byte Object stbo call #getadrz mov adr, pbase jmp #stbyte ' Execute Byte Object exbo call #getadrz mov adr, pbase jmp #exopbyte '*********************************************************************** ' Indexed DAT Variable Instructions '*********************************************************************** ' Load Long Object with Index ldlox call #getadrz call #pop_adr shl adr, #2 add adr, pbase jmp #ldlong ' Store Long Object with Index stlox call #getadrz call #pop_adr shl adr, #2 add adr, pbase jmp #stlong ' Execute Long Object with Index exlox call #getadrz call #pop_adr shl adr, #2 add adr, pbase jmp #exoplong ' Load Address Long Object with Index lalox call #getadrz call #popx1 shl x, #2 add x, op2 add x, pbase jmp #pushx1 ' Load Word Object with Index ldwox call #getadrz call #pop_adr shl adr, #1 add adr, pbase jmp #ldword ' Store Word Object with Index stwox call #getadrz call #pop_adr shl adr, #1 add adr, pbase jmp #stword ' Execute Word Object with Index exwox call #getadrz call #pop_adr shl adr, #1 add adr, pbase jmp #exopword ' Load Address Word Object with Index lawox call #getadrz call #popx1 shl x, #1 add x, op2 add x, pbase jmp #pushx1 ' Execute Byte Object with Index exbox call #getadrz call #pop_adr add adr, pbase jmp #exopbyte '*********************************************************************** ' Absolute Address Instructions '*********************************************************************** ' Store Byte Absolute stba call #popyx jmp #stba1 ' Store Word Absolute stwa call #popyx jmp #stwa1 ' Store Long Absolute stla call #popyx jmp #stla1 ' Execute Long Absolute exla sub dcurr, #4 rdlong adr, dcurr jmp #exoplong1 ' Execute Word Absolute exwa sub dcurr, #4 rdlong adr, dcurr jmp #exopword1 ' Execute Byte Absolute exba sub dcurr, #4 rdlong adr, dcurr jmp #exopbyte1 ' Load Address Absolute (NOP) la_a jmp #loop '*********************************************************************** ' Absolute Address with Index Instructions '*********************************************************************** ' Load Byte Absolute with Index ' Store Byte Absolute with Index stbax call #popayx add y, a stba1 wrbyte x, y jmp #loop ' Store Word Absolute with Index stwax call #popayx shl a, #1 add y, a stwa1 wrword x, y jmp #loop ' Store Long Absolute with Index stlax call #popayx shl a, #2 add y, a stla1 wrlong x, y jmp #loop ' Execute Long Absolute with Index exlax call #popay shl a, #2 mov adr, y add adr, a jmp #exoplong1 ' Load Address Long Absolute with Index lalax call #popyx shl y, #2 add x, y jmp #pushx1 ' Execute Word Absolute with Index exwax call #popay shl a, #1 mov adr, y add adr, a jmp #exopword1 ' Load Address Word Absolute with Index lawax call #popyx shl y, #1 add x, y jmp #pushx1 ' Execute Word Absolute with Index exbax call #popay mov adr, y add adr, a jmp #exopbyte1 ' Load Address Byte Absolute with Index labax call #popyx add x, y jmp #pushx1 '*********************************************************************** ' Extended Instructions '*********************************************************************** sexb shl x, #24 sar x, #24 jmp savex sexw shl x, #16 sar x, #16 jmp savex preinc add x, #1 jmp savex predec sub x, #1 jmp savex ' Repeat-from-to-step Instruction repeats call #popay sub dcurr, #4 rdlong t1, dcurr jmp #repeaty ' Repeat-from-to Instruction repeatx call #popay 'pop data (a=to, y=from, t1=step) mov t1, #1 repeaty call #getadrs cmps a,y wc 'reverse range? sumc x,t1 'add/sub step to/from var call #range 'check if x in range y..a according to c if_nc add pcurr,op2 'if in range, branch mov op2, #0 'ensure we don't push to the stack jmp savex ' Check range ' must be preceded by: cmps a,y wc ' range if_c xor a,y 'if reverse range, swap range values if_c xor y,a if_c xor a,y cmps x,y wc 'c=0 if x within range if_nc cmps a,x wc ret randf neg t1, #1 wz jmp #rand1 randr mov t1, #0 wz rand1 min x,#1 mov y,#32 mov a,#%10111 if_z ror a,#1 rand2 test x,a wc if_nz rcr x,#1 if_z rcl x,#1 djnz y,@rand2 jmp savex _sarx call #popy1 sar x, y jmp savex _mulx call #popy1 mul32 x, y getmull x jmp savex _mulhx call #popy1 mul32 x, y getmulh x jmp savex _addx call #popy1 add x, y jmp savex _subx call #popy1 sub x, y jmp savex _xorx call #popy1 xor x, y jmp savex '*********************************************************************** ' Math Instructions '*********************************************************************** _min call #popyx min x, y jmp savex _max call #popyx max x, y jmp savex _rev call #popyx rev x, y jmp savex decode call #popy1 mov x, #1 shl x, y jmp savex encode call #popy1 mov x, #1 encode1 if_z jmp savex add x, #1 shr y, #1 wz jmp #encode1 _sqrt call #popx1 _sqrtx sqrt32 x getsqrt x jmp savex '*********************************************************************** ' Extended Math Instructions '*********************************************************************** _andlx cmp x, #0 wz jmp #_andl+1 _orlx cmp x, #0 wz jmp #_orl+1 _cmpltx call #popy1 jmp #_cmplt+1 _cmpgtx call #popy1 jmp #_cmpgt+1 _cmpnex call #popy1 jmp #_cmpne+1 _cmpeqx call #popy1 jmp #_cmpeq+1 _cmplex call #popy1 jmp #_cmple+1 _cmpgex call #popy1 jmp #_cmpge+1 _minx call #popy1 min x, y jmp savex _maxx call #popy1 max x, y jmp savex _revx call #popy1 rev x, y jmp savex decodex mov y, x jmp #decode+1 encodex mov y, x jmp #encode+1 '*********************************************************************** ' This code is used when absolute address 0 is accessed '*********************************************************************** ldclkfreq mov x, ##_clkfreq jmp #pushx1 '*********************************************************************** ' Trap for unsupported instructions '*********************************************************************** _waitvi _clkset unsupp mov op2, #0 unsupx mov t1, ##@str1 call #putstr mov t1, op call #puthex mov x, #" " call #putch mov t1, op2 call #puthex mov x, #13 call #putch cogid x cogstop x puthex rol t1, #28 call #puthexdigit rol t1, #4 call #puthexdigit ret puthexdigit mov x, #15 and x, t1 mov y, ##@hexdigits add y, x rdbyte x, y call #putch ret putstr rdbyte x, t1 wz if_z ret add t1, #1 call #putch jmp #putstr putch or x, #$100 shl x, #1 mov y, #10 getcnt a add a, bitcycles :loop ror x, #1 wc 'setpc #30 setpc #90 waitcnt a, bitcycles djnz y, @:loop ret str1 byte "Unsupported opcode ", 0 hexdigits byte "0123456789ABCDEF" '*********************************************************************** ' Spin program binary file '*********************************************************************** testprog file "test.binary" {{ +-----------------------------------------------------------------------------+ | TERMS OF USE: MIT License | +-----------------------------------------------------------------------------+ |Permission is hereby granted, free of charge, to any person obtaining a copy | |of this software and associated documentation files (the "Software"), to deal| |in the Software without restriction, including without limitation the rights | |to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |copies of the Software, and to permit persons to whom the Software is | |furnished to do so, subject to the following conditions: | | | |The above copyright notice and this permission notice shall be included in | |all copies or substantial portions of the Software. | | | |THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,| |OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE| |SOFTWARE. | +-----------------------------------------------------------------------------+ }}