// ================================
// UART8N1 baud rate detection test
//		(c) 2021	1YEN Toru
//
//
//		2024/01/27	ver.1.02
//			brush up
//
//		2021/11/13	ver.1.00
//
// ================================
asm		"mcoc_irom.mem"
#asm		"mcoc_irom.dat2",bit16,list
#asm		"mcoc_irom.mif"
incl	"mcoc115.incl"
# ================================
# string macros
def		prog_name,"det_baud"
def		prog_vers,"1.02"
def		s,"#"							// simulation="" / real fpga="#"
# constants
equ		max_lbuf,64						// size of lbuf
equ		baud,9600						// baud rate
$(s)// ********************************
$(s)equ		baud,115200*2				// baud rate for sim
$(s)// ********************************
equ		uart_baud,fcpu/baud-1			// uartbaud setting
equ		chr_lf,0x0a						// lf code
equ		chr_cr,0x0d						// cr code
equ		led_blnk_coef,32				// led: blinking cycle coefficient
# variables
equ		va,ramtop
equ		msec_prev,va					// led: blink time [ms]
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

// port setting
ldbiu	r0,led_builtin
ldwi	r7,porset
stw		[r7],r0
ldwi	r7,pordir
ldw		r0,[r7]
andi	r0,~led_builtin
stw		[r7],r0

// 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

// send RDY
ldwi	r1,lab_str_msg_rdy
jalwr7	print

$(s)// ********************************
$(s)// for simulation
$(s)// wait brcnt overflow
$(s)ldwi	r0,0x800/3
$(s)subi	r0,1
$(s)bne		pcnt-4
$(s)// send data
$(s)ldwi	r7,uarttdat
$(s)ldbiu	r0,(0aU-0x20)
$(s)stw		[r7],r0
$(s)// check uartctl.RAVL
$(s)ldwi	r7,uartctl
$(s)ldw		r0,[r7]
$(s)andi	r0,uart_ravl
$(s)beq		pcnt-6
$(s)// wait brcnt overflow
$(s)ldwi	r0,0x800/3
$(s)subi	r0,1
$(s)bne		pcnt-4
$(s)// detect?
$(s)jalwr7	det_baud
$(s)cmpi	r0,uart_baud
$(s)bne		pcnt+2
$(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

// check "who" command
ldwi	r1,lbuf
ldwi	r2,lab_str_cmd_who
jalwr7	strcmp
cmpi	r0,0
bne		who_notid
// ================================
// who
ldwi	r1,lab_str_msg_baud
jalwr7	print
pushw	r1
ldwi	r7,uartbaud
ldw		r1,[r7]
jalwr7	print_hex
popw	r1
jalwr7	print
// 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:


// ================================
// led blink
// calculate blinking cycle
ldwi	r7,uartbaud
ldw		r1,[r7]
jalwr7	br2cycl
// check milli-second timer
ldwi	r7,sytmmill
ldw		r1,[r7]
mov		r3,r1
ldwi	r7,msec_prev
ldw		r2,[r7]
sub		r1,r2
cmp		r1,r0
blo		lbk_not_blink
// blink led
ldwi	r7,porout
ldw		r0,[r7]
eori	r0,led_builtin_b
stw		[r7],r0
// set current time
ldwi	r7,msec_prev
stw		[r7],r3
lbk_not_blink:


// ================================
// end of loop
bra		loop


// ================================
// baud rate to blinking cycle calculation ; disturbed r1,r2
//	parameter: r1=uartbaud value
//	return: r0=blinking cycle
// ================================
br2cycl:
ldbiu	r0,0
ldbiu	r2,0
b2c_loop:
lsfti	r0,-3
lsfti	r1,-1
bcc		pcnt+2
add		r0,r2
addi	r2,led_blnk_coef
mov		r1,r1
bne		b2c_loop
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
// 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
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,8
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

// ================================
// 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+ U\r\n"
dats	"OK+ who\r\n"
dats	"OK: help\r\n\0\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_cmd_who:
dats	"who\0"
str_cmd_help:
dats	"help\0"

