Propeller II update - BLOG

16970727475223

Comments

  • DaveJensonDaveJenson Posts: 261
    edited 2013-08-23 - 07:10:17
    Cluso99 wrote: »
    Actually a dice (correct?) encased in clear resin would be fantastic, but I don't know if there were spare die.

    Singular: Die
    Plural; Dice or Dies
  • Bill HenningBill Henning Posts: 6,445
    edited 2013-08-23 - 07:46:19
    I am crossing my fingers, and hoping that they are 100% functional - or at least as close to it as possible!
    cgracey wrote: »
    We are thinking that we should have packaged chips by the beginning of September. Either there will be 75% good chips, or 0% good chips. A single design error can render all chips useless. If there is any design error, let's hope it's one that doesn't leave the chip unable to be programmed.
    www.mikronauts.com / E-mail: mikronauts _at_ gmail _dot_ com / @Mikronauts on Twitter
    RoboPi: The most advanced Robot controller for the Raspberry Pi (Propeller based)
  • Oldbitcollector (Jeff)Oldbitcollector (Jeff) Posts: 8,090
    edited 2013-08-23 - 08:24:40
    Fingers crossed (toes crossed) here as well.

    Looks like we'll all know in a couple weeks.


    Jeff
    <br>
  • Jeff MartinJeff Martin Posts: 606
    edited 2013-08-23 - 11:14:09
    Cluso99 wrote: »
    Thanks for the info Jeff.

    Just wondering...
    For the P1 wafers, do you know statistically where the good ~400 come from (ie their position on the wafers)?
    Do you package all the ~524 before you can test for the ~400 good ones?

    You're welcome.

    We do have all die packaged first, then we test. We would love to do a wafer test, but to do is too expensive (money and time) to consider setting up that test at this time.

    The packager doesn't give us any information about die placement per packaged part, so we're only going off of what we know from other's experience and technical knowledge shared in the industry to say that it's likely a high percentage of the good parts were near the center and further from the edge.
    Jeff Martin
    Parallax Inc.
    (916) 624-8333 x3002
    jmartin@parallax.com
    http://www.parallax.com
  • localrogerlocalroger Posts: 3,290
    edited 2013-08-23 - 17:03:36
    Chip, on the (hopefully improbable) chance that there are problems but they are not catastrophic, leaving the prototypes at least partially usable, is there any chance some of us who couldn't justify the investment in a FPGA board could get samples so we'd finally have something to work with?
  • localrogerlocalroger Posts: 3,290
    edited 2013-08-23 - 17:09:07
    The packager doesn't give us any information about die placement per packaged part

    I realize it is far too late to do this for either Propeller, but I'm curious; given this limitation it would seem that a cheap workaround would be to give each chip on the die a different ID code which could be queried, so that the chips that function at all could announce what their die position was. This would also allow you to test something else I'm curious about, whether things like overclocking and temperature tolerances are affected by die placement. Is there any reason this would be unworkable?
  • cgraceycgracey Posts: 11,925
    edited 2013-08-24 - 00:52:00
    localroger wrote: »
    Chip, on the (hopefully improbable) chance that there are problems but they are not catastrophic, leaving the prototypes at least partially usable, is there any chance some of us who couldn't justify the investment in a FPGA board could get samples so we'd finally have something to work with?

    You bet. If it's at all usable, we can make little boards with the chips on them.
  • cgraceycgracey Posts: 11,925
    edited 2013-08-24 - 00:54:08
    localroger wrote: »
    I realize it is far too late to do this for either Propeller, but I'm curious; given this limitation it would seem that a cheap workaround would be to give each chip on the die a different ID code which could be queried, so that the chips that function at all could announce what their die position was. This would also allow you to test something else I'm curious about, whether things like overclocking and temperature tolerances are affected by die placement. Is there any reason this would be unworkable?

    This is not really possible, since the mask set is stepped along the wafer for lithography purposes, repeating the same image over and over. There is no way to introduce any unique patterns per chip.
  • cgraceycgracey Posts: 11,925
    edited 2013-08-24 - 02:01:08
    It's 2:00am here and it looks like the Spin2 compiler and interpreter are working together now. I'm sure there are going to be more bugs to fix and things to add, but it's finally 'alive'.

    Hopefully, I'll have a Spin2 version of PNUT.EXE to post in the next week, or so. I'll need to write some documentation to explain Spin2.

    Here's the interpreter:

    Spin2interpreter.spin
    CON
    
      int_org		= $147
    
    '
    '
    '***************
    '* Interpreter *
    '***************
    '
    DAT			orgh	$E80
    
    			org
    
    _vbase			long	0			'vbase (nop)	- modified by compiler
    _pbase			long	0			'pbase (nop)	- modified by compiler
    _pcurr			long	0			'pcurr (nop)	- modified by compiler
    _dlocs			long	0			'dcurr (nop)	- modified by compiler
    
    			reps	#int_res-int_org,#1	'move interpreter into position
    			setinds	#int_res-1,#int_obj+int_res-int_org-1
    			mov	indb--,inda--
    
    			reps	#$200-int_res,#1	'clear high regs (leaves indb at $000)
    			setindb	#int_res
    			mov	indb++,#0
    
    			reps	#$100,#1		'clear stack
    endaddr			long	@endcode		'(nop)
    			pushbr	#0
    
    			pushbr	endaddr			'push return pcurr, points to 'cogstop(cogid)'
    			subspb	#3			'push 3 locations (0's)
    
    			getspb	dbase			'set dbase
    			subspb	_dlocs			'set dcurr
    			mov	vbase,_vbase		'set vbase
    			mov	pbase,_pbase		'set pbase
    			setptrb	_pcurr			'set pcurr
    
    			jmp	#a			'clear low regs, start interpreter
    
    
    endcode			byte	(@op_get  - @descriptors) >> 2, $01	'cogid
    			byte	(@op_set1 - @descriptors) >> 2, $03	'cogstop
    '
    '
    ' Interpreter start
    '
    int_obj
    			org	int_org
    '
    '
    ' Constants/variables
    '
    descriptor_base		long	@descriptors
    
    h003C0000		long	$003C0000		'conditional field bits
    hFFFFFFFF		long	$FFFFFFFF		'all bits
    
    callwrites		call	#writes
    callwriter		call	#writer
    
    a			reps	#int_org,#1		'initially executes, becomes 'a'
    h0001FFF0		long	$0001FFF0		'vbase/pbase mask (nop)
    b			mov	indb++,#0		'initially executes, becomes 'b'
    jmpback			jmp	#getbyte
    '
    '
    ' Pre-move pops and check
    '
    premove			popbr	a
    			popbr	y
    			popbr	x
    
    			tjz	a,#getbyte
    
    			sub	a,#1
    
    premove_ret		ret
    '
    '
    ' Get sign-extended byte (c=0), used to make -$80..+$7F offset
    ' Get and append word to x (c=1), used to make $0xxxx or $1xxxx offset
    '
    xword			rdbytec	y,ptrb++
    			shl	x,#8
    			or	x,y
    	if_c		rdbytec	y,ptrb++
    	if_c		shl	x,#8
    	if_c		or	x,y
    	if_nc		shl	x,#24
    	if_nc		sar	x,#24
    
    xword_ret		ret
    '
    '
    ' 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
    			sub	dbase,#3
    
    			setspb	dcall			'get old dcall
    			popbr	dcall
    
    			getptrb	x			'set return pcurr
    			pushbr	x
    
    			setptrb	pbase			'set call pcurr
    			addptrb	y
    
    			shr	y,#32-4			'sub locals from dcurr
    			subspb	y
    
    			jmp	#getbyte		'loop to getbyte
    '
    '
    ' Bitfield addressing, pop and set bitfield parameters
    '
    bitfield		popbr	bshift			'pop range lsb
    			popbr	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
    
    			setbc	brev,#5			'save reverse flag
    
    			blmask	bmask			'get bitlength mask
    			shl	bmask,bshift		'bmask = mask, brev = reverse, bshift = lsb offset
    
    bitfield_ret		ret				'return
    '
    '
    ' Write register (addr = address, x = value)
    '
    ' if OUTA..OUTD then update PINA..PIND
    ' if DRVA..DRVD then update DIRA..DIRD
    '
    writer			movd	:mov,addr
    
    			and	addr,#$1FF		'check for OUTA..OUTD/DRVA..DRVD
    			cmp	addr,#$1E8	wc
    	if_nc		cmpr	addr,#$1EF	wc
    
    :mov	if_c		mov	$000,x			'normal register
    	if_c		jmp	writer_ret
    
    			movs	:xors,addr		'set OUTA..OUTD/DRVA..DRVD addresses
    			movd	:xord,addr
    			movd	:xor,addr
    			setb	:xor,#9+4
    
    :xors			xor	x,$1E8			'update OUTx/DRVx shadow register
    :xord			xor	$1E8,x
    :xor			xor	$1F8,x			'update PINx/DIRX atomically
    
    writer_ret		ret
    '
    '
    ' Write stack/local (addr = address, x = value)
    '
    writes			getspb	y
    			setspb	addr
    			pushb	x
    			setspb	y
    
    writes_ret		ret
    '
    '
    ' Do bitfield read (x = value)
    '
    readb			and	x,bmask
    			shr	x,bshift
    	if_c		rev	x,brev
    			pushbr	x
    
    			jmp	#getbyte
    '
    '
    ' Do bitfield write (bval = value, writeb_i = write instruction)
    '
    writeb			popbr	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		call	#writer			'call #writer / call #writes / 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
    			and	x,bmask			'extract bitfield for operation
    			shr	x,bshift
    	if_c		rev	x,brev
    
    			jmp	#assign_op		'get math operator and execute
    
    
    assignb_ret		testb	brev,#5		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
    			and	x,bmask			'extract bitfield for pushing
    			shr	x,bshift
    	if_c		rev	x,brev
    
    			jmp	#assign_p		'push it (optional)
    '
    '
    ' Do assignment (x = value, assign_i = write instruction, mask = sized mask)
    '
    assign_long		mov	mask,hFFFFFFFF		'set long mask
    
    assign			movs	jmpback,#assign_ret	'set jmpback address to :ret
    
    assign_op		rdbytec	a,ptrb++		'get math operator and flags
    			setzc	a		wz,wc	'load flags, operator already in position
    			muxz	assign_p,h003C0000	'set push condition to z
    
    	if_c		popbr	y			'swap args?
    			pushbr	x
    	if_c		pushbr	y
    
    			jmp	#hotbyte		'load and execute math snippet
    
    
    assign_ret		popbr	x			'snippet returns to here, pop value
    assign_i		call	#writer			'call #writer / call #writes / wrxxxx x,addr
    
    			and	x,mask			'mask it
    assign_p		pushbr	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,ptrb++		'	get byte code
    			shl	a,#2			'	shift to make long offset
    hotbyte			add	a,descriptor_base	'	add base address of descriptor longs
    
    			getptrb	y			'	save ptrb
    
    			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
    
    			setptrb	y			'	restore ptrb
    
    			mov	indb++,jmpback		'	finish in-line code with 'jmp #getbyte'
    			shr	x,#25-7		wz,wc	'	descriptor[31..25] is a value, [24] is C
    '
    '
    ' Reserved registers
    '
    int_res
    
    snippet			res	18			'	executable in-line code snippet, loops
    
    x			res	1
    y			res	1
    
    dcall			res	1
    dbase			res	1
    vbase			res	1
    pbase			res	1
    
    _outa			res	1			'@$1E8		OUTA..OUTD
    _outb			res	1			'@$1E9		(writes update PINA..PIND at $1F8..$1FB)
    _outc			res	1			'@$1EA
    _outd			res	1			'@$1EB
    
    _drva			res	1			'@$1EC		DRVA..DRVD
    _drvb			res	1			'@$1ED		(writes update DIRA..DIRD at $1FC..$1FD)
    _drvc			res	1			'@$1EE
    _drvd			res	1			'@$1EF
    
    bshift			res	1			'@$1F0		bitfield addressing
    bmask			res	1			'@$1F1
    brev			res	1			'@$1F2
    bval			res	1			'@$1F3
    
    addr			res	1			'@$1F4		assignment addressing
    mask			res	1			'@$1F5
    '
    '
    '************************
    '* Bytecode Descriptors *
    '************************
    '
    descriptors
    
    ' 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 (27)
    
    op_notb		long	%0000000_0 << 24 + @_notb     << 7 + 2	'NOT		%x0
    op_not		long	%0100101_0 << 24 + @_una      << 7 + 4	'!		%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_decod2	long	%0100000_0 << 24 + @_una      << 7 + 4	'DECOD2(x)	%x0
    op_decod3	long	%0100001_0 << 24 + @_una      << 7 + 4	'DECOD3(x)	%x0
    op_decod4	long	%0100010_0 << 24 + @_una      << 7 + 4	'DECOD4(x)	%x0
    op_decod5	long	%0100011_0 << 24 + @_una      << 7 + 4	'DECOD5(x), |<	%x0
    op_blmask	long	%0100100_0 << 24 + @_una      << 7 + 4	'BLMASK(x)	%x0
    op_onecnt	long	%0100110_0 << 24 + @_una      << 7 + 4	'ONECNT(x)	%x0
    op_zercnt	long	%0100111_0 << 24 + @_una      << 7 + 4	'ZERCNT(x)	%x0
    op_incpat	long	%0101000_0 << 24 + @_una      << 7 + 4	'INCPAT(x)	%x0
    op_decpat	long	%0101001_0 << 24 + @_una      << 7 + 4	'DECPAT(x)	%x0
    op_bingry	long	%0101010_0 << 24 + @_una      << 7 + 4	'BINGRY(x)	%x0
    op_grybin	long	%0101011_0 << 24 + @_una      << 7 + 4	'GRYBIN(x)	%x0
    op_mergew	long	%0101100_0 << 24 + @_una      << 7 + 4	'MERGEW(x)	%x0
    op_splitw	long	%0101101_0 << 24 + @_una      << 7 + 4	'SPLITW(x)	%x0
    op_seussf	long	%0101110_0 << 24 + @_una      << 7 + 4	'SEUSSF(x)	%x0
    op_seussr	long	%0101111_0 << 24 + @_una      << 7 + 4	'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
    op_rndf		long	%0000000_0 << 24 + @_rnd      << 7 + 8	'RNDF(x)	%x0
    op_rndr		long	%0000000_1 << 24 + @_rnd      << 7 + 8	'RNDR(x)	%x0
    op_subcnt	long	%0001100_0 << 24 + @_una      << 7 + 4	'SUBCNT(x)	%x0
    op_getpix	long	%0000000_0 << 24 + @_getpix   << 7 + 4	'GETPIX(x)	%x0
    
    ' binaries (23)
    
    op_andb		long	%0000000_0 << 24 + @_andorb   << 7 + 4	'AND		%x1
    op_orb		long	%0000000_1 << 24 + @_andorb   << 7 + 4	'OR		%x1
    op_xorb		long	%0000000_0 << 24 + @_xorb     << 7 + 5	'XOR		%x1
    op_andn		long	%0011001_0 << 24 + @_bin      << 7 + 5	'&!		%x1
    op_and		long	%0011000_0 << 24 + @_bin      << 7 + 5	'&		%x1
    op_or		long	%0011010_0 << 24 + @_bin      << 7 + 5	'|		%x1
    op_xor		long	%0011011_0 << 24 + @_bin      << 7 + 5	'^		%x1
    op_ror		long	%0001000_0 << 24 + @_bin      << 7 + 5	'->		%x1
    op_rol		long	%0001001_0 << 24 + @_bin      << 7 + 5	'<-		%x1
    op_shr		long	%0001010_0 << 24 + @_bin      << 7 + 5	'>>		%x1
    op_shl		long	%0001011_0 << 24 + @_bin      << 7 + 5	'<<		%x1
    op_sar		long	%0001110_0 << 24 + @_bin      << 7 + 5	'~>		%x1
    op_sal		long	%0000000_0 << 24 + @_sal      << 7 + 5	'<~		%x1
    op_rev		long	%0000000_0 << 24 + @_rev      << 7 + 4	'><		%x1
    op_min		long	%0010000_0 << 24 + @_bin      << 7 + 5	'#>		%x1
    op_max		long	%0010001_0 << 24 + @_bin      << 7 + 5	'<#		%x1
    op_add		long	%0100000_0 << 24 + @_bin      << 7 + 5	'+		%x1
    op_sub		long	%0100001_0 << 24 + @_bin      << 7 + 5	'-		%x1
    op_mul		long	%0000000_0 << 24 + @_mul      << 7 + 6	'*		%x1
    op_scl		long	%0000000_0 << 24 + @_scl      << 7 + 6	'**		%x1
    op_div		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 + @_m        << 7 + 6	'<
    op_a		long	%0000000_1 << 24 + @_m        << 7 + 6	'>
    op_ne		long	%0000000_0 << 24 + @_e        << 7 + 4	'<>
    op_eq		long	%0000000_1 << 24 + @_e        << 7 + 4	'==
    op_be		long	%0000001_1 << 24 + @_m        << 7 + 6	'=< / <=
    op_ae		long	%0000001_0 << 24 + @_m        << 7 + 6	'=> / >=
    
    ' 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	'select ? true : false
    
    ' math procedures (9)
    
    op_mul64	long	%0000000_0 << 24 + @_mul64    << 7 + 9	'MUL64(a,b : l,h)
    op_mul64u	long	%0000000_1 << 24 + @_mul64    << 7 + 9	'MUL64U(a,b : l,h)
    op_div64	long	%0000000_0 << 24 + @_div64    << 7 + 11	'DIV64(al,ah,b : q,r)
    op_div64u	long	%0000000_1 << 24 + @_div64    << 7 + 11	'DIV64U(al,ah,b : q,r)
    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_getacca	long	%0000000_0 << 24 + @_getacca  << 7 + 3	'GETACCA(l,h)
    op_getaccb	long	%0000000_0 << 24 + @_getaccb  << 7 + 3	'GETACCB(l,h)
    
    ' constants (9)
    
    op_con1n	long	%0000000_1 << 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 + @_con8     << 7 + 2	'constant $000000xx	+1 byte
    op_con8n	long	%0000000_1 << 24 + @_con8     << 7 + 2	'constant $FFFFFFxx	+1
    op_conexp	long	%0000000_0 << 24 + @_conexp   << 7 + 4	'constant 2^n,dec,not	+1
    op_con16p	long	%0000000_0 << 24 + @_con16    << 7 + 5	'constant $0000xxxx	+2
    op_con16n	long	%0000000_1 << 24 + @_con16    << 7 + 5	'constant $FFFFxxxx	+2
    op_con32	long	%0000000_0 << 24 + @_con32    << 7 + 5	'constant $xxxxxxxx	+4
    
    ' inter-memory moves (19)
    
    op_reg2reg	long	%0000000_0 << 24 + @_reg2reg  << 7 + 10	'REG_TO_REG(@reg,@reg,longs)
    op_reg2stk	long	%0000000_0 << 24 + @_reg2stk  << 7 + 7	'REG_TO_STK(@reg,@stk,longs)
    op_reg2loc	long	%0000000_0 << 24 + @_reg2loc  << 7 + 8	'REG_TO_LOC(@reg,@loc,longs)
    op_reg2mem	long	%0000000_0 << 24 + @_reg2mem  << 7 + 7	'REG_TO_MEM(@reg,@mem,longs)
    
    op_stk2reg	long	%0000000_0 << 24 + @_stk2reg  << 7 + 7	'STK_TO_REG(@stk,@reg,longs)
    op_stk2stk	long	%0000000_0 << 24 + @_stk2stk  << 7 + 14	'STK_TO_STK(@stk,@stk,longs)
    op_stk2loc	long	%0000000_0 << 24 + @_stk2loc  << 7 + 11	'STK_TO_LOC(@stk,@loc,longs)
    op_stk2mem	long	%0000000_0 << 24 + @_stk2mem  << 7 + 8	'STK_TO_MEM(@stk,@mem,longs)
    
    op_loc2reg	long	%0000000_0 << 24 + @_loc2reg  << 7 + 8	'LOC_TO_REG(@loc,@reg,longs)
    op_loc2stk	long	%0000000_0 << 24 + @_loc2stk  << 7 + 11	'LOC_TO_STK(@loc,@stk,longs)
    op_loc2loc	long	%0000000_0 << 24 + @_loc2loc  << 7 + 16	'LOC_TO_LOC(@loc,@loc,longs)
    op_loc2mem	long	%0000000_0 << 24 + @_loc2mem  << 7 + 8	'LOC_TO_MEM(@loc,@mem,longs)
    
    op_mem2reg	long	%0000000_0 << 24 + @_mem2reg  << 7 + 7	'MEM_TO_REG(@mem,@reg,longs)
    op_mem2stk	long	%0000000_0 << 24 + @_mem2stk  << 7 + 9	'MEM_TO_STK(@mem,@stk,longs)
    op_mem2loc	long	%0000000_0 << 24 + @_mem2loc  << 7 + 10	'MEM_TO_LOC(@mem,@loc,longs)
    op_mem2mem	long	%0000010_0 << 24 + @_xmove    << 7 + 15	'MEM_TO_MEM(@mem,@mem,longs), LONGMOVE(from,to,count)
    
    op_bytemove	long	%0000000_0 << 24 + @_xmove    << 7 + 15	'BYTEMOVE(from,to,count)
    op_wordmove	long	%0000001_0 << 24 + @_xmove    << 7 + 15	'WORDMOVE(from,to,count)
    op_quadmove	long	%0000100_1 << 24 + @_qmove    << 7 + 9	'QUADMOVE(from,to,count)
    
    ' 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	%0000001_0 << 24 + @_wrregb   << 7 + 7	'assign register bitfield
    
    ' stack reads/writes/assigns (6)
    
    op_rdstk	long	%0000000_0 << 24 + @_rdstk    << 7 + 5	'read stack
    op_wrstk	long	%0000000_0 << 24 + @_wrstk    << 7 + 5	'write stack
    op_asstk	long	%0000000_0 << 24 + @_asstk    << 7 + 8	'assign stack
    
    op_rdstkb	long	%0000000_0 << 24 + @_rdstkb   << 7 + 6	'read stack bitfield
    op_wrstkb	long	%0000000_0 << 24 + @_wrstkb   << 7 + 9	'write stack bitfield
    op_asstkb	long	%0000001_0 << 24 + @_wrstkb   << 7 + 10	'assign stack bitfield
    
    ' local reads/writes/assigns (30)
    
    op_rdloc0	long	%0000000_0 << 24 + @_rdlocx   << 7 + 5	'read local 0
    op_rdloc1	long	%0000001_0 << 24 + @_rdlocx   << 7 + 5	'read local 1
    op_rdloc2	long	%0000010_0 << 24 + @_rdlocx   << 7 + 5	'read local 2
    op_rdloc3	long	%0000011_0 << 24 + @_rdlocx   << 7 + 5	'read local 3
    op_rdloc4	long	%0000100_0 << 24 + @_rdlocx   << 7 + 5	'read local 4
    op_rdloc5	long	%0000101_0 << 24 + @_rdlocx   << 7 + 5	'read local 5
    op_rdloc6	long	%0000110_0 << 24 + @_rdlocx   << 7 + 5	'read local 6
    
    op_wrloc0	long	%0000000_0 << 24 + @_wrlocx   << 7 + 5	'write local 0
    op_wrloc1	long	%0000001_0 << 24 + @_wrlocx   << 7 + 5	'write local 1
    op_wrloc2	long	%0000010_0 << 24 + @_wrlocx   << 7 + 5	'write local 2
    op_wrloc3	long	%0000011_0 << 24 + @_wrlocx   << 7 + 5	'write local 3
    op_wrloc4	long	%0000100_0 << 24 + @_wrlocx   << 7 + 5	'write local 4
    op_wrloc5	long	%0000101_0 << 24 + @_wrlocx   << 7 + 5	'write local 5
    op_wrloc6	long	%0000110_0 << 24 + @_wrlocx   << 7 + 5	'write local 6
    
    op_asloc0	long	%0000000_0 << 24 + @_aslocx   << 7 + 7	'assign local 0
    op_asloc1	long	%0000001_0 << 24 + @_aslocx   << 7 + 7	'assign local 1
    op_asloc2	long	%0000010_0 << 24 + @_aslocx   << 7 + 7	'assign local 2
    op_asloc3	long	%0000011_0 << 24 + @_aslocx   << 7 + 7	'assign local 3
    op_asloc4	long	%0000100_0 << 24 + @_aslocx   << 7 + 7	'assign local 4
    op_asloc5	long	%0000101_0 << 24 + @_aslocx   << 7 + 7	'assign local 5
    op_asloc6	long	%0000110_0 << 24 + @_aslocx   << 7 + 7	'assign local 6
    
    op_rdloc	long	%0000000_0 << 24 + @_rdloc    << 7 + 7	'read local
    op_wrloc	long	%0000000_0 << 24 + @_wrloc    << 7 + 7	'write local
    op_asloc	long	%0000000_0 << 24 + @_asloc    << 7 + 9	'assign local
    
    op_rdloci	long	%0000000_1 << 24 + @_rdloci   << 7 + 8	'read local indexed
    op_wrloci	long	%0000000_1 << 24 + @_wrloci   << 7 + 8	'write local indexed
    op_asloci	long	%0000000_1 << 24 + @_asloci   << 7 + 10	'assign local indexed
    
    op_rdlocb	long	%0000000_0 << 24 + @_rdlocb   << 7 + 7	'read local bitfield
    op_wrlocb	long	%0000000_0 << 24 + @_wrlocb   << 7 + 9	'write local bitfield
    op_aslocb	long	%0000001_0 << 24 + @_wrlocb   << 7 + 10	'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 + 7	'write byte bitfield
    op_wrwordb	long	%0000000_0 << 24 + @_wrwordb  << 7 + 8	'write word bitfield
    op_wrlongb	long	%0000000_0 << 24 + @_wrlongb  << 7 + 6	'write long bitfield
    
    op_asbyteb	long	%0000001_0 << 24 + @_wrbyteb  << 7 + 7	'assign byte bitfield
    op_aswordb	long	%0000001_0 << 24 + @_wrwordb  << 7 + 8	'assign word bitfield
    op_aslongb	long	%0000001_0 << 24 + @_wrlongb  << 7 + 6	'assign long bitfield
    
    ' memory offsets and indexing (9)
    
    op_vbase	long	%0000000_0 << 24 + @_vbaseo   << 7 + 2	'vbase -$80..+$7F
    op_vbase0	long	%0000000_1 << 24 + @_vbaseo   << 7 + 2	'vbase $0xxxx
    op_vbase1	long	%0000001_1 << 24 + @_vbaseo   << 7 + 2	'vbase $1xxxx
    
    op_pbase	long	%0000000_0 << 24 + @_pbaseo   << 7 + 2	'pbase -$80..+$7F
    op_pbase0	long	%0000000_1 << 24 + @_pbaseo   << 7 + 2	'pbase $0xxxx
    op_pbase1	long	%0000001_1 << 24 + @_pbaseo   << 7 + 2	'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 (15)
    
    op_jmp		long	%0000000_0 << 24 + @_jmp      << 7 + 1	'jmp -$80..+$7F
    op_jmp0		long	%0000000_1 << 24 + @_jmp      << 7 + 1	'jmp +$0xxxx
    op_jmp1		long	%0000001_1 << 24 + @_jmp      << 7 + 1	'jmp +$1xxxx
    
    op_jz		long	%0000000_0 << 24 + @_jz       << 7 + 2	'jz -$80..+$7F
    op_jz0		long	%0000000_1 << 24 + @_jz       << 7 + 2	'jz +$0xxxx
    op_jz1		long	%0000001_1 << 24 + @_jz       << 7 + 2	'jz +$1xxxx
    
    op_jnz		long	%0000000_0 << 24 + @_jnz      << 7 + 2	'jnz -$80..+$7F
    op_jnz0		long	%0000000_1 << 24 + @_jnz      << 7 + 2	'jnz +$0xxxx
    op_jnz1		long	%0000001_1 << 24 + @_jnz      << 7 + 2	'jnz +$1xxxx
    
    op_tjz		long	%0000000_0 << 24 + @_tjz      << 7 + 3	'tjz -$80..+$7F
    op_tjz0		long	%0000000_1 << 24 + @_tjz      << 7 + 3	'tjz +$0xxxx
    op_tjz1		long	%0000001_1 << 24 + @_tjz      << 7 + 3	'tjz +$1xxxx
    
    op_djnz		long	%0000000_0 << 24 + @_djnz     << 7 + 4	'djnz -$80..+$7F
    op_djnz0	long	%0000000_1 << 24 + @_djnz     << 7 + 4	'djnz +$0xxxx
    op_djnz1	long	%0000001_1 << 24 + @_djnz     << 7 + 4	'djnz +$1xxxx
    
    ' anchor drops (4)
    
    op_drop		long	%0000010_0 << 24 + @_drop     << 7 + 6	'drop,  sub
    op_dropp	long	%0000011_0 << 24 + @_drop     << 7 + 6	'drop,  sub w/push
    op_dropt	long	%0000000_0 << 24 + @_drop     << 7 + 6	'drop, \sub
    op_droptp	long	%0000001_0 << 24 + @_drop     << 7 + 6	'drop, \sub w/push
    
    ' 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_returnv	long	%0000001_0 << 24 + @_return   << 7 + 13	'RETURN value
    op_abort	long	%0000000_1 << 24 + @_return   << 7 + 13	'ABORT
    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 (7)
    
    op_casev	long	%0000000_0 << 24 + @_casev    << 7 + 5	'case value, -$80..+$7F branch
    op_casev0	long	%0000000_1 << 24 + @_casev    << 7 + 5	'case value, +$0xxxx branch
    op_casev1	long	%0000001_1 << 24 + @_casev    << 7 + 5	'case value, +$1xxxx branch
    op_caser	long	%0000000_0 << 24 + @_caser    << 7 + 10	'case range, -$80..+$7F branch
    op_caser0	long	%0000000_1 << 24 + @_caser    << 7 + 10	'case range, +$0xxxx branch
    op_caser1	long	%0000001_1 << 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 (25) +231
    
    op_acc		long	%0000000_0 << 24 + @_acc      << 7 + 4	'acc   (CLRACCA/CLRACCB/CLRACCS/FITACCA/FITACCB/FITACCS)
    op_ctr		long	%0000000_0 << 24 + @_gen      << 7 + 4	'ctr   (SYNCTRA/CAPCTRA/SYNCTRB/CAPCTRB)
    op_pol		long	%0000000_0 << 24 + @_gen      << 7 + 6	'pol   (POLVID/POLCTRA/POLCTRB)
    op_get		long	%0000000_0 << 24 + @_get      << 7 + 5	'get   (COGID/GETCNT/GETLFSR/GETPHSA/GETPHZA/GETCOSA/GETSINA/GETPHSB/GETPHZB/GETCOSB/GETSINB)
    op_set1		long	%0000000_1 << 24 + @_gen      << 7 + 4	'set1  (CLKSET/COGSTOP/LOCKRET/LOCKSET/LOCKCLR/PASSCNT/SNDSER/NOP/SETPIXx/SETF/SETTASK/CFGDACx/SETDACx/CFGDACS/SETDACS/SETPORx..)
    op_set1r	long	%0000000_1 << 24 + @_gen      << 7 + 6	'set1p (LOCKSET/LOCKCLR/SNDSER w/push, CMPCNT)
    op_set2		long	%0000000_0 << 24 + @_set2     << 7 + 6	'set2  (SETACCA/SETACCB/MACA/MACB/CFGPINS/WAITVID/WAITCNT/WAITPEQ/WAITPNE)
    op_set2r	long	%0000000_0 << 24 + @_set2r    << 7 + 5	'set2r (MUL/MOVF/SCL/MIN/MAX/MOVS/MOVD/MOVI)
    
    op_coginit	long	%0000000_0 << 24 + @_coginit  << 7 + 5	'COGINIT(cog,pgm,ptr)
    op_cognew	long	%0000000_1 << 24 + @_coginit  << 7 + 5	'COGNEW(pgm,ptr)
    op_cognewp	long	%0000000_1 << 24 + @_coginit  << 7 + 7	'COGNEW(pgm,ptr) w/push
    op_locknew	long	%0000000_0 << 24 + @_locknew  << 7 + 2	'LOCKNEW
    op_rcvser	long	%0000000_0 << 24 + @_rcvser   << 7 + 3	'RCVSER(var)
    op_rcvserp	long	%0000000_1 << 24 + @_rcvser   << 7 + 3	'RCVSER(var) w/push
    op_getcnth	long	%0000000_0 << 24 + @_getcnth  << 7 + 2	'GETCNTH
    op_jmptask	long	%0000000_0 << 24 + @_jmptask  << 7 + 5	'JMPTASK(addr,mask)
    op_callb	long	%0000000_0 << 24 + @_callb    << 7 + 3	'CALLB(addr)
    
    op_strsize	long	%0000000_0 << 24 + @_strsize  << 7 + 6	'STRSIZE(@str)
    op_strcomp	long	%0000000_0 << 24 + @_strcomp  << 7 + 10	'STRCOMP(@stra,@strb)
    
    op_bytefill	long	%0000000_0 << 24 + @_xfill    << 7 + 15	'BYTEFILL(value,to,count)
    op_wordfill	long	%0000001_0 << 24 + @_xfill    << 7 + 15	'WORDFILL(value,to,count)
    op_longfill	long	%0000010_0 << 24 + @_xfill    << 7 + 15	'LONGFILL(value,to,count)
    op_quadfill	long	%0000100_1 << 24 + @_xfill    << 7 + 15	'QUADFILL(value,to,count)
    
    op_pushcopy	long	%0000000_0 << 24 + @_pushcopy << 7 + 2	'push copy
    op_pop		long	%0000000_0 << 24 + @_pop      << 7 + 1	'pop
    '
    '
    '************
    '* Snippets *
    '************
    '
    
    '
    '
    ' Variable modifiers
    '
    			org	snippet			'repeat-var loop (assign)
    
    _rep			popbr	:w			'pop var
    			popbr	y			'pop step
    			popbr	b			'pop terminal
    			popbr	a			'pop initial
    			popbr	:v			'pop branch offset
    
    			cmps	b,a		wc	'get reverse range into c
    			sumc	:w,y			'update var with step
    			rcl	x,#1		wz	'get c into nz
    	if_z		cmps	b,:w		wc	'if forward range, check if var > terminal
    	if_nz		cmps	:w,b		wc	'if reverse range, check if var < terminal
    
    	if_nc		subptrb	:v			'if var within range, branch
    	if_nc		addspb	#4			'..unpop offset/initial/terminal/step
    
    			pushbr	:w			'push new var
    
    			res	1			'(jmpback)
    :v			res	1
    :w			res	1
    
    
    			org	snippet			'var~, clear and post-clear (assign)
    
    _clr			popbr	x			'clear, pop var (single pop also used by op_writep)
    _clrpost		pushbr	#0			'post-clear, push 0 (leave var on stack)
    
    
    			org	snippet			'var~~, set and post-set (assign)
    
    _set			popbr	x			'set, pop var
    _setpost		pushbr	hFFFFFFFF		'post-set, push -1 (leave var on stack)
    
    
    			org	snippet			'++var/--var/var++/var-- (assign)
    
    _incdec			popbr	x			'pop var
    	if_nz		pushbr	x			'if nz, push original var
    			sumc	x,#1			'inc or dec var by c
    			pushbr	x			'push new var
    
    
    			org	snippet			'INCMOD/DECMOD(var,value) (assign)
    
    _idmod			setbc	:i,#26			'set INCMOD/DECMOD
    			popbr	x			'pop var
    			popbr	y			'pop value
    :i			incmod	x,y		wc	'INCMOD/DECMOD
    	if_nz_and_nc	pushbr	#0			'push false if nz and nc
    	if_nz_and_c	pushbr	hFFFFFFFF		'push true if nz and c
    			pushbr	x			'push new var
    '
    '
    ' Unary functions
    '
    			org	snippet
    
    _notb			popbr	x		wz	'NOT, boolean
    			muxz	x,hFFFFFFFF
    			pushbr	x
    
    
    			org	snippet
    
    _una			movs	:inst,x			'!, bitwise not..SUBCNT(x)
    			popbr	x
    			nop
    :inst			long	%000011_001_1_1111<<18 + x<<9
    			pushbr	x
    
    
    			org	snippet
    
    _neg			popbr	x			'-, negate
    			neg	x,x
    			pushbr	x
    
    
    			org	snippet
    
    _abs			popbr	x			'||, absolute
    			abs	x,x
    			pushbr	x
    
    
    			org	snippet
    
    _enc			popbr	x			'>|, encode (0..32)
    			enc	x,x
    			pushbr	x
    
    
    			org	snippet
    
    _sqrt			popbr	x			'SQRT(x)
    			setsqrl	x
    			getsqrt	x		wc
    	if_nc		jmp	#$-1
    			pushbr	x
    
    
    			org	snippet
    
    _qlogexp		popbr	x			'QLOG(x), c=0
    	if_nc		qlog	x			'QEXP(x), c=1
    	if_c		qexp	x
    			getqz	x		wc
    	if_nc		jmp	#$-1
    			pushbr	x
    
    
    			org	snippet
    
    _rnd			popbr	x			'RNDF(x), c=0
    			mov	y,#%10111		'RNDR(x), c=1
    	if_c		ror	y,#1
    	if_c		setb	:rot,#26
    			reps	#32,#2
    			min	x,#1
    			test	x,y		wc
    :rot			rcr	x,#1			'rcr/rcl
    			pushbr	x
    
    
    			org	snippet
    
    _getpix			popbr	x			'GETPIX(x)
    			nop	#2
    			nop	#2
    			getpix	x
    			pushbr	x
    '
    '
    ' Binary functions
    '
    			org	snippet
    
    _andorb			popbr	x		wz	'AND, boolean (c=0)
    	if_z_ne_c	popbr	x			'OR, boolean (c=1)
    	if_z_eq_c	popbr	x		wz
    			muxnz	x,hFFFFFFFF
    			pushbr	x
    			
    
    			org	snippet
    
    _xorb			popbr	y		wz	'XOR, boolean
    			muxnz	y,hFFFFFFFF
    			popbr	x		wz
    			muxnz	x,hFFFFFFFF
    			xor	x,y
    			pushbr	x
    
    
    			org	snippet
    
    _bin			shl	x,#26			'&! (bitwise andnot) .. - (sub)
    			or	:inst,x
    			popbr	y
    			popbr	x
    :inst			long	%000000_001_0_1111<<18 + x<<9 + y
    			pushbr	x
    
    
    			org	snippet
    
    _sal			popbr	y			'<~, shift arithmetic left
    			popbr	x
    			rev	x,#0
    			sar	x,y
    			rev	x,#0
    			pushbr	x
    
    
    			org	snippet
    
    _rev			popbr	y			'><, reverse bits
    			popbr	x
    			neg	y,y
    			rev	x,y
    			pushbr	x
    
    
    			org	snippet
    
    _mul			popbr	y			'*, multiply and return lower long
    			popbr	x
    			setmula	x
    			setmulb	y
    			getmull	x		wc
    	if_nc		jmp	#$-1
    			pushbr	x
    
    
    			org	snippet
    
    _scl			popbr	y			'**, multiply return upper long, unsigned
    			popbr	x
    			setmulu	x
    			setmulb	y
    			getmulh	x		wc
    	if_nc		jmp	#$-1
    			pushbr	x
    
    
    			org	snippet
    
    _divx			popbr	y			'/, divide and return quotient,   z=1
    			popbr	x			'//, divide and return remainder, z=0
    			setdiva	x
    			setdivb	y
    			getdivq	x		wc
    	if_nc		jmp	#$-1
    	if_nz		getdivr	x
    			pushbr	x
    
    
    			org	snippet
    
    _fra			popbr	y			'*/, fraction
    			popbr	x
    			setdivu	#0
    			setdivu	x
    			setdivb	y
    			getdivq	x		wc
    	if_nc		jmp	#$-1
    			pushbr	x
    '
    '
    ' Equality tests
    '
    			org	snippet
    
    _e			popbr	y			'<>, test not equal, c=0
    			popbr	a			' =, test equal,     c=1
    			cmp	a,y		wz
    	if_z_eq_c	not	x
    			pushbr	x
    
    
    			org	snippet
    
    _m	if_nc		popbr	y			'      <, test below,          z=1, c=0
    			popbr	x			'      >, test above,          z=1, c=1
    	if_c		popbr	y			'=> / >=, test above or equal, z=0, c=0
    			cmps	x,y		wc	'=< / <=, test below or equal, z=0, c=1
    			muxc	x,hFFFFFFFF
    	if_nz		not	x
    			pushbr	x
    '
    '
    ' Math terms
    '
    			org	snippet
    
    _divh64			popbr	y			'QUO64(al,ah,b),  z=1, c=0
    			popbr	x			'QUO64U(al,ah,b), z=1, c=1
    			popbr	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
    			pushbr	x
    
    
    			org	snippet
    
    _sqrt64			popbr	x			'SQRT64(l,h)
    			setsqrh	x
    			popbr	x
    			setsqrl	x
    			getsqrt	x		wc
    	if_nc		jmp	#$-1
    			pushbr	x
    
    
    			org	snippet
    
    _negb			popbr	x		wz	'NEGB(x,bool)
    			popbr	x
    			negnz	x,x
    			pushbr	x
    
    
    			org	snippet
    
    _muxb			popbr	y		wz	'MUXB(x,y,bool)
    			popbr	y
    			popbr	x
    			muxnz	x,y
    			pushbr	x
    
    
    			org	snippet
    
    _ternary		popbr	y			'a ? x : y
    			popbr	x
    			popbr	a		wz
    	if_nz		pushbr	x
    	if_z		pushbr	y
    '
    '
    ' Math procedures
    '
    			org	snippet
    
    _mul64			popbr	x			'MUL64(a,b : l,h),  c=0
    	if_nc		setmula	x			'MUL64U(a,b : l,h), c=1
    	if_c		setmulu	x
    			popbr	x
    			setmulb	x
    			getmulh	x		wc
    	if_nc		jmp	#$-1
    			pushbr	x
    			getmull	x
    			pushbr	x
    
    
    			org	snippet
    
    _div64			popbr	y			'DIV64(al,ah,b : q,r),  c=0
    			popbr	x			'DIV64U(al,ah,b : q,r), c=1
    			popbr	a
    	if_nc		setdiva	a
    	if_c		setdivu	a
    			setdiva	x
    			setdivb	y			
    			getdivr	x		wc
    	if_nc		jmp	#$-1
    			pushbr	x
    			getdivq	x		wc
    			pushbr	x
    
    
    			org	snippet
    
    _qtrig	if_z_and_c	popbr	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
    			popbr	y			'QARCTAN(x,y : r,t),   z=0
    			popbr	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
    			pushbr	x
    			getqx	x
    			pushbr	x
    
    
    			org	snippet
    
    _getacca		getacca	x			'GETACCA(l,h)
    			getacca	y
    			pushbr	y
    			pushbr	x
    
    
    			org	snippet
    
    _getaccb		getaccb	x			'GETACCB(l,h)
    			getaccb	y
    			pushbr	y
    			pushbr	x
    '
    '
    ' Constants
    '
    			org	snippet
    
    _con8			rdbytec	x,ptrb++		'con8p/con8n
    _conxn	if_c		not	x			'conm1
    _conxp			pushbr	x			'con0..con3
    
    
    			org	snippet
    
    _conexp			rdbytec	x,ptrb++		'conexp
    			decod5	x		wz, wc
    	if_z		sub	x,#1
    	if_c		not	x
    			pushbr	x
    
    
    			org	snippet
    
    _con16			rdbytec	x,ptrb++		'con16p/con16n
    			rdbytec	y,ptrb++
    			shl	x,#8
    			or	x,y
    	if_c		not	x
    			pushbr	x
    
    
    			org	snippet
    
    _con32			reps	#4,#3			'con32
    			nop
    			rdbytec	y,ptrb++
    			shl	x,#8
    			or	x,y
    			pushbr	x
    '
    '
    ' Inter-memory moves
    '
    			org	snippet
    
    _reg2reg		call	#premove		'reg2reg
    			cmp	x,y		wc
    	if_c		add	x,a
    			repd	a,#4
    
    	if_c		add	y,a
    			movs	:move,x
    			movd	:move,y
    
    :step			long	1<<9 + 1		'(nop)
    			nop
    :move			mov	0,0
    			sumc	:move,:step
    
    
    			org	snippet
    
    _reg2stk		call	#premove		'reg2stk
    			movd	:set,x
    			repd	a,#1
    
    			getspb	b
    			setspb	y
    :set			setindb	#0
    
    			pushb	indb++
    
    			setspb	b
    
    
    			org	snippet
    
    _reg2loc		call	#premove		'reg2loc
    			movd	:set,x
    			subr	y,dbase
    			repd	a,#1
    
    			getspb	b
    			setspb	y
    :set			setindb	#0
    
    			pushbr	indb++
    
    			setspb	b
    
    
    			org	snippet
    
    _reg2mem		call	#premove		'reg2mem
    			movd	:set,x
    			repd	a,#1
    
    			getptrb	b
    			setptrb	y
    :set			setindb	#0
    
    			wrlong	indb++,ptrb++
    
    			setptrb	b
    
    
    			org	snippet
    
    _stk2reg		call	#premove		'stk2reg
    			movd	:set,y
    			repd	a,#1
    
    			getspb	b
    			setspb	x
    :set			setindb	#0
    
    			popbr	indb++
    
    			setspb	b
    
    
    			org	snippet
    
    _stk2stk		call	#premove		'stk2stk
    			cmp	x,y		wc
    	if_c		add	x,a
    	if_c		add	y,a
    			repd	a,#6
    
    	if_c		xor	:rd,#%10
    	if_c		xor	:wr,#%10
    			getspb	b
    
    			setspb	x
    :rd			popbr	a
    			getspb	x
    			setspb	y
    :wr			pushb	a
    			getspb	y
    
    			setspb	b
    
    
    			org	snippet
    
    _stk2loc		call	#premove		'stk2loc
    			repd	a,#6
    
    			nop
    			subr	y,dbase
    			getspb	b
    
    			setspb	x
    			popbr	a
    			getspb	x
    			setspb	y
    			pushbr	a
    			getspb	y
    
    			setspb	b
    
    
    			org	snippet
    
    _stk2mem		call	#premove		'stk2mem
    			repd	a,#3
    
    			getspb	b
    			setspb	x
    			nop
    
    			popbr	x
    			wrlong	x,y
    			add	y,#4
    
    			setspb	b
    
    
    			org	snippet
    
    _loc2reg		call	#premove		'loc2reg
    			subr	x,dbase
    			movd	:set,y
    			repd	a,#1
    
    			getspb	b
    			setspb	x
    :set			setindb	#0
    
    			popb	indb++
    
    			setspb	b
    
    
    			org	snippet
    
    _loc2stk		call	#premove		'loc2stk
    			repd	a,#6
    
    			nop
    			subr	x,dbase
    			getspb	b
    
    			setspb	x
    			popb	a
    			getspb	x
    			setspb	y
    			pushb	a
    			getspb	y
    
    			setspb	b
    
    
    			org	snippet
    
    _loc2loc		call	#premove		'loc2loc
    			cmp	x,y		wc
    	if_c		add	x,a
    	if_c		add	y,a
    			subr	x,dbase
    			subr	y,dbase
    			repd	a,#6
    
    	if_c		xor	:rd,#%10
    	if_c		xor	:wr,#%10
    			getspb	b
    
    			setspb	x
    :rd			popb	a
    			getspb	x
    			setspb	y
    :wr			pushbr	a
    			getspb	y
    
    			setspb	b
    
    
    			org	snippet
    
    _loc2mem		call	#premove		'loc2mem
    			repd	a,#3
    
    			subr	x,dbase
    			getspb	b
    			setspb	x
    
    :loop			popb	x
    			wrlong	x,y
    			add	y,#4
    
    			setspb	b
    
    
    			org	snippet
    
    _mem2reg		call	#premove		'mem2reg
    			movd	:set,y
    			repd	a,#1
    
    			getptrb	b
    			setptrb	x
    :set			setindb	#0
    
    			rdlongc	indb++,ptrb++
    
    			setptrb	b
    
    
    			org	snippet
    
    _mem2stk		call	#premove		'mem2stk
    			getspb	b
    			setspb	y
    			repd	a,#2
    
    			getptrb	a
    			setptrb	x
    
    			rdlongc	x,ptrb++
    			pushb	x
    
    			setptrb	a
    			setspb	b
    
    
    			org	snippet
    
    _mem2loc		call	#premove		'mem2loc
    			subr	y,dbase
    			getspb	b
    			setspb	y
    			repd	a,#2
    
    			getptrb	a
    			setptrb	x
    
    			rdlongc	x,ptrb++
    			pushbr	x
    
    			setptrb	a
    			setspb	b
    
    
    			org	snippet
    
    _xmove			mov	b,x			'mem2mem/bytemove/wordmove/longmove
    			decod5	b
    			or	:shl,x
    			shl	x,#26
    			or	:rd,x
    			or	:wr,x
    			call	#premove
    			cmp	x,y		wc
    			repd	a,#4
    
    :shl	if_c		shl	a,#0
    	if_c		add	x,a
    	if_c		add	y,a
    
    :rd			rdbytec	a,x
    :wr			wrbyte	a,y
    			sumc	x,b
    			sumc	y,b
    
    
    			org	snippet
    
    _qmove			call	#premove		'quadmove
    			cmp	x,y		wc
    			repd	a,#4
    
    	if_c		shl	a,#4
    	if_c		add	x,a
    	if_c		add	y,a
    
    			rdquad	x
    			wrquad	y
    			sumc	x,#16
    			sumc	y,#16
    '
    '
    ' Register read/write/assign
    '
    			org	snippet
    
    _rdreg			popbr	a			'read register
    			movd	:rd,a
    			nop
    			nop
    :rd			pushbr	$000
    
    
    			org	snippet
    
    _wrreg			popbr	addr			'write register
    			popbr	x
    			call	#writer
    
    
    			org	snippet
    
    _asreg			popbr	addr			'assign register
    			movs	:rd,addr
    			mov	assign_i,callwriter
    			nop
    :rd			mov	x,$000
    			jmp	#assign_long
    
    			org 	snippet
    
    _rdregb			call	#bitfield		'read register bitfield
    			popbr	a
    			movs	:rd,a
    			nop
    			nop
    :rd			mov	x,$000
    			jmp	#readb
    
    
    			org 	snippet
    
    _wrregb			call	#bitfield		'write/assign register bitfield
    			popbr	addr
    			movs	:rd,addr
    			mov	writeb_i,callwriter
    			nop
    :rd			mov	bval,$000
    	if_z		jmp	#writeb			'write,  z=1
    			jmp	#assignb_long		'assign, z=0
    '
    '
    ' Stack read/write/assign
    '
    			org	snippet
    
    _rdstk			popbr	a			'read stack
    
    			getspb	y
    			setspb	a
    			popbr	x
    			setspb	y
    
    			pushbr	x
    
    
    			org	snippet
    
    _wrstk			popbr	a			'write stack
    			popbr	x
    
    			getspb	y
    			setspb	a
    			pushb	x
    			setspb	y
    
    
    			org	snippet
    
    _asstk			popbr	a			'assign stack
    
    			getspb	y
    			setspb	a
    			popbr	x
    			subspb	#1
    			getspb	addr
    			setspb	y
    
    			mov	assign_i,callwrites
    			jmp	#assign_long
    
    
    			org	snippet
    
    _rdstkb			call	#bitfield		'read stack bitfield
    
    			popbr	a
    
    			getspb	y
    			setspb	a
    			popbr	x
    			setspb	y
    
    			jmp	#readb
    
    
    			org	snippet
    
    _wrstkb			call	#bitfield		'write/assign stack bitfield
    
    			popbr	a
    
    			getspb	y
    			add	a,#1
    			setspb	a
    			popb	bval
    			getspb	addr
    			setspb	y
    
    			mov	writeb_i,callwrites
    	if_z		jmp	#writeb			'write,  z=1
    			jmp	#assignb_long		'assign, z=0
    '
    '
    ' Local read/write/assign
    '
    			org	snippet
    
    _rdloci			popbr	y			'read local, indexed
    _rdloc			rdbytec	x,ptrb++		'read local
    	if_c		add	x,y
    
    _rdlocx			getspb	y			'read local, fixed
    			setspb	dbase
    			subspb	x
    			popb	x
    			setspb	y
    
    			pushbr	x
    
    
    			org	snippet
    
    _wrloci			popbr	y			'write local, indexed
    _wrloc			rdbytec	x,ptrb++		'write local
    	if_c		add	x,y
    
    _wrlocx			popbr	a			'write local, fixed
    
    			getspb	y
    			setspb	dbase
    			subspb	x
    			pushbr	a
    			setspb	y
    
    
    			org	snippet
    
    _asloci			popbr	y			'assign local, indexed
    _asloc			rdbytec	x,ptrb++		'assign local
    	if_c		add	x,y
    
    _aslocx			getspb	y			'assign local, fixed
    			setspb	dbase
    			subspb	x
    			popb	x
    			getspb	addr
    			setspb	y
    
    			mov	assign_i,callwrites
    			jmp	#assign_long
    
    
    			org	snippet
    
    _rdlocb			call	#bitfield		'read local bitfield
    
    			popbr	x
    
    			getspb	y
    			setspb	dbase
    			subspb	x
    			popb	x
    			setspb	y
    
    			jmp	#readb
    
    
    			org	snippet
    
    _wrlocb			call	#bitfield		'write/assign local bitfield
    
    			popbr	x
    
    			getspb	y
    			setspb	dbase
    			subspb	x
    			popb	bval
    			getspb	addr
    			setspb	y
    
    			mov	writeb_i,callwrites
    	if_z		jmp	#writeb			'write,  z=1
    			jmp	#assignb_long		'assign, z=0
    '
    '
    ' Memory read/write/assign
    '
    			org	snippet
    
    _rdbyte			popbr	x			'read byte
    			rdbyte	x,x
    			pushbr	x
    
    
    			org	snippet
    
    _rdword			popbr	x			'read word
    			rdword	x,x
    			pushbr	x
    
    
    			org	snippet
    
    _rdlong			popbr	x			'read long
    			rdlong	x,x
    			pushbr	x
    
    
    			org	snippet
    
    _wrbyte			popbr	a			'write byte
    			popbr	x
    			wrbyte	x,a
    
    
    			org	snippet
    
    _wrword			popbr	a			'write word
    			popbr	x
    			wrword	x,a
    
    
    			org	snippet
    
    _wrlong			popbr	a			'write long
    			popbr	x
    			wrlong	x,a
    
    
    			org	snippet
    
    _asbyte			popbr	addr			'assign byte
    			rdbyte	x,addr
    			mov	assign_i,:i
    			mov	mask,#$FF
    			jmp	#assign
    
    :i			wrbyte	x,addr
    
    
    			org	snippet
    
    _asword			popbr	addr			'assign word
    			rdword	x,addr
    			mov	assign_i,:i
    			mov	mask,:m
    			jmp	#assign
    
    :i			wrword	x,addr
    :m			long	$0000FFFF
    
    
    			org	snippet
    
    _aslong			popbr	addr			'assign long
    			rdlong	x,addr
    			mov	assign_i,:i
    			jmp	#assign_long
    
    :i			wrlong	x,addr
    
    
    			org	snippet
    
    _rdbyteb		call	#bitfield		'read byte bitfield
    			popbr	x
    			rdbyte	x,x
    			jmp	#readb
    
    
    			org	snippet
    
    _rdwordb		call	#bitfield		'read word bitfield
    			popbr	x
    			rdword	x,x
    			jmp	#readb
    
    
    			org	snippet
    
    _rdlongb		call	#bitfield		'read long bitfield
    			popbr	x
    			rdlong	x,x
    			jmp	#readb
    
    
    			org	snippet
    
    _wrbyteb		call	#bitfield		'write/assign byte bitfield
    			popbr	addr
    			rdbyte	bval,addr
    			mov	writeb_i,:wr
    	if_z		jmp	#writeb			'write,  z=1
    			mov	mask,#$FF		'assign, z=0
    			jmp	#assignb
    
    :wr			wrbyte	x,addr
    
    
    			org	snippet
    
    _wrwordb		call	#bitfield		'write/assign word bitfield
    			popbr	addr
    			rdword	bval,addr
    			mov	writeb_i,:wr
    	if_z		jmp	#writeb			'write,  z=1
    			mov	mask,:mask		'assign, z=0
    			jmp	#assignb
    
    :wr			wrword	x,addr
    :mask			long	$0000FFFF
    
    
    			org	snippet
    
    _wrlongb		call	#bitfield		'write/assign long bitfield
    			popbr	addr
    			rdlong	bval,addr
    			mov	writeb_i,:wr
    	if_z		jmp	#writeb			'write,  z=1
    			jmp	#assignb_long		'assign, z=0
    
    :wr			wrlong	x,addr
    '
    '
    ' Memory offsets and indexing
    '
    			org	snippet
    
    _vbaseo			call	#xword
    			add	x,vbase
    			pushbr	x
    
    
    			org	snippet
    
    _pbaseo			call	#xword
    			add	x,pbase
    			pushbr	x
    
    
    			org	snippet
    
    _index			popbr	y			'ibyte, x=0
    			shl	y,x			'iword, x=1
    			popbr	x			'ilong, x=2
    			add	x,y
    			pushbr	x
    '
    '
    ' Branch jmp/jz/jnz/tjz/djnz
    '
    			org	snippet
    
    _jmp			call	#xword			'jmp
    			addptrb	x
    
    
    			org	snippet
    
    _jz			popbr	y		wz	'jz
    			call	#xword
    	if_z		addptrb	x
    
    
    			org	snippet
    
    _jnz			popbr	y		wz	'jnz
    			call	#xword
    	if_nz		addptrb	x
    
    
    			org	snippet
    
    _tjz			popbr	y		wz	'tjz
    	if_nz		pushbr	y
    			call	#xword
    	if_z		addptrb	x
    
    
    			org	snippet
    
    _djnz			popbr	y			'djnz
    			sub	y,#1		wz
    	if_nz		pushbr	y
    			call	#xword
    	if_nz		addptrb	x
    '
    '
    ' Drop anchor
    '
    ' \sub		x = %00
    ' \sub result	x = %01
    '  sub		x = %10
    '  sub result	x = %11
    '
    			org	snippet
    
    _drop			pushbr	dcall			'push dcall (later used for pcurr)
    			getspb	dcall			'set new dcall
    
    			pushbr	dbase			'push return dbase
    
    			pushbr	vbase			'push return vbase
    
    			or	x,pbase			'push return pbase w/flags
    			pushbr	x
    
    			pushbr	#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,ptrb++		'get obj byte
    	if_nz		popbr	a			'add any obj index
    	if_nz		add	x,a
    			rdbytec	y,ptrb++		'get sub byte
    	if_c		popbr	a			'add any sub index
    	if_c		add	y,a
    			jmp	#call_obj		'jump to handler
    
    
    			org	snippet
    
    _callsub		rdbytec	y,ptrb++		'get sub byte
    	if_c		popbr	a			'add any index
    	if_c		add	y,a
    			jmp	#call_sub		'jump to handler
    
    
    			org	snippet
    
    _callptr		popbr	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
    			shr	a,#16-3
    			and	a,#%000111
    			or	y,a
    			jmp	#call_ptr		'jump to handler
    '
    '
    ' 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		setspb	dbase			'if no value, return result
    	if_z		popb	x
    
    	if_nz		popbr	x			'if value, pop it
    
    :again			setspb	dbase			'set dbase
    
    			popbr	pbase			'pop pbase
    			popbr	vbase			'pop vbase
    			popbr	dbase			'pop dbase
    			popbr	y			'pop pcurr
    
    	if_c		test	pbase,#%10	wc	'if abort and try, return again
    	if_c		jmp	#:again
    
    			setptrb	y			'set ptrb to pcurr
    
    			test	pbase,#%01	wc	'push result?
    			andn	pbase,#%11
    	if_c		pushbr	x
    '
    '
    ' Get vbase/pbase
    '
    			org	snippet
    
    _basesub		mov	y,vbase
    			shl	y,#16-4
    
    			mov	x,pbase
    			shr	x,#4
    
    			or	x,y
    
    			pushbr	x
    '
    '
    ' Get pbase/vbase of obj
    '
    ' obj		c=0
    ' obj[]		c=1
    '
    			org	snippet
    
    _baseobj		rdbytec	x,ptrb++		'get obj byte
    
    	if_c		popbr	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
    
    			pushbr	x			'push obj vbase/pbase
    '
    '
    ' Make subroutine ptr
    '
    ' base.sub	c=0
    ' base.sub[]	c=1
    '
    			org	snippet
    
    _subptr			rdbytec	a,ptrb++		'get sub number
    
    	if_c		popbr	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
    
    			popbr	x			'pop base vbase/pbase
    
    			or	x,b			'install index into pbase/vbase
    			or	x,a
    
    			pushbr	x			'push subroutine pointer
    '
    '
    ' Case
    '
    			org	snippet			'case value
    
    _casev			call	#xword			'get branch address
    
    			popbr	a			'pop value
    			popbr	y			'pop target
    			cmp	a,y		wz	'value = target?
    			
    	if_nz		subspb	#1			'if mismatch, unpop target
    
    	if_z		addptrb	x			'if match, branch
    
    
    			org	snippet			'case range (z=1)
    
    _caser			call	#xword			'get branch address
    
    			popbr	b			'pop range end
    			popbr	a			'pop range begin
    			popbr	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		subspb	#1			'if mismatch, unpop target
    
    	if_nc		addptrb	x			'if match, branch
    
    
    			org	snippet			'case done
    
    _casedone		popbr	x			'pop target
    			popbr	x			'pop address
    			setptrb	x			'jump to address
    '
    '
    ' Lookup/lookdown
    '
    			org	snippet			'lookup value
    
    _lookupv		popbr	a			'pop value
    			popbr	x			'pop index
    			popbr	y			'pop target
    
    			cmp	x,y		wz	'match if index = target
    
    	if_nz		subspb	#1			'if no match, unpop target
    	if_nz		add	x,#1			'..increment index
    	if_nz		pushbr	x			'..push index
    
    	if_z		popbr	addr			'if match, pop address
    	if_z		pushbr	a			'..push result
    	if_z		setptrb	addr			'..branch
    
    
    			org	snippet			'lookup range
    
    _lookupr		popbr	b			'pop range end
    			popbr	a			'pop range begin
    			popbr	x			'pop index
    			popbr	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		subspb	#1			'if no match, unpop target
    	if_c		addx	x,b			'..add ||(end - begin) + 1 to index
    	if_c		pushbr	x			'..push index
    
    	if_nc		popbr	addr			'if match, pop address
    	if_nc		pushbr	a			'..push result
    	if_nc		setptrb	addr			'..branch
    
    
    			org	snippet			'lookdown value
    
    _lookdnv		popbr	a			'pop value
    			popbr	x			'pop index
    			popbr	y			'pop target
    
    			cmp	a,y		wz	'match if value = target
    
    	if_nz		subspb	#1			'if no match, unpop target
    	if_nz		add	x,#1			'..increment index
    	if_nz		pushbr	x			'..push index
    
    	if_z		popbr	addr			'if match, pop address
    	if_z		pushbr	x			'..push result
    	if_z		setptrb	addr			'..branch
    
    
    			org	snippet			'lookdown range
    
    _lookdnr		popbr	b			'pop range end
    			popbr	a			'pop range begin
    			popbr	x			'pop index
    			popbr	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		subspb	#1			'if no match, unpop target
    	if_c		addx	x,b			'..add ||(end - begin) + 1 to index
    	if_c		pushbr	x			'..push index
    
    	if_nc		popbr	addr			'if match, pop address
    	if_nc		add	x,y			'..result = index +/- (target - begin)
    	if_nc		pushbr	x			'..push result
    	if_nc		setptrb	addr			'..branch
    
    
    			org	snippet			'lookup/lookdown done
    
    _lookdone		addspb	#3			'pop index/target/address
    			pushbr	#0			'push 0 result
    '
    '
    ' Miscellaneous
    '
    			org	snippet
    
    _acc			rdbyte	a,ptrb++		'acc
    			movd	:inst,a
    			nop
    			nop
    :inst			long	%000011_000_1_1111_000000000_000001000
    
    
    			org	snippet
    
    _gen			rdbyte	a,ptrb++		'gen
    			movs	:inst,a
    	if_c		popbr	x
    			nop
    :inst			long	%000011_010_1_1111<<18 + x<<9
    	if_nc		pushbr	#0
    	if_c		pushbr	hFFFFFFFF
    
    
    			org	snippet
    
    _get			rdbyte	a,ptrb++		'get
    			movs	:inst,a
    			nop
    			nop
    :inst			long	%000011_001_1_1111<<18 + x<<9
    			pushbr	x
    
    
    			org	snippet
    
    _set2			rdbyte	a,ptrb++		'set2
    			shl	a,#24
    			sar	a,#1
    			or	:inst,a
    			popbr	y
    			popbr	x
    :inst			long	%000000_000_0_1111<<18 + x<<9 + y
    
    
    			org	snippet
    
    _set2r			rdbyte	a,ptrb++		'set2r
    			movi	:inst,a
    			popbr	y
    			popbr	x
    :inst			long	%000000_000_0_1111<<18 + x<<9 + y
    			pushbr	x
    
    
    			org	snippet
    
    _coginit		popbr	y			'COGINIT(cog,pgm,par) / COGNEW(pgm,par)
    			popbr	x
    	if_nc		popbr	a
    	if_c		mov	a,#8
    			setcog	a
    			coginit	x,y		wc,wr
    	if_c		mov	x,hFFFFFFFF
    			pushbr	x
    
    
    			org	snippet
    
    _locknew		locknew	x		wc	'LOCKNEW
    	if_c		mov	x,hFFFFFFFF
    			pushbr	x
    
    
    			org	snippet
    
    _rcvser			rcvser	x		wc	'RCVSER(var)
    	if_c		muxc	y,hFFFFFFFF
    	if_c		pushbr	y
    			pushbr	x
    
    
    			org	snippet
    
    _getcnth		getcnt	x			'GETCNTH
    			getcnt	x
    			pushbr	x
    
    
    			org	snippet
    
    _jmptask		popbr	y			'JMPTASK(addr,mask)
    			and	y,#%1111
    			or	:inst,y
    			popbr	x
    			nop
    :inst			jmptask	x,#0
    
    
    			org	snippet
    
    _callb			popbr	x			'CALLB(addr)
    			subspb	#1
    			callb	x
    			addspb	#1
    
    
    			org	snippet
    
    _strsize		popbr	x			'STRSIZE(@str)
    			mov	y,x
    
    :loop			rdbytec	a,x		wz
    	if_nz		add	x,#1
    	if_nz		jmp	#:loop
    
    			sub	x,y
    			pushbr	x
    
    
    			org	snippet
    
    _strcomp		popbr	y			'STRCOMP(@stra,@strb)
    			popbr	x
    
    :loop			rdbytec	a,x
    			rdbyte	b,y
    			add	x,#1
    			add	y,#1
    			cmp	a,b		wz
    	if_z		tjz	a,#:got
    	if_z		jmp	#:loop
    
    :got			muxz	x,hFFFFFFFF
    			pushbr	x
    
    
    			org	snippet
    
    _xfill			shl	x,#26			'BYTEFILL/WORDFILL/LONGFILL/QUADFILL(value,addr,count)
    			or	:wr,x
    			shr	x,#26
    			decod5	x
    
    			popbr	y		wz
    			popbr	a
    			popbr	b
    
    			setquad	#_xfill
    			reps	#4,#1
    			setindb	#_xfill
    			mov	indb++,b
    
    :wr	if_nz_and_nc	wrbyte	b,a
    	if_nz_and_c	wrquad	a
    	if_nz		add	a,x
    	if_nz		djnz	y,#:wr
    
    			setquad	#$1FF
    
    
    			org	snippet
    
    _pushcopy		popbr	x			'push copy
    			pushbr	x
    			pushbr	x
    
    
    			org	snippet
    
    _pop			rdbytec	x,ptrb++		'pop
    			addspb	x
    
  • ozpropdevozpropdev Posts: 2,604
    edited 2013-08-24 - 04:44:19
    Looks very good Chip!
    Nice work.
    Melbourne, Australia
  • Bill HenningBill Henning Posts: 6,445
    edited 2013-08-24 - 07:43:13
    Excellent news Chip! Looks great!

    I only took a quick glance so far, looks like plenty to chew over :)

    'org snippet' looks interesting...
    cgracey wrote: »
    It's 2:00am here and it looks like the Spin2 compiler and interpreter are working together now. I'm sure there are going to be more bugs to fix and things to add, but it's finally 'alive'.

    Hopefully, I'll have a Spin2 version of PNUT.EXE to post in the next week, or so. I'll need to write some documentation to explain Spin2.
    www.mikronauts.com / E-mail: mikronauts _at_ gmail _dot_ com / @Mikronauts on Twitter
    RoboPi: The most advanced Robot controller for the Raspberry Pi (Propeller based)
  • ElectrodudeElectrodude Posts: 1,291
    edited 2013-08-24 - 08:45:51
    Will you make it cache snippets?

    Making it cache them would be really easy - have a long for each snippet, the bottom 9 bits holding the snippet's cogram address or 0 if it's not loaded, and the rest holding when this snippet was last used. Whenever a new snippet is needed and there isn't enough room for it, the oldest one would be unloaded and replaced with the new one.

    Obviously, caching them cuts down on the amount of user PASM space you have, but maybe you could specify how much space you needed and it would make the cache size fill only the remainder?
  • Mike GreenMike Green Posts: 22,923
    edited 2013-08-24 - 09:09:35
    Caching also reduces the efficiency of the code execution mechanism. The cache table has to be searched. Any saved (cached) snippet has to be copied within the cog since there are no relative jumps, etc. Caches are great when there's a high cost to fetch the code snippet, like from an SD card or EEPROM. It's pretty cheap to fetch a small block of code from hub RAM.
  • cgraceycgracey Posts: 11,925
    edited 2013-08-24 - 10:28:33
    Mike Green wrote: »
    Caching also reduces the efficiency of the code execution mechanism. The cache table has to be searched. Any saved (cached) snippet has to be copied within the cog since there are no relative jumps, etc. Caches are great when there's a high cost to fetch the code snippet, like from an SD card or EEPROM. It's pretty cheap to fetch a small block of code from hub RAM.

    Mike's right. The hassle of determining whether or not what you wanted was already cached would take longer than just loading what are often 4-long snippets (using RDLONGC, which caches). This is where some kind of content-addressable memory subsystem would help a lot.
  • David BetzDavid Betz Posts: 13,589
    edited 2013-08-24 - 10:39:35
    cgracey wrote: »
    Mike's right. The hassle of determining whether or not what you wanted was already cached would take longer than just loading what are often 4-long snippets (using RDLONGC, which caches). This is where some kind of content-addressable memory subsystem would help a lot.
    Hi Chip,

    Are you planning to document the instruction set used by the Spin interpreter so that it could be used as a target for other languages?

    Thanks,
    David
  • cgraceycgracey Posts: 11,925
    edited 2013-08-24 - 10:52:15
    David Betz wrote: »
    Hi Chip,

    Are you planning to document the instruction set used by the Spin interpreter so that it could be used as a target for other languages?

    Thanks,
    David

    I haven't thought about it. Do you think documentation would be necessary for someone to use the code? I figure they'd probably modify it in some ways after figuring out how it works. The resident portion of the interpreter spans from $147 to $1F5, with some of that being variable space, so it's not that much to learn. Some instruction snippets push stuff and other instructions pop stuff, and some do both. It's RAM-based, so it's nothing that would have to be adhered to strictly.

    I was thinking that the bytecodes could be made dynamic at compile time, so that only those used need be included in the interpreter. That would shorten the descriptor table and eliminate unused snippets. Right now the whole interpreter is just over 5KB. Most programs would use way less than that. The advantage of keeping the whole interpreter resident leaves the door open for dynamic overlays.
  • Mike GreenMike Green Posts: 22,923
    edited 2013-08-24 - 10:55:01
    I would also hope that the Spin2 instruction set is documented so it could be used as a target for other languages. I would also put a "bid" in for similar documentation for the Prop1 Spin instruction set. I know a lot has been "reverse engineered" (Spin1), but it would be nice to have it organized and vetted / filled in for the same purpose.

    Sure, most of the Spin2 interpreter is hub RAM based and there's some potential benefit in trimming down the instruction set on an application by application basis, but then there's no run-time commonality from application to application ... not a bad thing if you want to think of the interpreter like a run-time library with the Spin2 compiler managing the packaging of the interpreter with the program and the assumption at run-time that there will always be a native interpreter or other "main" native program that will be given control initially. This is opposite of what Spin has assumed on the Prop1, that there's a built-in Spin machine that gets control initially and can surrender control to one of the native processors.

    I think the idea of multiple interpreters (for Spin2 or C or whatever) is fine, but the conceptual base then needs to shift to the native instruction set as the primary or initial program to be given control when booted.
  • cgraceycgracey Posts: 11,925
    edited 2013-08-24 - 11:18:55
    Mike Green wrote: »
    I would also hope that the Spin2 instruction set is documented so it could be used as a target for other languages. I would also put a "bid" in for similar documentation for the Prop1 Spin instruction set. I know a lot has been "reverse engineered" (Spin1), but it would be nice to have it organized and vetted / filled in for the same purpose.

    Sure, most of the Spin2 interpreter is hub RAM based and there's some potential benefit in trimming down the instruction set on an application by application basis, but then there's no run-time commonality from application to application ... not a bad thing if you want to think of the interpreter like a run-time library with the Spin2 compiler managing the packaging of the interpreter with the program and the assumption at run-time that there will always be a native interpreter or other "main" native program that will be given control initially. This is opposite of what Spin has assumed on the Prop1, that there's a built-in Spin machine that gets control initially and can surrender control to one of the native processors.

    I think the idea of multiple interpreters (for Spin2 or C or whatever) is fine, but the conceptual base then needs to shift to the native instruction set as the primary or initial program to be given control when booted.

    I think that as time goes by and the interpreter is improved, there will be many changes to it, making it a moving target for documentation. I think what you said about shifting focus to the native instruction set is the way to go. Spin2 is writ in water.
  • Mike GreenMike Green Posts: 22,923
    edited 2013-08-24 - 12:05:15
    By packaging the interpreter as part of the run-time library and making the assumption that some kind of native program is what is initially started by the bootstrap, the bootstrap doesn't care what version of the Spin interpreter or C interpreter or whatever is packaged as part of the program. Our programming systems and operating systems don't care which run-time library is packaged with the program, only that the format of the program on the storage device is known and any calls to ROM are at permanently standard locations and follow documented calling conventions.
  • jazzedjazzed Posts: 11,803
    edited 2013-08-24 - 16:04:51
    SPIN2 should not be limited to Propeller.

    With the bigger address space, SPIN2 can become a general purpose programming language.

    Someone will figure out how to make it interact easily with OS resources and GUI window managers like TK.

    Chip, you may as well face it, and accept it now so SPIN2 can grow ....
  • David BetzDavid Betz Posts: 13,589
    edited 2013-08-24 - 16:46:33
    jazzed wrote: »
    SPIN2 should not be limited to Propeller.

    With the bigger address space, SPIN2 can become a general purpose programming language.

    Someone will figure out how to make it interact easily with OS resources and GUI window managers like TK.

    Chip, you may as well face it, and accept it now so SPIN2 can grow ....
    What is the size of the address space in Spin2? I thought it was only the 128k of hub memory in the P2. Or is it using full 32 bit addresses?
  • jazzedjazzed Posts: 11,803
    edited 2013-08-24 - 17:16:26
    David Betz wrote: »
    What is the size of the address space in Spin2? I thought it was only the 128k of hub memory in the P2. Or is it using full 32 bit addresses?

    Good question ;-)
  • Cluso99Cluso99 Posts: 15,536
    edited 2013-08-24 - 17:32:00
    Spin2 looks good on a quick look.

    I would like to see better docs so that it could become part of a library to support other languages too. IOW I would like to see a BASIC frontend, and I would like to see a variant of Spin where indentation is not forced (ie using endif, endrepeat/endloop, endcase, or the horrid "{" and "}" from C etc.). Switching between the forced indentation and others should even be possible on the fly by extending the editor. Don't get me wrong, I love the enforced identation, but so many don't like it I think it would be great to provide an alternative.

    The overhead of testing to see whether small "snippets" are already loaded is a large percentage of the load time, so as others have said, is detrimental to the timing and a waste of code space.

    By being "soft", improvements can be made. Great times ahead.

    Thanks again Chip, well done!
    My Prop boards: P8XBlade2 , RamBlade , CpuBlade , TriBlade
    P1 Prop OS (also see Sphinx, PropDos, PropCmd, Spinix)
    Website: www.clusos.com
    P1: Tools (Index) , Emulators (Index) , ZiCog (Z80)
    P2: Tools & Code , Tricks & Traps
  • localrogerlocalroger Posts: 3,290
    edited 2013-08-24 - 20:03:16
    cgracey wrote: »
    This (identifying the chip position on wafer post hoc -- LR) is not really possible, since the mask set is stepped along the wafer for lithography purposes, repeating the same image over and over. There is no way to introduce any unique patterns per chip.

    Fascinating... I suppose I always envisioned that wafer being exposed all at once by a single great big mask for each step. I am amazed at the multiple disciplines you had to master to make these chips real. I might have thought to design my own CPU and maybe give it cores but the PLL's and counter-timers are genius totally out of my pay grade and the translation to IC mask HEAD EXPLODES.
  • Beau SchwabeBeau Schwabe Posts: 6,416
    edited 2013-08-24 - 21:07:20
    As far as ID'ing the location of each die on a wafer, everything comes at a cost. Laser etching is an option but not cost effective for our operation. Expanding that, the laser etching could simply be an enumerated mark on the individual dies or strategically aligned to readable fuses from the chip itself during normal operation of the chip, but again cost prohibitive to our focused efforts.


    Beau Schwabe --- Robotics applications- PCB design, embedded software, and mechanical
    Oklahoma Robotics -

    www.Kit-Start.com - bschwabe@Kit-Start.com ෴෴ www.BScircuitDesigns.com - icbeau@bscircuitdesigns.com ෴෴

  • KeithEKeithE Posts: 955
    edited 2013-08-24 - 21:49:51
    As far as ID'ing the location of each die on a wafer, everything comes at a cost. Laser etching is an option but not cost effective for our operation. Expanding that, the laser etching could simply be an enumerated mark on the individual dies or strategically aligned to readable fuses from the chip itself during normal operation of the chip, but again cost prohibitive to our focused efforts.

    If you did wafer probe then you could burn fuses to uniquely id each die during test, and keep a record of their locations. Some companies do this. (I could see the military wanting tracking like that, but have no experience with miltary electronics.) But it doesn't always make sense to do wafer probe even if you're setup to do it. Someone needs to run the numbers to see if it pays off. (e.g. not packaging bad parts.) For WLBGAs you typically test in wafer form (and hopefully several die in parallel), and then typically no testing is done after dicing the wafer. The chips that I've worked on lately are WLBGAs, and you can see the ATE pass/fail results mapped onto an image of the wafer.
  • Heater.Heater. Posts: 21,213
    edited 2013-08-25 - 02:32:34
    Jazzed,
    With the bigger address space, SPIN2 can become a general purpose programming language.
    That gives me a wonderfully evil idea. Retarget Spin for the XMOS devices so those poor users have something easier to work with:)

    How do you imagine this working:

    1) Compile Spin to native code for your target, say x86, ARM etc? Like a C compiler does.

    2) Compile Spin to the standard byte codes and have a native, x86, ARM.., program interpret them? Like a JVM.

    One thing that worries me with Spin as a general purpose language is that I'm used to the tight and seamless integration of the high level Spin syntax with the low level PASM. So much so that in my mind that Spin is Spin + PASM. Which leads to:

    3) Adopt the instruction set of the target machine for the PASM parts? Results in non-portable hence non-general purpose use.

    4) Keep the to PASM instruction set? Requires a Prop simulator on the target.

    Interesting idea...
  • GadgetmanGadgetman Posts: 2,436
    edited 2013-08-25 - 02:48:17
    One way of tracking yield of the different locations on the wafer could be to have the cut chips, then the packaged chips placed in a carrier with the same layout as the wafer. As long as the chips are always placed correctly, you'd know which position they came from.
    Of course, no one will do that...

    The other option is to make certain that when the wafer is cut, that the individual chips are always picked in the same order, and that they use a new tray for each wafer.
    (This assumes that when the chips are packaged, they're always picked in a predictable order off the tray, and also placed in a known order on the output tray)

    The problem is that it'll probably cost too much in man-hours to plan and verify this to make it worthwhile.
    (Unless there's one or more chips with the same faults from every wafer)
  • Heater.Heater. Posts: 21,213
    edited 2013-08-25 - 02:53:51
    Remind me again, why on earth do we care which parts of the wafer have the highest yield?
  • nutsonnutson Posts: 241
    edited 2013-08-25 - 03:28:19
    Because the main struggle in a wafer fab is to get yields up to an acceptable level. Information on the location and type of defects is vital to improving each process step. And almost all processing steps (25-30 times lithography, 10-15 times material deposition) have defects and inaccuracies that have a distribution over the the wafer surface. If a production line exhibits bad yields a team of process engineers will step in, try to pin down the problem ( "process step 6 aluminium oxyde deposition has a too low thickness on the top right side of the wafer") and adjust the equipment for that step.
Sign In or Register to comment.