So there is a whole set of new alternate instructions, albeit as shorthand stacking or something, being added then. I think this might count as instruction changes. How many? Maybe Spud's 90% done figure was more accurate after all.
So there is a whole set of new alternate instructions, albeit as shorthand stacking or something, being added then. I think this might count as instruction changes. How many? Maybe Spud's 90% done figure was more accurate after all.
These are software-defined bytecodes, not new instructions. It's just programming, but utilizing the XBYTE mechanism which reads a byte, translates it into a long via the lut RAM, and then does an EXECF using it.
Alright guys, everything I have read about the P2 over the last several years seems so darn confusing. Will the basic user need a masters degree in microcontroller technology just to fire up the P2?
And is there any new indication or prediction when we can expect to see the P2?
When we get to the real deal, you will see a SPIN and or C program, much like you do right now. There will be PASM too.
PASM has seen a significant expansion! But, the basics people know on a P1 are largely the same. Difference is depth. A ton more can be done, and done in a few ways.
This stuff, right now, is the making of SPIN interpreter. Given how the P2 can operate, it's worth it to revisit SPIN and maximize for speed and compact code size.
Here is a 13-instruction block to be executed by XBYTE which performs all the variable-modifier operations, including both stack terms and isolated modifiers:
'
' Variable modifiers
'
varmod alti rd 'read a b c d e f g h i j k a: ++var, var++ (isolated)
nop 'read a b c d e f g h i j k b: --var, var-- (isolated)
pusha x 'push | | c d e f | h | j | c: ++var (push)
mov x,v 'post | | | | e f | h | j | d: --var (push)
add v,#1 '++ a | c | e | | | | | | e: var++ (push)
sub v,#1 '-- | b | d | f | | | | | f: var-- (push)
triml v,tb '++,-- | | c d | | | | | | | g: var!! (isolated)
muxz v,_FFFFFFFF '!! | | | | | | g h | | | h: var!! (push)
not v '! | | | | | | | | i j | i: var! (isolated)
mov y,x '\ | | | | | | | | | | k j: var! (push)
mov x,v '\,pre | | c d | | | | | | k k: var\new (swap)
mov v,y '\ | | | | | | | | | | k
alti wr 'write a b c d e f g h i j k
'nop 'write a b c d e f g h i j k
There are no more than 7 dead spaces between active instructions, so no cycles are lost to NOPs. This is like 11 optimized subroutines packed into 13 instructions. These would have taken 60 instructions to code discretely.
What are you going to do with all that space you made?
Small and fast. Spin2 runtime overhead may be only 3KB. I want cog $000..$0FF available for user PASM code. The interpreter can occupy cog $100..$1EF and the LUT.
What are you going to do with all that space you made?
Small and fast. Spin2 runtime overhead may be only 3KB. I want cog $000..$0FF available for user PASM code. The interpreter can occupy cog $100..$1EF and the LUT.
I hope the world finds good uses for the Prop2. A lot of thought from everyone here has been sunk into it. I don't think any other chip effort has had such ongoing and passionate input from so many people.
All the time, I think about how implementation is a dirty word, anymore, but actually vital to anything working.
This chip is made for people who enjoy implementing ideas and don't suppose it's beneath them to get into the details. For this to be successful, we will ultimately need new people to discover the fun of working in this way. Seems like a longshot in this messy world, but I believe it will happen.
[In-line PASM and] even multiple resident routines that you can CALL. They can even be interrupt routines that run automatically in the background.
With the call provision for resident routines, then maybe in-line PASM could be omitted (but only if it would reduce the size of the SPIN2 interpreter, which it probably wouldn't do by much (if at all)).
Will there be a form of a call for resident PASM routines in SPIN2 that allows for passing a LONG and/or will SPIN2 be able to write to the LUT directly or a "leftover" (or possible fixed) long of the interpreter COG (to make for faster data exchange than sharing through the HUB)?
Seems like a longshot in this messy world, but I believe it will happen.
Keep the faith, Chip. Build it and they will come. Besides, you're basically committed, now. And what else would use your skills as well as this! Something good will come out of it. Probably something very good for a lot of people.
[In-line PASM and] even multiple resident routines that you can CALL. They can even be interrupt routines that run automatically in the background.
With the call provision for resident routines, then maybe in-line PASM could be omitted (but only if it would reduce the size of the SPIN2 interpreter, which it probably wouldn't do by much (if at all)).
Will there be a form of a call for resident PASM routines in SPIN2 that allows for passing a LONG and/or will SPIN2 be able to write to the LUT directly or a "leftover" (or possible fixed) long of the interpreter COG (to make for faster data exchange than sharing through the HUB)?
We could pass parameters simply by copying some stack longs into a fixed set of registers:
PASM(CogRoutine : param1, param2, param3)
Or, you could write some registers and do a call, even get results back that way. I think it will be pretty flexible in that department.
I've got all the math operators and variable modifiers coded. Including the EXECF table that XBYTE uses, this all adds up to almost 1/4th of the 3KB allowance for the interpreter. This code constitutes the biggest part of the interpreter, so there should be plenty of room for the rest of what's needed.
Here is the math/modifier code and its EXECF table:
'
'
' Math operators / variable modifiers
'
var_mod alti rd 'rd a b c d e f g h i j k a: ++var, var++ (isolated)
nop 'rd a b c d e f g h i j k b: --var, var-- (isolated)
pusha x 'push | | c d e f | h | j | c: ++var (push)
mov x,v 'post | | | | e f | h | j | d: --var (push)
add v,#1 '++ a | c | e | | | | | | e: var++ (push)
sub v,#1 '-- | b | d | f | | | | | f: var-- (push)
triml v,tb '++,-- | | c d | | | | | | | g: var!! (isolated)
muxz v,_FFFFFFFF '!! | | | | | | g h | | | h: var!! (push)
not v '! | | | | | | | | i j | i: var! (isolated)
mov y,x '\ | | | | | | | | | | k j: var! (push)
mov x,v '\,pre | | c d | | | | | | k k: var\new (swap)
mov v,y '\ | | | | | | | | | | k
alti wr 'wr a b c d e f g h i j k
' _ret_ nop 'wr a b c d e f g h i j k
una_mod alti rd 'rd m n
una_op mov v,x wz 'rd,op m n a b c d e f g h i a: !!
muxz v,_FFFFFFFF '!! x x a | | | | | | | | b: !
not v '! x x | b | | | | | | | c: - (neg)
neg v '- x x | | c | | | | | | d: ABS
abs v 'ABS x x | | | d | | | | | e: NCOD
topone v 'NCOD x x | | | | e | | | | f: DCOD
decod v 'DCOD x x | | | | | f | | | g: SQRT
qsqrt v,#0 'SQRT x x | | | | | | g | | h: LOG2
qlog v 'LOG2 x x | | | | | | | h | i: EXP2
qexp v 'EXP2 x x | | | | | | | | i
getqx v ' x x | | | | | | g h i
_ret_ mov x,v 'op | | a b c d e f g h i
pusha x 'push | n
mov x,v 'push | n
triml x,tb 'push | n m: ?= var (isolated)
alti wr 'wr m n n: ?= var (push)
' _ret_ nop 'wr m n x: use a..i
sha_mod alti rd 'rd m n
nop 'rd m n
sha_op mov y,x 'op x x a b c d e | | h i j k a: >>
not y,x 'SIGNX x x | | | | | f g | | | | b: <<
mov x,v 'mod m n | | | | | | | | | | | c: SAR
popa x 'op | | a b c d e f g h i j k d: ROR
rev x 'REV x x | | | | | f | | | | | e: ROL
shr x,y '>> x x a | | | | f | | | | | f: REV
shl x,y '<< x x | b | | | | g | | | | g: SIGNX
sar x,y 'SAR x x | | c | | | g | | | | h: +
ror x,y 'ROR x x | | | d | | | | | | | i: -
rol x,y 'ROL x x | | | | e | | | | | | j: !<
add x,y '+ x x | | | | | | | h | | | k: !>
sub x,y '- x x | | | | | | | | i | |
mins x,y '!< x x | | | | | | | | | j |
maxs x,y '!> x x | | | | | | | | | | k
ret 'op | | a b c d e f g h i j k
mov v,x 'mod m n
popa x 'iso m |
triml x,tb 'push | n m: var ?= exp (isolated)
alti wr 'wr m n n: var ?= exp (push)
' _ret_ nop 'wr m n x: use a..k
log_mod alti rd 'rd m n
log_op popa y wz 'rd,op m n a b c d e f a: &&
mov y,v wz 'mod m n b: ^^
muxnz y,_FFFFFFFF 'bool x x a b c | | | c: ||
test x wz 'bool x x a b c | | | d: &
muxnz x,_FFFFFFFF 'bool x x a b c | | | e: ^
and x,y '&&,& x x a | | d | | f: |
xor x,y '^^,^ x x | b | | e |
or x,y '||,| x x | | c | | f
ret 'op | | a b c d e f
mov v,x 'mod m n
popa x 'iso m |
triml x,tb 'push | n m: var ?= exp (isolated)
alti wr 'wr m n n: var ?= exp (push)
' _ret_ nop 'wr m n x: use a..f
mul_mod alti rd 'rd m n
mul_op popa y wc 'rd,op m n a b c d e a: *
mov y,v wc 'mod m n b: /
testb x,#31 wz 'c=ys x x a b c | | c: MOD
abs y '!z=xs x x a b c | | d: SCAL
abs x ' x x a b c | | e: FRAC
qmul y,x '*,SCAL x x a | | d |
qdiv y,x '/,MOD x x | b c | |
qfrac y,x 'FRAC x x | | | | e
getqx x ' x x a b | | e
if_c_eq_z neg x '*,/ x x a b | | |
getqy x ' x x | | c d |
if_c neg x 'MOD x x | | c | |
ret 'op | | a b c d e
mov v,x 'mod m n
popa x 'iso m |
triml x,tb 'push | n m: var ?= exp (isolated)
alti wr 'wr m n n: var ?= exp (push)
' _ret_ nop 'wr m n x: use a..e
long var_mod | %00111111101100 << 10 '++var, var++ (isolated)
long var_mod | %00111111011100 << 10 '--var, var-- (isolated)
long var_mod | %00101110101000 << 10 '++var (push)
long var_mod | %00101110011000 << 10 '--var (push)
long var_mod | %00111111100000 << 10 'var++ (push)
long var_mod | %00111111010000 << 10 'var-- (push)
long var_mod | %00111101111100 << 10 'var!! (isolated)
long var_mod | %00111101110000 << 10 'var!! (push)
long var_mod | %00111011111100 << 10 'var! (isolated)
long var_mod | %00111011110000 << 10 'var! (push)
long var_mod | %00000111111100 << 10 'var\new (swap)
long una_mod | %001111111111111000 << 10 '!!= var (isolated)
long una_mod | %000001111111111000 << 10 '!!= var (push)
long una_op | %011111111100_ << 10 '!!exp
long una_mod | %001111111111110100 << 10 '!= var (isolated)
long una_mod | %000001111111110100 << 10 '!= var (push)
long una_op | %011111111010_ << 10 '!exp
long una_mod | %001111111111101100 << 10 '-= var (isolated)
long una_mod | %000001111111101100 << 10 '-= var (push)
long una_op | %011111110110_ << 10 '-exp
long una_mod | %001111111111011100 << 10 'ABS= var (isolated)
long una_mod | %000001111111011100 << 10 'ABS= var (push)
long una_op | %011111101110_ << 10 'ABS exp
long una_mod | %001111111110111100 << 10 'NCOD= var (isolated)
long una_mod | %000001111110111100 << 10 'NCOD= var (push)
long una_op | %011111011110_ << 10 'NCOD exp
long una_mod | %001111111101111100 << 10 'DCOD= var (isolated)
long una_mod | %000001111101111100 << 10 'DCOD= var (push)
long una_op | %011110111110_ << 10 'DCOD exp
long una_mod | %001111011011111100 << 10 'SQRT= var (isolated)
long una_mod | %000001011011111100 << 10 'SQRT= var (push)
long una_op | %001101111110_ << 10 'SQRT exp
long una_mod | %001111010111111100 << 10 'LOG2= var (isolated)
long una_mod | %000001010111111100 << 10 'LOG2= var (push)
long una_op | %001011111110_ << 10 'LOG2 exp
long una_mod | %001111001111111100 << 10 'EXP2= var (isolated)
long una_mod | %000001001111111100 << 10 'EXP2= var (push)
long una_op | %000111111110_ << 10 'EXP2 exp
long sha_mod | %0010011111111101011000 << 10 'var >>= exp (isolated)
long sha_mod | %0001011111111101011000 << 10 'var >>= exp (push)
long sha_op | %011111111010110__ << 10 'exp >> exp
long sha_mod | %0010011111111011011000 << 10 'var <<= exp (isolated)
long sha_mod | %0001011111111011011000 << 10 'var <<= exp (push)
long sha_op | %011111110110110__ << 10 'exp << exp
long sha_mod | %0010011111110111011000 << 10 'var SAR= exp (isolated)
long sha_mod | %0001011111110111011000 << 10 'var SAR= exp (push)
long sha_op | %011111101110110__ << 10 'exp SAR exp
long sha_mod | %0010011111101111011000 << 10 'var ROR= exp (isolated)
long sha_mod | %0001011111101111011000 << 10 'var ROR= exp (push)
long sha_op | %011111011110110__ << 10 'exp ROR exp
long sha_mod | %0010011111011111011000 << 10 'var ROL= exp (isolated)
long sha_mod | %0001011111011111011000 << 10 'var ROL= exp (push)
long sha_op | %011110111110110__ << 10 'exp ROL exp
long sha_mod | %0010011111111100010100 << 10 'var REV= exp (isolated)
long sha_mod | %0001011111111100010100 << 10 'var REV= exp (push)
long sha_op | %011111111000101__ << 10 'exp REV exp
long sha_mod | %0010011111110011010100 << 10 'var SIGNX= exp (isolated)
long sha_mod | %0001011111110011010100 << 10 'var SIGNX= exp (push)
long sha_op | %011111100110101__ << 10 'exp SIGNX exp
long sha_mod | %0010011110111111011000 << 10 'var += exp (isolated)
long sha_mod | %0001011110111111011000 << 10 'var += exp (push)
long sha_op | %011101111110110__ << 10 'exp + exp
long sha_mod | %0010011101111111011000 << 10 'var -= exp (isolated)
long sha_mod | %0001011101111111011000 << 10 'var -= exp (push)
long sha_op | %011011111110110__ << 10 'exp - exp
long sha_mod | %0010011011111111011000 << 10 'var !<= exp (isolated)
long sha_mod | %0001011011111111011000 << 10 'var !<= exp (push)
long sha_op | %010111111110110__ << 10 'exp !< exp
long sha_mod | %0010010111111111011000 << 10 'var !>= exp (isolated)
long sha_mod | %0001010111111111011000 << 10 'var !>= exp (push)
long sha_op | %001111111110110__ << 10 'exp !> exp
long log_mod | %001001110000000 << 10 'var &&= exp (isolated)
long log_mod | %000101110000000 << 10 'var &&= exp (push)
long log_op | %011000010_ << 10 'exp && exp
long log_mod | %001001101000000 << 10 'var ^^= exp (isolated)
long log_mod | %000101101000000 << 10 'var ^^= exp (push)
long log_op | %010100010_ << 10 'exp ^^ exp
long log_mod | %001001011000000 << 10 'var ||= exp (isolated)
long log_mod | %000101011000000 << 10 'var ||= exp (push)
long log_op | %001100010_ << 10 'exp || exp
long log_mod | %001001110111000 << 10 'var &= exp (isolated)
long log_mod | %000101110111000 << 10 'var &= exp (push)
long log_op | %011011110_ << 10 'exp & exp
long log_mod | %001001101111000 << 10 'var ^= exp (isolated)
long log_mod | %000101101111000 << 10 'var ^= exp (push)
long log_op | %010111110_ << 10 'exp ^ exp
long log_mod | %001001011111000 << 10 'var |= exp (isolated)
long log_mod | %000101011111000 << 10 'var |= exp (push)
long log_op | %001111110_ << 10 'exp | exp
long mul_mod | %0010011100110000000 << 10 'var *= exp (isolated)
long mul_mod | %0001011100110000000 << 10 'var *= exp (push)
long mul_op | %0110011000010_ << 10 'exp * exp
long mul_mod | %0010011100101000000 << 10 'var /= exp (isolated)
long mul_mod | %0001011100101000000 << 10 'var /= exp (push)
long mul_op | %0110010100010_ << 10 'exp / exp
long mul_mod | %0010010011101000000 << 10 'var MOD= exp (isolated)
long mul_mod | %0001010011101000000 << 10 'var MOD= exp (push)
long mul_op | %0001110100010_ << 10 'exp MOD exp
long mul_mod | %0010011011110111000 << 10 'var SCAL= exp (isolated)
long mul_mod | %0001011011110111000 << 10 'var SCAL= exp (push)
long mul_op | %0101111011110_ << 10 'exp SCAL exp
long mul_mod | %0010011110011111000 << 10 'var FRAC= exp (isolated)
long mul_mod | %0001011110011111000 << 10 'var FRAC= exp (push)
long mul_op | %0111001111110_ << 10 'exp FRAC exp
I'm looking into trying to implement an interpreter on P2 as well, so I have some questions about your code if you don't mind:
(1) How does the "rd" get set up for the "alti rd" instructions? If it's the same all the time, why do "alti rd ; nop" instead of just putting the instruction inline?
(2) What's the purpose of the "triml x,tb" instruction that appears on some paths?
I'm looking into trying to implement an interpreter on P2 as well, so I have some questions about your code if you don't mind:
(1) How does the "rd" get set up for the "alti rd" instructions? If it's the same all the time, why do "alti rd ; nop" instead of just putting the instruction inline?
(2) What's the purpose of the "triml x,tb" instruction that appears on some paths?
Thanks,
Eric
There are variable setup routines that establish RD and WR, which are the actual r/w instructions (RDxxxx, MOV, RDLUT, WRxxxx, MOV, RDLUT). Also, they setup the address (M) and mask (TB). Register V is the data conduit. X is the current top of the stack.
The 'TRIML X,TB' trims the value left on the stack, after a variable modifier, to the appropriate size. Imagine this Spin2 code, where J is a byte:
K += ++J
If J was $FF before, it must become $00, not $100. Same goes for buried assignments:
IF K == (J *= 5)
I'll have all this variable/constant/operator code done today and I'll put it into a post.
I'm looking into trying to implement an interpreter on P2 as well, so I have some questions about your code if you don't mind:
(1) How does the "rd" get set up for the "alti rd" instructions? If it's the same all the time, why do "alti rd ; nop" instead of just putting the instruction inline?
(2) What's the purpose of the "triml x,tb" instruction that appears on some paths?
Thanks,
Eric
There are variable setup routines that establish RD and WR, which are the actual r/w instructions (RDxxxx, MOV, RDLUT, WRxxxx, MOV, RDLUT). Also, they setup the address (M) and mask (TB). Register V is the data conduit. X is the current top of the stack.
Thanks, Chip. I kind of figured it was something like that, but then I wondered when those routines would get run. I guess they're part of a previous opcode?
One other question, perhaps a silly one: what happens if a routine invoked by the XBYTE interpreter needs more than 22 instructions (e.g. some kind of complicated JVM operation)? Is there a way to bypass the SKIPF mechanism (maybe if the SKIPF mask is 0)?
I'm looking into trying to implement an interpreter on P2 as well, so I have some questions about your code if you don't mind:
(1) How does the "rd" get set up for the "alti rd" instructions? If it's the same all the time, why do "alti rd ; nop" instead of just putting the instruction inline?
(2) What's the purpose of the "triml x,tb" instruction that appears on some paths?
Thanks,
Eric
There are variable setup routines that establish RD and WR, which are the actual r/w instructions (RDxxxx, MOV, RDLUT, WRxxxx, MOV, RDLUT). Also, they setup the address (M) and mask (TB). Register V is the data conduit. X is the current top of the stack.
Thanks, Chip. I kind of figured it was something like that, but then I wondered when those routines would get run. I guess they're part of a previous opcode?
One other question, perhaps a silly one: what happens if a routine invoked by the XBYTE interpreter needs more than 22 instructions (e.g. some kind of complicated JVM operation)? Is there a way to bypass the SKIPF mechanism (maybe if the SKIPF mask is 0)?
Thanks,
Eric
Yes, prior bytecodes establish variable setup.
If you set the SKIPF mask to 0, no skipping will occur.
Q: One other question, perhaps a silly one: what happens if a routine invoked by the XBYTE interpreter needs more than 22 instructions (e.g. some kind of complicated JVM operation)? Is there a way to bypass the SKIPF mechanism (maybe if the SKIPF mask is 0)?
Yes, prior bytecodes establish variable setup.
If you set the SKIPF mask to 0, no skipping will occur.
I think Eric was meaning some method to chain more than 32 skips, like maybe 40 or 57 or ?
Q: One other question, perhaps a silly one: what happens if a routine invoked by the XBYTE interpreter needs more than 22 instructions (e.g. some kind of complicated JVM operation)? Is there a way to bypass the SKIPF mechanism (maybe if the SKIPF mask is 0)?
Yes, prior bytecodes establish variable setup.
If you set the SKIPF mask to 0, no skipping will occur.
I think Eric was meaning some method to chain more than 32 skips, like maybe 40 or 57 or ?
You could selectively SKIPF into another SKIPF instruction.
Q: One other question, perhaps a silly one: what happens if a routine invoked by the XBYTE interpreter needs more than 22 instructions (e.g. some kind of complicated JVM operation)? Is there a way to bypass the SKIPF mechanism (maybe if the SKIPF mask is 0)?
Yes, prior bytecodes establish variable setup.
If you set the SKIPF mask to 0, no skipping will occur.
I think Eric was meaning some method to chain more than 32 skips, like maybe 40 or 57 or ?
No, actually, I was checking about whether there's a skip-less option; sometimes it may be necessary (or convenient). It makes sense that a SKIPF mask of 0 means "no skips", so that's great.
Longer skips might be nice, but as Chip says you can always manually insert SKIPFs. Once you're over 20 instructions adding another SKIPF is not going to be a big deal.
Q: One other question, perhaps a silly one: what happens if a routine invoked by the XBYTE interpreter needs more than 22 instructions (e.g. some kind of complicated JVM operation)? Is there a way to bypass the SKIPF mechanism (maybe if the SKIPF mask is 0)?
Yes, prior bytecodes establish variable setup.
If you set the SKIPF mask to 0, no skipping will occur.
I think Eric was meaning some method to chain more than 32 skips, like maybe 40 or 57 or ?
No, actually, I was checking about whether there's a skip-less option; sometimes it may be necessary (or convenient). It makes sense that a SKIPF mask of 0 means "no skips", so that's great.
Longer skips might be nice, but as Chip says you can always manually insert SKIPFs. Once you're over 20 instructions adding another SKIPF is not going to be a big deal.
and you can always CALL or JUMP to additional PASM code (first half of COG or HUBEXEC) ...
and after the SKIPF pattern is used up code just continues ... right?
Comments
These are software-defined bytecodes, not new instructions. It's just programming, but utilizing the XBYTE mechanism which reads a byte, translates it into a long via the lut RAM, and then does an EXECF using it.
Alright guys, everything I have read about the P2 over the last several years seems so darn confusing. Will the basic user need a masters degree in microcontroller technology just to fire up the P2?
And is there any new indication or prediction when we can expect to see the P2?
I am not rushing anyone.... just asking
When we get to the real deal, you will see a SPIN and or C program, much like you do right now. There will be PASM too.
PASM has seen a significant expansion! But, the basics people know on a P1 are largely the same. Difference is depth. A ton more can be done, and done in a few ways.
This stuff, right now, is the making of SPIN interpreter. Given how the P2 can operate, it's worth it to revisit SPIN and maximize for speed and compact code size.
I thought so, but just making sure
There are no more than 7 dead spaces between active instructions, so no cycles are lost to NOPs. This is like 11 optimized subroutines packed into 13 instructions. These would have taken 60 instructions to code discretely.
What are you going to do with all that space you made?
Small and fast. Spin2 runtime overhead may be only 3KB. I want cog $000..$0FF available for user PASM code. The interpreter can occupy cog $100..$1EF and the LUT.
So, does keeping the first 1KB of cog available for "user PASM code" refer to in-line PASM?
Yes, even multiple resident routines that you can CALL. They can even be interrupt routines that run automatically in the background.
All the time, I think about how implementation is a dirty word, anymore, but actually vital to anything working.
This chip is made for people who enjoy implementing ideas and don't suppose it's beneath them to get into the details. For this to be successful, we will ultimately need new people to discover the fun of working in this way. Seems like a longshot in this messy world, but I believe it will happen.
Will there be a form of a call for resident PASM routines in SPIN2 that allows for passing a LONG and/or will SPIN2 be able to write to the LUT directly or a "leftover" (or possible fixed) long of the interpreter COG (to make for faster data exchange than sharing through the HUB)?
We could pass parameters simply by copying some stack longs into a fixed set of registers:
PASM(CogRoutine : param1, param2, param3)
Or, you could write some registers and do a call, even get results back that way. I think it will be pretty flexible in that department.
Here is the math/modifier code and its EXECF table:
I'm looking into trying to implement an interpreter on P2 as well, so I have some questions about your code if you don't mind:
(1) How does the "rd" get set up for the "alti rd" instructions? If it's the same all the time, why do "alti rd ; nop" instead of just putting the instruction inline?
(2) What's the purpose of the "triml x,tb" instruction that appears on some paths?
Thanks,
Eric
There are variable setup routines that establish RD and WR, which are the actual r/w instructions (RDxxxx, MOV, RDLUT, WRxxxx, MOV, RDLUT). Also, they setup the address (M) and mask (TB). Register V is the data conduit. X is the current top of the stack.
The 'TRIML X,TB' trims the value left on the stack, after a variable modifier, to the appropriate size. Imagine this Spin2 code, where J is a byte:
K += ++J
If J was $FF before, it must become $00, not $100. Same goes for buried assignments:
IF K == (J *= 5)
I'll have all this variable/constant/operator code done today and I'll put it into a post.
Thanks, Chip. I kind of figured it was something like that, but then I wondered when those routines would get run. I guess they're part of a previous opcode?
One other question, perhaps a silly one: what happens if a routine invoked by the XBYTE interpreter needs more than 22 instructions (e.g. some kind of complicated JVM operation)? Is there a way to bypass the SKIPF mechanism (maybe if the SKIPF mask is 0)?
Thanks,
Eric
Yes, prior bytecodes establish variable setup.
If you set the SKIPF mask to 0, no skipping will occur.
I think Eric was meaning some method to chain more than 32 skips, like maybe 40 or 57 or ?
You could selectively SKIPF into another SKIPF instruction.
No, actually, I was checking about whether there's a skip-less option; sometimes it may be necessary (or convenient). It makes sense that a SKIPF mask of 0 means "no skips", so that's great.
Longer skips might be nice, but as Chip says you can always manually insert SKIPFs. Once you're over 20 instructions adding another SKIPF is not going to be a big deal.
and after the SKIPF pattern is used up code just continues ... right?
Here is a scope picture of Prop1/Spin1 (top) and Prop2/Spin2 (bottom) both running the following loop at 80MHz:
You can see that the new Prop2/Spin2 interpreter is over 9x faster than the Prop1/Spin1.
Here is the interpreter in its current state: