Shop OBEX P1 Docs P2 Docs Learn Events
Fast Bytecode Interpreter - Page 21 — Parallax Forums

Fast Bytecode Interpreter

1181921232430

Comments

  • evanhevanh Posts: 15,091
    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. :)
  • cgraceycgracey Posts: 14,131
    evanh wrote: »
    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.
  • Fast Bytecode and Interpreters.....

    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 :)
  • You are seeing the guts Bruce.

    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.

  • evanhevanh Posts: 15,091
    Cool. Got it. It's not my area of interest so wasn't keen to try and solve that riddle myself.
  • potatohead
    When we get to the real deal, you will see a SPIN and or C program, much like you do right now.

    I thought so, but just making sure :)
  • cgraceycgracey Posts: 14,131
    edited 2017-04-21 06:04
    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.
  • TubularTubular Posts: 4,620
    edited 2017-04-21 06:31
    Nice example Chip.

    What are you going to do with all that space you made?
  • cgraceycgracey Posts: 14,131
    edited 2017-04-21 06:57
    Tubular wrote: »
    Nice example Chip.

    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.
  • JRetSapDoogJRetSapDoog Posts: 954
    edited 2017-04-21 06:58
    It's lean (compact) and mean (fast), a double win!!

    So, does keeping the first 1KB of cog available for "user PASM code" refer to in-line PASM?
  • cgraceycgracey Posts: 14,131
    edited 2017-04-21 07:01
    It's lean (compact) and mean (fast), a double win!!

    So, does keeping the first 1KB of cog available for PASM code provide for in-line PASM?

    Yes, even multiple resident routines that you can CALL. They can even be interrupt routines that run automatically in the background.
  • evanhevanh Posts: 15,091
    edited 2017-04-21 07:03
    Yet more Chip magic, seemingly with such ease. :)
  • cgracey wrote: »
    Tubular wrote: »
    Nice example Chip.

    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.
    Brilliant work Chip! :)
  • That's really impressive. Really cements the usefulness of the LUT too.
  • cgraceycgracey Posts: 14,131
    edited 2017-04-21 08:39
    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.
  • cgracey wrote: »
    [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)?
  • cgracey wrote: »
    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.

  • cgraceycgracey Posts: 14,131
    cgracey wrote: »
    [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.
  • cgraceycgracey Posts: 14,131
    edited 2017-04-21 10:21
    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
    
  • Chip:

    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
  • cgraceycgracey Posts: 14,131
    ersmith wrote: »
    Chip:

    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.
  • cgracey wrote: »
    ersmith wrote: »
    Chip:

    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
  • cgraceycgracey Posts: 14,131
    ersmith wrote: »
    cgracey wrote: »
    ersmith wrote: »
    Chip:

    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.
  • jmgjmg Posts: 15,140
    cgracey wrote: »
    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 ?
  • cgraceycgracey Posts: 14,131
    jmg wrote: »
    cgracey wrote: »
    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.
  • jmg wrote: »
    cgracey wrote: »
    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.
  • MJBMJB Posts: 1,235
    ersmith wrote: »
    jmg wrote: »
    cgracey wrote: »
    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?
  • cgraceycgracey Posts: 14,131
    I've got the interpreter to a point where it can run simple loops that manipulate variables, including pins.

    Here is a scope picture of Prop1/Spin1 (top) and Prop2/Spin2 (bottom) both running the following loop at 80MHz:
    repeat
      outa++
    

    Spin2.jpg

    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:

    new_interpreter2.spin2
    828 x 644 - 124K
  • Very cool, and if we get 160Mhz, then it will be over 18 times faster.
  • At that speed, P2 SPIN will be comparable to P1 PASM.
Sign In or Register to comment.