Shop OBEX P1 Docs P2 Docs Learn Events
Propeller II update - BLOG - Page 67 — Parallax Forums

Propeller II update - BLOG

16465676970223

Comments

  • cgraceycgracey Posts: 14,131
    edited 2013-06-26 20:42
    Any information regarding power requirements? Just doing some preliminary work for our in-house development boards and need a ball park figure to proceed.

    Many thanks

    Rob

    We don't know yet, but on our module we are using a 2-amp 1.8V switching power supply. It's possible that the chip could dissipate over two watts, going full-bore with everything running. Hopefully, we'll know what the power requirements are in 8 weeks when we hope to get a working chip back from the foundry.
  • David BetzDavid Betz Posts: 14,511
    edited 2013-06-27 05:22
    cgracey wrote: »
    We don't know yet, but on our module we are using a 2-amp 1.8V switching power supply. It's possible that the chip could dissipate over two watts, going full-bore with everything running. Hopefully, we'll know what the power requirements are in 8 weeks when we hope to get a working chip back from the foundry.
    8 weeks until a new chip! That's very exciting! Did you end up staying with TSMC or did you go to a different foundry?
  • bruceebrucee Posts: 239
    edited 2013-06-27 11:24
    2W seems like an awful lot, if that is indeed possible, you'll need to consider a thermally enhanced QFP (exposed pad type) and tie that into the PCB to dissipate that power.

    It can't be just the logic, is that the peripheral analog circuitry? In which case the worst case won't be typical. In a standard QFP package of that size will see a 50 deg-C rise in junction temp/Watt. With most chips will begin failing at 150 C
  • Bill HenningBill Henning Posts: 6,445
    edited 2013-06-27 12:58
    Chip,

    Eight weeks is survivable, I'm crossing my fingers that everything works :)

    Do you have an updated pinout for the modules, and descriptions of how you will handle the *DQM strapping?
    cgracey wrote: »
    We don't know yet, but on our module we are using a 2-amp 1.8V switching power supply. It's possible that the chip could dissipate over two watts, going full-bore with everything running. Hopefully, we'll know what the power requirements are in 8 weeks when we hope to get a working chip back from the foundry.
  • KC_RobKC_Rob Posts: 465
    edited 2013-06-30 09:10
    brucee wrote: »
    [Over] 2W seems like an awful lot, if that is indeed possible, you'll need to consider a thermally enhanced QFP (exposed pad type) and tie that into the PCB to dissipate that power.
    Agreed, even as a theoretical maximum that seems a bit much.
  • jmgjmg Posts: 15,140
    edited 2013-06-30 16:03
    brucee wrote: »
    2W seems like an awful lot, if that is indeed possible, you'll need to consider a thermally enhanced QFP (exposed pad type) and tie that into the PCB to dissipate that power.

    Exposed pad is a relatively simple change, (I think no die impact?) and it would be a good idea to bond some of the pilot run into Exposed -Pad QFP.

    That way, Parallax can measure the differences, and decide if the performance gains, are worth the (small) added cost.

    The Exposed Pad variants I like the most, are ones where the package designer thought to allow via-space between the exposed pad, and pin areas.
    In a larger package like TQFP128, this should be practical.
  • jmgjmg Posts: 15,140
    edited 2013-06-30 17:41
    Are there any updates on Prop 2 Counters documenting ?

    - have some threads been removed from here ? Seems less than there was in my browser.
  • whickerwhicker Posts: 749
    edited 2013-06-30 17:48
    jmg wrote: »
    Are there any updates on Prop 2 Counters documenting ?

    - have some threads been removed from here ? Seems less than there was in my browser.
    By default in the "Thread Display Options", only threads up to a month old are shown.
  • cgraceycgracey Posts: 14,131
    edited 2013-06-30 17:53
    jmg wrote: »
    Are there any updates on Prop 2 Counters documenting ?

    - have some threads been removed from here ? Seems less than there was in my browser.


    I have been working on the new Spin compiler. I think I've got the interpreter code operable, but I must get the compiler done to prove it all. I've been working on this for over a month and so I haven't made any new documentation during this period. I really want to get the compiler operating, since that's the biggest thing hanging over my head, at this point. The rest is like a mop-up operation.

    About a thermal-pad TQFP package: This could be done, but it will be a custom package design that will cost us $50k, since our die is too big for the thermal-pad package offered by our packager. If we see that the die works and runs hot, we'll spring for this, but first we must learn what we're dealing with.
  • Cluso99Cluso99 Posts: 18,066
    edited 2013-06-30 19:20
    WTG Chip. I would love to see your interpreter code :) Any chance you may post it yet?
  • cgraceycgracey Posts: 14,131
    edited 2013-07-01 12:35
    Here's the Spin2 Interpreter, so far:

    Spin2interpreter.spin
    CON
    
      base	= $E80
    
    '
    '
    '***************
    '* Interpreter *
    '***************
    '
    DAT
    			orgh	base
    			org	$15B
    '
    '
    ' Append word to x - used to make $0xxxx or $1xxxx address
    '
    xword			rdbytec	y,ptra++
    
    xword_ret		retd
    
    			movf	x,y
    			rdbytec	y,ptra++
    			movf	x,y
    
    '
    '
    ' call obj.sub
    ' call obj.sub[]
    ' call obj[].sub
    ' call obj[].sub[]
    ' call sub
    ' call sub[]
    ' call ptr
    '
    call_obj		shl	x,#2			'lookup obj vbase/pbase offsets
    			add	x,pbase
    			rdlong	x,x
    
    call_ptr		rol	x,#4			'set relative pbase
    			add	pbase,x
    			and	pbase,h0001FFF0
    
    			ror	x,#16			'set relative vbase
    			add	vbase,x
    			and	vbase,h0001FFF0
    
    call_sub		shl	y,#2			'lookup locals/pbase offsets
    			add	y,pbase
    			rdlong	y,y
    
    			mov	dbase,dcall		'set call dbase
    			add	dbase,#3
    
    			setspb	dcall			'get old dcall
    			popb	dcall
    
    			getptra	x			'set return pcurr
    			pushb	x
    
    			setptra	pbase			'set call pcurr
    
    			jmpd	#getbyte		'loop to getbyte, delayed
    
    			addptra	y
    
    			shr	y,#32-4			'add locals to dcurr
    			addspa	y
    '
    '
    ' Bitfield addressing, pop and set bitfield parameters
    '
    bitfield		popa	bshift			'pop range lsb
    			popa	bmask			'pop range msb
    
    			and	bshift,#$1F		'trim lsb/msb
    			and	bmask,#$1F
    
    			cmp	bmask,bshift	wc	'reverse range?
    
    	if_c		xor	bshift,bmask		'if reverse range, swap msb/lsb
    	if_c		xor	bmask,bshift
    	if_c		xor	bshift,bmask
    
    			sub	bmask,bshift		'get number of bits
    			add	bmask,#1
    
    			neg	brev,bmask		'get rev count
    
    bitfield_ret		retd				'return, delayed
    
    			setbc	brev,#6			'save reverse flag
    
    			blmask	bmask			'get bitlength mask
    			shl	bmask,bshift		'bmask = mask, brev = reverse, bshift = lsb offset
    '
    '
    ' Write register, if OUTA..OUTD then update PINA..PIND (x = value)
    '
    writer			movd	writer_reg,addr
    			movd	writer_pin,addr
    			setb	writer_pin,#9+3
    writer_reg		mov	$000,x
    
    writer_ret		retd
    
    			xor	addr,#$1F0
    			test	addr,#$1FC	wz
    writer_pin	if_z	mov	$000,x
    '
    '
    ' Do bitfield read (x = value)
    '
    readb			and	x,bmask
    
    			jmpd	#getbyte
    
    			shr	x,bshift
    	if_c		rev	x,brev
    			pusha	x
    '
    '
    ' Do bitfield write (bval = value, writeb_i = write instruction)
    '
    writeb			popa	x			'pop value to write
    	if_c		rev	x,brev			'reverse bits?
    			shl	x,bshift		'shift into position
    			and	x,bmask			'mask bits
    			andn	bval,bmask		'mask away original bits
    			or	x,bval			'merge bits
    writeb_i		pushbr	x			'call #writer / pushbr x / wrxxxx x,addr
    
    writeb_ret		jmp	#getbyte
    '
    '
    ' Do bitfield assignment (bval = value, assignb_i = write instruction, mask = sized mask)
    '
    assignb_long		mov	mask,hFFFFFFFF		'set long mask
    
    assignb			movs	jmpback,#assignb_ret	'set jmpback address to assignb_ret
    			mov	x,bval			'save original value
    			jmpd	#assign_op		'get math operator and execute, delayed
    
    			and	x,bmask			'extract bitfield for operation
    			shr	x,bshift
    	if_c		rev	x,brev
    
    
    assignb_ret		testb	brev,#6		wc	'snippet returns to here, get reverse flag into c
    			call	#writeb			'write bitfield
    			movs	writeb_ret,#getbyte	'restore jump to getbyte
    
    			and	x,mask			'mask it
    			jmpd	#assign_p		'push it (optional), delayed
    
    			and	x,bmask			'extract bitfield for pushing
    			shr	x,bshift
    	if_c		rev	x,brev
    '
    '
    ' Do assignment (x = value, assign_i = write instruction, mask = sized mask)
    '
    assign_local		mov	assign_i,pushbrx	'set local write
    assign_long		mov	mask,hFFFFFFFF		'set long mask
    
    assign			movs	jmpback,#assign_ret	'set jmpback address to :ret
    
    assign_op		rdbytec	a,ptra++		'get math operator and flags
    			setzc	a		wz,wc	'load flags, operator already in position
    			muxz	assign_p,h003C0000	'set push condition to z
    
    			jmpd	#hotbyte		'load and execute math snippet, delayed
    
    	if_c		popa	y			'swap args?
    			pusha	x
    	if_c		pusha	y
    
    
    assign_ret		popa	x			'snippet returns to here, pop value
    assign_i		pushbr	x			'write it (call #writer / pushbr x / wrxxxx x,addr)
    
    			and	x,mask			'mask it
    assign_p		pusha	x			'push it (optional)
    
    			movs	jmpback,#getbyte	'replace jmpback address, getbyte next
    '
    '
    ' Get byte code, look up descriptor long, load code longs in-line, execute, repeat
    '
    getbyte			rdbytec	a,ptra++	wz	'	get byte code, extended?
    
    	if_z		rdbytec	a,ptra++		'	if extended, get extended byte code
    	if_z		or	a,#$100			'	...and add offset
    
    			shl	a,#2			'	shift to make long offset
    
    hotbyte			add	a,descbase		'	add base address of descriptor longs
    
    			rdlong	x,a			'..2	get descriptor long
    
    			movd	:reps,x			'3	descriptor[8..0] holds code longs minus 1
    
    			shr	x,#7			'4	descriptor[23..7] is code offset
    			setptrb	x			'5	point PTRB to code longs
    
    :reps			reps	#1,#1			'6	ready for fast in-line code load
    			setindb	#snippet		'7	point INDB to in-line code
    			rdlongc	indb++,ptrb++		'0..	load code longs in-line using cached read
    
    			mov	indb++,jmpback		'+1	finish in-line code with 'jmp #getbyte'
    			shr	x,#25-7		wz,wc	'+1	descriptor[31..25] is a value, [24] is C
    
    snippet			long	0[22]			'?	execute in-line code snippet, loop
    '
    '
    ' Constants
    '
    pushbrx			pushbr	x
    callwriter		call	#writer
    jmpback			jmp	#getbyte
    
    descbase		long	@descs-4		'account for $01 offset
    
    h0001FFF0		long	$0001FFF0		'vbase/pbase mask
    h003C0000		long	$003C0000		'conditional field bits
    hFFFFFFFF		long	$FFFFFFFF		'all bits
    
    x			long	0			'variables
    y			long	0
    a			long	0
    b			long	0
    
    addr			long	0			'assignment
    mask			long	0
    
    bshift			long	0			'bitfield addressing
    bmask			long	0
    brev			long	0
    bval			long	0
    
    dcall			long	0			'		pointer
    dbase			long	0			'		pointer
    
    outa			long	0			'@$1F0		OUTA..OUTD
    outb			long	0			'@$1F1		(writes update PINA..PIND)
    outc			long	0			'@$1F2
    outd			long	0			'@$1F3
    
    vbase			long	0			'@$1F4		pointer
    pbase			long	0			'@$1F5		pointer
    '
    '
    '************************
    '* Bytecode Descriptors *
    '************************
    '
    descs
    
    ' variable modifiers (14)
    
    op_writep	long	%0000000_0 << 24 + @_clr     << 7 + 0	'write w/push	%10 push
    op_rep		long	%0000000_0 << 24 + @_rep     << 7 + 12	'repeat var	%00 no
    op_clr		long	%0000000_0 << 24 + @_clr     << 7 + 1	'clear		%00 no
    op_clrpost	long	%0000000_0 << 24 + @_clrpost << 7 + 0	'clear post	%00 push
    op_set		long	%0000000_0 << 24 + @_set     << 7 + 1	'set		%00 no
    op_setpost	long	%0000000_0 << 24 + @_setpost << 7 + 0	'set post	%00 push
    op_incpre	long	%0000000_0 << 24 + @_incdec  << 7 + 3	'inc pre / inc	%10 push / %00 no
    op_incpost	long	%0000001_0 << 24 + @_incdec  << 7 + 3	'inc post	%00 push
    op_decpre	long	%0000000_1 << 24 + @_incdec  << 7 + 3	'dec pre / dec 	%10 push / %00 no
    op_decpost	long	%0000001_1 << 24 + @_incdec  << 7 + 3	'dec post	%00 push
    op_incmod	long	%0000000_0 << 24 + @_idmod   << 7 + 6	'incmod		%00 no
    op_incmodp	long	%0000001_0 << 24 + @_idmod   << 7 + 6	'incmod w/push	%00 push
    op_decmod	long	%0000000_1 << 24 + @_idmod   << 7 + 6	'decmod		%00 no
    op_decmodp	long	%0000001_1 << 24 + @_idmod   << 7 + 6	'decmod w/push	%00 push
    
    ' unaries (23)
    
    op_notb		long	%0000000_0 << 24 + @_notb    << 7 + 2	'NOT		%x0
    op_not		long	%0000000_0 << 24 + @_not     << 7 + 2	'!		%x0
    op_neg		long	%0000000_0 << 24 + @_neg     << 7 + 2	'-		%x0
    op_abs		long	%0000000_0 << 24 + @_abs     << 7 + 2	'||		%x0
    op_enc		long	%0000000_0 << 24 + @_enc     << 7 + 2	'>|		%x0
    op_decod5	long	%0000000_0 << 24 + @_decod5  << 7 + 2	'|<, DECOD5(x)	%x0
    op_decod4	long	%0000000_0 << 24 + @_decod4  << 7 + 2	'DECOD4(x)	%x0
    op_decod3	long	%0000000_0 << 24 + @_decod3  << 7 + 2	'DECOD3(x)	%x0
    op_decod2	long	%0000000_0 << 24 + @_decod2  << 7 + 2	'DECOD2(x)	%x0
    op_blmask	long	%0000000_0 << 24 + @_blmask  << 7 + 2	'BLMASK(x)	%x0
    op_onecnt	long	%0000000_0 << 24 + @_onecnt  << 7 + 2	'ONECNT(x)	%x0
    op_zercnt	long	%0000000_0 << 24 + @_zercnt  << 7 + 2	'ZERCNT(x)	%x0
    op_incpat	long	%0000000_0 << 24 + @_incpat  << 7 + 2	'INCPAT(x)	%x0
    op_decpat	long	%0000000_0 << 24 + @_decpat  << 7 + 2	'DECPAT(x)	%x0
    op_bingry	long	%0000000_0 << 24 + @_bingry  << 7 + 2	'BINGRY(x)	%x0
    op_grybin	long	%0000000_0 << 24 + @_grybin  << 7 + 2	'GRYBIN(x)	%x0
    op_mergew	long	%0000000_0 << 24 + @_mergew  << 7 + 2	'MERGEW(x)	%x0
    op_splitw	long	%0000000_0 << 24 + @_splitw  << 7 + 2	'SPLITW(x)	%x0
    op_seussf	long	%0000000_0 << 24 + @_seussf  << 7 + 2	'SEUSSF(x)	%x0
    op_seussr	long	%0000000_0 << 24 + @_seussr  << 7 + 2	'SEUSSR(x)	%x0
    op_sqrt		long	%0000000_0 << 24 + @_sqrt    << 7 + 4	'SQRT(x)	%x0
    op_qlog		long	%0000000_0 << 24 + @_qlogexp << 7 + 5	'QLOG(x)	%x0
    op_qexp		long	%0000000_1 << 24 + @_qlogexp << 7 + 5	'QEXP(x)	%x0
    
    ' binaries (23)
    
    op_andb		long	%0000000_0 << 24 + @_andb    << 7 + 4	'AND		%x1
    op_orb		long	%0000000_0 << 24 + @_orb     << 7 + 4	'OR		%x1
    op_xorb		long	%0000000_0 << 24 + @_xorb    << 7 + 5	'XOR		%x1
    op_andn		long	%0000000_0 << 24 + @_andn    << 7 + 3	'&!		%x1
    op_and		long	%0000000_0 << 24 + @_and     << 7 + 3	'&		%x1
    op_or		long	%0000000_0 << 24 + @_or      << 7 + 3	'|		%x1
    op_xor		long	%0000000_0 << 24 + @_xor     << 7 + 3	'^		%x1
    op_ror		long	%0000000_0 << 24 + @_ror     << 7 + 3	'->		%x1
    op_rol		long	%0000000_0 << 24 + @_rol     << 7 + 3	'<-		%x1
    op_shr		long	%0000000_0 << 24 + @_shr     << 7 + 3	'>>		%x1
    op_shl		long	%0000000_0 << 24 + @_shl     << 7 + 3	'<<		%x1
    op_sar		long	%0000000_0 << 24 + @_sar     << 7 + 3	'~>		%x1
    op_sal		long	%0000000_0 << 24 + @_sal     << 7 + 5	'<~		%x1
    op_rev		long	%0000000_0 << 24 + @_rev     << 7 + 4	'><		%x1
    op_mins		long	%0000000_0 << 24 + @_mins    << 7 + 3	'#>		%x1
    op_maxs		long	%0000000_0 << 24 + @_maxs    << 7 + 3	'<#		%x1
    op_add		long	%0000000_0 << 24 + @_add     << 7 + 3	'+		%x1
    op_sub		long	%0000000_0 << 24 + @_sub     << 7 + 3	'-		%x1
    op_mul		long	%0000000_0 << 24 + @_mul     << 7 + 6	'*		%x1
    op_scl		long	%0000001_0 << 24 + @_scl     << 7 + 6	'**		%x1
    op_quo		long	%0000000_0 << 24 + @_divx    << 7 + 7	'/		%x1
    op_rem		long	%0000001_0 << 24 + @_divx    << 7 + 7	'//		%x1
    op_fra		long	%0000000_0 << 24 + @_fra     << 7 + 7	'*/		%x1
    
    ' equality tests (6)
    
    op_b		long	%0000000_0 << 24 + @_b       << 7 + 4	'<
    op_a		long	%0000000_0 << 24 + @_a       << 7 + 4	'>
    op_ne		long	%0000000_0 << 24 + @_ne      << 7 + 4	'<>
    op_eq		long	%0000000_0 << 24 + @_eq      << 7 + 4	'==
    op_be		long	%0000000_0 << 24 + @_be      << 7 + 4	'=< / <=
    op_ae		long	%0000000_0 << 24 + @_ae      << 7 + 4	'=> / >=
    
    ' math terms (8)
    
    op_quo64	long	%0000000_0 << 24 + @_divh64  << 7 + 10	'QUO64(al,ah,b)
    op_quo64u	long	%0000000_1 << 24 + @_divh64  << 7 + 10	'QUO64U(al,ah,b)
    op_rem64	long	%0000001_0 << 24 + @_divh64  << 7 + 10	'REM64(al,ah,b)
    op_rem64u	long	%0000001_1 << 24 + @_divh64  << 7 + 10	'REM64U(al,ah,b)
    op_sqrt64	long	%0000000_0 << 24 + @_sqrt64  << 7 + 6	'SQRT64(l,h)
    op_negb		long	%0000000_0 << 24 + @_negb    << 7 + 3	'NEGB(x,bool)
    op_muxb		long	%0000000_0 << 24 + @_muxb    << 7 + 4	'MUXB(x,y,bool)
    op_ternary	long	%0000000_0 << 24 + @_ternary << 7 + 4	'sel ? true : false
    
    ' math procedures (20)
    
    op_mul64	long	%0000000_0 << 24 + @_mul64   << 7 + 9	'MUL64(a,b : l,h)
    op_mulu64	long	%0000000_1 << 24 + @_mul64   << 7 + 9	'MUL64U(a,b : l,h)
    op_div64	long	%0000000_0 << 24 + @_div64   << 7 + 11	'DIV64(a,b : l,h)
    op_divu64	long	%0000000_1 << 24 + @_div64   << 7 + 11	'DIV64U(a,b : l,h)
    op_qsincos	long	%0000000_0 << 24 + @_qtrig   << 7 + 12	'QSINCOS(r,t : x,y)
    op_qarctan	long	%0000001_0 << 24 + @_qtrig   << 7 + 12	'QARCTAN(x,y : r,t)
    op_qrotate	long	%0000000_1 << 24 + @_qtrig   << 7 + 12	'QROTATE(x,y,t : x,y)
    op_setqi	long	%0000000_1 << 24 + @_div64   << 7 + 1	'SETQI(x)
    op_clraccs	long	%0000000_0 << 24 + @_clraccs << 7 + 0	'CLRACCS
    op_clracca	long	%0000000_0 << 24 + @_clracca << 7 + 0	'CLRACCA
    op_clraccb	long	%0000000_0 << 24 + @_clraccb << 7 + 0	'CLRACCB
    op_fitaccs	long	%0000000_0 << 24 + @_fitaccs << 7 + 0	'FITACCS
    op_fitacca	long	%0000000_0 << 24 + @_fitacca << 7 + 0	'FITACCA
    op_fitaccb	long	%0000000_0 << 24 + @_fitaccb << 7 + 0	'FITACCB
    op_setacca	long	%0000000_0 << 24 + @_setacca << 7 + 2	'SETACCA(l,h)
    op_setaccb	long	%0000000_0 << 24 + @_setaccb << 7 + 2	'SETACCB(l,h)
    op_getacca	long	%0000000_0 << 24 + @_getacca << 7 + 3	'GETACCA(l,h)
    op_getaccb	long	%0000000_0 << 24 + @_getaccb << 7 + 3	'GETACCB(l,h)
    op_maca		long	%0000000_0 << 24 + @_maca    << 7 + 2	'MACA(x,y)
    op_macb		long	%0000000_0 << 24 + @_macb    << 7 + 2	'MACB(x,y)
    
    ' constants (13)
    
    op_con1n	long	%0000000_0 << 24 + @_conxn    << 7 + 1	'constant -1
    op_con0		long	%0000000_0 << 24 + @_conxp    << 7 + 0	'constant 0
    op_con1		long	%0000001_0 << 24 + @_conxp    << 7 + 0	'constant 1
    op_con8p	long	%0000000_0 << 24 + @_con8p    << 7 + 1	'constant $000000xx
    op_con9p	long	%0000000_0 << 24 + @_con9p    << 7 + 2	'constant $000001xx
    op_con8n	long	%0000000_0 << 24 + @_con8n    << 7 + 2	'constant $FFFFFFxx
    op_con16p	long	%0000000_0 << 24 + @_con16p   << 7 + 3	'constant $0000xxxx
    op_con17p	long	%0000000_0 << 24 + @_con17p   << 7 + 3	'constant $0001xxxx
    op_con16n	long	%0000000_0 << 24 + @_con16n   << 7 + 4	'constant $FFFFxxxx
    op_con24p	long	%0000000_0 << 24 + @_con24    << 7 + 4	'constant $00xxxxxx
    op_con24n	long	%0000000_1 << 24 + @_con24    << 7 + 4	'constant $FFxxxxxx
    op_con32	long	%0000000_0 << 24 + @_con32    << 7 + 4	'constant $xxxxxxxx
    op_conexp	long	%0000000_0 << 24 + @_conexp   << 7 + 4	'constant 2^n,dec,not
    
    ' register reads/writes/assigns (6)
    
    op_rdreg	long	%0000000_0 << 24 + @_rdreg    << 7 + 4	'read register
    op_wrreg	long	%0000000_0 << 24 + @_wrreg    << 7 + 2	'write register
    op_asreg	long	%0000000_0 << 24 + @_asreg    << 7 + 5	'assign register
    
    op_rdregb	long	%0000000_0 << 24 + @_rdregb    << 7 + 6	'read register bitfield
    op_wrregb	long	%0000000_0 << 24 + @_wrregb    << 7 + 6	'write register bitfield
    op_asregb	long	%0000000_0 << 24 + @_asregb    << 7 + 6	'assign register bitfield
    
    ' local reads/writes/assigns (54)
    
    op_rdloc0	long	%0000000_0 << 24 + @_rdloc    << 7 + 3	'read local 0
    op_rdloc1	long	%0000001_0 << 24 + @_rdloc    << 7 + 3	'read local 1
    op_rdloc2	long	%0000010_0 << 24 + @_rdloc    << 7 + 3	'read local 2
    op_rdloc3	long	%0000011_0 << 24 + @_rdloc    << 7 + 3	'read local 3
    op_rdloc4	long	%0000100_0 << 24 + @_rdloc    << 7 + 3	'read local 4
    op_rdloc5	long	%0000101_0 << 24 + @_rdloc    << 7 + 3	'read local 5
    op_rdloc6	long	%0000110_0 << 24 + @_rdloc    << 7 + 3	'read local 6
    op_rdloc7	long	%0000111_0 << 24 + @_rdloc    << 7 + 3	'read local 7
    op_rdloc8	long	%0001000_0 << 24 + @_rdloc    << 7 + 3	'read local 8
    op_rdloc9	long	%0001001_0 << 24 + @_rdloc    << 7 + 3	'read local 9
    op_rdloc10	long	%0001010_0 << 24 + @_rdloc    << 7 + 3	'read local 10
    op_rdloc11	long	%0001011_0 << 24 + @_rdloc    << 7 + 3	'read local 11
    op_rdloc12	long	%0001100_0 << 24 + @_rdloc    << 7 + 3	'read local 12
    op_rdloc13	long	%0001101_0 << 24 + @_rdloc    << 7 + 3	'read local 13
    op_rdloc14	long	%0001110_0 << 24 + @_rdloc    << 7 + 3	'read local 14
    op_rdloc15	long	%0001111_0 << 24 + @_rdloc    << 7 + 3	'read local 15
    
    op_wrloc0	long	%0000000_0 << 24 + @_wrloc    << 7 + 3	'write local 0
    op_wrloc1	long	%0000001_0 << 24 + @_wrloc    << 7 + 3	'write local 1
    op_wrloc2	long	%0000010_0 << 24 + @_wrloc    << 7 + 3	'write local 2
    op_wrloc3	long	%0000011_0 << 24 + @_wrloc    << 7 + 3	'write local 3
    op_wrloc4	long	%0000100_0 << 24 + @_wrloc    << 7 + 3	'write local 4
    op_wrloc5	long	%0000101_0 << 24 + @_wrloc    << 7 + 3	'write local 5
    op_wrloc6	long	%0000110_0 << 24 + @_wrloc    << 7 + 3	'write local 6
    op_wrloc7	long	%0000111_0 << 24 + @_wrloc    << 7 + 3	'write local 7
    op_wrloc8	long	%0001000_0 << 24 + @_wrloc    << 7 + 3	'write local 8
    op_wrloc9	long	%0001001_0 << 24 + @_wrloc    << 7 + 3	'write local 9
    op_wrloc10	long	%0001010_0 << 24 + @_wrloc    << 7 + 3	'write local 10
    op_wrloc11	long	%0001011_0 << 24 + @_wrloc    << 7 + 3	'write local 11
    op_wrloc12	long	%0001100_0 << 24 + @_wrloc    << 7 + 3	'write local 12
    op_wrloc13	long	%0001101_0 << 24 + @_wrloc    << 7 + 3	'write local 13
    op_wrloc14	long	%0001110_0 << 24 + @_wrloc    << 7 + 3	'write local 14
    op_wrloc15	long	%0001111_0 << 24 + @_wrloc    << 7 + 3	'write local 15
    
    op_asloc0	long	%0000000_0 << 24 + @_asloc    << 7 + 3	'assign local 0
    op_asloc1	long	%0000001_0 << 24 + @_asloc    << 7 + 3	'assign local 1
    op_asloc2	long	%0000010_0 << 24 + @_asloc    << 7 + 3	'assign local 2
    op_asloc3	long	%0000011_0 << 24 + @_asloc    << 7 + 3	'assign local 3
    op_asloc4	long	%0000100_0 << 24 + @_asloc    << 7 + 3	'assign local 4
    op_asloc5	long	%0000101_0 << 24 + @_asloc    << 7 + 3	'assign local 5
    op_asloc6	long	%0000110_0 << 24 + @_asloc    << 7 + 3	'assign local 6
    op_asloc7	long	%0000111_0 << 24 + @_asloc    << 7 + 3	'assign local 7
    op_asloc8	long	%0001000_0 << 24 + @_asloc    << 7 + 3	'assign local 8
    op_asloc9	long	%0001001_0 << 24 + @_asloc    << 7 + 3	'assign local 9
    op_asloc10	long	%0001010_0 << 24 + @_asloc    << 7 + 3	'assign local 10
    op_asloc11	long	%0001011_0 << 24 + @_asloc    << 7 + 3	'assign local 11
    op_asloc12	long	%0001100_0 << 24 + @_asloc    << 7 + 3	'assign local 12
    op_asloc13	long	%0001101_0 << 24 + @_asloc    << 7 + 3	'assign local 13
    op_asloc14	long	%0001110_0 << 24 + @_asloc    << 7 + 3	'assign local 14
    op_asloc15	long	%0001111_0 << 24 + @_asloc    << 7 + 3	'assign local 15
    
    op_rdloci	long	%0000000_0 << 24 + @_rdloci   << 7 + 6	'read local indexed
    op_wrloci	long	%0000000_0 << 24 + @_wrloci   << 7 + 6	'write local indexed
    op_asloci	long	%0000000_0 << 24 + @_asloci   << 7 + 6	'assign local indexed
    
    op_rdlocb	long	%0000000_0 << 24 + @_rdlocb   << 7 + 5	'read local bitfield
    op_wrlocb	long	%0000000_0 << 24 + @_wrlocb   << 7 + 6	'write local bitfield
    op_aslocb	long	%0000000_0 << 24 + @_aslocb   << 7 + 6	'assign local bitfield
    
    ' memory reads/writes/assigns (18)
    
    op_rdbyte	long	%0000000_0 << 24 + @_rdbyte   << 7 + 2	'read byte
    op_rdword	long	%0000000_0 << 24 + @_rdword   << 7 + 2	'read word
    op_rdlong	long	%0000000_0 << 24 + @_rdlong   << 7 + 2	'read long
    
    op_wrbyte	long	%0000000_0 << 24 + @_wrbyte   << 7 + 2	'write byte
    op_wrword	long	%0000000_0 << 24 + @_wrword   << 7 + 2	'write word
    op_wrlong	long	%0000000_0 << 24 + @_wrlong   << 7 + 2	'write long
    
    op_asbyte	long	%0000000_0 << 24 + @_asbyte   << 7 + 5	'assign byte
    op_asword	long	%0000000_0 << 24 + @_asword   << 7 + 6	'assign word
    op_aslong	long	%0000000_0 << 24 + @_aslong   << 7 + 4	'assign long
    
    op_rdbyteb	long	%0000000_0 << 24 + @_rdbyteb  << 7 + 3	'read byte bitfield
    op_rdwordb	long	%0000000_0 << 24 + @_rdwordb  << 7 + 3	'read word bitfield
    op_rdlongb	long	%0000000_0 << 24 + @_rdlongb  << 7 + 3	'read long bitfield
    
    op_wrbyteb	long	%0000000_0 << 24 + @_wrbyteb  << 7 + 5	'write byte bitfield
    op_wrwordb	long	%0000000_0 << 24 + @_wrwordb  << 7 + 5	'write word bitfield
    op_wrlongb	long	%0000000_0 << 24 + @_wrlongb  << 7 + 5	'write long bitfield
    
    op_asbyteb	long	%0000000_0 << 24 + @_asbyteb  << 7 + 6	'assign byte bitfield
    op_aswordb	long	%0000000_0 << 24 + @_aswordb  << 7 + 7	'assign word bitfield
    op_aslongb	long	%0000000_0 << 24 + @_aslongb  << 7 + 5	'assign long bitfield
    
    ' memory offsets and indexing (7)
    
    op_vbase0	long	%0000000_0 << 24 + @_base     << 7 + 3	'vbase $0xxxx
    op_pbase0	long	%0000000_1 << 24 + @_base     << 7 + 3	'pbase $0xxxx
    op_vbase1	long	%0000001_0 << 24 + @_base     << 7 + 3	'vbase $1xxxx
    op_pbase1	long	%0000001_1 << 24 + @_base     << 7 + 3	'pbase $1xxxx
    
    op_ibyte	long	%0000000_0 << 24 + @_index    << 7 + 4	'byte index
    op_iword	long	%0000001_0 << 24 + @_index    << 7 + 4	'word index
    op_ilong	long	%0000010_0 << 24 + @_index    << 7 + 4	'long index
    
    ' branches jmp/jz/jnz/tjz/djnz (10)
    
    op_jmp0		long	%0000000_0 << 24 + @_jmp      << 7 + 1	'jmp +$0xxxx
    op_jmp1		long	%0000001_0 << 24 + @_jmp      << 7 + 1	'jmp +$1xxxx
    
    op_jz0		long	%0000000_1 << 24 + @_jxz      << 7 + 2	'jz +$0xxxx
    op_jz1		long	%0000001_1 << 24 + @_jxz      << 7 + 2	'jz +$1xxxx
    
    op_jnz0		long	%0000000_0 << 24 + @_jxz      << 7 + 2	'jnz +$0xxxx
    op_jnz1		long	%0000001_0 << 24 + @_jxz      << 7 + 2	'jnz +$1xxxx
    
    op_tjz0		long	%0000000_0 << 24 + @_tjz      << 7 + 3	'tjz +$0xxxx
    op_tjz1		long	%0000001_0 << 24 + @_tjz      << 7 + 3	'tjz +$1xxxx
    
    op_djnz0	long	%0000000_0 << 24 + @_djnz     << 7 + 4	'djnz +$0xxxx
    op_djnz1	long	%0000001_0 << 24 + @_djnz     << 7 + 4	'djnz +$1xxxx
    
    ' anchor drops (4)
    
    op_dropt	long	%0000000_0 << 24 + @_drop     << 7 + 6	'drop, \sub
    op_droptr	long	%0000001_0 << 24 + @_drop     << 7 + 6	'drop, \sub w/result
    op_drop		long	%0000010_0 << 24 + @_drop     << 7 + 6	'drop,  sub
    op_dropr	long	%0000011_0 << 24 + @_drop     << 7 + 6	'drop,  sub w/result
    
    ' calls (7)
    
    op_callos	long	%0000000_0 << 24 + @_callobj  << 7 + 6	'call obj.sub
    op_callosi	long	%0000000_1 << 24 + @_callobj  << 7 + 6	'call obj.sub[]
    op_callois	long	%0000001_0 << 24 + @_callobj  << 7 + 6	'call obj[].sub
    op_calloisi	long	%0000001_1 << 24 + @_callobj  << 7 + 6	'call obj[].sub[]
    op_calls	long	%0000000_0 << 24 + @_callsub  << 7 + 3	'call sub
    op_callsi	long	%0000000_1 << 24 + @_callsub  << 7 + 3	'call sub[]
    op_callp	long	%0000000_0 << 24 + @_callptr  << 7 + 10	'call ptr
    
    ' returns (4)
    
    op_return	long	%0000000_0 << 24 + @_return   << 7 + 13	'RETURN
    op_abort	long	%0000000_1 << 24 + @_return   << 7 + 13	'ABORT
    op_returnv	long	%0000001_0 << 24 + @_return   << 7 + 13	'RETURN value
    op_abortv	long	%0000001_1 << 24 + @_return   << 7 + 13	'ABORT value
    
    ' call pointer generation (5)
    
    op_basesub	long	%0000000_0 << 24 + @_basesub  << 7 + 5	'vbase/pbase of current
    op_baseobj	long	%0000000_0 << 24 + @_baseobj  << 7 + 16	'vbase/pbase of obj
    op_baseobji	long	%0000000_1 << 24 + @_baseobj  << 7 + 16	'vbase/pbase of obj[]
    op_subptr	long	%0000000_0 << 24 + @_subptr   << 7 + 11	'base.sub
    op_subptri	long	%0000000_1 << 24 + @_subptr   << 7 + 11	'base.sub[]
    
    ' case (5)
    
    op_casev0	long	%0000000_0 << 24 + @_casev    << 7 + 5	'case value, +$0xxxx branch
    op_casev1	long	%0000001_0 << 24 + @_casev    << 7 + 5	'case value, +$1xxxx branch
    op_caser0	long	%0000000_0 << 24 + @_caser    << 7 + 10	'case range, +$0xxxx branch
    op_caser1	long	%0000001_0 << 24 + @_caser    << 7 + 10	'case range, +$1xxxx branch
    
    op_casedone	long	%0000000_0 << 24 + @_casedone << 7 + 2	'case done
    
    ' lookup/lookdown (5)
    
    op_lookupv	long	%0000000_0 << 24 + @_lookupv  << 7 + 9	'lookup value
    op_lookupr	long	%0000000_0 << 24 + @_lookupr  << 7 + 14	'lookup range
    op_lookdnv	long	%0000000_0 << 24 + @_lookdnv  << 7 + 9	'lookdown value
    op_lookdnr	long	%0000000_0 << 24 + @_lookdnr  << 7 + 15	'lookdown range
    
    op_lookdone	long	%0000000_0 << 24 + @_lookdone << 7 + 1	'lookup/lookdown done
    
    ' miscellaneous (6)
    
    op_pop		long	%0000000_0 << 24 + @_pop      << 7 + 1	'pop
    
    op_clkset	long	%0000000_0 << 24 + @_clkset   << 7 + 1	'clkset
    op_cogid	long	%0000000_0 << 24 + @_cogid    << 7 + 1	'cogid
    op_coginit	long	%0000000_0 << 24 + @_coginit  << 7 + 6	'coginit
    op_coginitp	long	%0000001_0 << 24 + @_coginit  << 7 + 6	'coginit w/push
    op_cogstop	long	%0000000_0 << 24 + @_cogstop  << 7 + 1	'cogstop
    
    '
    '
    '************
    '* Snippets *
    '************
    '
    
    '
    '
    ' Variable modifiers
    '
    			org	snippet			'repeat-var loop (assign)
    
    _rep			popa	mask			'pop var
    			popa	y			'pop step
    			popa	b			'pop terminal
    			popa	a			'pop initial
    			popa	addr			'pop branch offset
    
    			cmps	b,a		wc	'get reverse range into c
    			sumc	mask,y			'update var with step
    			rcl	x,#1		wz	'get c into nz
    	if_z		cmps	b,mask		wc	'if forward range, check if var > terminal
    	if_nz		cmps	mask,b		wc	'if reverse range, check if var < terminal
    
    	if_nc		subptra	addr			'if var within range, branch
    	if_nc		addspa	#4			'..unpop offset/initial/terminal/step
    
    			pusha	mask			'push new var
    
    
    			org	snippet			'var~, clear and post-clear (assign)
    
    _clr			popa	x			'clear, pop var (single pop also used by op_writep)
    _clrpost		pusha	#0			'post-clear, push 0 (leave var on stack)
    
    
    			org	snippet			'var~~, set and post-set (assign)
    
    _set			popa	x			'set, pop var
    _setpost		pusha	hFFFFFFFF		'post-set, push -1 (leave var on stack)
    
    
    			org	snippet			'++var/--var/var++/var-- (assign)
    
    _incdec			popa	x			'pop var
    	if_nz		pusha	x			'if nz, push original var
    			sumc	x,#1			'inc or dec var by c
    			pusha	x			'push new var
    
    
    			org	snippet			'INCMOD/DECMOD(var,limit) (assign)
    
    _idmod			setbc	:i,#26			'set INCMOD/DECMOD by c
    			popa	y			'pop limit
    			popa	x			'pop var
    :i			incmod	x,y		wc	'incmod/decmod, c=limit
    	if_nz_and_nc	pusha	#0			'push false if nz and nc
    	if_nz_and_c	pusha	hFFFFFFFF		'push true if nz and c
    			pusha	x			'push new var
    '
    '
    ' Unary functions
    '
    			org	snippet
    
    _notb			popa	x		wz	'NOT, boolean
    			muxz	x,hFFFFFFFF
    			pusha	x
    
    
    			org	snippet
    
    _not			popa	x			'!, bitwise not
    			not	x
    			pusha	x
    
    
    			org	snippet
    
    _neg			popa	x			'-, negate
    			neg	x,x
    			pusha	x
    
    
    			org	snippet
    
    _abs			popa	x			'||, absolute
    			abs	x,x
    			pusha	x
    
    
    			org	snippet
    
    _enc			popa	x			'>|, encode (0..32)
    			enc	x,x
    			pusha	x
    
    
    			org	snippet
    
    _decod5			popa	x			'|< / DECOD5(x)
    			decod5	x
    			pusha	x
    
    
    			org	snippet
    
    _decod4			popa	x			'DECOD4(x)
    			decod4	x
    			pusha	x
    
    
    			org	snippet
    
    _decod3			popa	x			'DECOD3(x)
    			decod3	x
    			pusha	x
    
    
    			org	snippet
    
    _decod2			popa	x			'DECOD2(x)
    			decod2	x
    			pusha	x
    
    
    			org	snippet
    
    _blmask			popa	x			'BLMASK(x)
    			blmask	x
    			pusha	x
    
    
    			org	snippet
    
    _onecnt			popa	x			'ONECNT(x)
    			onecnt	x
    			pusha	x
    
    
    			org	snippet
    
    _zercnt			popa	x			'ZERCNT(x)
    			zercnt	x
    			pusha	x
    
    
    			org	snippet
    
    _incpat			popa	x			'INCPAT(x)
    			incpat	x
    			pusha	x
    
    
    			org	snippet
    
    _decpat			popa	x			'DECPAT(x)
    			decpat	x
    			pusha	x
    
    
    			org	snippet
    
    _bingry			popa	x			'BINGRY(x)
    			bingry	x
    			pusha	x
    
    
    			org	snippet
    
    _grybin			popa	x			'GRYBIN(x)
    			grybin	x
    			pusha	x
    
    
    			org	snippet
    
    _mergew			popa	x			'MERGEW(x)
    			mergew	x
    			pusha	x
    
    
    			org	snippet
    
    _splitw			popa	x			'SPLITW(x)
    			splitw	x
    			pusha	x
    
    
    			org	snippet
    
    _seussf			popa	x			'SEUSSF(x)
    			seussf	x
    			pusha	x
    
    
    			org	snippet
    
    _seussr			popa	x			'SEUSSR(x)
    			seussr	x
    			pusha	x
    
    
    			org	snippet
    
    _sqrt			popa	x			'SQRT(x)
    			setsqrl	x
    			getsqrt	x		wc
    	if_nc		jmp	#$-1
    			pusha	x
    
    
    			org	snippet
    
    _qlogexp		popa	x			'QLOG(x), c=0
    	if_nc		qlog	x			'QEXP(x), c=1
    	if_c		qexp	x
    			getqz	x		wc
    	if_nc		jmp	#$-1
    			pusha	x
    '
    '
    ' Binary functions
    '
    			org	snippet
    
    _andb			popa	x		wz	'AND, boolean
    	if_z		popa	x
    	if_nz		popa	x		wz
    			muxnz	x,hFFFFFFFF
    			pusha	x
    			
    
    			org	snippet
    
    _orb			popa	x		wz	'OR, boolean
    	if_nz		popa	x
    	if_z		popa	x		wz
    			muxnz	x,hFFFFFFFF
    			pusha	x
    			
    
    			org	snippet
    
    _xorb			popa	y		wz	'XOR, boolean
    			muxnz	y,hFFFFFFFF
    			popa	x		wz
    			muxnz	x,hFFFFFFFF
    			xor	x,y
    			pusha	x
    
    
    			org	snippet
    
    _andn			popa	y			'&!, bitwise andnot
    			popa	x
    			andn	x,y
    			pusha	x
    
    
    			org	snippet
    
    _and			popa	y			'&, bitwise and
    			popa	x
    			and	x,y
    			pusha	x
    
    
    			org	snippet
    
    _or			popa	y			'|, bitwise or
    			popa	x
    			or	x,y
    			pusha	x
    
    
    			org	snippet
    
    _xor			popa	y			'^, bitwise xor
    			popa	x
    			xor	x,y
    			pusha	x
    
    
    			org	snippet
    
    _ror			popa	y			'->, rotate right
    			popa	x
    			ror	x,y
    			pusha	x
    
    
    			org	snippet
    
    _rol			popa	y			'<-, rotate left
    			popa	x
    			rol	x,y
    			pusha	x
    
    
    			org	snippet
    
    _shr			popa	y			'>>, shift right
    			popa	x
    			shr	x,y
    			pusha	x
    
    
    			org	snippet
    
    _shl			popa	y			'<<, shift left
    			popa	x
    			shl	x,y
    			pusha	x
    
    
    			org	snippet
    
    _sar			popa	y			'~>, shift arithmetic right
    			popa	x
    			sar	x,y
    			pusha	x
    
    
    			org	snippet
    
    _sal			popa	y			'<~, shift arithmetic left
    			popa	x
    			rev	x,#0
    			sar	x,y
    			rev	x,#0
    			pusha	x
    
    
    			org	snippet
    
    _rev			popa	y			'><, reverse bits
    			popa	x
    			neg	y,y
    			rev	x,y
    			pusha	x
    
    
    			org	snippet
    
    _mins			popa	y			'|>, limit minimum
    			popa	x
    			mins	x,y
    			pusha	x
    
    
    			org	snippet
    
    _maxs			popa	y			'<|, limit maximum
    			popa	x
    			maxs	x,y
    			pusha	x
    
    
    			org	snippet
    
    _add			popa	y			'+, add
    			popa	x
    			add	x,y
    			pusha	x
    
    
    			org	snippet
    
    _sub			popa	y			'-, sub
    			popa	x
    			sub	x,y
    			pusha	x
    
    
    			org	snippet
    
    _mul			popa	y			'*, multiply and return lower long
    			popa	x
    			setmula	x
    			setmulb	y
    			getmull	x		wc
    	if_nc		jmp	#$-1
    			pusha	x
    
    
    			org	snippet
    
    _scl			popa	y			'**, multiply return upper long, unsigned
    			popa	x
    			setmulu	x
    			setmulb	y
    			getmulh	x		wc
    	if_nc		jmp	#$-1
    			pusha	x
    
    
    			org	snippet
    
    _divx			popa	y			'/, divide and return quotient,   z=1
    			popa	x			'//, divide and return remainder, z=0
    			setdiva	x
    			setdivb	y
    			getdivq	x		wc
    	if_nc		jmp	#$-1
    	if_nz		getdivr	x
    			pusha	x
    
    
    			org	snippet
    
    _fra			popa	y			'*/, fraction
    			popa	x
    			setdivu	#0
    			setdivu	x
    			setdivb	y
    			getdivq	x		wc
    	if_nc		jmp	#$-1
    			pusha	x
    '
    '
    ' Equality tests
    '
    			org	snippet
    
    _b			popa	y			'<, test below
    			popa	x
    			cmps	x,y		wc
    			muxc	x,hFFFFFFFF
    			pusha	x
    
    
    			org	snippet
    
    _a			popa	y			'>, test above
    			popa	x
    			cmps	y,x		wc
    			muxc	x,hFFFFFFFF
    			pusha	x
    
    
    			org	snippet
    
    _ne			popa	y			'<>, test not equal
    			popa	x
    			cmps	x,y		wz
    			muxnz	x,hFFFFFFFF
    			pusha	x
    
    
    			org	snippet
    
    _eq			popa	y			'==, test equal
    			popa	x
    			cmps	x,y		wz
    			muxz	x,hFFFFFFFF
    			pusha	x
    
    
    			org	snippet
    
    _be			popa	y			'=< / <=, test below or equal
    			popa	x
    			cmps	y,x		wc
    			muxnc	x,hFFFFFFFF
    			pusha	x
    
    
    			org	snippet
    
    _ae			popa	y			'=> / >=, test above or equal
    			popa	x
    			cmps	x,y		wc
    			muxnc	x,hFFFFFFFF
    			pusha	x
    '
    '
    ' Math terms
    '
    			org	snippet
    
    _divh64			popa	y			'QUO64(al,ah,b),  z=1, c=0
    			popa	x			'QUO64U(al,ah,b), z=1, c=1
    			popa	a			'REM64(al,ah,b),  z=0, c=0
    	if_nc		setdiva	a			'REM64U(al,ah,b), z=0, c=1
    	if_c		setdivu	a
    			setdiva	x
    			setdivb	y			
    			getdivq	x		wc
    	if_nc		jmp	#$-1
    	if_nz		getdivr	x		wc
    			pusha	x
    
    
    			org	snippet
    
    _sqrt64			popa	x			'SQRT64(l,h)
    			setsqrh	x
    			popa	x
    			setsqrl	x
    			getsqrt	x		wc
    	if_nc		jmp	#$-1
    			pusha	x
    
    
    			org	snippet
    
    _negb			popa	x		wz	'NEGB(x,bool)
    			popa	x
    			negnz	x,x
    			pusha	x
    
    
    			org	snippet
    
    _muxb			popa	y		wz	'MUXB(x,y,bool)
    			popa	y
    			popa	x
    			muxnz	x,y
    			pusha	x
    
    
    			org	snippet
    
    _ternary		popa	y			'a ? x : y
    			popa	x
    			popa	a		wz
    	if_z		pusha	y
    	if_nz		pusha	x
    '
    '
    ' Math procedures
    '
    
    			org	snippet
    
    _mul64			popa	x			'MUL64(a,b : l,h), c=0
    	if_nc		setmula	x			'MUL64U(a,b : l,h), c=1
    	if_c		setmulu	x
    			popa	x
    			setmulb	x
    			getmulh	x		wc
    	if_nc		jmp	#$-1
    			pusha	x
    			getmull	x
    			pusha	x
    
    
    			org	snippet
    
    _div64			popa	y			'DIV64(al,ah,b : q,r),  c=0
    			popa	x			'DIV64U(al,ah,b : q,r), c=1
    			popa	a
    	if_nc		setdiva	a
    	if_c		setdivu	a
    			setdiva	x
    			setdivb	y			
    			getdivr	x		wc
    	if_nc		jmp	#$-1
    			pusha	x
    			getdivq	x		wc
    			pusha	x
    
    
    			org	snippet
    
    _qtrig	if_z_and_c	popa	x			'QSINCOS(r,t : x,y),   z=1, c=0
    	if_z_and_c	setqz	x			'QROTATE(x,y,t : x,y), z=1, c=1
    			popa	y			'QARCTAN(x,y : r,t),   z=0
    			popa	x
    	if_z_and_nc	qsincos	y,x
    	if_z_and_c	qrotate	x,y
    	if_nz		qarctan	x,y
    			getqz	x		wc
    	if_nc		jmp	#$-1
    	if_z		getqy	x
    			pusha	x
    			getqx	x
    			pusha	x
    
    
    			org	snippet
    
    _setqi			popa	x			'SETQI(i)
    			setqi	x
    
    
    			org	snippet
    
    _clraccs		clraccs				'CLRACCS
    
    
    			org	snippet
    
    _clracca		clracca				'CLRACCA
    
    
    			org	snippet
    
    _clraccb		clraccb				'CLRACCB
    
    
    			org	snippet
    
    _fitaccs		fitaccs				'FITACCS
    
    
    			org	snippet
    
    _fitacca		fitacca				'FITACCA
    
    
    			org	snippet
    
    _fitaccb		fitaccb				'FITACCB
    
    
    			org	snippet
    
    _setacca		popa	y			'SETACCA(l,h)
    			popa	x
    			setacca	x,y
    
    
    			org	snippet
    
    _setaccb		popa	y			'SETACCB(l,h)
    			popa	x
    			setaccb	x,y
    
    
    			org	snippet
    
    _getacca		getacca	x			'GETACCA(l,h)
    			getacca	y
    			pusha	y
    			pusha	x
    
    
    			org	snippet
    
    _getaccb		getaccb	x			'GETACCB(l,h)
    			getaccb	y
    			pusha	y
    			pusha	x
    
    
    			org	snippet
    
    _maca			popa	y			'MACA(x,y)
    			popa	x
    			maca	x,y
    
    
    			org	snippet
    
    _macb			popa	y			'MACB(x,y)
    			popa	x
    			macb	x,y
    '
    '
    ' Constants
    '
    			org	snippet
    
    _con8p			rdbytec	x,ptra++		'con8p
    _conxp			pusha	x			'con0..con3
    
    
    			org	snippet
    
    _con9p			rdbytec	x,ptra++		'con9p
    			setb	x,#8
    			pusha	x
    
    
    			org	snippet
    
    _con8n			rdbytec	x,ptra++		'con8n
    _conxn			xor	x,hFFFFFFFF		'conm1
    			pusha	x
    
    
    			org	snippet
    
    _con16p			rdbytec	x,ptra++		'con16p
    			rdbytec	y,ptra++
    			movf	x,y
    			pusha	x
    
    
    			org	snippet
    
    _con17p			rdbytec	x,ptra++		'con17p
    			rdbytec	y,ptra++
    			movf	x,y
    			setb	x,#16
    			pusha	x
    
    
    			org	snippet
    
    _con16n			rdbytec	x,ptra++		'con16n
    			rdbytec	y,ptra++
    			movf	x,y
    			xor	x,hFFFFFFFF
    			pusha	x
    
    
    			org	snippet
    
    _con24			reps	#3,#2			'con24p, con24n
    			muxc	x,#$FF
    			rdbytec	y,ptra++
    			movf	x,y
    			pusha	x
    
    _con32			reps	#4,#2			'con32
    			nop
    			rdbytec	y,ptra++
    			movf	x,y
    			pusha	x
    
    
    			org	snippet
    
    _conexp			rdbytec	x,ptra++		'conexp
    			decod5	x		wz, wc
    	if_z		sub	x,#1
    	if_c		not	x
    			pusha	x
    '
    '
    ' Register read/write/assign
    '
    			org	snippet
    
    _rdreg			popa	x			'read register
    			movd	:rd,x
    			nop
    			nop
    :rd			pusha	$000
    
    
    			org	snippet
    
    _wrreg			popa	addr			'write register
    			popa	x
    			call	#writer
    
    
    			org	snippet
    
    _asreg			popa	addr			'assign register
    			movs	:rd,addr
    			jmpd	#assign_long
    			mov	assign_i,callwriter
    :rd			mov	x,$000
    			nop
    
    			org 	snippet
    
    _rdregb			call	#bitfield		'read register bitfield
    			popa	x
    			movs	:rd,x
    			jmpd	#readb
    			nop
    :rd			mov	x,$000
    			nop
    
    
    			org 	snippet
    
    _wrregb			call	#bitfield		'write register bitfield
    			popa	addr
    			movs	:rd,addr
    			jmpd	#writeb
    			mov	writeb_i,callwriter
    :rd			mov	bval,$000
    			nop
    
    
    			org 	snippet
    
    _asregb			call	#bitfield		'assign register bitfield
    			popa	addr
    			movs	:rd,addr
    			jmpd	#assignb_long
    			mov	writeb_i,callwriter
    :rd			mov	bval,$000
    			nop
    '
    '
    ' Local read/write/assign
    '
    			org	snippet
    
    _rdloci			popa	y			'read local, indexed
    			rdbytec	x,ptra++
    			add	x,y
    
    _rdloc			add	x,dbase			'read local, fixed
    			setspb	x
    			popbr	x
    			pusha	x
    
    
    			org	snippet
    
    _wrloci			popa	y			'write local, indexed
    			rdbytec	x,ptra++
    			add	x,y
    
    _wrloc			add	x,dbase			'write local, fixed
    			setspb	x
    			popa	x
    			pushb	x
    
    
    			org	snippet
    
    _asloci			popa	y			'assign local, indexed
    			rdbytec	x,ptra++
    			add	x,y
    
    _asloc			jmpd	#assign_local		'assign local, fixed
    			add	x,dbase
    			setspb	x
    			popbr	x
    
    
    			org	snippet
    
    _rdlocb			call	#bitfield		'read local bitfield
    			popa	x
    			jmpd	#readb
    			add	x,dbase
    			setspb	x
    			popbr	x
    
    
    			org	snippet
    
    _wrlocb			call	#bitfield		'write local bitfield
    			popa	x
    			add	x,dbase
    			jmpd	#writeb
    			setspb	x
    			popbr	bval
    			mov	writeb_i,pushbrx
    
    
    			org	snippet
    
    _aslocb			call	#bitfield		'assign local bitfield
    			popa	x
    			add	x,dbase
    			jmpd	#assignb_long
    			setspb	x
    			popbr	bval
    			mov	writeb_i,pushbrx
    '
    '
    ' Memory read/write/assign
    '
    			org	snippet
    
    _rdbyte			popa	x			'read byte
    			rdbyte	x,x
    			pusha	x
    
    
    			org	snippet
    
    _rdword			popa	x			'read word
    			rdword	x,x
    			pusha	x
    
    
    			org	snippet
    
    _rdlong			popa	x			'read long
    			rdlong	x,x
    			pusha	x
    
    
    			org	snippet
    
    _wrbyte			popa	y			'write byte
    			popa	x
    			wrbyte	x,y
    
    
    			org	snippet
    
    _wrword			popa	y			'write word
    			popa	x
    			wrword	x,y
    
    
    			org	snippet
    
    _wrlong			popa	y			'write long
    			popa	x
    			wrlong	x,y
    
    
    			org	snippet
    
    _asbyte			popa	addr			'assign byte
    			jmpd	#assign
    			rdbyte	x,addr
    			mov	assign_i,:i
    			mov	mask,#$FF
    
    :i			wrbyte	x,addr
    
    
    			org	snippet
    
    _asword			popa	addr			'assign word
    			jmpd	#assign
    			rdword	x,addr
    			mov	assign_i,:i
    			mov	mask,:m
    
    :i			wrword	x,addr
    :m			long	$0000FFFF
    
    
    			org	snippet
    
    _aslong			jmpd	#assign_long		'assign long
    			popa	addr
    			rdlong	x,addr
    			mov	assign_i,:i
    
    :i			wrlong	x,addr
    
    
    			org	snippet
    
    _rdbyteb		call	#bitfield		'read byte bitfield
    			popa	x
    			rdbyte	x,x
    			jmp	#readb
    
    
    			org	snippet
    
    _rdwordb		call	#bitfield		'read word bitfield
    			popa	x
    			rdword	x,x
    			jmp	#readb
    
    
    			org	snippet
    
    _rdlongb		call	#bitfield		'read long bitfield
    			popa	x
    			rdlong	x,x
    			jmp	#readb
    
    
    			org	snippet
    
    _wrbyteb		call	#bitfield		'write byte bitfield
    			jmpd	#writeb
    			popa	addr
    			rdbyte	bval,addr
    			mov	writeb_i,:wr
    
    :wr			wrbyte	x,addr
    
    
    			org	snippet
    
    _wrwordb		call	#bitfield		'write word bitfield
    			jmpd	#writeb
    			popa	addr
    			rdword	bval,addr
    			mov	writeb_i,:wr
    
    :wr			wrword	x,addr
    
    
    			org	snippet
    
    _wrlongb		call	#bitfield		'write long bitfield
    			jmpd	#writeb
    			popa	addr
    			rdlong	bval,addr
    			mov	writeb_i,:wr
    
    :wr			wrlong	x,addr
    
    
    			org	snippet
    
    _asbyteb		call	#bitfield		'assign byte bitfield
    			mov	mask,#$FF
    			jmpd	#assignb
    			popa	addr
    			rdbyte	bval,addr
    			mov	writeb_i,:wr
    
    :wr			wrbyte	x,addr
    
    
    			org	snippet
    
    _aswordb		call	#bitfield		'assign word bitfield
    			mov	mask,:mask
    			jmpd	#assignb
    			popa	addr
    			rdword	bval,addr
    			mov	writeb_i,:wr
    
    :wr			wrword	x,addr
    :mask			long	$0000FFFF
    
    
    			org	snippet
    
    _aslongb		call	#bitfield		'assign long bitfield
    			jmpd	#assignb_long
    			popa	addr
    			rdlong	bval,addr
    			mov	writeb_i,:wr
    
    :wr			wrlong	x,addr
    '
    '
    ' Memory offsets and indexing
    '
    			org	snippet
    
    _base			call	#xword
    	if_nc		add	x,vbase			'vbase, c=0
    	if_c		add	x,pbase			'pbase, c=1
    			pusha	x
    
    
    			org	snippet
    
    _index			popa	y			'ibyte, x=0
    			shl	y,x			'iword, x=1
    			popa	x			'ilong, x=2
    			add	x,y
    			pusha	x
    '
    '
    ' Branch jmp/jz/jnz/tjz/djnz
    '
    			org	snippet
    
    _jmp			call	#xword			'jmp
    			addptra	x
    
    
    			org	snippet
    
    _jxz			popa	y		wz	'jz,  c=1	jnz, c=0
    			call	#xword
    	if_z_eq_c	addptra	x
    
    
    			org	snippet
    
    _tjz			popa	y		wz	'tjz
    	if_nz		pusha	y
    			call	#xword
    	if_z		addptra	x
    
    
    			org	snippet
    
    _djnz			popa	y			'djnz
    			sub	y,#1		wz
    	if_nz		pusha	y
    			call	#xword
    	if_nz		addptra	x
    '
    '
    ' Drop anchor
    '
    ' \sub		x = %00
    ' \sub result	x = %01
    '  sub		x = %10
    '  sub result	x = %11
    '
    			org	snippet
    
    _drop			pusha	dcall			'push dcall (later used for pcurr)
    			getspa	dcall			'set new dcall
    
    			pusha	dbase			'push return dbase
    
    			pusha	vbase			'push return vbase
    
    			or	x,pbase			'push return pbase w/flags
    			pusha	x
    
    			pusha	#0			'init 'result' to 0
    '
    '
    ' Call
    '
    ' obj.sub	z=1, c=0
    ' obj.sub[]	z=1, c=1
    ' obj[].sub	z=0, c=0
    ' obj[].sub[]	z=0, c=1
    ' sub		     c=0
    ' sub[]		     c=1
    ' ptr
    '
    			org	snippet
    
    _callobj		rdbytec	x,ptra++		'get obj byte
    	if_nz		popa	a			'add any index
    	if_nz		add	x,a
    
    			jmpd	#call_obj		'jump to handler, delayed
    
    			rdbytec	y,ptra++		'get sub byte
    	if_c		popa	a			'add any index
    	if_c		add	y,a
    
    
    			org	snippet
    
    _callsub		jmpd	#call_sub		'jump to handler, delayed
    
    			rdbytec	y,ptra++		'get sub byte
    	if_c		popa	a			'add any index
    	if_c		add	y,a
    
    
    			org	snippet
    
    _callptr		popa	x			'get sub [31..29]/[15..13], vbase [28..16], pbase [12..0]
    
    			mov	vbase,#0		'clear vbase/pbase
    			mov	pbase,#0
    
    			mov	y,x			'get sub (6-bits)
    			mov	a,x
    			shr	y,#32-3-3
    			and	y,#%111000
    			jmpd	#call_ptr		'jump to handler, delayed
    			shr	a,#16-3
    			and	a,#%000111
    			or	y,a
    '
    '
    ' RETURN/ABORT
    '
    ' RETURN	z=1, c=0
    ' ABORT		z=1, c=1
    ' RETURN value	z=0, c=0
    ' ABORT value	z=0, c=1
    '
    			org	snippet
    
    _return	if_z		setspa	dbase			'if no value, return result
    	if_z		popar	x
    
    	if_nz		popa	x			'if value, pop it
    
    :again			setspa	dbase			'set dbase
    
    			popa	pbase			'pop pbase
    	if_c		test	pbase,#%10	wc	'if abort and try, return again
    
    	if_c		jmpd	#:again
    
    			popa	vbase			'pop vbase
    			popa	dbase			'pop dbase
    			popa	y			'pop pcurr
    
    			setptra	y			'set ptra to pcurr
    
    			test	pbase,#%01	wc	'push result?
    			andn	pbase,#%11
    	if_c		pusha	x
    '
    '
    ' Get vbase/pbase
    '
    			org	snippet
    
    _basesub		mov	y,vbase
    			shl	y,#16-4
    
    			mov	x,pbase
    			shr	x,#4
    
    			or	x,y
    
    			pusha	x
    '
    '
    ' Get pbase/vbase of obj
    '
    ' obj		c=0
    ' obj[]		c=1
    '
    			org	snippet
    
    _baseobj		rdbytec	x,ptra++		'get obj byte
    
    	if_c		popa	y			'handle index
    	if_c		add	x,y
    
    			shl	x,#2			'scale offset
    
    			add	x,pbase			'get obj pbase/vbase offset
    			rdlong	x,x
    
    			mov	y,x			'get obj vbase
    			shr	y,#16-4
    			add	y,vbase
    			and	y,h0001FFF0
    			shl	y,#16-4
    
    			shl	x,#4			'get obj pbase
    			add	x,pbase
    			and	x,h0001FFF0
    			shr	x,#4
    
    			or	x,y			'merge vbase/pbase
    
    			pusha	x			'push obj vbase/pbase
    '
    '
    ' Make subroutine ptr
    '
    ' base.sub	c=0
    ' base.sub[]	c=1
    '
    			org	snippet
    
    _subptr			rdbytec	a,ptra++		'get sub number
    
    	if_c		popa	b			'handle sub index
    	if_c		add	a,b
    
    			mov	b,a			'split 6-bit index
    			and	b,#%111000		'top 3 bits into [31..29]
    			shl	b,#32-6
    			and	a,#%000111		'bottom 3 bits into [15..13]
    			shl	a,#16-3
    
    			popa	x			'pop base vbase/pbase
    
    			or	x,b			'install index into pbase/vbase
    			or	x,a
    
    			pusha	x			'push subroutine pointer
    '
    '
    ' Case
    '
    			org	snippet			'case value
    
    _casev			call	#xword			'get branch address
    
    			popa	a			'pop value
    			popa	y			'pop target
    			cmp	a,y		wz	'value = target?
    			
    	if_nz		addspa	#1			'if mismatch, unpop target
    
    	if_z		addptra	x			'if match, branch
    
    
    			org	snippet			'case range (z=1)
    
    _caser			call	#xword			'get branch address
    
    			popa	b			'pop range end
    			popa	a			'pop range begin
    			popa	y			'pop target
    
    			sub	b,a			'||(end - begin), c=1 if reverse range
    			abs	b,b		wc
    
    			sub	y,a			'+/-(target - begin)
    			negc	y,y
    
    			cmp	b,y		wc	'match if ||(end - begin) => +/-(target - begin)
    
    	if_c		addspa	#1			'if mismatch, unpop target
    
    	if_nc		addptra	x			'if match, branch
    
    
    			org	snippet			'case done
    
    _casedone		popa	x			'pop target
    			popa	x			'pop address
    			addptra	x			'jump to address
    '
    '
    ' Lookup/lookdown
    '
    			org	snippet			'lookup value
    
    _lookupv		popa	a			'pop value
    			popa	x			'pop index
    			popa	y			'pop target
    
    			cmp	x,y		wz	'match if index = target
    
    	if_nz		addspa	#1			'if no match, unpop target
    	if_nz		add	x,#1			'..increment index
    	if_nz		pusha	x			'..push index
    
    	if_z		popa	addr			'if match, pop address
    	if_z		pusha	a			'..push result
    	if_z		setptra	addr			'..branch
    
    
    			org	snippet			'lookup range
    
    _lookupr		popa	b			'pop range end
    			popa	a			'pop range begin
    			popa	x			'pop index
    			popa	y			'pop target
    
    			sub	b,a			'end - begin
    			abs	b,b		wc	'||(end - begin), c=1 if reverse range
    			sub	y,x			'target - index
    			sumc	a,y			'result = begin +/- (target - index)
    
    			cmp	b,y		wc	'match if ||(end - begin) => (target - index)
    
    	if_c		addspa	#1			'if no match, unpop target
    	if_c		addx	x,b			'..add ||(end - begin) + 1 to index
    	if_c		pusha	x			'..push index
    
    	if_nc		popa	addr			'if match, pop address
    	if_nc		pusha	a			'..push result
    	if_nc		setptra	addr			'..branch
    
    
    			org	snippet			'lookdown value
    
    _lookdnv		popa	a			'pop value
    			popa	x			'pop index
    			popa	y			'pop target
    
    			cmp	a,y		wz	'match if value = target
    
    	if_nz		addspa	#1			'if no match, unpop target
    	if_nz		add	x,#1			'..increment index
    	if_nz		pusha	x			'..push index
    
    	if_z		popa	addr			'if match, pop address
    	if_z		pusha	x			'..push result
    	if_z		setptra	addr			'..branch
    
    
    			org	snippet			'lookdown range
    
    _lookdnr		popa	b			'pop range end
    			popa	a			'pop range begin
    			popa	x			'pop index
    			popa	y			'pop target
    
    			sub	b,a			'||(end - begin), c=1 if reverse range
    			abs	b,b		wc
    
    			sub	y,a			'+/-(target - begin)
    			negc	y,y
    
    			cmp	b,y		wc	'match if ||(end - begin) => +/-(target - begin)
    
    	if_c		addspa	#1			'if no match, unpop target
    	if_c		addx	x,b			'..add ||(end - begin) + 1 to index
    	if_c		pusha	x			'..push index
    
    	if_nc		popa	addr			'if match, pop address
    	if_nc		add	x,y			'..result = index +/- (target - begin)
    	if_nc		pusha	x			'..push result
    	if_nc		setptra	addr			'..branch
    
    
    			org	snippet			'lookup/lookdown done
    
    _lookdone		subspa	#3			'pop index/target/address
    			pusha	#0			'push 0 result
    '
    '
    ' Miscellaneous
    '
    			org	snippet
    
    _pop			rdbytec	x,ptra++		'pop
    			subspa	x
    
    
    			org	snippet
    
    _clkset			popa	x			'clkset
    			clkset	x
    
    
    			org	snippet
    
    _cogid			cogid	x			'cogid
    			pusha	x
    
    
    			org	snippet
    
    _coginit		popa	y			'coginit
    			popa	x
    			popa	a
    			setcog	a
    			coginit	x,y		wc
    	if_nz_and_c	pusha	#0
    	if_nz_and_nc	pusha	hFFFFFFFF
    
    
    			org	snippet
    
    _cogstop		popa	x			'cogstop
    			cogstop	x
    

    This interpreter is for the built-in 17-bit address space (128KB), but can easily be changed to 32-bit XMM. I started out on the 32-bit addressing path, but figured it was more practical, at first, to make a native 17-bit version, as an external SDRAM can easily be managed by Spin code for huge data.

    This interpreter leaves the first $150+ longs in the cog free for in-line assembly code and terminate-stay-resident type applications which can run concurrently with the interpreter via hardware multi-tasking.

    In the new Spin, all variables are bit-range addressable for read/write/read-modify-write operations. Bit ranges can be high..low or low..high. This is mainly important for I/O registers which relate to physical pins, but it makes bit fields within other types (locals, hub ram, cog RAM registers) easy to manipulate, as well.

    This interpreter works by getting a byte code, looking up a descriptor long, loading a snippet of assembly code, and executing it. The interpreter currently lacks initialization code, which will be written last, but it has all the snippets for math operations, calls, branches, lookup/lookdown, cog starting and stopping, and housekeeping. It's about 4.5KB now. Once I get the compiler working on the PC side, I'll augment the interpreter to include special I/O handling and other functions that are not needed at first, but make it complete.
  • SapiehaSapieha Posts: 2,964
    edited 2013-07-01 13:07
    Hi Chip.

    Why You don't use that sequence in this place

    orgh base
    org $0
    orgF $15B

    That give even correct place with loading to COG.

    cgracey wrote: »
    Here's the Spin2 Interpreter, so far:

    Spin2interpreter.spin
    CON
    
      base    = $E80
    
    '
    '
    '***************
    '* Interpreter *
    '***************
    '
    DAT
    [B][COLOR=#ff0000]            orgh    base
                org    $15B
    [/COLOR][/B]'
    '
    ' Append word to x - used to make $0xxxx or $1xxxx address
    '
    xword            rdbytec    y,ptra++
    
    xword_ret        retd
    
                movf    x,y
                rdbytec    y,ptra++
                movf    x,y
    
    '
    '
    ' call obj.sub
    ' call obj.sub[]
    ' call obj[].sub
    ' call obj[].sub[]
    ' call sub
    ' call sub[]
    ' call ptr
    '
    call_obj        shl    x,#2            'lookup obj vbase/pbase offsets
                add    x,pbase
                rdlong    x,x
    
    call_ptr        rol    x,#4            'set relative pbase
                add    pbase,x
                and    pbase,h0001FFF0
    
                ror    x,#16            'set relative vbase
                add    vbase,x
                and    vbase,h0001FFF0
    
    call_sub        shl    y,#2            'lookup locals/pbase offsets
                add    y,pbase
                rdlong    y,y
    
                mov    dbase,dcall        'set call dbase
                add    dbase,#3
    
                setspb    dcall            'get old dcall
                popb    dcall
    
                getptra    x            'set return pcurr
                pushb    x
    
                setptra    pbase            'set call pcurr
    
                jmpd    #getbyte        'loop to getbyte, delayed
    
                addptra    y
    
                shr    y,#32-4            'add locals to dcurr
                addspa    y
    '
    '
    ' Bitfield addressing, pop and set bitfield parameters
    '
    bitfield        popa    bshift            'pop range lsb
                popa    bmask            'pop range msb
    
                and    bshift,#$1F        'trim lsb/msb
                and    bmask,#$1F
    
                cmp    bmask,bshift    wc    'reverse range?
    
        if_c        xor    bshift,bmask        'if reverse range, swap msb/lsb
        if_c        xor    bmask,bshift
        if_c        xor    bshift,bmask
    
                sub    bmask,bshift        'get number of bits
                add    bmask,#1
    
                neg    brev,bmask        'get rev count
    
    bitfield_ret        retd                'return, delayed
    
                setbc    brev,#6            'save reverse flag
    
                blmask    bmask            'get bitlength mask
                shl    bmask,bshift        'bmask = mask, brev = reverse, bshift = lsb offset
    '
    '
    ' Write register, if OUTA..OUTD then update PINA..PIND (x = value)
    '
    writer            movd    writer_reg,addr
                movd    writer_pin,addr
                setb    writer_pin,#9+3
    writer_reg        mov    $000,x
    
    writer_ret        retd
    
                xor    addr,#$1F0
                test    addr,#$1FC    wz
    writer_pin    if_z    mov    $000,x
    '
    '
    ' Do bitfield read (x = value)
    '
    readb            and    x,bmask
    
                jmpd    #getbyte
    
                shr    x,bshift
        if_c        rev    x,brev
                pusha    x
    '
    '
    ' Do bitfield write (bval = value, writeb_i = write instruction)
    '
    writeb            popa    x            'pop value to write
        if_c        rev    x,brev            'reverse bits?
                shl    x,bshift        'shift into position
                and    x,bmask            'mask bits
                andn    bval,bmask        'mask away original bits
                or    x,bval            'merge bits
    writeb_i        pushbr    x            'call #writer / pushbr x / wrxxxx x,addr
    
    writeb_ret        jmp    #getbyte
    '
    '
    ' Do bitfield assignment (bval = value, assignb_i = write instruction, mask = sized mask)
    '
    assignb_long        mov    mask,hFFFFFFFF        'set long mask
    
    assignb            movs    jmpback,#assignb_ret    'set jmpback address to assignb_ret
                mov    x,bval            'save original value
                jmpd    #assign_op        'get math operator and execute, delayed
    
                and    x,bmask            'extract bitfield for operation
                shr    x,bshift
        if_c        rev    x,brev
    
    
    assignb_ret        testb    brev,#6        wc    'snippet returns to here, get reverse flag into c
                call    #writeb            'write bitfield
                movs    writeb_ret,#getbyte    'restore jump to getbyte
    
                and    x,mask            'mask it
                jmpd    #assign_p        'push it (optional), delayed
    
                and    x,bmask            'extract bitfield for pushing
                shr    x,bshift
        if_c        rev    x,brev
    '
    '
    ' Do assignment (x = value, assign_i = write instruction, mask = sized mask)
    '
    assign_local        mov    assign_i,pushbrx    'set local write
    assign_long        mov    mask,hFFFFFFFF        'set long mask
    
    assign            movs    jmpback,#assign_ret    'set jmpback address to :ret
    
    assign_op        rdbytec    a,ptra++        'get math operator and flags
                setzc    a        wz,wc    'load flags, operator already in position
                muxz    assign_p,h003C0000    'set push condition to z
    
                jmpd    #hotbyte        'load and execute math snippet, delayed
    
        if_c        popa    y            'swap args?
                pusha    x
        if_c        pusha    y
    
    
    assign_ret        popa    x            'snippet returns to here, pop value
    assign_i        pushbr    x            'write it (call #writer / pushbr x / wrxxxx x,addr)
    
                and    x,mask            'mask it
    assign_p        pusha    x            'push it (optional)
    
                movs    jmpback,#getbyte    'replace jmpback address, getbyte next
    '
    '
    ' Get byte code, look up descriptor long, load code longs in-line, execute, repeat
    '
    getbyte            rdbytec    a,ptra++    wz    '    get byte code, extended?
    
        if_z        rdbytec    a,ptra++        '    if extended, get extended byte code
        if_z        or    a,#$100            '    ...and add offset
    
                shl    a,#2            '    shift to make long offset
    
    hotbyte            add    a,descbase        '    add base address of descriptor longs
    
                rdlong    x,a            '..2    get descriptor long
    
                movd    :reps,x            '3    descriptor[8..0] holds code longs minus 1
    
                shr    x,#7            '4    descriptor[23..7] is code offset
                setptrb    x            '5    point PTRB to code longs
    
    :reps            reps    #1,#1            '6    ready for fast in-line code load
                setindb    #snippet        '7    point INDB to in-line code
                rdlongc    indb++,ptrb++        '0..    load code longs in-line using cached read
    
                mov    indb++,jmpback        '+1    finish in-line code with 'jmp #getbyte'
                shr    x,#25-7        wz,wc    '+1    descriptor[31..25] is a value, [24] is C
    
    snippet            long    0[22]            '?    execute in-line code snippet, loop
    '
    '
    ' Constants
    '
    pushbrx            pushbr    x
    callwriter        call    #writer
    jmpback            jmp    #getbyte
    
    descbase        long    @descs-4        'account for $01 offset
    
    h0001FFF0        long    $0001FFF0        'vbase/pbase mask
    h003C0000        long    $003C0000        'conditional field bits
    hFFFFFFFF        long    $FFFFFFFF        'all bits
    
    x            long    0            'variables
    y            long    0
    a            long    0
    b            long    0
    
    addr            long    0            'assignment
    mask            long    0
    
    bshift            long    0            'bitfield addressing
    bmask            long    0
    brev            long    0
    bval            long    0
    
    dcall            long    0            '        pointer
    dbase            long    0            '        pointer
    
    outa            long    0            '@$1F0        OUTA..OUTD
    outb            long    0            '@$1F1        (writes update PINA..PIND)
    outc            long    0            '@$1F2
    outd            long    0            '@$1F3
    
    vbase            long    0            '@$1F4        pointer
    pbase            long    0            '@$1F5        pointer
    '
    '
    '************************
    '* Bytecode Descriptors *
    '************************
    '
    descs
    
    ' variable modifiers (14)
    
    op_writep    long    %0000000_0 << 24 + @_clr     << 7 + 0    'write w/push    %10 push
    op_rep        long    %0000000_0 << 24 + @_rep     << 7 + 12    'repeat var    %00 no
    op_clr        long    %0000000_0 << 24 + @_clr     << 7 + 1    'clear        %00 no
    op_clrpost    long    %0000000_0 << 24 + @_clrpost << 7 + 0    'clear post    %00 push
    op_set        long    %0000000_0 << 24 + @_set     << 7 + 1    'set        %00 no
    op_setpost    long    %0000000_0 << 24 + @_setpost << 7 + 0    'set post    %00 push
    op_incpre    long    %0000000_0 << 24 + @_incdec  << 7 + 3    'inc pre / inc    %10 push / %00 no
    op_incpost    long    %0000001_0 << 24 + @_incdec  << 7 + 3    'inc post    %00 push
    op_decpre    long    %0000000_1 << 24 + @_incdec  << 7 + 3    'dec pre / dec     %10 push / %00 no
    op_decpost    long    %0000001_1 << 24 + @_incdec  << 7 + 3    'dec post    %00 push
    op_incmod    long    %0000000_0 << 24 + @_idmod   << 7 + 6    'incmod        %00 no
    op_incmodp    long    %0000001_0 << 24 + @_idmod   << 7 + 6    'incmod w/push    %00 push
    op_decmod    long    %0000000_1 << 24 + @_idmod   << 7 + 6    'decmod        %00 no
    op_decmodp    long    %0000001_1 << 24 + @_idmod   << 7 + 6    'decmod w/push    %00 push
    
    ' unaries (23)
    
    op_notb        long    %0000000_0 << 24 + @_notb    << 7 + 2    'NOT        %x0
    op_not        long    %0000000_0 << 24 + @_not     << 7 + 2    '!        %x0
    op_neg        long    %0000000_0 << 24 + @_neg     << 7 + 2    '-        %x0
    op_abs        long    %0000000_0 << 24 + @_abs     << 7 + 2    '||        %x0
    op_enc        long    %0000000_0 << 24 + @_enc     << 7 + 2    '>|        %x0
    op_decod5    long    %0000000_0 << 24 + @_decod5  << 7 + 2    '|<, DECOD5(x)    %x0
    op_decod4    long    %0000000_0 << 24 + @_decod4  << 7 + 2    'DECOD4(x)    %x0
    op_decod3    long    %0000000_0 << 24 + @_decod3  << 7 + 2    'DECOD3(x)    %x0
    op_decod2    long    %0000000_0 << 24 + @_decod2  << 7 + 2    'DECOD2(x)    %x0
    op_blmask    long    %0000000_0 << 24 + @_blmask  << 7 + 2    'BLMASK(x)    %x0
    op_onecnt    long    %0000000_0 << 24 + @_onecnt  << 7 + 2    'ONECNT(x)    %x0
    op_zercnt    long    %0000000_0 << 24 + @_zercnt  << 7 + 2    'ZERCNT(x)    %x0
    op_incpat    long    %0000000_0 << 24 + @_incpat  << 7 + 2    'INCPAT(x)    %x0
    op_decpat    long    %0000000_0 << 24 + @_decpat  << 7 + 2    'DECPAT(x)    %x0
    op_bingry    long    %0000000_0 << 24 + @_bingry  << 7 + 2    'BINGRY(x)    %x0
    op_grybin    long    %0000000_0 << 24 + @_grybin  << 7 + 2    'GRYBIN(x)    %x0
    op_mergew    long    %0000000_0 << 24 + @_mergew  << 7 + 2    'MERGEW(x)    %x0
    op_splitw    long    %0000000_0 << 24 + @_splitw  << 7 + 2    'SPLITW(x)    %x0
    op_seussf    long    %0000000_0 << 24 + @_seussf  << 7 + 2    'SEUSSF(x)    %x0
    op_seussr    long    %0000000_0 << 24 + @_seussr  << 7 + 2    'SEUSSR(x)    %x0
    op_sqrt        long    %0000000_0 << 24 + @_sqrt    << 7 + 4    'SQRT(x)    %x0
    op_qlog        long    %0000000_0 << 24 + @_qlogexp << 7 + 5    'QLOG(x)    %x0
    op_qexp        long    %0000000_1 << 24 + @_qlogexp << 7 + 5    'QEXP(x)    %x0
    
    ' binaries (23)
    
    op_andb        long    %0000000_0 << 24 + @_andb    << 7 + 4    'AND        %x1
    op_orb        long    %0000000_0 << 24 + @_orb     << 7 + 4    'OR        %x1
    op_xorb        long    %0000000_0 << 24 + @_xorb    << 7 + 5    'XOR        %x1
    op_andn        long    %0000000_0 << 24 + @_andn    << 7 + 3    '&!        %x1
    op_and        long    %0000000_0 << 24 + @_and     << 7 + 3    '&        %x1
    op_or        long    %0000000_0 << 24 + @_or      << 7 + 3    '|        %x1
    op_xor        long    %0000000_0 << 24 + @_xor     << 7 + 3    '^        %x1
    op_ror        long    %0000000_0 << 24 + @_ror     << 7 + 3    '->        %x1
    op_rol        long    %0000000_0 << 24 + @_rol     << 7 + 3    '<-        %x1
    op_shr        long    %0000000_0 << 24 + @_shr     << 7 + 3    '>>        %x1
    op_shl        long    %0000000_0 << 24 + @_shl     << 7 + 3    '<<        %x1
    op_sar        long    %0000000_0 << 24 + @_sar     << 7 + 3    '~>        %x1
    op_sal        long    %0000000_0 << 24 + @_sal     << 7 + 5    '<~        %x1
    op_rev        long    %0000000_0 << 24 + @_rev     << 7 + 4    '><        %x1
    op_mins        long    %0000000_0 << 24 + @_mins    << 7 + 3    '#>        %x1
    op_maxs        long    %0000000_0 << 24 + @_maxs    << 7 + 3    '<#        %x1
    op_add        long    %0000000_0 << 24 + @_add     << 7 + 3    '+        %x1
    op_sub        long    %0000000_0 << 24 + @_sub     << 7 + 3    '-        %x1
    op_mul        long    %0000000_0 << 24 + @_mul     << 7 + 6    '*        %x1
    op_scl        long    %0000001_0 << 24 + @_scl     << 7 + 6    '**        %x1
    op_quo        long    %0000000_0 << 24 + @_divx    << 7 + 7    '/        %x1
    op_rem        long    %0000001_0 << 24 + @_divx    << 7 + 7    '//        %x1
    op_fra        long    %0000000_0 << 24 + @_fra     << 7 + 7    '*/        %x1
    
    ' equality tests (6)
    
    op_b        long    %0000000_0 << 24 + @_b       << 7 + 4    '<
    op_a        long    %0000000_0 << 24 + @_a       << 7 + 4    '>
    op_ne        long    %0000000_0 << 24 + @_ne      << 7 + 4    '<>
    op_eq        long    %0000000_0 << 24 + @_eq      << 7 + 4    '==
    op_be        long    %0000000_0 << 24 + @_be      << 7 + 4    '=< / <=
    op_ae        long    %0000000_0 << 24 + @_ae      << 7 + 4    '=> / >=
    
    ' math terms (8)
    
    op_quo64    long    %0000000_0 << 24 + @_divh64  << 7 + 10    'QUO64(al,ah,b)
    op_quo64u    long    %0000000_1 << 24 + @_divh64  << 7 + 10    'QUO64U(al,ah,b)
    op_rem64    long    %0000001_0 << 24 + @_divh64  << 7 + 10    'REM64(al,ah,b)
    op_rem64u    long    %0000001_1 << 24 + @_divh64  << 7 + 10    'REM64U(al,ah,b)
    op_sqrt64    long    %0000000_0 << 24 + @_sqrt64  << 7 + 6    'SQRT64(l,h)
    op_negb        long    %0000000_0 << 24 + @_negb    << 7 + 3    'NEGB(x,bool)
    op_muxb        long    %0000000_0 << 24 + @_muxb    << 7 + 4    'MUXB(x,y,bool)
    op_ternary    long    %0000000_0 << 24 + @_ternary << 7 + 4    'sel ? true : false
    
    ' math procedures (20)
    
    op_mul64    long    %0000000_0 << 24 + @_mul64   << 7 + 9    'MUL64(a,b : l,h)
    op_mulu64    long    %0000000_1 << 24 + @_mul64   << 7 + 9    'MUL64U(a,b : l,h)
    op_div64    long    %0000000_0 << 24 + @_div64   << 7 + 11    'DIV64(a,b : l,h)
    op_divu64    long    %0000000_1 << 24 + @_div64   << 7 + 11    'DIV64U(a,b : l,h)
    op_qsincos    long    %0000000_0 << 24 + @_qtrig   << 7 + 12    'QSINCOS(r,t : x,y)
    op_qarctan    long    %0000001_0 << 24 + @_qtrig   << 7 + 12    'QARCTAN(x,y : r,t)
    op_qrotate    long    %0000000_1 << 24 + @_qtrig   << 7 + 12    'QROTATE(x,y,t : x,y)
    op_setqi    long    %0000000_1 << 24 + @_div64   << 7 + 1    'SETQI(x)
    op_clraccs    long    %0000000_0 << 24 + @_clraccs << 7 + 0    'CLRACCS
    op_clracca    long    %0000000_0 << 24 + @_clracca << 7 + 0    'CLRACCA
    op_clraccb    long    %0000000_0 << 24 + @_clraccb << 7 + 0    'CLRACCB
    op_fitaccs    long    %0000000_0 << 24 + @_fitaccs << 7 + 0    'FITACCS
    op_fitacca    long    %0000000_0 << 24 + @_fitacca << 7 + 0    'FITACCA
    op_fitaccb    long    %0000000_0 << 24 + @_fitaccb << 7 + 0    'FITACCB
    op_setacca    long    %0000000_0 << 24 + @_setacca << 7 + 2    'SETACCA(l,h)
    op_setaccb    long    %0000000_0 << 24 + @_setaccb << 7 + 2    'SETACCB(l,h)
    op_getacca    long    %0000000_0 << 24 + @_getacca << 7 + 3    'GETACCA(l,h)
    op_getaccb    long    %0000000_0 << 24 + @_getaccb << 7 + 3    'GETACCB(l,h)
    op_maca        long    %0000000_0 << 24 + @_maca    << 7 + 2    'MACA(x,y)
    op_macb        long    %0000000_0 << 24 + @_macb    << 7 + 2    'MACB(x,y)
    
    ' constants (13)
    
    op_con1n    long    %0000000_0 << 24 + @_conxn    << 7 + 1    'constant -1
    op_con0        long    %0000000_0 << 24 + @_conxp    << 7 + 0    'constant 0
    op_con1        long    %0000001_0 << 24 + @_conxp    << 7 + 0    'constant 1
    op_con8p    long    %0000000_0 << 24 + @_con8p    << 7 + 1    'constant $000000xx
    op_con9p    long    %0000000_0 << 24 + @_con9p    << 7 + 2    'constant $000001xx
    op_con8n    long    %0000000_0 << 24 + @_con8n    << 7 + 2    'constant $FFFFFFxx
    op_con16p    long    %0000000_0 << 24 + @_con16p   << 7 + 3    'constant $0000xxxx
    op_con17p    long    %0000000_0 << 24 + @_con17p   << 7 + 3    'constant $0001xxxx
    op_con16n    long    %0000000_0 << 24 + @_con16n   << 7 + 4    'constant $FFFFxxxx
    op_con24p    long    %0000000_0 << 24 + @_con24    << 7 + 4    'constant $00xxxxxx
    op_con24n    long    %0000000_1 << 24 + @_con24    << 7 + 4    'constant $FFxxxxxx
    op_con32    long    %0000000_0 << 24 + @_con32    << 7 + 4    'constant $xxxxxxxx
    op_conexp    long    %0000000_0 << 24 + @_conexp   << 7 + 4    'constant 2^n,dec,not
    
    ' register reads/writes/assigns (6)
    
    op_rdreg    long    %0000000_0 << 24 + @_rdreg    << 7 + 4    'read register
    op_wrreg    long    %0000000_0 << 24 + @_wrreg    << 7 + 2    'write register
    op_asreg    long    %0000000_0 << 24 + @_asreg    << 7 + 5    'assign register
    
    op_rdregb    long    %0000000_0 << 24 + @_rdregb    << 7 + 6    'read register bitfield
    op_wrregb    long    %0000000_0 << 24 + @_wrregb    << 7 + 6    'write register bitfield
    op_asregb    long    %0000000_0 << 24 + @_asregb    << 7 + 6    'assign register bitfield
    
    ' local reads/writes/assigns (54)
    
    op_rdloc0    long    %0000000_0 << 24 + @_rdloc    << 7 + 3    'read local 0
    op_rdloc1    long    %0000001_0 << 24 + @_rdloc    << 7 + 3    'read local 1
    op_rdloc2    long    %0000010_0 << 24 + @_rdloc    << 7 + 3    'read local 2
    op_rdloc3    long    %0000011_0 << 24 + @_rdloc    << 7 + 3    'read local 3
    op_rdloc4    long    %0000100_0 << 24 + @_rdloc    << 7 + 3    'read local 4
    op_rdloc5    long    %0000101_0 << 24 + @_rdloc    << 7 + 3    'read local 5
    op_rdloc6    long    %0000110_0 << 24 + @_rdloc    << 7 + 3    'read local 6
    op_rdloc7    long    %0000111_0 << 24 + @_rdloc    << 7 + 3    'read local 7
    op_rdloc8    long    %0001000_0 << 24 + @_rdloc    << 7 + 3    'read local 8
    op_rdloc9    long    %0001001_0 << 24 + @_rdloc    << 7 + 3    'read local 9
    op_rdloc10    long    %0001010_0 << 24 + @_rdloc    << 7 + 3    'read local 10
    op_rdloc11    long    %0001011_0 << 24 + @_rdloc    << 7 + 3    'read local 11
    op_rdloc12    long    %0001100_0 << 24 + @_rdloc    << 7 + 3    'read local 12
    op_rdloc13    long    %0001101_0 << 24 + @_rdloc    << 7 + 3    'read local 13
    op_rdloc14    long    %0001110_0 << 24 + @_rdloc    << 7 + 3    'read local 14
    op_rdloc15    long    %0001111_0 << 24 + @_rdloc    << 7 + 3    'read local 15
    
    op_wrloc0    long    %0000000_0 << 24 + @_wrloc    << 7 + 3    'write local 0
    op_wrloc1    long    %0000001_0 << 24 + @_wrloc    << 7 + 3    'write local 1
    op_wrloc2    long    %0000010_0 << 24 + @_wrloc    << 7 + 3    'write local 2
    op_wrloc3    long    %0000011_0 << 24 + @_wrloc    << 7 + 3    'write local 3
    op_wrloc4    long    %0000100_0 << 24 + @_wrloc    << 7 + 3    'write local 4
    op_wrloc5    long    %0000101_0 << 24 + @_wrloc    << 7 + 3    'write local 5
    op_wrloc6    long    %0000110_0 << 24 + @_wrloc    << 7 + 3    'write local 6
    op_wrloc7    long    %0000111_0 << 24 + @_wrloc    << 7 + 3    'write local 7
    op_wrloc8    long    %0001000_0 << 24 + @_wrloc    << 7 + 3    'write local 8
    op_wrloc9    long    %0001001_0 << 24 + @_wrloc    << 7 + 3    'write local 9
    op_wrloc10    long    %0001010_0 << 24 + @_wrloc    << 7 + 3    'write local 10
    op_wrloc11    long    %0001011_0 << 24 + @_wrloc    << 7 + 3    'write local 11
    op_wrloc12    long    %0001100_0 << 24 + @_wrloc    << 7 + 3    'write local 12
    op_wrloc13    long    %0001101_0 << 24 + @_wrloc    << 7 + 3    'write local 13
    op_wrloc14    long    %0001110_0 << 24 + @_wrloc    << 7 + 3    'write local 14
    op_wrloc15    long    %0001111_0 << 24 + @_wrloc    << 7 + 3    'write local 15
    
    op_asloc0    long    %0000000_0 << 24 + @_asloc    << 7 + 3    'assign local 0
    op_asloc1    long    %0000001_0 << 24 + @_asloc    << 7 + 3    'assign local 1
    op_asloc2    long    %0000010_0 << 24 + @_asloc    << 7 + 3    'assign local 2
    op_asloc3    long    %0000011_0 << 24 + @_asloc    << 7 + 3    'assign local 3
    op_asloc4    long    %0000100_0 << 24 + @_asloc    << 7 + 3    'assign local 4
    op_asloc5    long    %0000101_0 << 24 + @_asloc    << 7 + 3    'assign local 5
    op_asloc6    long    %0000110_0 << 24 + @_asloc    << 7 + 3    'assign local 6
    op_asloc7    long    %0000111_0 << 24 + @_asloc    << 7 + 3    'assign local 7
    op_asloc8    long    %0001000_0 << 24 + @_asloc    << 7 + 3    'assign local 8
    op_asloc9    long    %0001001_0 << 24 + @_asloc    << 7 + 3    'assign local 9
    op_asloc10    long    %0001010_0 << 24 + @_asloc    << 7 + 3    'assign local 10
    op_asloc11    long    %0001011_0 << 24 + @_asloc    << 7 + 3    'assign local 11
    op_asloc12    long    %0001100_0 << 24 + @_asloc    << 7 + 3    'assign local 12
    op_asloc13    long    %0001101_0 << 24 + @_asloc    << 7 + 3    'assign local 13
    op_asloc14    long    %0001110_0 << 24 + @_asloc    << 7 + 3    'assign local 14
    op_asloc15    long    %0001111_0 << 24 + @_asloc    << 7 + 3    'assign local 15
    
    op_rdloci    long    %0000000_0 << 24 + @_rdloci   << 7 + 6    'read local indexed
    op_wrloci    long    %0000000_0 << 24 + @_wrloci   << 7 + 6    'write local indexed
    op_asloci    long    %0000000_0 << 24 + @_asloci   << 7 + 6    'assign local indexed
    
    op_rdlocb    long    %0000000_0 << 24 + @_rdlocb   << 7 + 5    'read local bitfield
    op_wrlocb    long    %0000000_0 << 24 + @_wrlocb   << 7 + 6    'write local bitfield
    op_aslocb    long    %0000000_0 << 24 + @_aslocb   << 7 + 6    'assign local bitfield
    
    ' memory reads/writes/assigns (18)
    
    op_rdbyte    long    %0000000_0 << 24 + @_rdbyte   << 7 + 2    'read byte
    op_rdword    long    %0000000_0 << 24 + @_rdword   << 7 + 2    'read word
    op_rdlong    long    %0000000_0 << 24 + @_rdlong   << 7 + 2    'read long
    
    op_wrbyte    long    %0000000_0 << 24 + @_wrbyte   << 7 + 2    'write byte
    op_wrword    long    %0000000_0 << 24 + @_wrword   << 7 + 2    'write word
    op_wrlong    long    %0000000_0 << 24 + @_wrlong   << 7 + 2    'write long
    
    op_asbyte    long    %0000000_0 << 24 + @_asbyte   << 7 + 5    'assign byte
    op_asword    long    %0000000_0 << 24 + @_asword   << 7 + 6    'assign word
    op_aslong    long    %0000000_0 << 24 + @_aslong   << 7 + 4    'assign long
    
    op_rdbyteb    long    %0000000_0 << 24 + @_rdbyteb  << 7 + 3    'read byte bitfield
    op_rdwordb    long    %0000000_0 << 24 + @_rdwordb  << 7 + 3    'read word bitfield
    op_rdlongb    long    %0000000_0 << 24 + @_rdlongb  << 7 + 3    'read long bitfield
    
    op_wrbyteb    long    %0000000_0 << 24 + @_wrbyteb  << 7 + 5    'write byte bitfield
    op_wrwordb    long    %0000000_0 << 24 + @_wrwordb  << 7 + 5    'write word bitfield
    op_wrlongb    long    %0000000_0 << 24 + @_wrlongb  << 7 + 5    'write long bitfield
    
    op_asbyteb    long    %0000000_0 << 24 + @_asbyteb  << 7 + 6    'assign byte bitfield
    op_aswordb    long    %0000000_0 << 24 + @_aswordb  << 7 + 7    'assign word bitfield
    op_aslongb    long    %0000000_0 << 24 + @_aslongb  << 7 + 5    'assign long bitfield
    
    ' memory offsets and indexing (7)
    
    op_vbase0    long    %0000000_0 << 24 + @_base     << 7 + 3    'vbase $0xxxx
    op_pbase0    long    %0000000_1 << 24 + @_base     << 7 + 3    'pbase $0xxxx
    op_vbase1    long    %0000001_0 << 24 + @_base     << 7 + 3    'vbase $1xxxx
    op_pbase1    long    %0000001_1 << 24 + @_base     << 7 + 3    'pbase $1xxxx
    
    op_ibyte    long    %0000000_0 << 24 + @_index    << 7 + 4    'byte index
    op_iword    long    %0000001_0 << 24 + @_index    << 7 + 4    'word index
    op_ilong    long    %0000010_0 << 24 + @_index    << 7 + 4    'long index
    
    ' branches jmp/jz/jnz/tjz/djnz (10)
    
    op_jmp0        long    %0000000_0 << 24 + @_jmp      << 7 + 1    'jmp +$0xxxx
    op_jmp1        long    %0000001_0 << 24 + @_jmp      << 7 + 1    'jmp +$1xxxx
    
    op_jz0        long    %0000000_1 << 24 + @_jxz      << 7 + 2    'jz +$0xxxx
    op_jz1        long    %0000001_1 << 24 + @_jxz      << 7 + 2    'jz +$1xxxx
    
    op_jnz0        long    %0000000_0 << 24 + @_jxz      << 7 + 2    'jnz +$0xxxx
    op_jnz1        long    %0000001_0 << 24 + @_jxz      << 7 + 2    'jnz +$1xxxx
    
    op_tjz0        long    %0000000_0 << 24 + @_tjz      << 7 + 3    'tjz +$0xxxx
    op_tjz1        long    %0000001_0 << 24 + @_tjz      << 7 + 3    'tjz +$1xxxx
    
    op_djnz0    long    %0000000_0 << 24 + @_djnz     << 7 + 4    'djnz +$0xxxx
    op_djnz1    long    %0000001_0 << 24 + @_djnz     << 7 + 4    'djnz +$1xxxx
    
    ' anchor drops (4)
    
    op_dropt    long    %0000000_0 << 24 + @_drop     << 7 + 6    'drop, \sub
    op_droptr    long    %0000001_0 << 24 + @_drop     << 7 + 6    'drop, \sub w/result
    op_drop        long    %0000010_0 << 24 + @_drop     << 7 + 6    'drop,  sub
    op_dropr    long    %0000011_0 << 24 + @_drop     << 7 + 6    'drop,  sub w/result
    
    ' calls (7)
    
    op_callos    long    %0000000_0 << 24 + @_callobj  << 7 + 6    'call obj.sub
    op_callosi    long    %0000000_1 << 24 + @_callobj  << 7 + 6    'call obj.sub[]
    op_callois    long    %0000001_0 << 24 + @_callobj  << 7 + 6    'call obj[].sub
    op_calloisi    long    %0000001_1 << 24 + @_callobj  << 7 + 6    'call obj[].sub[]
    op_calls    long    %0000000_0 << 24 + @_callsub  << 7 + 3    'call sub
    op_callsi    long    %0000000_1 << 24 + @_callsub  << 7 + 3    'call sub[]
    op_callp    long    %0000000_0 << 24 + @_callptr  << 7 + 10    'call ptr
    
    ' returns (4)
    
    op_return    long    %0000000_0 << 24 + @_return   << 7 + 13    'RETURN
    op_abort    long    %0000000_1 << 24 + @_return   << 7 + 13    'ABORT
    op_returnv    long    %0000001_0 << 24 + @_return   << 7 + 13    'RETURN value
    op_abortv    long    %0000001_1 << 24 + @_return   << 7 + 13    'ABORT value
    
    ' call pointer generation (5)
    
    op_basesub    long    %0000000_0 << 24 + @_basesub  << 7 + 5    'vbase/pbase of current
    op_baseobj    long    %0000000_0 << 24 + @_baseobj  << 7 + 16    'vbase/pbase of obj
    op_baseobji    long    %0000000_1 << 24 + @_baseobj  << 7 + 16    'vbase/pbase of obj[]
    op_subptr    long    %0000000_0 << 24 + @_subptr   << 7 + 11    'base.sub
    op_subptri    long    %0000000_1 << 24 + @_subptr   << 7 + 11    'base.sub[]
    
    ' case (5)
    
    op_casev0    long    %0000000_0 << 24 + @_casev    << 7 + 5    'case value, +$0xxxx branch
    op_casev1    long    %0000001_0 << 24 + @_casev    << 7 + 5    'case value, +$1xxxx branch
    op_caser0    long    %0000000_0 << 24 + @_caser    << 7 + 10    'case range, +$0xxxx branch
    op_caser1    long    %0000001_0 << 24 + @_caser    << 7 + 10    'case range, +$1xxxx branch
    
    op_casedone    long    %0000000_0 << 24 + @_casedone << 7 + 2    'case done
    
    ' lookup/lookdown (5)
    
    op_lookupv    long    %0000000_0 << 24 + @_lookupv  << 7 + 9    'lookup value
    op_lookupr    long    %0000000_0 << 24 + @_lookupr  << 7 + 14    'lookup range
    op_lookdnv    long    %0000000_0 << 24 + @_lookdnv  << 7 + 9    'lookdown value
    op_lookdnr    long    %0000000_0 << 24 + @_lookdnr  << 7 + 15    'lookdown range
    
    op_lookdone    long    %0000000_0 << 24 + @_lookdone << 7 + 1    'lookup/lookdown done
    
    ' miscellaneous (6)
    
    op_pop        long    %0000000_0 << 24 + @_pop      << 7 + 1    'pop
    
    op_clkset    long    %0000000_0 << 24 + @_clkset   << 7 + 1    'clkset
    op_cogid    long    %0000000_0 << 24 + @_cogid    << 7 + 1    'cogid
    op_coginit    long    %0000000_0 << 24 + @_coginit  << 7 + 6    'coginit
    op_coginitp    long    %0000001_0 << 24 + @_coginit  << 7 + 6    'coginit w/push
    op_cogstop    long    %0000000_0 << 24 + @_cogstop  << 7 + 1    'cogstop
    
    '
    '
    '************
    '* Snippets *
    '************
    '
    
    '
    '
    ' Variable modifiers
    '
                org    snippet            'repeat-var loop (assign)
    
    _rep            popa    mask            'pop var
                popa    y            'pop step
                popa    b            'pop terminal
                popa    a            'pop initial
                popa    addr            'pop branch offset
    
                cmps    b,a        wc    'get reverse range into c
                sumc    mask,y            'update var with step
                rcl    x,#1        wz    'get c into nz
        if_z        cmps    b,mask        wc    'if forward range, check if var > terminal
        if_nz        cmps    mask,b        wc    'if reverse range, check if var < terminal
    
        if_nc        subptra    addr            'if var within range, branch
        if_nc        addspa    #4            '..unpop offset/initial/terminal/step
    
                pusha    mask            'push new var
    
    
                org    snippet            'var~, clear and post-clear (assign)
    
    _clr            popa    x            'clear, pop var (single pop also used by op_writep)
    _clrpost        pusha    #0            'post-clear, push 0 (leave var on stack)
    
    
                org    snippet            'var~~, set and post-set (assign)
    
    _set            popa    x            'set, pop var
    _setpost        pusha    hFFFFFFFF        'post-set, push -1 (leave var on stack)
    
    
                org    snippet            '++var/--var/var++/var-- (assign)
    
    _incdec            popa    x            'pop var
        if_nz        pusha    x            'if nz, push original var
                sumc    x,#1            'inc or dec var by c
                pusha    x            'push new var
    
    
                org    snippet            'INCMOD/DECMOD(var,limit) (assign)
    
    _idmod            setbc    :i,#26            'set INCMOD/DECMOD by c
                popa    y            'pop limit
                popa    x            'pop var
    :i            incmod    x,y        wc    'incmod/decmod, c=limit
        if_nz_and_nc    pusha    #0            'push false if nz and nc
        if_nz_and_c    pusha    hFFFFFFFF        'push true if nz and c
                pusha    x            'push new var
    '
    '
    ' Unary functions
    '
                org    snippet
    
    _notb            popa    x        wz    'NOT, boolean
                muxz    x,hFFFFFFFF
                pusha    x
    
    
                org    snippet
    
    _not            popa    x            '!, bitwise not
                not    x
                pusha    x
    
    
                org    snippet
    
    _neg            popa    x            '-, negate
                neg    x,x
                pusha    x
    
    
                org    snippet
    
    _abs            popa    x            '||, absolute
                abs    x,x
                pusha    x
    
    
                org    snippet
    
    _enc            popa    x            '>|, encode (0..32)
                enc    x,x
                pusha    x
    
    
                org    snippet
    
    _decod5            popa    x            '|< / DECOD5(x)
                decod5    x
                pusha    x
    
    
                org    snippet
    
    _decod4            popa    x            'DECOD4(x)
                decod4    x
                pusha    x
    
    
                org    snippet
    
    _decod3            popa    x            'DECOD3(x)
                decod3    x
                pusha    x
    
    
                org    snippet
    
    _decod2            popa    x            'DECOD2(x)
                decod2    x
                pusha    x
    
    
                org    snippet
    
    _blmask            popa    x            'BLMASK(x)
                blmask    x
                pusha    x
    
    
                org    snippet
    
    _onecnt            popa    x            'ONECNT(x)
                onecnt    x
                pusha    x
    
    
                org    snippet
    
    _zercnt            popa    x            'ZERCNT(x)
                zercnt    x
                pusha    x
    
    
                org    snippet
    
    _incpat            popa    x            'INCPAT(x)
                incpat    x
                pusha    x
    
    
                org    snippet
    
    _decpat            popa    x            'DECPAT(x)
                decpat    x
                pusha    x
    
    
                org    snippet
    
    _bingry            popa    x            'BINGRY(x)
                bingry    x
                pusha    x
    
    
                org    snippet
    
    _grybin            popa    x            'GRYBIN(x)
                grybin    x
                pusha    x
    
    
                org    snippet
    
    _mergew            popa    x            'MERGEW(x)
                mergew    x
                pusha    x
    
    
                org    snippet
    
    _splitw            popa    x            'SPLITW(x)
                splitw    x
                pusha    x
    
    
                org    snippet
    
    _seussf            popa    x            'SEUSSF(x)
                seussf    x
                pusha    x
    
    
                org    snippet
    
    _seussr            popa    x            'SEUSSR(x)
                seussr    x
                pusha    x
    
    
                org    snippet
    
    _sqrt            popa    x            'SQRT(x)
                setsqrl    x
                getsqrt    x        wc
        if_nc        jmp    #$-1
                pusha    x
    
    
                org    snippet
    
    _qlogexp        popa    x            'QLOG(x), c=0
        if_nc        qlog    x            'QEXP(x), c=1
        if_c        qexp    x
                getqz    x        wc
        if_nc        jmp    #$-1
                pusha    x
    '
    '
    ' Binary functions
    '
                org    snippet
    
    _andb            popa    x        wz    'AND, boolean
        if_z        popa    x
        if_nz        popa    x        wz
                muxnz    x,hFFFFFFFF
                pusha    x
                
    
                org    snippet
    
    _orb            popa    x        wz    'OR, boolean
        if_nz        popa    x
        if_z        popa    x        wz
                muxnz    x,hFFFFFFFF
                pusha    x
                
    
                org    snippet
    
    _xorb            popa    y        wz    'XOR, boolean
                muxnz    y,hFFFFFFFF
                popa    x        wz
                muxnz    x,hFFFFFFFF
                xor    x,y
                pusha    x
    
    
                org    snippet
    
    _andn            popa    y            '&!, bitwise andnot
                popa    x
                andn    x,y
                pusha    x
    
    
                org    snippet
    
    _and            popa    y            '&, bitwise and
                popa    x
                and    x,y
                pusha    x
    
    
                org    snippet
    
    _or            popa    y            '|, bitwise or
                popa    x
                or    x,y
                pusha    x
    
    
                org    snippet
    
    _xor            popa    y            '^, bitwise xor
                popa    x
                xor    x,y
                pusha    x
    
    
                org    snippet
    
    _ror            popa    y            '->, rotate right
                popa    x
                ror    x,y
                pusha    x
    
    
                org    snippet
    
    _rol            popa    y            '<-, rotate left
                popa    x
                rol    x,y
                pusha    x
    
    
                org    snippet
    
    _shr            popa    y            '>>, shift right
                popa    x
                shr    x,y
                pusha    x
    
    
                org    snippet
    
    _shl            popa    y            '<<, shift left
                popa    x
                shl    x,y
                pusha    x
    
    
                org    snippet
    
    _sar            popa    y            '~>, shift arithmetic right
                popa    x
                sar    x,y
                pusha    x
    
    
                org    snippet
    
    _sal            popa    y            '<~, shift arithmetic left
                popa    x
                rev    x,#0
                sar    x,y
                rev    x,#0
                pusha    x
    
    
                org    snippet
    
    _rev            popa    y            '><, reverse bits
                popa    x
                neg    y,y
                rev    x,y
                pusha    x
    
    
                org    snippet
    
    _mins            popa    y            '|>, limit minimum
                popa    x
                mins    x,y
                pusha    x
    
    
                org    snippet
    
    _maxs            popa    y            '<|, limit maximum
                popa    x
                maxs    x,y
                pusha    x
    
    
                org    snippet
    
    _add            popa    y            '+, add
                popa    x
                add    x,y
                pusha    x
    
    
                org    snippet
    
    _sub            popa    y            '-, sub
                popa    x
                sub    x,y
                pusha    x
    
    
                org    snippet
    
    _mul            popa    y            '*, multiply and return lower long
                popa    x
                setmula    x
                setmulb    y
                getmull    x        wc
        if_nc        jmp    #$-1
                pusha    x
    
    
                org    snippet
    
    _scl            popa    y            '**, multiply return upper long, unsigned
                popa    x
                setmulu    x
                setmulb    y
                getmulh    x        wc
        if_nc        jmp    #$-1
                pusha    x
    
    
                org    snippet
    
    _divx            popa    y            '/, divide and return quotient,   z=1
                popa    x            '//, divide and return remainder, z=0
                setdiva    x
                setdivb    y
                getdivq    x        wc
        if_nc        jmp    #$-1
        if_nz        getdivr    x
                pusha    x
    
    
                org    snippet
    
    _fra            popa    y            '*/, fraction
                popa    x
                setdivu    #0
                setdivu    x
                setdivb    y
                getdivq    x        wc
        if_nc        jmp    #$-1
                pusha    x
    '
    '
    ' Equality tests
    '
                org    snippet
    
    _b            popa    y            '<, test below
                popa    x
                cmps    x,y        wc
                muxc    x,hFFFFFFFF
                pusha    x
    
    
                org    snippet
    
    _a            popa    y            '>, test above
                popa    x
                cmps    y,x        wc
                muxc    x,hFFFFFFFF
                pusha    x
    
    
                org    snippet
    
    _ne            popa    y            '<>, test not equal
                popa    x
                cmps    x,y        wz
                muxnz    x,hFFFFFFFF
                pusha    x
    
    
                org    snippet
    
    _eq            popa    y            '==, test equal
                popa    x
                cmps    x,y        wz
                muxz    x,hFFFFFFFF
                pusha    x
    
    
                org    snippet
    
    _be            popa    y            '=< / <=, test below or equal
                popa    x
                cmps    y,x        wc
                muxnc    x,hFFFFFFFF
                pusha    x
    
    
                org    snippet
    
    _ae            popa    y            '=> / >=, test above or equal
                popa    x
                cmps    x,y        wc
                muxnc    x,hFFFFFFFF
                pusha    x
    '
    '
    ' Math terms
    '
                org    snippet
    
    _divh64            popa    y            'QUO64(al,ah,b),  z=1, c=0
                popa    x            'QUO64U(al,ah,b), z=1, c=1
                popa    a            'REM64(al,ah,b),  z=0, c=0
        if_nc        setdiva    a            'REM64U(al,ah,b), z=0, c=1
        if_c        setdivu    a
                setdiva    x
                setdivb    y            
                getdivq    x        wc
        if_nc        jmp    #$-1
        if_nz        getdivr    x        wc
                pusha    x
    
    
                org    snippet
    
    _sqrt64            popa    x            'SQRT64(l,h)
                setsqrh    x
                popa    x
                setsqrl    x
                getsqrt    x        wc
        if_nc        jmp    #$-1
                pusha    x
    
    
                org    snippet
    
    _negb            popa    x        wz    'NEGB(x,bool)
                popa    x
                negnz    x,x
                pusha    x
    
    
                org    snippet
    
    _muxb            popa    y        wz    'MUXB(x,y,bool)
                popa    y
                popa    x
                muxnz    x,y
                pusha    x
    
    
                org    snippet
    
    _ternary        popa    y            'a ? x : y
                popa    x
                popa    a        wz
        if_z        pusha    y
        if_nz        pusha    x
    '
    '
    ' Math procedures
    '
    
                org    snippet
    
    _mul64            popa    x            'MUL64(a,b : l,h), c=0
        if_nc        setmula    x            'MUL64U(a,b : l,h), c=1
        if_c        setmulu    x
                popa    x
                setmulb    x
                getmulh    x        wc
        if_nc        jmp    #$-1
                pusha    x
                getmull    x
                pusha    x
    
    
                org    snippet
    
    _div64            popa    y            'DIV64(al,ah,b : q,r),  c=0
                popa    x            'DIV64U(al,ah,b : q,r), c=1
                popa    a
        if_nc        setdiva    a
        if_c        setdivu    a
                setdiva    x
                setdivb    y            
                getdivr    x        wc
        if_nc        jmp    #$-1
                pusha    x
                getdivq    x        wc
                pusha    x
    
    
                org    snippet
    
    _qtrig    if_z_and_c    popa    x            'QSINCOS(r,t : x,y),   z=1, c=0
        if_z_and_c    setqz    x            'QROTATE(x,y,t : x,y), z=1, c=1
                popa    y            'QARCTAN(x,y : r,t),   z=0
                popa    x
        if_z_and_nc    qsincos    y,x
        if_z_and_c    qrotate    x,y
        if_nz        qarctan    x,y
                getqz    x        wc
        if_nc        jmp    #$-1
        if_z        getqy    x
                pusha    x
                getqx    x
                pusha    x
    
    
                org    snippet
    
    _setqi            popa    x            'SETQI(i)
                setqi    x
    
    
                org    snippet
    
    _clraccs        clraccs                'CLRACCS
    
    
                org    snippet
    
    _clracca        clracca                'CLRACCA
    
    
                org    snippet
    
    _clraccb        clraccb                'CLRACCB
    
    
                org    snippet
    
    _fitaccs        fitaccs                'FITACCS
    
    
                org    snippet
    
    _fitacca        fitacca                'FITACCA
    
    
                org    snippet
    
    _fitaccb        fitaccb                'FITACCB
    
    
                org    snippet
    
    _setacca        popa    y            'SETACCA(l,h)
                popa    x
                setacca    x,y
    
    
                org    snippet
    
    _setaccb        popa    y            'SETACCB(l,h)
                popa    x
                setaccb    x,y
    
    
                org    snippet
    
    _getacca        getacca    x            'GETACCA(l,h)
                getacca    y
                pusha    y
                pusha    x
    
    
                org    snippet
    
    _getaccb        getaccb    x            'GETACCB(l,h)
                getaccb    y
                pusha    y
                pusha    x
    
    
                org    snippet
    
    _maca            popa    y            'MACA(x,y)
                popa    x
                maca    x,y
    
    
                org    snippet
    
    _macb            popa    y            'MACB(x,y)
                popa    x
                macb    x,y
    '
    '
    ' Constants
    '
                org    snippet
    
    _con8p            rdbytec    x,ptra++        'con8p
    _conxp            pusha    x            'con0..con3
    
    
                org    snippet
    
    _con9p            rdbytec    x,ptra++        'con9p
                setb    x,#8
                pusha    x
    
    
                org    snippet
    
    _con8n            rdbytec    x,ptra++        'con8n
    _conxn            xor    x,hFFFFFFFF        'conm1
                pusha    x
    
    
                org    snippet
    
    _con16p            rdbytec    x,ptra++        'con16p
                rdbytec    y,ptra++
                movf    x,y
                pusha    x
    
    
                org    snippet
    
    _con17p            rdbytec    x,ptra++        'con17p
                rdbytec    y,ptra++
                movf    x,y
                setb    x,#16
                pusha    x
    
    
                org    snippet
    
    _con16n            rdbytec    x,ptra++        'con16n
                rdbytec    y,ptra++
                movf    x,y
                xor    x,hFFFFFFFF
                pusha    x
    
    
                org    snippet
    
    _con24            reps    #3,#2            'con24p, con24n
                muxc    x,#$FF
                rdbytec    y,ptra++
                movf    x,y
                pusha    x
    
    _con32            reps    #4,#2            'con32
                nop
                rdbytec    y,ptra++
                movf    x,y
                pusha    x
    
    
                org    snippet
    
    _conexp            rdbytec    x,ptra++        'conexp
                decod5    x        wz, wc
        if_z        sub    x,#1
        if_c        not    x
                pusha    x
    '
    '
    ' Register read/write/assign
    '
                org    snippet
    
    _rdreg            popa    x            'read register
                movd    :rd,x
                nop
                nop
    :rd            pusha    $000
    
    
                org    snippet
    
    _wrreg            popa    addr            'write register
                popa    x
                call    #writer
    
    
                org    snippet
    
    _asreg            popa    addr            'assign register
                movs    :rd,addr
                jmpd    #assign_long
                mov    assign_i,callwriter
    :rd            mov    x,$000
                nop
    
                org     snippet
    
    _rdregb            call    #bitfield        'read register bitfield
                popa    x
                movs    :rd,x
                jmpd    #readb
                nop
    :rd            mov    x,$000
                nop
    
    
                org     snippet
    
    _wrregb            call    #bitfield        'write register bitfield
                popa    addr
                movs    :rd,addr
                jmpd    #writeb
                mov    writeb_i,callwriter
    :rd            mov    bval,$000
                nop
    
    
                org     snippet
    
    _asregb            call    #bitfield        'assign register bitfield
                popa    addr
                movs    :rd,addr
                jmpd    #assignb_long
                mov    writeb_i,callwriter
    :rd            mov    bval,$000
                nop
    '
    '
    ' Local read/write/assign
    '
                org    snippet
    
    _rdloci            popa    y            'read local, indexed
                rdbytec    x,ptra++
                add    x,y
    
    _rdloc            add    x,dbase            'read local, fixed
                setspb    x
                popbr    x
                pusha    x
    
    
                org    snippet
    
    _wrloci            popa    y            'write local, indexed
                rdbytec    x,ptra++
                add    x,y
    
    _wrloc            add    x,dbase            'write local, fixed
                setspb    x
                popa    x
                pushb    x
    
    
                org    snippet
    
    _asloci            popa    y            'assign local, indexed
                rdbytec    x,ptra++
                add    x,y
    
    _asloc            jmpd    #assign_local        'assign local, fixed
                add    x,dbase
                setspb    x
                popbr    x
    
    
                org    snippet
    
    _rdlocb            call    #bitfield        'read local bitfield
                popa    x
                jmpd    #readb
                add    x,dbase
                setspb    x
                popbr    x
    
    
                org    snippet
    
    _wrlocb            call    #bitfield        'write local bitfield
                popa    x
                add    x,dbase
                jmpd    #writeb
                setspb    x
                popbr    bval
                mov    writeb_i,pushbrx
    
    
                org    snippet
    
    _aslocb            call    #bitfield        'assign local bitfield
                popa    x
                add    x,dbase
                jmpd    #assignb_long
                setspb    x
                popbr    bval
                mov    writeb_i,pushbrx
    '
    '
    ' Memory read/write/assign
    '
                org    snippet
    
    _rdbyte            popa    x            'read byte
                rdbyte    x,x
                pusha    x
    
    
                org    snippet
    
    _rdword            popa    x            'read word
                rdword    x,x
                pusha    x
    
    
                org    snippet
    
    _rdlong            popa    x            'read long
                rdlong    x,x
                pusha    x
    
    
                org    snippet
    
    _wrbyte            popa    y            'write byte
                popa    x
                wrbyte    x,y
    
    
                org    snippet
    
    _wrword            popa    y            'write word
                popa    x
                wrword    x,y
    
    
                org    snippet
    
    _wrlong            popa    y            'write long
                popa    x
                wrlong    x,y
    
    
                org    snippet
    
    _asbyte            popa    addr            'assign byte
                jmpd    #assign
                rdbyte    x,addr
                mov    assign_i,:i
                mov    mask,#$FF
    
    :i            wrbyte    x,addr
    
    
                org    snippet
    
    _asword            popa    addr            'assign word
                jmpd    #assign
                rdword    x,addr
                mov    assign_i,:i
                mov    mask,:m
    
    :i            wrword    x,addr
    :m            long    $0000FFFF
    
    
                org    snippet
    
    _aslong            jmpd    #assign_long        'assign long
                popa    addr
                rdlong    x,addr
                mov    assign_i,:i
    
    :i            wrlong    x,addr
    
    
                org    snippet
    
    _rdbyteb        call    #bitfield        'read byte bitfield
                popa    x
                rdbyte    x,x
                jmp    #readb
    
    
                org    snippet
    
    _rdwordb        call    #bitfield        'read word bitfield
                popa    x
                rdword    x,x
                jmp    #readb
    
    
                org    snippet
    
    _rdlongb        call    #bitfield        'read long bitfield
                popa    x
                rdlong    x,x
                jmp    #readb
    
    
                org    snippet
    
    _wrbyteb        call    #bitfield        'write byte bitfield
                jmpd    #writeb
                popa    addr
                rdbyte    bval,addr
                mov    writeb_i,:wr
    
    :wr            wrbyte    x,addr
    
    
                org    snippet
    
    _wrwordb        call    #bitfield        'write word bitfield
                jmpd    #writeb
                popa    addr
                rdword    bval,addr
                mov    writeb_i,:wr
    
    :wr            wrword    x,addr
    
    
                org    snippet
    
    _wrlongb        call    #bitfield        'write long bitfield
                jmpd    #writeb
                popa    addr
                rdlong    bval,addr
                mov    writeb_i,:wr
    
    :wr            wrlong    x,addr
    
    
                org    snippet
    
    _asbyteb        call    #bitfield        'assign byte bitfield
                mov    mask,#$FF
                jmpd    #assignb
                popa    addr
                rdbyte    bval,addr
                mov    writeb_i,:wr
    
    :wr            wrbyte    x,addr
    
    
                org    snippet
    
    _aswordb        call    #bitfield        'assign word bitfield
                mov    mask,:mask
                jmpd    #assignb
                popa    addr
                rdword    bval,addr
                mov    writeb_i,:wr
    
    :wr            wrword    x,addr
    :mask            long    $0000FFFF
    
    
                org    snippet
    
    _aslongb        call    #bitfield        'assign long bitfield
                jmpd    #assignb_long
                popa    addr
                rdlong    bval,addr
                mov    writeb_i,:wr
    
    :wr            wrlong    x,addr
    '
    '
    ' Memory offsets and indexing
    '
                org    snippet
    
    _base            call    #xword
        if_nc        add    x,vbase            'vbase, c=0
        if_c        add    x,pbase            'pbase, c=1
                pusha    x
    
    
                org    snippet
    
    _index            popa    y            'ibyte, x=0
                shl    y,x            'iword, x=1
                popa    x            'ilong, x=2
                add    x,y
                pusha    x
    '
    '
    ' Branch jmp/jz/jnz/tjz/djnz
    '
                org    snippet
    
    _jmp            call    #xword            'jmp
                addptra    x
    
    
                org    snippet
    
    _jxz            popa    y        wz    'jz,  c=1    jnz, c=0
                call    #xword
        if_z_eq_c    addptra    x
    
    
                org    snippet
    
    _tjz            popa    y        wz    'tjz
        if_nz        pusha    y
                call    #xword
        if_z        addptra    x
    
    
                org    snippet
    
    _djnz            popa    y            'djnz
                sub    y,#1        wz
        if_nz        pusha    y
                call    #xword
        if_nz        addptra    x
    '
    '
    ' Drop anchor
    '
    ' \sub        x = %00
    ' \sub result    x = %01
    '  sub        x = %10
    '  sub result    x = %11
    '
                org    snippet
    
    _drop            pusha    dcall            'push dcall (later used for pcurr)
                getspa    dcall            'set new dcall
    
                pusha    dbase            'push return dbase
    
                pusha    vbase            'push return vbase
    
                or    x,pbase            'push return pbase w/flags
                pusha    x
    
                pusha    #0            'init 'result' to 0
    '
    '
    ' Call
    '
    ' obj.sub    z=1, c=0
    ' obj.sub[]    z=1, c=1
    ' obj[].sub    z=0, c=0
    ' obj[].sub[]    z=0, c=1
    ' sub             c=0
    ' sub[]             c=1
    ' ptr
    '
                org    snippet
    
    _callobj        rdbytec    x,ptra++        'get obj byte
        if_nz        popa    a            'add any index
        if_nz        add    x,a
    
                jmpd    #call_obj        'jump to handler, delayed
    
                rdbytec    y,ptra++        'get sub byte
        if_c        popa    a            'add any index
        if_c        add    y,a
    
    
                org    snippet
    
    _callsub        jmpd    #call_sub        'jump to handler, delayed
    
                rdbytec    y,ptra++        'get sub byte
        if_c        popa    a            'add any index
        if_c        add    y,a
    
    
                org    snippet
    
    _callptr        popa    x            'get sub [31..29]/[15..13], vbase [28..16], pbase [12..0]
    
                mov    vbase,#0        'clear vbase/pbase
                mov    pbase,#0
    
                mov    y,x            'get sub (6-bits)
                mov    a,x
                shr    y,#32-3-3
                and    y,#%111000
                jmpd    #call_ptr        'jump to handler, delayed
                shr    a,#16-3
                and    a,#%000111
                or    y,a
    '
    '
    ' RETURN/ABORT
    '
    ' RETURN    z=1, c=0
    ' ABORT        z=1, c=1
    ' RETURN value    z=0, c=0
    ' ABORT value    z=0, c=1
    '
                org    snippet
    
    _return    if_z        setspa    dbase            'if no value, return result
        if_z        popar    x
    
        if_nz        popa    x            'if value, pop it
    
    :again            setspa    dbase            'set dbase
    
                popa    pbase            'pop pbase
        if_c        test    pbase,#%10    wc    'if abort and try, return again
    
        if_c        jmpd    #:again
    
                popa    vbase            'pop vbase
                popa    dbase            'pop dbase
                popa    y            'pop pcurr
    
                setptra    y            'set ptra to pcurr
    
                test    pbase,#%01    wc    'push result?
                andn    pbase,#%11
        if_c        pusha    x
    '
    '
    ' Get vbase/pbase
    '
                org    snippet
    
    _basesub        mov    y,vbase
                shl    y,#16-4
    
                mov    x,pbase
                shr    x,#4
    
                or    x,y
    
                pusha    x
    '
    '
    ' Get pbase/vbase of obj
    '
    ' obj        c=0
    ' obj[]        c=1
    '
                org    snippet
    
    _baseobj        rdbytec    x,ptra++        'get obj byte
    
        if_c        popa    y            'handle index
        if_c        add    x,y
    
                shl    x,#2            'scale offset
    
                add    x,pbase            'get obj pbase/vbase offset
                rdlong    x,x
    
                mov    y,x            'get obj vbase
                shr    y,#16-4
                add    y,vbase
                and    y,h0001FFF0
                shl    y,#16-4
    
                shl    x,#4            'get obj pbase
                add    x,pbase
                and    x,h0001FFF0
                shr    x,#4
    
                or    x,y            'merge vbase/pbase
    
                pusha    x            'push obj vbase/pbase
    '
    '
    ' Make subroutine ptr
    '
    ' base.sub    c=0
    ' base.sub[]    c=1
    '
                org    snippet
    
    _subptr            rdbytec    a,ptra++        'get sub number
    
        if_c        popa    b            'handle sub index
        if_c        add    a,b
    
                mov    b,a            'split 6-bit index
                and    b,#%111000        'top 3 bits into [31..29]
                shl    b,#32-6
                and    a,#%000111        'bottom 3 bits into [15..13]
                shl    a,#16-3
    
                popa    x            'pop base vbase/pbase
    
                or    x,b            'install index into pbase/vbase
                or    x,a
    
                pusha    x            'push subroutine pointer
    '
    '
    ' Case
    '
                org    snippet            'case value
    
    _casev            call    #xword            'get branch address
    
                popa    a            'pop value
                popa    y            'pop target
                cmp    a,y        wz    'value = target?
                
        if_nz        addspa    #1            'if mismatch, unpop target
    
        if_z        addptra    x            'if match, branch
    
    
                org    snippet            'case range (z=1)
    
    _caser            call    #xword            'get branch address
    
                popa    b            'pop range end
                popa    a            'pop range begin
                popa    y            'pop target
    
                sub    b,a            '||(end - begin), c=1 if reverse range
                abs    b,b        wc
    
                sub    y,a            '+/-(target - begin)
                negc    y,y
    
                cmp    b,y        wc    'match if ||(end - begin) => +/-(target - begin)
    
        if_c        addspa    #1            'if mismatch, unpop target
    
        if_nc        addptra    x            'if match, branch
    
    
                org    snippet            'case done
    
    _casedone        popa    x            'pop target
                popa    x            'pop address
                addptra    x            'jump to address
    '
    '
    ' Lookup/lookdown
    '
                org    snippet            'lookup value
    
    _lookupv        popa    a            'pop value
                popa    x            'pop index
                popa    y            'pop target
    
                cmp    x,y        wz    'match if index = target
    
        if_nz        addspa    #1            'if no match, unpop target
        if_nz        add    x,#1            '..increment index
        if_nz        pusha    x            '..push index
    
        if_z        popa    addr            'if match, pop address
        if_z        pusha    a            '..push result
        if_z        setptra    addr            '..branch
    
    
                org    snippet            'lookup range
    
    _lookupr        popa    b            'pop range end
                popa    a            'pop range begin
                popa    x            'pop index
                popa    y            'pop target
    
                sub    b,a            'end - begin
                abs    b,b        wc    '||(end - begin), c=1 if reverse range
                sub    y,x            'target - index
                sumc    a,y            'result = begin +/- (target - index)
    
                cmp    b,y        wc    'match if ||(end - begin) => (target - index)
    
        if_c        addspa    #1            'if no match, unpop target
        if_c        addx    x,b            '..add ||(end - begin) + 1 to index
        if_c        pusha    x            '..push index
    
        if_nc        popa    addr            'if match, pop address
        if_nc        pusha    a            '..push result
        if_nc        setptra    addr            '..branch
    
    
                org    snippet            'lookdown value
    
    _lookdnv        popa    a            'pop value
                popa    x            'pop index
                popa    y            'pop target
    
                cmp    a,y        wz    'match if value = target
    
        if_nz        addspa    #1            'if no match, unpop target
        if_nz        add    x,#1            '..increment index
        if_nz        pusha    x            '..push index
    
        if_z        popa    addr            'if match, pop address
        if_z        pusha    x            '..push result
        if_z        setptra    addr            '..branch
    
    
                org    snippet            'lookdown range
    
    _lookdnr        popa    b            'pop range end
                popa    a            'pop range begin
                popa    x            'pop index
                popa    y            'pop target
    
                sub    b,a            '||(end - begin), c=1 if reverse range
                abs    b,b        wc
    
                sub    y,a            '+/-(target - begin)
                negc    y,y
    
                cmp    b,y        wc    'match if ||(end - begin) => +/-(target - begin)
    
        if_c        addspa    #1            'if no match, unpop target
        if_c        addx    x,b            '..add ||(end - begin) + 1 to index
        if_c        pusha    x            '..push index
    
        if_nc        popa    addr            'if match, pop address
        if_nc        add    x,y            '..result = index +/- (target - begin)
        if_nc        pusha    x            '..push result
        if_nc        setptra    addr            '..branch
    
    
                org    snippet            'lookup/lookdown done
    
    _lookdone        subspa    #3            'pop index/target/address
                pusha    #0            'push 0 result
    '
    '
    ' Miscellaneous
    '
                org    snippet
    
    _pop            rdbytec    x,ptra++        'pop
                subspa    x
    
    
                org    snippet
    
    _clkset            popa    x            'clkset
                clkset    x
    
    
                org    snippet
    
    _cogid            cogid    x            'cogid
                pusha    x
    
    
                org    snippet
    
    _coginit        popa    y            'coginit
                popa    x
                popa    a
                setcog    a
                coginit    x,y        wc
        if_nz_and_c    pusha    #0
        if_nz_and_nc    pusha    hFFFFFFFF
    
    
                org    snippet
    
    _cogstop        popa    x            'cogstop
                cogstop    x
    

    This interpreter is for the built-in 17-bit address space (128KB), but can easily be changed to 32-bit XMM. I started out on the 32-bit addressing path, but figured it was more practical, at first, to make a native 17-bit version, as an external SDRAM can easily be managed by Spin code for huge data.

    This interpreter leaves the first $150+ longs in the cog free for in-line assembly code and terminate-stay-resident type applications which can run concurrently with the interpreter via hardware multi-tasking.

    In the new Spin, all variables are bit-range addressable for read/write/read-modify-write operations. Bit ranges can be high..low or low..high. This is mainly important for I/O registers which relate to physical pins, but it makes bit fields within other types (locals, hub ram, cog RAM registers) easy to manipulate, as well.

    This interpreter works by getting a byte code, looking up a descriptor long, loading a snippet of assembly code, and executing it. The interpreter currently lacks initialization code, which will be written last, but it has all the snippets for math operations, calls, branches, lookup/lookdown, cog starting and stopping, and housekeeping. It's about 4.5KB now. Once I get the compiler working on the PC side, I'll augment the interpreter to include special I/O handling and other functions that are not needed at first, but make it complete.
  • cgraceycgracey Posts: 14,131
    edited 2013-07-01 13:11
    Sapieha wrote: »
    Hi Chip.

    Why You don't use that sequence in this place

    orgh base
    org $0
    orgF $15B

    That give even correct place with loading to COG.

    I will do something like that. I'm just not there yet.
  • SapiehaSapieha Posts: 2,964
    edited 2013-07-01 13:13
    Hi Chip.

    Thanks for replay.

    I have posted in PNut thread one dumb question to You.
    Have You read that?

    cgracey wrote: »
    I will do something like that. I'm just not there yet.
  • AribaAriba Posts: 2,682
    edited 2013-07-01 16:15
    cgracey wrote: »
    ....
    This interpreter leaves the first $150+ longs in the cog free for in-line assembly code and terminate-stay-resident type applications which can run concurrently with the interpreter via hardware multi-tasking.
    ....

    Thanks Chip for the very interesting code.

    A lot to study, but one thing caught my eye immediatly: You use a lot of delayed jumps/calls/returns. All with 3 delay slots. The problem is: if you do hardware multi tasking the number of the delay slots depends on the number of tasks and the task-scheduler settings.
    So if the assembly code installs hardware tasks, the interpreter will no longer work. The only reliable solution for code that should work with and without tasks is to avoid delayed instructions. Unfortunatly this will make the interpreter a bit slower.

    Andy
  • Cluso99Cluso99 Posts: 18,066
    edited 2013-07-01 16:34
    Great work Chip.

    Some of the snippets (the short ones) would be faster implemented as LMM but of course that can come later.

    I noticed that you don't have the return from the snippet coded within each snippet, nor a way to determine its length, so do you plan to make the compiler add this? Some form of a macro expansion would be nice for this.
  • AribaAriba Posts: 2,682
    edited 2013-07-01 17:00
    Cluso

    The description table holds the length of the snippets in the lower 7 bits and the overlay loader always adds a jump back at the end of the loaded instructions.

    Andy
  • cgraceycgracey Posts: 14,131
    edited 2013-07-01 17:34
    Ariba wrote: »
    Thanks Chip for the very interesting code.

    A lot to study, but one thing caught my eye immediatly: You use a lot of delayed jumps/calls/returns. All with 3 delay slots. The problem is: if you do hardware multi tasking the number of the delay slots depends on the number of tasks and the task-scheduler settings.
    So if the assembly code installs hardware tasks, the interpreter will no longer work. The only reliable solution for code that should work with and without tasks is to avoid delayed instructions. Unfortunatly this will make the interpreter a bit slower.

    Andy

    Good observation, Ariba! I guess I was on the road to "finding out" there was a problem. I'll have to get rid of all delayed jumps, as you've pointed out.

    There is another more insidious problem that I've been thinking about: read-modify-writes to PINx and DIRx registers in Spin will conflict with concurrent multi-tasking PASM code doing atomic operations on PINx/DIRx. The only way around this is to limit Spin operations on PINx/DIRx to atomic operations like concurrent PASM code is likely to do. It makes affecting a bit field within those registers kind of impossible, unless your desire is to simply set or clear some bits. If we revise the Verilog, I'll make some atomic masked-write instructions that could get around this problem. For now, it's a problem. Even multi-threading can't get around this, as several Spin instructions might perform a r-m-w process on PINx/DIRx.
  • AribaAriba Posts: 2,682
    edited 2013-07-01 19:31
    cgracey wrote: »
    Good observation, Ariba! I guess I was on the road to "finding out" there was a problem. I'll have to get rid of all delayed jumps, as you've pointed out.

    There is another more insidious problem that I've been thinking about: read-modify-writes to PINx and DIRx registers in Spin will conflict with concurrent multi-tasking PASM code doing atomic operations on PINx/DIRx. The only way around this is to limit Spin operations on PINx/DIRx to atomic operations like concurrent PASM code is likely to do. It makes affecting a bit field within those registers kind of impossible, unless your desire is to simply set or clear some bits. If we revise the Verilog, I'll make some atomic masked-write instructions that could get around this problem. For now, it's a problem. Even multi-threading can't get around this, as several Spin instructions might perform a r-m-w process on PINx/DIRx.

    With an XOR instruction it should be possible to change a field of bits to any state you wish with an atomic instruction:.
    Example:
    outa[9..3] := $55
    
      mov bits,#$55
      mov mask,#%1111111
      shl bits,#3
      shl mask,#3
      mov tmp,outa
      xor tmp,bits
      and tmp,mask
      xor outa,tmp   'atomic modify
    
    As long as the concurrent PASM code does not change bits 3..9 of outa this should work.

    Andy
  • cgraceycgracey Posts: 14,131
    edited 2013-07-01 21:40
    Ariba wrote: »
    With an XOR instruction it should be possible to change a field of bits to any state you wish with an atomic instruction:.
    Example:
    outa[9..3] := $55
    
      mov bits,#$55
      mov mask,#%1111111
      shl bits,#3
      shl mask,#3
      mov tmp,outa
      xor tmp,bits
      and tmp,mask
      xor outa,tmp   'atomic modify
    
    As long as the concurrent PASM code does not change bits 3..9 of outa this should work.

    Andy

    Wow!!! That's a great idea. As long as the Spin code and concurrent PASM code don't mess with each other's pins, there would be no conflict. Problem solved. And no need for new instructions!

    Thanks for thinking about this, Andy.

    I'll have to make shadow registers for not just PINx, but DIRx, as well.
  • Bill HenningBill Henning Posts: 6,445
    edited 2013-07-02 08:36
    Thanks for posting Chip - looks very interesting.

    I especially like the 150 long fcache area, that is going to be extremely useful.

    I think perhaps there should be two versions of the interpreter:

    1) supports tasks, does not use delayed instructions

    2) does not support tasks, but uses delayed instructions

    The second version should probably come well after (1) is fully functional and debugged :)

    Looking forward to the new PNut with Spin support!
  • parskoparsko Posts: 501
    edited 2013-07-05 20:03
    Hi Guys!

    Sorry for the news on the first run. 8 weeks will go by quick. I'm very eager to play with the new chip when the time arrives.

    Good luck!!!!!

    -Parsko
  • cgraceycgracey Posts: 14,131
    edited 2013-07-05 23:13
    parsko wrote: »
    Hi Guys!

    Sorry for the news on the first run. 8 weeks will go by quick. I'm very eager to play with the new chip when the time arrives.

    Good luck!!!!!

    -Parsko

    If this new chip works, we'll be able to make 100k more units from the same mask set, so there won't be much delay for actual chips.
  • SRLMSRLM Posts: 5,045
    edited 2013-07-06 01:42
    cgracey wrote: »
    If this new chip works, we'll be able to make 100k more units from the same mask set, so there won't be much delay for actual chips.

    That sounds like you decided not to go with the shuttle run and share a mask with other designs?
  • ElectrodudeElectrodude Posts: 1,614
    edited 2013-07-06 11:42
    You used pusha and popa for the spin stack. Will there be a way to extend stack space into hub ram if the whole stack doesn't fit in stack ram?
  • SapiehaSapieha Posts: 2,964
    edited 2013-07-06 11:54
    Stack are part of COG -- and can't be extended

    You used pusha and popa for the spin stack. Will there be a way to extend stack space into hub ram if the whole stack doesn't fit in stack ram?
  • potatoheadpotatohead Posts: 10,253
    edited 2013-07-06 15:13
    Oh, but it could easily be extended outside the COG for SPIN, which is what the other person was asking.
  • SapiehaSapieha Posts: 2,964
    edited 2013-07-06 18:36
    Sorry my bad thinking
    potatohead wrote: »
    Oh, but it could easily be extended outside the COG for SPIN, which is what the other person was asking.
  • cgraceycgracey Posts: 14,131
    edited 2013-07-06 19:01
    SRLM wrote: »
    That sounds like you decided not to go with the shuttle run and share a mask with other designs?

    The foundry we are using offers multi-layer reticles, not just single-layer. This means that a mask will have images for more than one process step. It's not ideal for mass production because they expose only half the area (or 1/3 or 1/4, etc.) at a time that a single-layer reticle would.
Sign In or Register to comment.