	.module main

	;; define code segments link order
	.area CODE (CODE)
	.area CSEG (CODE)
	.area GSINIT (CODE)
	.area GSINIT2 (CODE)

	;; -----------------------------------------------------

	;; special function registers (which are not predefined)
	dpl0    = 0x82
	dph0    = 0x83
	dpl1    = 0x84
	dph1    = 0x85
	dps     = 0x86
	ckcon   = 0x8E
	spc_fnc = 0x8F
	exif    = 0x91
	mpage   = 0x92
	scon0   = 0x98
	sbuf0   = 0x99
	scon1   = 0xC0
	sbuf1   = 0xC1
	eicon   = 0xD8
	eie     = 0xE8
	eip     = 0xF8

	;; anchor xdata registers
	IN0BUF		= 0x7F00
	OUT0BUF		= 0x7EC0
	IN1BUF		= 0x7E80
	OUT1BUF		= 0x7E40
	IN2BUF		= 0x7E00
	OUT2BUF		= 0x7DC0
	IN3BUF		= 0x7D80
	OUT3BUF		= 0x7D40
	IN4BUF		= 0x7D00
	OUT4BUF		= 0x7CC0
	IN5BUF		= 0x7C80
	OUT5BUF		= 0x7C40
	IN6BUF		= 0x7C00
	OUT6BUF		= 0x7BC0
	IN7BUF		= 0x7B80
	OUT7BUF		= 0x7B40
	SETUPBUF	= 0x7FE8
	SETUPDAT	= 0x7FE8

	EP0CS		= 0x7FB4
	IN0BC		= 0x7FB5
	IN1CS		= 0x7FB6
	IN1BC		= 0x7FB7
	IN2CS		= 0x7FB8
	IN2BC		= 0x7FB9
	IN3CS		= 0x7FBA
	IN3BC		= 0x7FBB
	IN4CS		= 0x7FBC
	IN4BC		= 0x7FBD
	IN5CS		= 0x7FBE
	IN5BC		= 0x7FBF
	IN6CS		= 0x7FC0
	IN6BC		= 0x7FC1
	IN7CS		= 0x7FC2
	IN7BC		= 0x7FC3
	OUT0BC		= 0x7FC5
	OUT1CS		= 0x7FC6
	OUT1BC		= 0x7FC7
	OUT2CS		= 0x7FC8
	OUT2BC		= 0x7FC9
	OUT3CS		= 0x7FCA
	OUT3BC		= 0x7FCB
	OUT4CS		= 0x7FCC
	OUT4BC		= 0x7FCD
	OUT5CS		= 0x7FCE
	OUT5BC		= 0x7FCF
	OUT6CS		= 0x7FD0
	OUT6BC		= 0x7FD1
	OUT7CS		= 0x7FD2
	OUT7BC		= 0x7FD3

	IVEC		= 0x7FA8
	IN07IRQ		= 0x7FA9
	OUT07IRQ	= 0x7FAA
	USBIRQ		= 0x7FAB
	IN07IEN		= 0x7FAC
	OUT07IEN	= 0x7FAD
	USBIEN		= 0x7FAE
	USBBAV		= 0x7FAF
	BPADDRH		= 0x7FB2
	BPADDRL		= 0x7FB3

	SUDPTRH		= 0x7FD4
	SUDPTRL		= 0x7FD5
	USBCS		= 0x7FD6
	TOGCTL		= 0x7FD7
	USBFRAMEL	= 0x7FD8
	USBFRAMEH	= 0x7FD9
	FNADDR		= 0x7FDB
	USBPAIR		= 0x7FDD
	IN07VAL		= 0x7FDE
	OUT07VAL	= 0x7FDF
	AUTOPTRH	= 0x7FE3
	AUTOPTRL	= 0x7FE4
	AUTODATA	= 0x7FE5

	;; isochronous endpoints. only available if ISODISAB=0

	OUT8DATA	= 0x7F60
	OUT9DATA	= 0x7F61
	OUT10DATA	= 0x7F62
	OUT11DATA	= 0x7F63
	OUT12DATA	= 0x7F64
	OUT13DATA	= 0x7F65
	OUT14DATA	= 0x7F66
	OUT15DATA	= 0x7F67

	IN8DATA		= 0x7F68
	IN9DATA		= 0x7F69
	IN10DATA	= 0x7F6A
	IN11DATA	= 0x7F6B
	IN12DATA	= 0x7F6C
	IN13DATA	= 0x7F6D
	IN14DATA	= 0x7F6E
	IN15DATA	= 0x7F6F

	OUT8BCH		= 0x7F70
	OUT8BCL		= 0x7F71
	OUT9BCH		= 0x7F72
	OUT9BCL		= 0x7F73
	OUT10BCH	= 0x7F74
	OUT10BCL	= 0x7F75
	OUT11BCH	= 0x7F76
	OUT11BCL	= 0x7F77
	OUT12BCH	= 0x7F78
	OUT12BCL	= 0x7F79
	OUT13BCH	= 0x7F7A
	OUT13BCL	= 0x7F7B
	OUT14BCH	= 0x7F7C
	OUT14BCL	= 0x7F7D
	OUT15BCH	= 0x7F7E
	OUT15BCL	= 0x7F7F

	OUT8ADDR	= 0x7FF0
	OUT9ADDR	= 0x7FF1
	OUT10ADDR	= 0x7FF2
	OUT11ADDR	= 0x7FF3
	OUT12ADDR	= 0x7FF4
	OUT13ADDR	= 0x7FF5
	OUT14ADDR	= 0x7FF6
	OUT15ADDR	= 0x7FF7
	IN8ADDR		= 0x7FF8
	IN9ADDR		= 0x7FF9
	IN10ADDR	= 0x7FFA
	IN11ADDR	= 0x7FFB
	IN12ADDR	= 0x7FFC
	IN13ADDR	= 0x7FFD
	IN14ADDR	= 0x7FFE
	IN15ADDR	= 0x7FFF

	ISOERR		= 0x7FA0
	ISOCTL		= 0x7FA1
	ZBCOUNT		= 0x7FA2
	INISOVAL	= 0x7FE0
	OUTISOVAL	= 0x7FE1
	FASTXFR		= 0x7FE2

	;; CPU control registers

	CPUCS		= 0x7F92

	;; IO port control registers

	PORTACFG	= 0x7F93
	PORTBCFG	= 0x7F94
	PORTCCFG	= 0x7F95
	OUTA		= 0x7F96
	OUTB		= 0x7F97
	OUTC		= 0x7F98
	PINSA		= 0x7F99
	PINSB		= 0x7F9A
	PINSC		= 0x7F9B
	OEA		= 0x7F9C
	OEB		= 0x7F9D
	OEC		= 0x7F9E

	;; I2C controller registers

	I2CS		= 0x7FA5
	I2DAT		= 0x7FA6

	;; FPGA defines
	XC4K_IRLENGTH	= 3
	XC4K_EXTEST	= 0
	XC4K_PRELOAD	= 1
	XC4K_CONFIGURE	= 5
	XC4K_BYPASS	= 7

	FPGA_CONFIGSIZE		= 11876
	FPGA_BOUND		= 344			; in bits
	FPGA_BOUND_BYTES	= ((FPGA_BOUND-1)/8)
	FPGA_BOUND_RESIDUE	= (FPGA_BOUND-8*FPGA_BOUND_BYTES)
	FPGA_BOUND_BSIZE	= ((FPGA_BOUND+7)/8)

	
	;; -----------------------------------------------------

	.area CODE (CODE)
	ljmp	startup
	ljmp	int0_isr
	.ds	5
	ljmp	timer0_isr
	.ds	5
	ljmp	int1_isr
	.ds	5
	ljmp	timer1_isr
	.ds	5
	ljmp	ser0_isr
	.ds	5
	ljmp	timer2_isr
	.ds	5
	ljmp	resume_isr
	.ds	5
	ljmp	ser1_isr
	.ds	5
	ljmp	usb_isr
	.ds	5
	ljmp	i2c_isr
	.ds	5
	ljmp	int4_isr
	.ds	5
	ljmp	int5_isr
	.ds	5
	ljmp	int6_isr
	.ds	0x8a

stringserial:
	.db	stringserialsz		; bLength
	.db	USB_DT_STRING		; bDescriptorType
	.db	'0,0,'0,0,'0,0,'0,0,'0,0,'1,0
stringserialsz = . - stringserial
	.ds	0x10-stringserialsz

usb_isr:
	ljmp	usb_sudav_isr
	.ds	1
	ljmp	usb_sof_isr
	.ds	1
	ljmp	usb_sutok_isr
	.ds	1
	ljmp	usb_suspend_isr
	.ds	1
	ljmp	usb_usbreset_isr
	.ds	1
	reti
	.ds	3
	ljmp	usb_ep0in_isr
	.ds	1
	ljmp	usb_ep0out_isr
	.ds	1
	ljmp	usb_ep1in_isr
	.ds	1
	ljmp	usb_ep1out_isr
	.ds	1
	ljmp	usb_ep2in_isr
	.ds	1
	ljmp	usb_ep2out_isr
	.ds	1
	ljmp	usb_ep3in_isr
	.ds	1
	ljmp	usb_ep3out_isr
	.ds	1
	ljmp	usb_ep4in_isr
	.ds	1
	ljmp	usb_ep4out_isr
	.ds	1
	ljmp	usb_ep5in_isr
	.ds	1
	ljmp	usb_ep5out_isr
	.ds	1
	ljmp	usb_ep6in_isr
	.ds	1
	ljmp	usb_ep6out_isr
	.ds	1
	ljmp	usb_ep7in_isr
	.ds	1
	ljmp	usb_ep7out_isr

	;; -----------------------------------------------------

	.area	OSEG (OVR,DATA)
	.area	BSEG (BIT)


	.area	ISEG (DATA)
stack:		.ds	0x80

	.area	DSEG (DATA)
errcode:	.ds	1
errval:		.ds	1
cfgcount:	.ds	2
leddiv:		.ds	1
irqcount:	.ds	1
ctrlcode:	.ds	1
ctrladdr:	.ds	2
ctrllen:	.ds	2

	.area	XSEG (DATA)
fpgabound:	.db	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
		.db	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
		.db	0xff,0xcf,0xff,0xff,0xff,0xff,0xff,0xff
		.db	0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff
		.db	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
		.db	0xff,0xff,0xff,0xff

	.area	GSINIT (CODE)
startup:
	mov	sp,#stack	; -1
	clr	a
	mov	psw,a
	mov	dps,a
	;lcall	__sdcc_external_startup
	;mov	a,dpl0
	;jz	__sdcc_init_data
	;ljmp	__sdcc_program_startup
__sdcc_init_data:

	.area	GSINIT2 (CODE)

	ar2 = 0x02
	ar3 = 0x03
	ar4 = 0x04
	ar5 = 0x05
	ar6 = 0x06
	ar7 = 0x07
	ar0 = 0x00
	ar1 = 0x01

__sdcc_program_startup:
	;; assembler code startup
	clr	a
	mov	errcode,a
	mov	errval,a
	mov	cfgcount,a
	mov	cfgcount+1,a
 	mov	irqcount,a
 	mov	ctrlcode,a
	;; some indirect register setup
	mov	ckcon,#0x31	; one external wait state, to avoid chip bugs
	;; Timer setup:
	;; timer 0: LED blink    : T0M=0, CT0=0, MODE0=1
	;; timer 1: Baudrate gen : T1M=1, CT1=0, MODE1=2
	mov	tmod,#0x21
	mov	tcon,#0x55	; INT0/INT1 edge
	mov	th1,#256-156	; 1200 bauds
	mov	pcon,#0		; SMOD0=0
	;; init USB subsystem
	mov	dptr,#ISOCTL
	mov	a,#1		; disable ISO endpoints
	movx	@dptr,a
	mov	dptr,#USBBAV
	mov	a,#1		; enable autovector, disable breakpoint logic
	movx	@dptr,a
	clr	a
	mov	dptr,#INISOVAL
	movx	@dptr,a
	mov	dptr,#OUTISOVAL
	movx	@dptr,a
	mov	dptr,#USBPAIR
	mov	a,#0x9		; pair EP 2&3 for input & output
	movx	@dptr,a
	mov	dptr,#IN07VAL
	mov	a,#0x3		; enable EP0+EP1
	movx	@dptr,a
	mov	dptr,#OUT07VAL
	mov	a,#0x5		; enable EP0+EP2
	movx	@dptr,a
	;; USB:	init endpoint toggles
	mov	dptr,#TOGCTL
	mov	a,#0x12
	movx	@dptr,a
	mov	a,#0x32		; clear EP 2 in toggle
	movx	@dptr,a
	mov	a,#0x02
	movx	@dptr,a
	mov	a,#0x22		; clear EP 2 out toggle
	movx	@dptr,a
	;; configure IO ports
	mov	dptr,#PORTACFG
	mov	a,#0
	movx	@dptr,a
	mov	dptr,#OUTA
	mov	a,#0x80		; set PROG lo
	movx	@dptr,a
	mov	dptr,#OEA
	mov	a,#0xc2		; out: TMS,TDI,PROG  in: DONE
	movx	@dptr,a
	mov	dptr,#PORTBCFG
	mov	a,#0
	movx	@dptr,a
	mov	dptr,#OEB
	mov	a,#0
	movx	@dptr,a
	mov	dptr,#PORTCCFG
	mov	a,#0
	movx	@dptr,a
	mov	dptr,#OUTC
	mov	a,#0x20
	movx	@dptr,a
	mov	dptr,#OEC
	mov	a,#0x2e		; out: LEDCON,LEDSTA,TCK,INIT  in: TDO
	movx	@dptr,a
	;; enable interrupts
	mov	ie,#0x82	; enable timer 0 int
	mov	eie,#0x01	; enable USB interrupts
	mov	dptr,#USBIEN
	mov	a,#1		; enable SUDAV interrupt
	movx	@dptr,a
	mov	dptr,#IN07IEN
	mov	a,#1		; enable EP0 interrupt
	movx	@dptr,a
	mov	dptr,#OUT07IEN
	mov	a,#3		; enable EP0+EP1 interrupt
	movx	@dptr,a
	;; initialize UART 0 for config loading
	mov	scon0,#0x20	; mode 0, CLK24/4
	mov	sbuf0,#0xff
	;; initialize EP1 IN (irq)
	lcall	fillusbintr

	;; some short delay
	mov	dptr,#OUTA
	mov	a,#0x82		; set PROG hi
	movx	@dptr,a
	mov	dptr,#PINSA
	movx	a,@dptr
	jnb	acc.2,1$
	;; DONE stuck high
	mov	errcode,#0x80
	ljmp	fpgaerr
1$:	lcall	jtag_reset_tap
	mov	r2,#5
	mov	r3,#0
	mov	r4,#6
	lcall	jtag_shiftout	; enter SHIFT-IR state
	mov	r2,#8
	mov	r3,#0
	mov	r4,#0
	lcall	jtag_shiftout	; assume max. 8bit IR
	mov	r2,#8
	mov	r3,#1
	mov	r4,#0
	lcall	jtag_shift	; shift in a single bit
	mov	a,#-(1<<XC4K_IRLENGTH)
	add	a,r7
	jz	2$
	;; JTAG instruction register error
	mov	errcode,#0x81
	mov	errval,r7
	ljmp	fpgaerr
2$:	mov	r2,#XC4K_IRLENGTH+4
	mov	r3,#XC4K_PRELOAD
	mov	r4,#7<<(XC4K_IRLENGTH-1)
	lcall	jtag_shiftout	; shift in PRELOAD insn, goto SHIFTDR state
	lcall	boundary
	mov	r2,#5
	mov	r3,#0
	mov	r4,#7
	lcall	jtag_shiftout	; goto SHIFTIR state
	mov	r2,#XC4K_IRLENGTH+2
	mov	r3,#XC4K_EXTEST
	mov	r4,#3<<(XC4K_IRLENGTH-1)
	lcall	jtag_shiftout	; shift in EXTEST insn, goto RUNTEST/IDLE state
boundaryloop1:
	mov	errcode,#0x20
boundaryloop:
	mov	a,errcode
	cjne	a,#0x21,boundaryloop
	mov	r2,#3
	mov	r3,#0
	mov	r4,#1
	lcall	jtag_shiftout
	lcall	boundary
	mov	r2,#2
	mov	r3,#0
	mov	r4,#1
	lcall	jtag_shiftout
	sjmp	boundaryloop1

fpgaerr:
	sjmp	fpgaerr

	.area	CSEG (CODE)
	ar2 = 0x02
	ar3 = 0x03
	ar4 = 0x04
	ar5 = 0x05
	ar6 = 0x06
	ar7 = 0x07
	ar0 = 0x00
	ar1 = 0x01

	;; jtag_shift
	;; r2 = num
	;; r3 = tdi
	;; r4 = tms
	;; return: r7 = tdo
jtag_reset_tap:
	mov	r2,#5
	mov	r3,#0
	mov	r4,#0xff
jtag_shiftout:
jtag_shift:
	mov	r6,#1
	mov	r7,#0
1$:	mov	a,#2
	xch	a,r3
	rrc	a
	xch	a,r3
	mov	acc.6,c
	xch	a,r4
	rrc	a
	xch	a,r4
	mov	acc.7,c
	mov	dptr,#OUTA
	movx	@dptr,a
	mov	dptr,#PINSC
	movx	a,@dptr
	jnb	acc.0,2$
	mov	a,r6
	orl	ar7,a
2$:	mov	dptr,#OUTC
	movx	a,@dptr
	setb	acc.1
	movx	@dptr,a
	clr	acc.1
	movx	@dptr,a
	mov	a,r6
	rl	a
	mov	r6,a
	djnz	r2,1$
	ret

boundary:
	mov	dps,#0
	mov	dptr,#fpgabound
	mov	r0,#FPGA_BOUND_BYTES
1$:	mov	r2,#8
	movx	a,@dptr
	mov	r3,a
	mov	r4,#0	
	push	dpl0
	push	dph0
	lcall	jtag_shift
	pop	dph0
	pop	dpl0
	mov	a,r7
	movx	@dptr,a
	inc	dptr
	djnz	r0,1$
	mov	r2,#FPGA_BOUND_RESIDUE
	movx	a,@dptr
	mov	r3,a
	mov	r4,#(1<<(FPGA_BOUND_RESIDUE-1))
	push	dpl0
	push	dph0
	lcall	jtag_shift
	pop	dph0
	pop	dpl0
	mov	a,r7
	movx	@dptr,a
	ret
	
	;; ------------------ interrupt handlers ------------------------

int0_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	clr	tcon+1
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

timer0_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	clr	tcon+5
	;; handle interrupt
	inc	leddiv
	mov	a,leddiv
	anl	a,#7
	jnz	0$
	mov	dptr,#OUTC
	movx	a,@dptr
	xrl	a,#0x08
	movx	@dptr,a
0$:
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

int1_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	clr	tcon+3
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

timer1_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	clr	tcon+7
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

ser0_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	clr	scon0+0
	clr	scon0+1
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

timer2_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	clr	t2con+7
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

resume_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	clr	eicon+4
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

ser1_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	clr	scon1+0
	clr	scon1+1
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

i2c_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	mov	a,exif
	clr	acc.5
	mov	exif,a
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

int4_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	mov	a,exif
	clr	acc.6
	mov	exif,a
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

int5_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	mov	a,exif
	clr	acc.7
	mov	exif,a
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

int6_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	clr	eicon+3
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

xmemread::
	mov	a,ctrllen
	orl	a,ctrllen+1
	jnz	4$
2$:	clr	a
	mov	ctrlcode,a
	mov	a,#2		; ack control transfer
	mov	dptr,#EP0CS
	movx	@dptr,a
	ret
4$:	mov	a,ctrllen
	mov	r7,a
	add	a,#-64
	mov	ctrllen,a
	mov	a,ctrllen+1
	addc	a,#0xff
	jc	0$
	clr	a
	mov	ctrllen,a
	mov	ctrllen+1,a
	mov	a,r7
	jz	2$
	sjmp	1$
0$:	mov	ctrllen+1,a
	mov	a,#64
1$:	mov	r7,a
	mov	r0,a
	mov	dpl0,ctrladdr
	mov	dph0,ctrladdr+1
	mov	dps,#1
	mov	dptr,#IN0BUF
	dec	dps
3$:	movx	a,@dptr
	inc	dptr
	inc	dps
	movx	@dptr,a
	inc	dptr
	dec	dps
	djnz	r0,3$
	mov	ctrladdr,dpl0
	mov	ctrladdr+1,dph0
	mov	a,r7
	mov	dptr,#IN0BC
	movx	@dptr,a
	ret

usb_sudav_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	dpl1
	push	dph1
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	push	ar0
	push	ar7
	;; clear interrupt
	mov	a,exif
	clr	acc.4
	mov	exif,a
	mov	dptr,#USBIRQ
	mov	a,#0x01
	movx	@dptr,a
	;; handle interrupt
	mov	ctrlcode,#0		; reset control out code
	mov	dptr,#SETUPDAT+1
	movx	a,@dptr			; bRequest field
	;; vendor specific commands
	;; 0xb1
	cjne	a,#0xb1,cmdnotb1
	mov	dptr,#SETUPDAT		; bRequestType == 0xc0
	movx	a,@dptr
	cjne	a,#0xc0,setupstallb1
	mov	dptr,#IN0BUF
	mov	a,errcode
	movx	@dptr,a
	inc	dptr
	mov	a,errval
	movx	@dptr,a
	inc	dptr
	mov	a,sp

;;; xxxx
	push	dpl0
	push	dph0
	mov	dptr,#OUT07VAL
	movx	a,@dptr
	pop	dph0
	pop	dpl0
;;; xxxx
	
	movx	@dptr,a
	inc	dptr
	mov	a,#0

;;; xxxx
	push	dpl0
	push	dph0
	mov	dptr,#OUT2CS
	movx	a,@dptr
	pop	dph0
	pop	dpl0
;;; xxxx
	
	movx	@dptr,a
	inc	dptr
	mov	dptr,#IN0BC
	mov	a,#4
	movx	@dptr,a
	ljmp	setupack
setupstallb1:
	ljmp	setupstall
cmdnotb1:
	;; 0xb2
	cjne	a,#0xb2,cmdnotb2
	mov	dptr,#SETUPDAT		; bRequestType == 0xc0
	movx	a,@dptr
	cjne	a,#0xc0,setupstallb2
	mov	dptr,#IN0BUF
	mov	a,errcode
	movx	@dptr,a
	inc	dptr
	mov	a,errval
	movx	@dptr,a
	inc	dptr
	mov	a,cfgcount
	movx	@dptr,a
	inc	dptr
	mov	a,cfgcount+1
	movx	@dptr,a
	inc	dptr
	mov	a,irqcount
	movx	@dptr,a
	mov	dptr,#IN0BC
	mov	a,#5
	movx	@dptr,a
	inc	irqcount
	ljmp	setupack
setupstallb2:
	ljmp	setupstall
cmdnotb2:
	;; 0xb8
	cjne	a,#0xb8,cmdnotb8
	mov	a,errcode
	cjne	a,#0x20,setupstallb2
	mov	dptr,#SETUPDAT+6
	movx	a,@dptr
	cjne	a,#FPGA_BOUND_BSIZE,setupstallb2
	inc	dptr
	movx	a,@dptr
	cjne	a,#FPGA_BOUND_BSIZE>>8,setupstallb2
	mov	ctrladdr,#fpgabound
	mov	ctrladdr+1,#fpgabound>>8
	mov	ctrllen,#FPGA_BOUND_BSIZE
	mov	ctrllen+1,#FPGA_BOUND_BSIZE>>8
	mov	dptr,#SETUPDAT		; bRequestType == 0x40
	movx	a,@dptr
	cjne	a,#0x40,1$
	mov	ctrlcode,#1
	mov	dptr,#OUT0BC
	movx	@dptr,a
	ljmp	endusbisr
1$:	cjne	a,#0xc0,setupstallb8	; bRequestType == 0xc0
	mov	ctrlcode,#2
	lcall	xmemread
	ljmp	endusbisr
setupstallb8:
	ljmp	setupstall
cmdnotb8:
	;; 0xb9
	cjne	a,#0xb9,cmdnotb9
	mov	dptr,#SETUPDAT		; bRequestType == 0xc0
	movx	a,@dptr
	cjne	a,#0xc0,setupstallb8
	mov	a,errcode
	cjne	a,#0x20,setupstallb8
	mov	errcode,#0x21
	mov	dptr,#IN0BC
	clr	a
	movx	@dptr,a
	ljmp	setupack
cmdnotb9:
	;; 0xc8
	cjne	a,#0xc8,cmdnotc8
	mov	dptr,#SETUPDAT	; bRequestType == 0xc0
	movx	a,@dptr
	cjne	a,#0xc0,setupstallc8
	mov	a,#5
	mov	dptr,#IN0BUF
	movx	@dptr,a
	mov	dptr,#IN0BC
	mov	a,#1
	movx	@dptr,a
	ljmp	setupack
setupstallc8:
	ljmp	setupstall
cmdnotc8:
	;; 0xc9
	cjne	a,#0xc9,cmdnotc9
	mov	dptr,#SETUPDAT	; bRequestType == 0xc0
	movx	a,@dptr
	cjne	a,#0xc0,setupstallc9
	mov	dptr,#IN0BUF
	inc	dps
	mov	dptr,#stringserial+2
	mov	r7,#(stringserialsz-2)/2
0$:	movx	a,@dptr
	inc	dptr
	inc	dptr
	dec	dps
	movx	@dptr,a
	inc	dptr
	inc	dps
	djnz	r7,0$
	dec	dps
	mov	a,#(stringserialsz-2)/2
	mov	dptr,#IN0BC
	movx	@dptr,a
	ljmp	setupack
setupstallc9:
	ljmp	setupstall
cmdnotc9:
	;; unknown commands fall through to setupstall

setupstall:
	mov	a,#3
	sjmp	endsetup
setupack:
	mov	a,#2
endsetup:
	mov	dptr,#EP0CS
	movx	@dptr,a
endusbisr:
	;; epilogue
	pop	ar7
	pop	ar0
	pop	dps
	pop	psw
	pop	dph1
	pop	dpl1
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

usb_sof_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	mov	a,exif
	clr	acc.4
	mov	exif,a
	mov	dptr,#USBIRQ
	mov	a,#0x02
	movx	@dptr,a
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti


usb_sutok_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	mov	a,exif
	clr	acc.4
	mov	exif,a
	mov	dptr,#USBIRQ
	mov	a,#0x04
	movx	@dptr,a
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

usb_suspend_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	mov	a,exif
	clr	acc.4
	mov	exif,a
	mov	dptr,#USBIRQ
	mov	a,#0x08
	movx	@dptr,a
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

usb_usbreset_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	mov	a,exif
	clr	acc.4
	mov	exif,a
	mov	dptr,#USBIRQ
	mov	a,#0x10
	movx	@dptr,a
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

usb_ep0in_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	dpl1
	push	dph1
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	push	ar0
	push	ar7
	;; clear interrupt
	mov	a,exif
	clr	acc.4
	mov	exif,a
	mov	dptr,#IN07IRQ
	mov	a,#0x01
	movx	@dptr,a
	;; handle interrupt
	mov	a,ctrlcode
	cjne	a,#2,0$
	lcall	xmemread
	sjmp	ep0inendisr
0$:	mov	dptr,#IN0BC
	clr	a
	movx	@dptr,a
	sjmp	ep0inack

ep0install:
	mov	a,#3
	sjmp	ep0incs
ep0inack:
	mov	a,#2
ep0incs:
	mov	dptr,#EP0CS
	movx	@dptr,a
ep0inendisr:
	;; epilogue
	pop	ar7
	pop	ar0
	pop	dps
	pop	psw
	pop	dph1
	pop	dpl1
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

usb_ep0out_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	dpl1
	push	dph1
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	push	ar7
	;; clear interrupt
	mov	a,exif
	clr	acc.4
	mov	exif,a
	mov	dptr,#OUT07IRQ
	mov	a,#0x01
	movx	@dptr,a
	;; handle interrupt
	mov	a,ctrlcode		; check control code
	cjne	a,#0x01,ep0outstall
	;; write to external memory
	mov	dptr,#OUT0BC
	movx	a,@dptr
	jz	0$
	mov	r7,a
	clr	c
	mov	a,ctrllen
	subb	a,r7
	mov	ctrllen,a
	mov	a,ctrllen+1
	subb	a,#0
	mov	ctrllen+1,a
	jc	ep0outstall
	mov	dptr,#OUT0BUF
	mov	dpl1,ctrladdr
	mov	dph1,ctrladdr+1
1$:	movx	a,@dptr
	inc	dptr
	inc	dps
	movx	@dptr,a
	inc	dptr
	dec	dps
	djnz	r7,1$
	mov	ctrladdr,dpl1
	mov	ctrladdr+1,dph1
0$:	mov	a,ctrllen
	orl	a,ctrllen+1
	jz	ep0outack
	sjmp	ep0outendisr

ep0outstall:
	mov	ctrlcode,#0
	mov	a,#3
	sjmp	ep0outcs
ep0outack:
	mov	ctrlcode,#0
	mov	a,#2
ep0outcs:
	mov	dptr,#EP0CS
	movx	@dptr,a
ep0outendisr:
	;; epilogue
	pop	ar7
	pop	dps
	pop	psw
	pop	dph1
	pop	dpl1
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

fillusbintr::
	mov	dptr,#IN1BUF
	mov	a,errcode
	movx	@dptr,a
	inc	dptr
	mov	a,errval
	movx	@dptr,a
	inc	dptr
	mov	a,cfgcount
	movx	@dptr,a
	inc	dptr
	mov	a,cfgcount+1
	movx	@dptr,a
	inc	dptr
	mov	a,irqcount
	movx	@dptr,a
	mov	dptr,#IN1BC
	mov	a,#5
	movx	@dptr,a
	inc	irqcount
	ret

usb_ep1in_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	mov	a,exif
	clr	acc.4
	mov	exif,a
	mov	dptr,#IN07IRQ
	mov	a,#0x02
	movx	@dptr,a
	;; handle interrupt
	lcall	fillusbintr
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

usb_ep1out_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	mov	a,exif
	clr	acc.4
	mov	exif,a
	mov	dptr,#OUT07IRQ
	mov	a,#0x02
	movx	@dptr,a
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

usb_ep2in_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	mov	a,exif
	clr	acc.4
	mov	exif,a
	mov	dptr,#IN07IRQ
	mov	a,#0x04
	movx	@dptr,a
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

usb_ep2out_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	mov	a,exif
	clr	acc.4
	mov	exif,a
	mov	dptr,#OUT07IRQ
	mov	a,#0x04
	movx	@dptr,a
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

usb_ep3in_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	mov	a,exif
	clr	acc.4
	mov	exif,a
	mov	dptr,#IN07IRQ
	mov	a,#0x08
	movx	@dptr,a
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

usb_ep3out_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	mov	a,exif
	clr	acc.4
	mov	exif,a
	mov	dptr,#OUT07IRQ
	mov	a,#0x08
	movx	@dptr,a
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

usb_ep4in_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	mov	a,exif
	clr	acc.4
	mov	exif,a
	mov	dptr,#IN07IRQ
	mov	a,#0x10
	movx	@dptr,a
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

usb_ep4out_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	mov	a,exif
	clr	acc.4
	mov	exif,a
	mov	dptr,#OUT07IRQ
	mov	a,#0x10
	movx	@dptr,a
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

usb_ep5in_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	mov	a,exif
	clr	acc.4
	mov	exif,a
	mov	dptr,#IN07IRQ
	mov	a,#0x20
	movx	@dptr,a
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

usb_ep5out_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	mov	a,exif
	clr	acc.4
	mov	exif,a
	mov	dptr,#OUT07IRQ
	mov	a,#0x20
	movx	@dptr,a
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

usb_ep6in_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	mov	a,exif
	clr	acc.4
	mov	exif,a
	mov	dptr,#IN07IRQ
	mov	a,#0x40
	movx	@dptr,a
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

usb_ep6out_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	mov	a,exif
	clr	acc.4
	mov	exif,a
	mov	dptr,#OUT07IRQ
	mov	a,#0x40
	movx	@dptr,a
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

usb_ep7in_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	mov	a,exif
	clr	acc.4
	mov	exif,a
	mov	dptr,#IN07IRQ
	mov	a,#0x80
	movx	@dptr,a
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

usb_ep7out_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	mov	a,exif
	clr	acc.4
	mov	exif,a
	mov	dptr,#OUT07IRQ
	mov	a,#0x80
	movx	@dptr,a
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

	
	;; -----------------------------------------------------
	;; USB descriptors
	;; -----------------------------------------------------

	;; Device and/or Interface Class codes
	USB_CLASS_PER_INTERFACE         = 0
	USB_CLASS_AUDIO                 = 1
	USB_CLASS_COMM                  = 2
	USB_CLASS_HID                   = 3
	USB_CLASS_PRINTER               = 7
	USB_CLASS_MASS_STORAGE          = 8
	USB_CLASS_HUB                   = 9
	USB_CLASS_VENDOR_SPEC           = 0xff

	USB_SUBCLASS_AUDIOCONTROL	= 1
	USB_SUBCLASS_AUDIOSTREAMING	= 2
	
	;; Descriptor types
	USB_DT_DEVICE                   = 0x01
	USB_DT_CONFIG                   = 0x02
	USB_DT_STRING                   = 0x03
	USB_DT_INTERFACE                = 0x04
	USB_DT_ENDPOINT                 = 0x05

	;; Audio Class descriptor types
	USB_DT_AUDIO_UNDEFINED		= 0x20
	USB_DT_AUDIO_DEVICE		= 0x21
	USB_DT_AUDIO_CONFIG		= 0x22
	USB_DT_AUDIO_STRING		= 0x23
	USB_DT_AUDIO_INTERFACE		= 0x24
	USB_DT_AUDIO_ENDPOINT		= 0x25

	USB_SDT_AUDIO_UNDEFINED		= 0x00
	USB_SDT_AUDIO_HEADER		= 0x01
	USB_SDT_AUDIO_INPUT_TERMINAL	= 0x02
	USB_SDT_AUDIO_OUTPUT_TERMINAL	= 0x03
	USB_SDT_AUDIO_MIXER_UNIT	= 0x04
	USB_SDT_AUDIO_SELECTOR_UNIT	= 0x05
	USB_SDT_AUDIO_FEATURE_UNIT	= 0x06
	USB_SDT_AUDIO_PROCESSING_UNIT	= 0x07
	USB_SDT_AUDIO_EXTENSION_UNIT	= 0x08
	
	;; Standard requests
	USB_REQ_GET_STATUS              = 0x00
	USB_REQ_CLEAR_FEATURE           = 0x01
	USB_REQ_SET_FEATURE             = 0x03
	USB_REQ_SET_ADDRESS             = 0x05
	USB_REQ_GET_DESCRIPTOR          = 0x06
	USB_REQ_SET_DESCRIPTOR          = 0x07
	USB_REQ_GET_CONFIGURATION       = 0x08
	USB_REQ_SET_CONFIGURATION       = 0x09
	USB_REQ_GET_INTERFACE           = 0x0A
	USB_REQ_SET_INTERFACE           = 0x0B
	USB_REQ_SYNCH_FRAME             = 0x0C

	;; Audio Class Requests
	USB_REQ_AUDIO_SET_CUR		= 0x01
	USB_REQ_AUDIO_GET_CUR		= 0x81
	USB_REQ_AUDIO_SET_MIN		= 0x02
	USB_REQ_AUDIO_GET_MIN		= 0x82
	USB_REQ_AUDIO_SET_MAX		= 0x03
	USB_REQ_AUDIO_GET_MAX		= 0x83
	USB_REQ_AUDIO_SET_RES		= 0x04
	USB_REQ_AUDIO_GET_RES		= 0x84
	USB_REQ_AUDIO_SET_MEM		= 0x05
	USB_REQ_AUDIO_GET_MEM		= 0x85
	USB_REQ_AUDIO_GET_STAT		= 0xff
	
	;; USB Request Type and Endpoint Directions
	USB_DIR_OUT                     = 0
	USB_DIR_IN                      = 0x80

	USB_TYPE_STANDARD               = (0x00 << 5)
	USB_TYPE_CLASS                  = (0x01 << 5)
	USB_TYPE_VENDOR                 = (0x02 << 5)
	USB_TYPE_RESERVED               = (0x03 << 5)

	USB_RECIP_DEVICE                = 0x00
	USB_RECIP_INTERFACE             = 0x01
	USB_RECIP_ENDPOINT              = 0x02
	USB_RECIP_OTHER                 = 0x03

	;; Request target types.
	USB_RT_DEVICE                   = 0x00
	USB_RT_INTERFACE                = 0x01
	USB_RT_ENDPOINT                 = 0x02

	VENDID	= 0xbac0
	PRODID	= 0x6134

