// ================================
// delta-sigma d/a converter (DAC121) test
//		(c) 2023	1YEN Toru
//
//
//		2023/01/28	ver.1.00
//
// ================================
asm		"mcoc_irom.mif"
#asm		"mcoc_irom.mem"
#asm		"mcoc_irom.dat2",bit16,list
incl	"mcoc115.incl"
# ================================
# string macros
def		prog_name,"test_dac"
def		prog_vers,"1.00"
def		s,"#"							// simulation="" / real fpga="#"
# delta-sigma d/a converter channel select
equ		dacctl,dacctl0
equ		dacdat,dacdat0
# constants
equ		max_lbuf,64						// size of lbuf
equ		baud,9600						// baud rate
equ		uart_baud,fcpu/baud-1			// uartbaud setting
equ		chr_lf,0x0a						// lf code
equ		chr_cr,0x0d						// cr code
equ		chr_cma,0x2c					// comma ',' code
equ		dac_WAIT,20						// dac: stabilization time [ms]
# variables
equ		va,ramtop
equ		dactl_bitw,va					// bit width
equ		va,va+2
equ		dactl_clks,va					// pdm clock select
equ		va,va+2
equ		daco_dat,va						// dac data
equ		va,va+2
equ		eval_anlg,va					// adc data
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
// ================================

// set sp to the bottom of ram area
ldwi	r7,idrgramt						// idrg: ram top addr.
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

// 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

// adc124 setting:
ldwi	r7,adcctl
ldbiu	r0,adc_adce
stw		[r7],r0
ldw		r0,[r7]
andi	r0,adc_adce
bne		adc_found
// ERROR: adc124 not found
ldwi	r1,lab_str_err_noadc
jalwr7	print
$(s)// ********************************
$(s)ldwi	r0,simfail
$(s)ldwi	r7,simfnsh
$(s)stw		[r7],r0
$(s)// ********************************
pause
bra		pcnt-4
adc_found:
ldw		r0,[r7]
andi	r0,adc_ardy
beq		pcnt-6
ldwi	r7,adcint
ldbiu	r0,adc_cene_a
stw		[r7],r0

// dac121 setting: pdm output enable, 6 bits, fcpu/1
ldwi	r7,dacctl
ldbiu	r0,dac_dace|dac_bitw_6b|0
stw		[r7],r0
ldw		r0,[r7]
andi	r0,dac_dace
bne		dac_found
// ERROR: dac121 not found
ldwi	r1,lab_str_err_nodac
jalwr7	print
$(s)// ********************************
$(s)ldwi	r0,simfail
$(s)ldwi	r7,simfnsh
$(s)stw		[r7],r0
$(s)// ********************************
pause
bra		pcnt-4
dac_found:

// 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)mov		r0,r0
$(s)bne		sim_cmnd_loop
$(s)pushw	r6
$(s)jalwr7	sim_cmnd
$(s)// skip nil, check end mark (*)
$(s)popw	r6
$(s)ldb		r0,[r6]
$(s)addi	r6,1
$(s)cmpi	r0,0
$(s)beq		pcnt-8
$(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	"daco,12\0"
$(s)dats	"who\0"
$(s)dats	"*"							// end mark
$(s)dats	"dactl,7,1\0"
$(s)dats	"daco,32\0"
$(s)dats	"eval\0"
$(s)dats	"who\0"
$(s)dats	"help\0"
$(s)sim_cmnd_end:
$(s)ldbiu	r0,0
$(s)// simulation finish
$(s)mov		r0,r0
$(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
beq		no_data
jalwr7	get_line
$(s)// ********************************
$(s)sim_cmnd:
$(s)// ********************************

// check "dactl," command
ldwi	r1,lbuf
ldwi	r2,lab_str_cmd_dactl
ldbiu	r5,6
jalwr7	strncmp
mov		r0,r0
bne		dactl_notid
// ================================
// dactl,<bit_width_6_12>,<pdm_clock_0_15>
ldwi	r1,lbuf+6
// <bit_width_6_12>
jalwr7	atoi
cmpi	r0,12+1
blo		pcnt+2
ldbiu	r0,12
cmpi	r0,6
bhs		pcnt+2
ldbiu	r0,6
subi	r0,6
ldwi	r7,dactl_bitw
stw		[r7],r0
// ,
ldb		r0,[r1]
cmpi	r0,chr_cma
bne		err_syntx
// <pdm_clock_0_15>
addi	r1,1
jalwr7	atoi
cmpi	r0,15+1
blo		pcnt+2
ldbiu	r0,0
ldwi	r7,dactl_clks
stw		[r7],r0
// set dacctl register
ldwi	r0,dactl_bitw
ldw		r0,[r0]
lsfti	r0,4
ori		r0,dac_dace
ldwi	r1,dactl_clks
ldw		r1,[r1]
or		r0,r1
ldwi	r7,dacctl
stw		[r7],r0
// response
ldwi	r1,lab_str_msg_dactl
jalwr7	print
bra		no_data
dactl_notid:

// check "daco," command
ldwi	r1,lbuf
ldwi	r2,lab_str_cmd_daco
ldbiu	r5,5
jalwr7	strncmp
mov		r0,r0
bne		daco_notid
// ================================
// daco,<digital_lsb>
// <digital_lsb>
jalwr7	atoi
ldwi	r7,daco_dat
stw		[r7],r0
// set dacdat
ldwi	r7,dacdat
stw		[r7],r0
// wait stabilization
ldwi	r1,dac_WAIT
jalwr7	delay
// adc read
ldwi	r7,adcctl
ldbiu	r0,adc_adce|adc_cenb|adc_csel_0
stw		[r7],r0
pause
ldwi	r7,adcint
ldw		r0,[r7]
ori		r0,adc_cenf_a
stw		[r7],r0							// flag clear
ldwi	r7,adcdat0
ldw		r0,[r7]
ldwi	r7,eval_anlg
stw		[r7],r0
// response
ldwi	r1,lab_str_msg_daco
jalwr7	print
pushw	r1
ldwi	r1,daco_dat
ldw		r1,[r1]
jalwr7	print_dec
popw	r1
jalwr7	print
pushw	r1
ldwi	r1,eval_anlg
ldw		r1,[r1]
jalwr7	print_dec
popw	r1
jalwr7	print
bra		no_data
daco_notid:

// check "eval" command
ldwi	r1,lbuf
ldwi	r2,lab_str_cmd_eval
ldbiu	r5,4
jalwr7	strncmp
mov		r0,r0
bne		eval_notid
// ================================
// eval
ldwi	r1,lab_str_msg_eval
jalwr7	print
pushw	r1
// evaluation
ldwi	r0,dactl_bitw
ldw		r0,[r0]
addi	r0,6
ldbiu	r4,1
lsft	r4,r0
$(s)// ********************************
$(s)ldbiu	r4,4
$(s)// ********************************
// loop
ldbiu	r3,0
eval_loop:
// set dacdat
ldwi	r7,dacdat
stw		[r7],r3
// wait stabilization
ldwi	r1,dac_WAIT
jalwr7	delay
// adc read
ldwi	r7,adcctl
ldbiu	r0,adc_adce|adc_cenb|adc_csel_0
stw		[r7],r0
pause
ldwi	r7,adcint
ldw		r0,[r7]
ori		r0,adc_cenf_a
stw		[r7],r0							// flag clear
ldwi	r7,adcdat0
ldw		r0,[r7]
ldwi	r7,eval_anlg
stw		[r7],r0
// <dac_lsb>,<adc_lsb>
pushwm	r3,r4
mov		r1,r3
jalwr7	print_dec
ldwi	r1,lab_str_msg_eval_dat
jalwr7	print
pushw	r1
ldwi	r1,eval_anlg
ldw		r1,[r1]
jalwr7	print_dec
popw	r1
jalwr7	print
popwm	r4,r3
// end of loop
addi	r3,1
cmp		r3,r4
blo		eval_loop
// response
popw	r1
jalwr7	print
bra		no_data
eval_notid:

// check "who" command
ldwi	r1,lbuf
ldwi	r2,lab_str_cmd_who
jalwr7	strcmp
mov		r0,r0
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
mov		r0,r0
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]
mov		r0,r0
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

no_data:
// end of command interpretation


// ================================
// end of loop
$(s)// ********************************
$(s)rtnw
$(s)// ********************************
bra		loop


// ================================
// get line from uart ; disturbed r0,r5~r7
// ================================
get_line:
ldwi	r7,uartrdat
ldwi	r6,uartctl
ldwi	r5,lbuf
gl_loop:
// 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
// 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
// check CR code
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
mov		r2,r2
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]
mov		r0,r0
bne		print_lst
rtnw

// ================================
// print_chr r1 ; disturbed r0,r7
// ================================
print_chr:
$(s)// ********************************
$(s)ldwi	r7,princhr
$(s)stw		[r7],r1
$(s)rtnw
$(s)// ********************************
// polling uartctl.TFUL=0
ldwi	r7,uartctl
pc_poll:
ldw		r0,[r7]
andi	r0,uart_tful
bne		pc_poll
// send data
ldwi	r7,uarttdat
stw		[r7],r1
rtnw

// ================================
// print decimal2 r1 ; disturbed r0~r4,r6,r7
// ================================
print_dec2:
mov		r1,r1
bne		pdc2_not_0
// 00
ldbiu	r1,0a0
jalwr7	print_chr
ldbiu	r1,0a0
jalwr7	print_chr
bra		pdc2_fin

pdc2_not_0:
// for each r0=10, 1
ldwi	r6,lab_pdc2_tab
ldbiu	r3,false						// omit leading zero flag
pdc2_loop:
ldw		r0,[r6]
mov		r0,r0
beq		pdc2_fin
// r2=r1/r0
ldbiu	r2,0
pdc2_div:
sub		r1,r0
blo		pcnt+4
addi	r2,1
bra		pdc2_div

// omit leading zero
mov		r3,r3
beq		pcnt+4
mov		r2,r2
beq		pdc2_omit
// print 1 digit
addi	r2,0a0
pushwm	r0,r1,r7
mov		r1,r2
jalwr7	print_chr
popwm	r7,r1,r0
ldbiu	r3,false
pdc2_omit:
// add back r1; loop
add		r1,r0
addi	r6,2
bra		pdc2_loop

pdc2_fin:
rtnw

pdc2_tab:
datw	10
datw	1
datw	0

// ================================
// print decimal r1 ; disturbed r0~r4,r6,r7
// ================================
print_dec:
#$(s)// ********************************
#$(s)ldwi	r7,prindec
#$(s)stw		[r7],r1
#$(s)rtnw
#$(s)// ********************************
mov		r1,r1
bne		pdc_not_0
// 0
ldbiu	r1,0a0
jalwr7	print_chr
bra		pdc_fin

pdc_not_0:
// for each r0=10000, ~, 10, 1
ldwi	r6,lab_pdc_tab
ldbiu	r3,true							// omit leading zero flag
pdc_loop:
ldw		r0,[r6]
mov		r0,r0
beq		pdc_fin
// r2=r1/r0
ldbiu	r2,0
pdc_div:
sub		r1,r0
blo		pcnt+4
addi	r2,1
bra		pdc_div

// omit leading zero
mov		r3,r3
beq		pcnt+4
mov		r2,r2
beq		pdc_omit
// print 1 digit
addi	r2,0a0
pushwm	r0,r1,r7
mov		r1,r2
jalwr7	print_chr
popwm	r7,r1,r0
ldbiu	r3,false
pdc_omit:
// add back r1; loop
add		r1,r0
addi	r6,2
bra		pdc_loop

pdc_fin:
rtnw

pdc_tab:
datw	10000
datw	1000
datw	100
datw	10
datw	1
datw	0

// ================================
// 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
mov		r3,r3
beq		sc_finish
mov		r4,r4
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
mov		r3,r3
beq		snc_finish
mov		r4,r4
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
lsfti	r3,3
add		r0,r0
add		r0,r3
add		r0,r2
// loop
addi	r1,1
bra		atoi+2
a2i_finish:
rtnw

// ================================
// delay r1 [ms] ; disturbed r0,r7,sytmctl[MLOE]
// ================================
delay:
$(s)// ********************************
$(s)ldbiu	r1,3
$(s)// ********************************
// sytmmil: set offset
ldwi	r7,sytmctl
ldw		r0,[r7]
andi	r0,~sytm_mloe
stw		[r7],r0
ori		r0,sytm_mloe
stw		[r7],r0
// wait r1 [ms]
ldwi	r7,sytmmill
dly_loop:
ldw		r0,[r7]
cmp		r0,r1
blo		dly_loop
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+ dactl,<bit_width_6_12>,<pdm_clock_0_15>\r\n"
dats	"OK+ daco,<digital_lsb>\r\n"
dats	"OK+ eval\r\n"
dats	"OK+ who\r\n"
dats	"OK: help\r\n\0\0"
str_msg_dactl:
dats	"OK: dactl\r\n\0"
str_msg_daco:
dats	"OK: daco,\0 (adci=\0)\r\n\0"
str_msg_eval:
dats	"EVAL\r\n\0END\r\nOK: eval\r\n\0"
str_msg_eval_dat:
dats	",\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_noadc:
dats	"ERR: adc124 not found.\r\n\0"
str_err_nodac:
dats	"ERR: dac121 not found.\r\n\0"
str_cmd_dactl:
dats	"dactl,\0"
str_cmd_daco:
dats	"daco,\0"
str_cmd_eval:
dats	"eval\0"
str_cmd_who:
dats	"who\0"
str_cmd_help:
dats	"help\0"

