// ================================
//	Digital camera with OV7670
//		(c) 2024	1YEN Toru
//
//
//		2024/06/22	ver.1.00
//
// ================================
asm		"mcoc_irom.mem"
#asm		"mcoc_irom.dat2",bit16,list
romsiz	8*1024
incl	"mcoc115.incl"
incl	"mcvm_lib_wire_h.incl"
incl	"ov7670.incl"
# ================================
# string macros
def		prog_name,"digital_camera"
def		prog_vers,"1.00"
def		s,"#"							// simulation="" / real fpga="#"
# constants
equ		max_lbuf,64						// size of lbuf
equ		baud,9600						// baud rate
equ		uart_baud,fcpu/baud-1			// uartbaud setting
equ		stws_baud,fcpu/400000-1			// i2c: clock speed
$(s)// ********************************
$(s)equ		stws_baud,fcpu/400000/3-1	// i2c: clock speed for sim
$(s)// ********************************
equ		err_fifo_full,1					// cam: fifo full
equ		pin_reset,7						// cam: ov7670 reset=port_iop[7]
equ		chr_bs,0x08						// bs code
equ		chr_lf,0x0a						// lf code
equ		chr_cr,0x0d						// cr code
equ		chr_cma,0x2c					// comma ',' code
# variables
equ		va,ramtop
equ		reg_addr,va						// register address
equ		va,va+2
equ		reg_data,va						// register data
equ		va,va+2
equ		bs64_chr,va						// base64 character + '\0'
equ		va,va+2
equ		mgc_gain,va						// mgc gain
equ		va,va+2
equ		mec_exps,va						// mec exposure
equ		va,va+2
equ		static_va,va
# array variables
equ		lbuf,va							// receive data buffer
equ		va,va+max_lbuf
equ		array_va,va
# ================================


// ================================
// setup
// ================================

// uart setting: RXE, TXE, baud rate
ldwi	r7,uartbaud
ldwi	r0,uart_baud
stw		[r7],r0
ldwi	r7,uartctl
ldbiu	r0,uart_rxe|uart_txe
stw		[r7],r0

// set sp to the bottom of ram area
ldwi	r7,idrgramt						// idrg: ram top address
ldw		r7,[r7]
ldwi	r6,idrgrams						// idrg: ram size
ldw		r6,[r6]
add		r7,r6
movtc	sp,r7

// clear variables
ldwi	r7,ramtop
ldwi	r1,static_va
ldbiu	r0,0
st_clrvar:
stw		[r7],r0
addi	r7,2
cmp		r7,r1
blo		st_clrvar

// check sramc512k
ldc		tr,sramtop>>16
ldwi	r7,sramtop&0xffff
ldwi	r0,0xaa55
ldwi	r1,0x3cc3
stwx	[tr:r7],r0
ldwx	r2,[tr:r7]
stwx	[tr:r7],r1
ldwx	r3,[tr:r7]
cmp		r0,r2
bne		srm_not_found
cmp		r1,r3
beq		srm_found
// ERROR: sramc512k unit not found
srm_not_found:
ldwi	r1,lab_str_err_srmno
jalwr7	print
// clear frame buffer
srm_found:
ldwi	r7,sramtop&0xffff
ldbiu	r0,0
stwx	[tr:r7],r0

// stwser setting
ldwi	r0,stws_baud
ldwi	r7,stwmbaud
stw		[r7],r0
// check stwser
ldw		r1,[r7]
cmp		r0,r1
beq		stw_found
// ERROR: stwser unit not found
ldwi	r1,lab_str_err_stwno
jalwr7	print
stw_found:
$(s)// ********************************
$(s)// setup dummy slave
$(s)ldbiu	r0,i2c_ov7670
$(s)ldwi	r7,stwsadr
$(s)stw		[r7],r0
$(s)// ********************************

// cam7670 setting
// XCLK output
ldwi	r7,cm76ctl
ldbiu	r0,cm76_xcke
stw		[r7],r0
// have cam7670?
ldw		r0,[r7]
cmpi	r0,0
bne		cm76_found
// ERROR: cam7670 unit not found
ldwi	r1,lab_str_err_cm76no
jalwr7	print
bra		cm76_break
cm76_found:
// set time over (r1=1000[ms])
ldwi	r6,sytmctl
ldbiu	r0,sytm_mloe
stw		[r6],r0
ldwi	r6,sytmmill
ldwi	r1,1000
// polling until PCKV=1
cm76_poll_pckv:
// check time over
ldw		r0,[r6]
cmp		r0,r1
bhs		cm76_break
// check PCKV
ldw		r0,[r7]
andi	r0,cm76_pckv
beq		cm76_poll_pckv
cm76_break:
ldw		r0,[r7]
andi	r0,cm76_pckv
bne		cm76_pclk_det
// ERROR:
ldwi	r1,lab_str_err_cm76pckv
jalwr7	print
cm76_pclk_det:
// clear sytmctl[MLOE]
ldwi	r7,sytmctl
ldbiu	r0,0
stw		[r7],r0

// OV7670 initialize
$(s)// ********************************
$(s)bra		pcnt+6
$(s)// ********************************
jalwr7	o76_init

// send RDY
ldwi	r1,lab_str_msg_rdy
jalwr7	print

$(s)// ********************************
$(s)// for simulation
#0$(s)// cancel time out
#0$(s)ldwi	r7,simctrl
#0$(s)ldbiu	r0,simc_noto
#0$(s)stw		[r7],r0
$(s)// command test
$(s)ldwi	r6,lab_sim_str_cmnd
$(s)sim_cmnd_loop2:
$(s)ldwi	r7,lbuf
$(s)sim_cmnd_loop:
$(s)ldb		r0,[r6]
$(s)addi	r6,1
$(s)stb		[r7],r0
$(s)addi	r7,1
$(s)cmpi	r0,0
$(s)bne		sim_cmnd_loop
$(s)pushw	r6
$(s)jalwr7	sim_cmnd
$(s)// skip nil, check end mark (*)
$(s)popw	r6
$(s)sim_loop_1:
$(s)ldb		r0,[r6]
$(s)addi	r6,1
$(s)cmpi	r0,0
$(s)beq		sim_loop_1
$(s)subi	r6,1
$(s)cmpi	r0,0x2a						// asterisk(*)
$(s)bne		sim_cmnd_loop2
$(s)bra		sim_cmnd_end
$(s)sim_str_cmnd:
$(s)dats	"who\0"
$(s)dats	"help\0"
$(s)dats	"*"							// end mark
$(s)dats	"vga\0"
$(s)dats	"vgaq\0"
$(s)dats	"vgaqq\0"
$(s)dats	"vgaqqq\0"
$(s)dats	"mgc\0"
$(s)dats	"mgc,0\0"
$(s)dats	"mgc,35a\0"
$(s)dats	"mec\0"
$(s)dats	"mec,0\0"
$(s)dats	"mec,3a5\0"
$(s)dats	"take\0"
$(s)dats	"save\0"
$(s)dats	"rd1,0a\0"					// ov7670 read
$(s)dats	"wr1,12,80\0"				// ov7670 write
$(s)sim_cmnd_end:
$(s)ldbiu	r0,0
$(s)// simulation finish
$(s)cmpi	r0,0
$(s)beq		pcnt+6
$(s)ldwi	r0,simfail
$(s)bra		pcnt+4
$(s)ldwi	r0,simpass
$(s)ldwi	r7,simfnsh
$(s)stw		[r7],r0
$(s)bra		pcnt-2
$(s)// ********************************


// ================================
// loop
// ================================
loop:

// ================================
// serial monitor handling
// check uartctl.RAVL
ldwi	r7,uartctl
ldw		r0,[r7]
andi	r0,uart_ravl|uart_brdf
beq		no_data
jalwr7	get_line
$(s)// ********************************
$(s)sim_cmnd:
$(s)// ********************************

// check "take" command
ldwi	r1,lbuf
ldwi	r2,lab_str_cmd_take
ldbiu	r5,4
jalwr7	strncmp
cmpi	r0,0
bne		take_notid
// ================================
// take
jalwr7	o76_take

// response
cmpi	r0,0
beq		take_ok
// ERROR:
pushw	r0
ldwi	r1,lab_str_err_take
jalwr7	print
popw	r0
pushw	r1
mov		r1,r0
jalwr7	print_hex
popw	r1
jalwr7	print
bra		no_data

take_ok:
ldwi	r1,lab_str_msg_take
jalwr7	print
bra		no_data
take_notid:

// check "save" command
ldwi	r1,lbuf
ldwi	r2,lab_str_cmd_save
ldbiu	r5,4
jalwr7	strncmp
cmpi	r0,0
bne		save_notid
// ================================
// save
// check frame buffer
ldc		tr,sramtop>>16
ldwi	r7,sramtop&0xffff
ldwx	r0,[tr:r7]
cmpi	r0,0
bne		save_has_frame
// ERROR: empty frame buffer
ldwi	r1,lab_str_err_save
jalwr7	print
pushw	r1
ldbiu	r1,2
jalwr7	print_hex
popw	r1
jalwr7	print
bra		no_data

save_has_frame:
// send header
ldwi	r1,lab_str_save_head
jalwr7	print

// r6:r5=frame buffer read pointer
ldwi	r6,sramtop>>16
ldwi	r5,sramtop&0xffff
ldbiu	r4,0
// save load loop
save_loop:
// read frame buffer
movtc	tr,r6
ldbx	r0,[tr:r5]
addi	r5,1
adcz	r6

// check vsync
cmpi	r4,0
beq		save_skip_chk
mov		r1,r0
andi	r1,cm76_vsyn
bne		save_break
save_skip_chk:

// check hsync
mov		r1,r0
andi	r1,cm76_hsyn
beq		save_not_hsync
// send new line
pushwm	r0,r4,r5,r6
ldwi	r1,lab_str_save_crlf
jalwr7	print
popwm	r6,r5,r4,r0
addi	r4,1

save_not_hsync:
// encode pixel
ldwi	r7,lab_str_save_bs64
mov		r1,r0
andi	r1,0x3f
add		r7,r1
ldb		r1,[r7]
cendw	r1
ldwi	r7,bs64_chr
stw		[r7],r1
// send pixel
pushwm	r0,r4,r5,r6
mov		r1,r7
jalwr7	print
popwm	r6,r5,r4,r0

// end of loop
save_continue:
bra		save_loop

save_break:
// pass code
ldbiu	r0,0
pushwm	r0,r4

// send end mark
ldwi	r1,lab_str_save_endm
jalwr7	print

// response
popwm	r4,r0
cmpi	r0,0
beq		save_ok
// ERROR:
pushw	r0
ldwi	r1,lab_str_err_save
jalwr7	print
popw	r0
pushw	r1
mov		r1,r0
jalwr7	print_hex
popw	r1
jalwr7	print
bra		no_data

save_ok:
pushw	r4
ldwi	r1,lab_str_msg_save
jalwr7	print
popw	r4
pushw	r1
mov		r1,r4
jalwr7	print_hex
popw	r1
jalwr7	print
bra		no_data
save_notid:

// check "vga" command
ldwi	r1,lbuf
ldwi	r2,lab_str_cmd_vga
ldbiu	r5,3
jalwr7	strncmp
cmpi	r0,0
bne		vga_notid
// ================================
// vga
// vgaq
// vgaqq
// vgaqqq
ldwi	r7,lbuf+3
ldb		r0,[r7]
cmpi	r0,0aq
bne		vga_size_vga
addi	r7,1
ldb		r0,[r7]
cmpi	r0,0aq
bne		vga_size_qvga
addi	r7,1
ldb		r0,[r7]
cmpi	r0,0aq
bne		vga_size_qqvga
// QQQVGA size
vga_size_qqqvga:
ldwi	r1,lab_vga_i2cf_set_qqqvga
bra		vga_reg_setting

// QQVGA size
vga_size_qqvga:
ldwi	r1,lab_vga_i2cf_set_qqvga
bra		vga_reg_setting

// QVGA size
vga_size_qvga:
ldwi	r1,lab_vga_i2cf_set_qvga
bra		vga_reg_setting

// VGA size
vga_size_vga:
ldwi	r1,lab_vga_i2cf_set_vga
bra		vga_reg_setting

// ov7670 register setting
vga_reg_setting:
jalwr7	i2c_frame_list

// response
cmpi	r0,0
beq		vga_ok
// ERROR:
pushw	r0
ldwi	r1,lab_str_err_vga
jalwr7	print
popw	r0
pushw	r1
mov		r1,r0
jalwr7	print_hex
popw	r1
jalwr7	print
bra		no_data

vga_ok:
ldwi	r1,lab_str_msg_vga
jalwr7	print
bra		no_data

// i2c frame list
// vga setting
vga_i2cf_set_vga:
// com3: (default)
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_com3
datw	wire_send+0x00
datw	wire_stop
// com14: normal pclk, no scale manually, pclk/1
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_com14
datw	wire_send+0x00
datw	wire_stop
// pclkdiv: 1/1
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_pclkdiv
datw	wire_send+0x00
datw	wire_stop
// dcwctr: horizontal 1/1, vertical 1/1
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_dcwctr
datw	wire_send+0x00
datw	wire_stop
// end of list
datw	0

// qvga setting
vga_i2cf_set_qvga:
// com3: dcw
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_com3
datw	wire_send+0x04
datw	wire_stop
// com14: dcw&spclk, scale, pclk/2
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_com14
datw	wire_send+0x19
datw	wire_stop
// pclkdiv: 1/2
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_pclkdiv
datw	wire_send+0x01
datw	wire_stop
// dcwctr: (default)
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_dcwctr
datw	wire_send+0x11
datw	wire_stop
// end of list
datw	0

// qqvga setting
vga_i2cf_set_qqvga:
// com3: dcw
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_com3
datw	wire_send+0x04
datw	wire_stop
// com14: dcw&spclk, scale, pclk/4
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_com14
datw	wire_send+0x1a
datw	wire_stop
// pclkdiv: 1/4
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_pclkdiv
datw	wire_send+0x02
datw	wire_stop
// dcwctr: horizontal 1/4, vertical 1/4
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_dcwctr
datw	wire_send+0x22
datw	wire_stop
// end of list
datw	0

// qqqvga setting
vga_i2cf_set_qqqvga:
// com3: dcw
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_com3
datw	wire_send+0x04
datw	wire_stop
// com14: dcw&spclk, scale, pclk/8
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_com14
datw	wire_send+0x1b
datw	wire_stop
// pclkdiv: 1/8
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_pclkdiv
datw	wire_send+0x03
datw	wire_stop
// dcwctr: horizontal 1/8, vertical 1/8
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_dcwctr
datw	wire_send+0x33
datw	wire_stop
// end of list
datw	0

vga_notid:

// check "mgc" command
ldwi	r1,lbuf
ldwi	r2,lab_str_cmd_mgc
ldbiu	r5,3
jalwr7	strncmp
cmpi	r0,0
bne		mgc_notid
// ================================
// mgc[,<mgc_gain_hex3>]
ldwi	r7,lbuf+3
ldb		r0,[r7]
cmpi	r0,chr_cma
bne		mgc_show
// <mgc_gain_hex3>
addi	r7,1
mov		r1,r7
jalwr7	xtoi
ldwi	r7,mgc_gain
stw		[r7],r0

// check mgc_gain
cmpi	r0,0
bne		mgc_manual
// agc enable
// i2c_read (com8)
ldbiu	r1,o76_reg_com8
jalwr7	i2c_read
// i2c_write (com8,agc enable)
mov		r0,r1
ori		r0,0x04							// agc enable bit
ldbiu	r1,o76_reg_com8
jalwr7	i2c_write
bra		mgc_endif

// mgc setting
mgc_manual:
// i2c_read (com8)
ldbiu	r1,o76_reg_com8
jalwr7	i2c_read
// i2c_write (com8,agc disable)
mov		r0,r1
andi	r0,(~0x04)						// agc enable bit
ldbiu	r1,o76_reg_com8
jalwr7	i2c_write
// i2c_write (vref,(mgc_gain>>2)&0xc0)
ldwi	r7,mgc_gain
ldw		r0,[r7]
lsri	r0,2
andi	r0,0xc0
ldbiu	r1,o76_reg_vref
jalwr7	i2c_write
// i2c_write (gain,mgc_gain&0xff)
ldwi	r7,mgc_gain
ldw		r0,[r7]
andi	r0,0xff
ldbiu	r1,o76_reg_gain
jalwr7	i2c_write
bra		mgc_endif

// show mgc
mgc_show:
// i2c_read (vref)
ldbiu	r1,o76_reg_vref
jalwr7	i2c_read
ldwi	r7,mgc_gain
andi	r1,0xc0
lsli	r1,2
stw		[r7],r1
// i2c_read (gain)
ldbiu	r1,o76_reg_gain
jalwr7	i2c_read
ldwi	r7,mgc_gain
ldw		r0,[r7]
or		r0,r1
stw		[r7],r0

mgc_endif:

// response
ldwi	r1,lab_str_msg_mgc
jalwr7	print
pushw	r1
ldwi	r7,mgc_gain
ldw		r1,[r7]
jalwr7	print_hex
popw	r1
jalwr7	print
bra		no_data
mgc_notid:

// check "mec" command
ldwi	r1,lbuf
ldwi	r2,lab_str_cmd_mec
ldbiu	r5,3
jalwr7	strncmp
cmpi	r0,0
bne		mec_notid
// ================================
// mec[,<mec_exps_hex4>]
ldwi	r7,lbuf+3
ldb		r0,[r7]
cmpi	r0,chr_cma
bne		mec_show
// <mec_exps_hex4>
addi	r7,1
mov		r1,r7
jalwr7	xtoi
ldwi	r7,mec_exps
stw		[r7],r0

// check mec_exps
cmpi	r0,0
bne		mec_manual
// aec enable
// i2c_read (com8)
ldbiu	r1,o76_reg_com8
jalwr7	i2c_read
// i2c_write (com8,aec enable)
mov		r0,r1
ori		r0,0x01							// aec enable bit
ldbiu	r1,o76_reg_com8
jalwr7	i2c_write
bra		mec_endif

// mec setting
mec_manual:
// i2c_read (com8)
ldbiu	r1,o76_reg_com8
jalwr7	i2c_read
// i2c_write (com8,aec disable)
mov		r0,r1
andi	r0,(~0x01)						// aec enable bit
ldbiu	r1,o76_reg_com8
jalwr7	i2c_write
// i2c_write (aechh,(mec_exps>>10)&0x3f)
ldwi	r7,mec_exps
ldw		r0,[r7]
lsri	r0,10
andi	r0,0x3f
ldbiu	r1,o76_reg_aechh
jalwr7	i2c_write
// i2c_write (aech,(mec_exps>>2)&0xff)
ldwi	r7,mec_exps
ldw		r0,[r7]
lsri	r0,2
andi	r0,0xff
ldbiu	r1,o76_reg_aech
jalwr7	i2c_write
// i2c_write (com1,mec_exps&0x03)
ldwi	r7,mec_exps
ldw		r0,[r7]
andi	r0,0x03
ldbiu	r1,o76_reg_com1
jalwr7	i2c_write
bra		mec_endif

// show mec
mec_show:
// i2c_read (aechh)
ldbiu	r1,o76_reg_aechh
jalwr7	i2c_read
ldwi	r7,mec_exps
andi	r1,0x3f
lsli	r1,10
stw		[r7],r1
// i2c_read (aech)
ldbiu	r1,o76_reg_aech
jalwr7	i2c_read
ldwi	r7,mec_exps
ldw		r0,[r7]
lsli	r1,2
or		r0,r1
stw		[r7],r0
// i2c_read (com1)
ldbiu	r1,o76_reg_com1
jalwr7	i2c_read
ldwi	r7,mec_exps
andi	r1,0x03
ldw		r0,[r7]
or		r0,r1
stw		[r7],r0

mec_endif:

// response
ldwi	r1,lab_str_msg_mec
jalwr7	print
pushw	r1
ldwi	r7,mec_exps
ldw		r1,[r7]
jalwr7	print_hex
popw	r1
jalwr7	print
bra		no_data
mec_notid:

// check "wr1," command
ldwi	r1,lbuf
ldwi	r2,lab_str_cmd_wr1
ldbiu	r5,4
jalwr7	strncmp
cmpi	r0,0
bne		wr1_notid
// ================================
// wr1,<reg_addr_hex>,<data_hex>
ldwi	r1,lbuf+4
// <reg_addr_hex>
jalwr7	xtoi
andi	r0,0xff
ldwi	r7,reg_addr
stw		[r7],r0
// check ','
ldb		r0,[r1]
cmpi	r0,chr_cma
bne		err_syntx
addi	r1,1
// <data_hex>
jalwr7	xtoi
andi	r0,0xff
ldwi	r7,reg_data
stw		[r7],r0

// write to ov7670
ldwi	r7,reg_addr
ldw		r1,[r7]
ldwi	r7,reg_data
ldw		r0,[r7]
jalwr7	i2c_write

// response
cmpi	r0,0
beq		wr1_ok
// ERROR:
pushw	r0
ldwi	r1,lab_str_err_o76ak
jalwr7	print
popw	r0
pushw	r1
mov		r1,r0
jalwr7	print_hex
popw	r1
jalwr7	print
bra		no_data

wr1_ok:
ldwi	r1,lab_str_msg_wr1
jalwr7	print
pushw	r1
ldwi	r7,reg_addr
ldw		r1,[r7]
cendw	r1
ldbiu	r3,2
jalwr7	print_hex+2
popw	r1
jalwr7	print
pushw	r1
ldwi	r7,reg_data
ldw		r1,[r7]
cendw	r1
ldbiu	r3,2
jalwr7	print_hex+2
popw	r1
jalwr7	print
bra		no_data
wr1_notid:

// check "rd1," command
ldwi	r1,lbuf
ldwi	r2,lab_str_cmd_rd1
ldbiu	r5,4
jalwr7	strncmp
cmpi	r0,0
bne		rd1_notid
// ================================
// rd1,<reg_addr_hex>
ldwi	r1,lbuf+4
// <reg_addr_hex>
jalwr7	xtoi
andi	r0,0xff
ldwi	r7,reg_addr
stw		[r7],r0

// read from ov7670
mov		r1,r0
jalwr7	i2c_read
ldwi	r7,reg_data
stw		[r7],r1

// response
cmpi	r0,0
beq		rd1_ok
// ERROR:
pushw	r0
ldwi	r1,lab_str_err_o76ak
jalwr7	print
popw	r0
pushw	r1
mov		r1,r0
jalwr7	print_hex
popw	r1
jalwr7	print
bra		no_data

rd1_ok:
ldwi	r1,lab_str_msg_rd1
jalwr7	print
pushw	r1
ldwi	r7,reg_addr
ldw		r1,[r7]
lsli	r1,8
ldbiu	r3,2
jalwr7	print_hex+2
popw	r1
jalwr7	print
pushw	r1
ldwi	r7,reg_data
ldw		r1,[r7]
lsli	r1,8
ldbiu	r3,2
jalwr7	print_hex+2
popw	r1
jalwr7	print
bra		no_data
rd1_notid:

// check "who" command
ldwi	r1,lbuf
ldwi	r2,lab_str_cmd_who
jalwr7	strcmp
cmpi	r0,0
bne		who_notid
// ================================
// who
// response
ldwi	r1,lab_str_msg_who
jalwr7	print
bra		no_data
who_notid:

// check "help" command
ldwi	r1,lbuf
ldwi	r2,lab_str_cmd_help
jalwr7	strcmp
cmpi	r0,0
bne		help_notid
// ================================
// help
// response
ldwi	r1,lab_str_msg_help
jalwr7	print_lst
bra		no_data
help_notid:

// ================================
// ignore empty line
ldwi	r1,lbuf
ldb		r0,[r1]
cmpi	r0,0
beq		no_data
// ================================
// ERROR: unsupported command
ldwi	r1,lab_str_err_unspt
jalwr7	print
pushw	r1
ldwi	r1,lbuf
jalwr7	print
popw	r1
jalwr7	print
bra		no_data

// ERROR: syntax
err_syntx:
ldwi	r1,lab_str_err_syntx
jalwr7	print
bra		no_data

// end of command interpretation
no_data:


// ================================
// end of loop
$(s)// ********************************
$(s)ldwi	r1,lab_sim_str_delim
$(s)jalwr7	print
$(s)rtnw
$(s)sim_str_delim:
$(s)dats	"--------\r\n\0"
$(s)// ********************************
bra		loop


// ================================
// vga camera (ov7670) initialize
// ================================
o76_init:
// reset
ldbiu	r0,~(1<<pin_reset)
ldwi	r7,pordir
stw		[r7],r0
ldwi	r7,porclr
not		r0
stw		[r7],r0
// wait
ldwi	r7,sytmctl
ldbiu	r1,sytm_mloe
stw		[r7],r1
ldwi	r7,sytmmill
ldbiu	r2,100							// [ms]
$(s)// ********************************
$(s)ldbiu	r2,2
$(s)// ********************************
ldw		r1,[r7]
cmp		r1,r2
blo		pcnt-6
// negate reset
ldwi	r7,porset
stw		[r7],r0
// wait a moment
ldwi	r7,sytmmill
addi	r2,10							// [ms]
$(s)// ********************************
$(s)addi	r2,2
$(s)// ********************************
ldw		r1,[r7]
cmp		r1,r2
blo		pcnt-6
ldwi	r7,sytmctl
ldbiu	r1,0
stw		[r7],r1

// ov7670 i/o register initialize
ldwi	r1,lab_o76i_init_reg
jalwr7	i2c_frame_list
cmpi	r0,0
beq		o76i_no_err
// ERROR:
pushwm	r1,r0
ldwi	r1,lab_str_err_o76wire
jalwr7	print
popw	r2
pushw	r1
mov		r1,r2
jalwr7	print_hex
popw	r1
jalwr7	print
popw	r2
pushw	r1
mov		r1,r2
addi	r1,2
jalwr7	print_hex
popw	r1
jalwr7	print
o76i_no_err:
rtnw

// i2c frame: ov7670 initialization
o76i_init_reg:
// ov7670 setting
// clkrc: xclk/8
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_clkrc
datw	wire_send+0x80+(8-1)
datw	wire_stop
// com10: free running pclk
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_com10
datw	wire_send+0x00
datw	wire_stop

// rgb444 output mode
// com7: rgb
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_com7
datw	wire_send+0x04
datw	wire_stop
// com15: RGB565 output
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_com15
datw	wire_send+0xc0+0x10
datw	wire_stop
// rgb444: enable, xRGB4444
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_rgb444
datw	wire_send+0x02
datw	wire_stop

// tslb: yuyv, aowin
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_tslb
datw	wire_send+0x05
datw	wire_stop
// com13: gamma, uvsat, yuyv
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_com13
datw	wire_send+0xc8
datw	wire_stop
// com16: disable edge, disable de-noise, AWB gain enable, color matrix double
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_com16
datw	wire_send+0x08+0x02
datw	wire_stop

// vga setting
// com3: (default)
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_com3
datw	wire_send+0x00
datw	wire_stop
// com14: normal pclk, no scale manually, pclk/1
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_com14
datw	wire_send+0x00
datw	wire_stop
// pclkdiv: 1/1
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_pclkdiv
datw	wire_send+0x00
datw	wire_stop
// dcwctr: horizontal 1/1, vertical 1/1
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_dcwctr
datw	wire_send+0x00
datw	wire_stop

#%// xsc: (default)
#%datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
#%datw	wire_send+o76_reg_xsc
#%datw	wire_send+0x4a+0x00
#%datw	wire_stop
#%// ysc: (default)
#%datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
#%datw	wire_send+o76_reg_ysc
#%datw	wire_send+0x35+0x00
#%datw	wire_stop
#%// pclkdelay: (default)
#%datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
#%datw	wire_send+o76_reg_pclkdelay
#%datw	wire_send+0x02
#%datw	wire_stop

// agc: automatic gain control
// awc: automatic white balance control
// aec: automatic exposure control
// com8: agc, awb, aec
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_com8
datw	wire_send+0x8f
datw	wire_stop
#%// manual setting
#%// com8: no agc, awb, no aec
#%datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
#%datw	wire_send+o76_reg_com8
#%datw	wire_send+0x8a
#%datw	wire_stop
#%equ		mgc,900							// manual gain control
#%// vref: agc[9:8]
#%datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
#%datw	wire_send+o76_reg_vref
#%datw	wire_send+((mgc&0x300)>>2)
#%datw	wire_stop
#%// gain: agc[7:0]
#%datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
#%datw	wire_send+o76_reg_gain
#%datw	wire_send+(mgc&0xff)
#%datw	wire_stop
#%equ		mec,20							// manual exposure control
#%// aechh: [5:0]=aec[15:10]
#%datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
#%datw	wire_send+o76_reg_aechh
#%datw	wire_send+((mec>>10)&0x3f)
#%datw	wire_stop
#%// aech: [7:0]=aec[9:2]
#%datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
#%datw	wire_send+o76_reg_aech
#%datw	wire_send+((mec>>2)&0xff)
#%datw	wire_stop
#%// com1: [1:0]=aec[1:0]
#%datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
#%datw	wire_send+o76_reg_com1
#%datw	wire_send+(mec&0x03)
#%datw	wire_stop

// color matrix (simple)
// mtx1:
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_mtx1
datw	wire_send+0x00
datw	wire_stop
// mtx2:
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_mtx2
datw	wire_send+0x80
datw	wire_stop
// mtx3:
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_mtx3
datw	wire_send+0x80
datw	wire_stop
// mtx4:
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_mtx4
datw	wire_send+0x80
datw	wire_stop
// mtx5:
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_mtx5
datw	wire_send+0x00
datw	wire_stop
// mtx6:
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_mtx6
datw	wire_send+0x80
datw	wire_stop
// mtxs:
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_mtxs
datw	wire_send+0x24
datw	wire_stop

// gamma correction (gamma=2.2)
// slop:
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_slop
datw	wire_send+0x1e
datw	wire_stop
// gam1:
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_gam1
datw	wire_send+0x26
datw	wire_stop
// gam2:
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_gam2
datw	wire_send+0x34
datw	wire_stop
// gam3:
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_gam3
datw	wire_send+0x48
datw	wire_stop
// gam4:
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_gam4
datw	wire_send+0x63
datw	wire_stop
// gam5:
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_gam5
datw	wire_send+0x6e
datw	wire_stop
// gam6:
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_gam6
datw	wire_send+0x77
datw	wire_stop
// gam7:
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_gam7
datw	wire_send+0x80
datw	wire_stop
// gam8:
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_gam8
datw	wire_send+0x88
datw	wire_stop
// gam9:
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_gam9
datw	wire_send+0x8f
datw	wire_stop
// gam10:
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_gam10
datw	wire_send+0x96
datw	wire_stop
// gam11:
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_gam11
datw	wire_send+0xa3
datw	wire_stop
// gam12:
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_gam12
datw	wire_send+0xaf
datw	wire_stop
// gam13:
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_gam13
datw	wire_send+0xc5
datw	wire_stop
// gam14:
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_gam14
datw	wire_send+0xd7
datw	wire_stop
// gam15:
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_gam15
datw	wire_send+0xe8
datw	wire_stop

// window
// mvfp: mirror, vflip
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_mvfp
datw	wire_send+0x01+0x30				// +0x20(mirror) / +0x10(vflip)
datw	wire_stop
// hstart: 136/8 (default)
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_hstart
datw	wire_send+0x11
datw	wire_stop
// href: (default)
datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
datw	wire_send+o76_reg_href
datw	wire_send+0x80+0x00
datw	wire_stop
#%// hstop: (hstart + 648)/8
#%datw	wire_send+wire_star+wire_adrw+(i2c_ov7670<<1)
#%datw	wire_send+o76_reg_hstop
#%datw	wire_send+0x62
#%datw	wire_stop

// end of initialization
datw	0


// ================================
// vga camera (ov7670) take a picture
//	return: r0=0 (no error) / !=0 (error)
// ================================
o76_take:
// cam7670 enable
ldwi	r7,cm76ctl
ldbiu	r0,cm76_cenb|cm76_xcke
stw		[r7],r0
// polling until FRBS=0
ldw		r0,[r7]
andi	r0,cm76_frbs
bne		pcnt-6
// take a picture loop
ldwi	r6,sramtop>>16					// r6:r5 frame buffer write pointer
ldwi	r5,sramtop&0xffff
o76t_loop:
// polling until FABL=1 or FFUL=1
ldwi	r7,cm76ctl
ldw		r0,[r7]
// check FFUL=1?
mov		r2,r0
andi	r2,cm76_fful
beq		o76t_not_fful
// ERROR: fifo full
#// clear frame buffer
#ldbiu	r0,0
#ldc		tr,sramtop>>16
#ldwi	r7,sramtop&0xffff
#stwx	[tr:r7],r0
// force terminate frame buffer
ldbiu	r0,cm76_vsyn
movtc	tr,r6
stbx	[tr:r5],r0
// error code
ldbiu	r0,err_fifo_full
pushw	r0
bra		o76t_stop

o76t_not_fful:
// check FABL=1?
andi	r0,cm76_fabl
beq		o76t_loop+4
// read from fifo
ldwi	r7,cm76pix
ldw		r0,[r7]
// write to frame buffer
movtc	tr,r6
stbx	[tr:r5],r0
addi	r5,1
adcz	r6
// if (r6:r5=1) continue;
cmpi	r5,1
ldwi	r1,sramtop>>16
cmb		r6,r1
beq		o76t_continue

// check if vsync=1?
andi	r0,cm76_vsyn
bne		o76t_break

// end of loop
o76t_continue:
bra		o76t_loop

o76t_break:
ldbiu	r0,0
pushw	r0

// stop cam7670
o76t_stop:
ldwi	r7,cm76ctl
ldbiu	r0,cm76_xcke
stw		[r7],r0

// end of subroutine
o76t_return:
popw	r0
rtnw


// ================================
// transfer i2c frame list r1 ; disturbed r7
//		return: r0=0(ErrNo) / !=0(ERROR)
//			returns with pointing the error location to r1
// ================================
i2c_frame_list:
ifl_loop:
// check end of frame list
ldw		r0,[r1]
cmpi	r0,0
beq		ifl_break
// call mcvm_wire
jalwr7	mcvm_wire
cmpi	r0,wire_err_no
bne		ifl_break
// end of loop
addi	r1,2
bra		ifl_loop
ifl_break:
rtnw

// ================================
// r1=i2c_read (r1) ; disturbed r7
//	return: r0=0 (no error) / r0!=0 (error)
// ================================
i2c_read:
// make i2c frame: S [ADR,W] [reg_addr] P S [ADR,R] [[RCV]](N) P
movfc	r7,sp
subi	r7,2*6
movtc	sp,r7
// S [ADR,W]
ldwi	r0,wire_send|wire_star|(i2c_ov7670<<1)|wire_adrw
stw		[r7],r0
pushw	r0
// [reg_addr]
addi	r7,2
ldwi	r0,wire_send
andi	r1,0xff
add		r0,r1
stw		[r7],r0
// P
addi	r7,2
ldbiu	r0,wire_stop
stw		[r7],r0
// S [ADR,R]
addi	r7,2
popw	r0
ori		r0,wire_adrr
stw		[r7],r0
// [[RCV]](N)
addi	r7,2
ldwi	r0,wire_recv|wire_nack
stw		[r7],r0
// P
addi	r7,2
ldbiu	r0,wire_stop
stw		[r7],r0
// call mcvm_wire
$(s)// ********************************
$(s)// dummy slave response data set
$(s)ldwi	r7,stwsdats
$(s)ldbiu	r0,0xaa
$(s)stw		[r7],r0
$(s)// ********************************
movfc	r1,sp
jalwr7	mcvm_wire
addi	r1,2
jalwr7	mcvm_wire
// data received
subi	r1,1							// rewind to [[RCV]] position
ldb		r1,[r1]
// destroy i2c frame
movfc	r7,sp
addi	r7,2*6
movtc	sp,r7
// end of subroutine
rtnw

// ================================
// r0=i2c_write (r1,r0) ; disturbed r1, r7
//	return: r0=0 (no error) / r0!=0 (error)
// ================================
i2c_write:
// make i2c frame: S [ADR,W] [reg_addr] [reg_data] P
movfc	r7,sp
subi	r7,2*4
movtc	sp,r7
pushw	r0
// S [ADR,W]
ldwi	r0,wire_send|wire_star|(i2c_ov7670<<1)|wire_adrw
stw		[r7],r0
// [reg_addr]
addi	r7,2
ldwi	r0,wire_send
andi	r1,0xff
add		r0,r1
stw		[r7],r0
// [reg_data]
addi	r7,2
ldwi	r1,wire_send
popw	r0
andi	r0,0xff
add		r0,r1
stw		[r7],r0
// P
addi	r7,2
ldbiu	r0,wire_stop
stw		[r7],r0
// call mcvm_wire
movfc	r1,sp
jalwr7	mcvm_wire
// destroy i2c frame
movfc	r7,sp
addi	r7,2*4
movtc	sp,r7
// end of subroutine
rtnw


// ================================
// baud rate detection ; disturbed none
//	return: r0=new baud rate detected
// ================================
det_baud:
pushwm	r1,r2,r3,r4,r5,r6,r7
ldwi	r7,uartctl
ldw		r0,[r7]
stw		[r7],r0							// clear brdf
andi	r0,uart_brdf
beq		dbr_not_brdf
// detected
ldwi	r7,uartbres
ldw		r0,[r7]
ldwi	r7,uartbaud
ldw		r3,[r7]
// margin
mov		r2,r3
lsri	r2,6
// r3=abs (r3 - r0)
$(s)// ********************************
$(s)lsli	r3,1
$(s)// ********************************
sub		r3,r0
bpl		dbr_plus
neg		r3
dbr_plus:
cmp		r3,r2
blo		dbr_not_brdf
// update uartbaud
stw		[r7],r0
// message
ldwi	r1,lab_dbr_str_msg_det
jalwr7	print
pushw	r1
ldwi	r7,uartbaud
ldw		r1,[r7]
jalwr7	print_hex
popw	r1
jalwr7	print
ldwi	r7,uartbres
ldw		r0,[r7]
bra		dbr_not_brdf+2
// return
dbr_not_brdf:
ldbiu	r0,0
popwm	r7,r6,r5,r4,r3,r2,r1
rtnw

dbr_str_msg_det:
dats	"OK: new baud rate detected: uartbaud=0x\0\r\n\0"

// ================================
// get line from uart ; disturbed r0,r5~r7
// ================================
get_line:
ldwi	r7,uartrdat
ldwi	r6,uartctl
ldwi	r5,lbuf
gl_loop:
// check baud rate detection
jalwr0	det_baud
// polling until RAVL=1
ldw		r0,[r6]
andi	r0,uart_ravl
beq		gl_loop
// get byte
ldw		r0,[r7]
stb		[r5],r0
addi	r5,1
// LF code check
cmpi	r0,chr_lf
beq		gl_got
// BS code check
cmpi	r0,chr_bs
bne		gl_bs_endif
subi	r5,2
ldwi	r0,lbuf
cmp		r5,r0
bhs		gl_bs_endif
mov		r5,r0
gl_bs_endif:
// size check
ldwi	r0,lbuf+max_lbuf-1
cmp		r5,r0
blo		gl_loop
// got line
gl_got:
// string terminate
ldbiu	r0,0
subi	r5,1
stb		[r5],r0
// CR code check
subi	r5,1
ldb		r0,[r5]
cmpi	r0,chr_cr
bne		gl_notcr
ldbiu	r0,0
stb		[r5],r0
gl_notcr:
rtnw

// ================================
// print r1 ; disturbed r0~r2,r6,r7
// ================================
print:
ldwi	r7,uarttdat
ldwi	r6,uartctl
pr_loop:
// get 1 byte
ldb		r2,[r1]
addi	r1,1
cmpi	r2,0
beq		pr_finish
$(s)// ********************************
$(s)ldwi	r7,princhr
$(s)stw		[r7],r2
$(s)bra		pr_loop
$(s)// ********************************
// polling uartctl.TFUL=0
pr_poll:
ldw		r0,[r6]
andi	r0,uart_tful
bne		pr_poll
// send data
stw		[r7],r2
bra		pr_loop
pr_finish:
rtnw

// ================================
// print_lst r1 ; disturbed r0~r2,r6,r7
// ================================
print_lst:
jalwr7	print
ldb		r0,[r1]
cmpi	r0,0
bne		print_lst
rtnw

// ================================
// print_hex r1 ; disturbed r0~r7
//		print r1 as 4 digits hexadecimal number
// ================================
print_hex:
ldbiu	r3,4
$(s)// ********************************
$(s)ldwi	r7,princtl
$(s)ldbiu	r0,prin_nld
$(s)stw		[r7],r0
$(s)ldwi	r7,prinhex
$(s)cmpi	r3,4
$(s)beq		ph_else
$(s)cendw	r1
$(s)stb		[r7],r1
$(s)bra		ph_endif
$(s)ph_else:
$(s)stw		[r7],r1
$(s)ph_endif:
$(s)rtnw
$(s)// ********************************
ldwi	r7,uarttdat
ldwi	r6,uartctl
ldwi	r5,lab_ph_hexdig
ph_loop:
// print nibble
mov		r0,r1
mov		r4,r5
cendw	r0
lsri	r0,4
andi	r0,0x0f
add		r4,r0
ldb		r2,[r4]
// polling uartctl.TFUL=0
ph_poll:
ldw		r0,[r6]
andi	r0,uart_tful
bne		ph_poll
// send data
stw		[r7],r2
// loop
lsli	r1,4
subi	r3,1
bne		ph_loop
rtnw

ph_hexdig:
dats	"0123456789abcdef"

// ================================
// string compare: r0=strcmp (r1,r2) ; disturbed r1~r4
// ================================
strcmp:
ldb		r3,[r1]
addi	r1,1
ldb		r4,[r2]
addi	r2,1
mov		r0,r3
sub		r0,r4
bne		sc_finish
// check nil code
cmpi	r3,0
beq		sc_finish
cmpi	r4,0
bne		strcmp
sc_finish:
rtnw

// ================================
// string n compare: r0=strncmp (r1,r2,r5) ; disturbed r1~r5
// ================================
strncmp:
ldb		r3,[r1]
addi	r1,1
ldb		r4,[r2]
addi	r2,1
mov		r0,r3
sub		r0,r4
bne		snc_finish
// check n character
subi	r5,1
beq		snc_finish
// check nil code
cmpi	r3,0
beq		snc_finish
cmpi	r4,0
bne		strncmp
snc_finish:
rtnw

// ================================
// ascii to integer: r0=atoi (r1)>=0 ; disturbed r1~r3
// ================================
atoi:
ldbiu	r0,0
// r2=[r1]-'0'
ldb		r2,[r1]
subi	r2,0a0
blo		a2i_finish
cmpi	r2,10
bhs		a2i_finish
// r0=10*r0+r2
mov		r3,r0
lsli	r3,3
add		r0,r0
add		r0,r3
add		r0,r2
// end of loop
addi	r1,1
bra		atoi+2
a2i_finish:
rtnw

// ================================
// hexadecimal to integer: r0=xtoi (r1) ; disturbed r1,r2
// ================================
xtoi:
ldbiu	r0,0
// r2=[r1]-'0'
ldb		r2,[r1]
subi	r2,0a0
blo		x2i_finish						// [r1]<'0'
cmpi	r2,10
blo		x2i_next						// [r1]<='9'
subi	r2,(0aA-0x20)-0a0-10
blo		x2i_finish						// [r1]<'A'
cmpi	r2,16
blo		x2i_next						// [r1]<='F'
subi	r2,0aa-(0aA-0x20)
blo		x2i_finish						// [r1]<'a'
cmpi	r2,16
bhs		x2i_finish						// [r1]>'f'
x2i_next:
// r0=16*r0+r2
lsli	r0,4
add		r0,r2
// end of loop
addi	r1,1
bra		xtoi+2
x2i_finish:
rtnw

// ================================
// c string data
// ================================
str_msg_who:
dats	"OK: $(prog_name) ver.$(prog_vers)\r\n\0"
str_msg_rdy:
dats	"RDY\r\n\0"
str_msg_help:
dats	"OK+ take\r\n"
dats	"OK+ save\r\n"
dats	"OK+ vga\r\n"
dats	"OK+ vgaq\r\n"
dats	"OK+ vgaqq\r\n"
dats	"OK+ vgaqqq\r\n"
dats	"OK+ mgc[,<mgc_gain_hex3>]\r\n"
dats	"OK+ mec[,<mec_exps_hex4>]\r\n"
dats	"OK+ wr1,<reg_addr_hex2>,<data_hex2>\r\n"
dats	"OK+ rd1,<reg_addr_hex2>\r\n"
dats	"OK+ U\r\n"
dats	"OK+ who\r\n"
dats	"OK: help\r\n\0\0"
str_msg_take:
dats	"OK: take\r\n\0"
str_msg_save:
dats	"OK: save n_line=0x\0\r\n\0"
str_msg_vga:
dats	"OK: vga*\r\n\0"
str_msg_mgc:
dats	"OK: mgc,0x\0\r\n\0"
str_msg_mec:
dats	"OK: mec,0x\0\r\n\0"
str_msg_wr1:
dats	"OK: wr1[0x\0]=0x\0\r\n\0"
str_msg_rd1:
dats	"OK: rd1[0x\0]=0x\0\r\n\0"
str_msg_baud:
dats	"OK+ uartbaud=0x\0\r\n\0"
str_err_unspt:
dats	"ERR: unsupported command: \0\r\n\0"
str_err_syntx:
dats	"ERR: syntax\r\n\0"
str_err_srmno:
dats	"ERR: sramc512k unit not found.\r\n\0"
str_err_stwno:
dats	"ERR: stwser unit not found.\r\n\0"
str_err_cm76no:
dats	"ERR: cam7670 unit not found.\r\n\0"
str_err_cm76pckv:
dats	"ERR: pclk not detected.\r\n\0"
str_err_o76ak:
dats	"ERR: could not communicate ov7670: \0\r\n\0"
str_err_o76wire:
dats	"ERR: ov7670 wire err=\0 adr=0x\0\r\n\0"
str_err_take:
dats	"ERR: take \0\r\n\0"
str_err_save:
dats	"ERR: save \0\r\n\0"
str_err_vga:
dats	"ERR: vga \0\r\n\0"
str_cmd_take:
dats	"take\0"
str_cmd_save:
dats	"save\0"
str_cmd_vga:
dats	"vga\0"
str_cmd_mgc:
dats	"mgc\0"
str_cmd_mec:
dats	"mec\0"
str_cmd_wr1:
dats	"wr1,\0"
str_cmd_rd1:
dats	"rd1,\0"
str_cmd_who:
dats	"who\0"
str_cmd_help:
dats	"help\0"
str_save_head:
dats	"SAVE\0"
str_save_crlf:
dats	"\r\n\0"
str_save_endm:
dats	"\r\nEND\r\n\0"
str_save_bs64:
dats	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\0"

# ================================
incl	"mcvm_lib_wire_m.incl"

