// ================================
//	RGB LED Blink with Serial monitor
//		(c) 2021	1YEN Toru
//
//
//		2026/06/27	ver.1.12
//			fix: xtoi; range check for hexadecimal digits
//
//		2024/12/14	ver.1.10
//			corresponding to >=32KB ROM edition
//				R6 always point at RAM top address
//
//		2023/09/23	ver.1.08
//			corresponding to Cmod A7 FPGA board
//			corresponding to Tennessine core
//			new command: rd, wr
//
//		2023/07/08	ver.1.06
//			brushed up
//
//		2022/04/23	ver.1.04
//			corresponding to dual core cpu edition
//
//		2021/09/04	ver.1.02
//			corresponding to new idrgedit register
//
//		2021/04/10	ver.1.00
//
// ================================
def		target,"moscovium"
#def		target,"tennessine"
asm		"mcoc_irom.mem",$(target)
#asm		"mcoc_irom.dat2",bit16,list,$(target)
#asm		"mcoc_irom.mif",$(target)
incl	"mcoc115.incl"
$(target_mn)incl	"mcvm_remv_mcr_word.incl"
$(target_ts)incl	"tnsn_mcr_word.incl"
# ================================
# string macros
def		prog_name,"rgb_led_blink"
def		prog_vers,"1.12"
def		s,"#"							// simulation="" / fpga="#"
# constants
equ		max_lbuf,64						// size of lbuf
equ		baud,9600						// baud rate
equ		uart_baud,fcpu/baud-1			// uartbaud setting
equ		msec_s,150						// short: 150ms
equ		msec_l,550						// long: 550ms
# variables
equ		va,0
equ		led_stat,va						// state code: 0, 2, 4, 6
equ		va,va+2
equ		led_colr,va						// rgb led drive code: 0~7
equ		va,va+2
equ		acc_adr,va						// address to access (16 bit)
equ		va,va+2
equ		acc_dat,va						// data for access (16 bit)
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
# user macros
macro	ldvar	rd,vnam
ldwi	$(rd),$(vnam)
addw	$(rd),r6
endm
# ================================


// ================================
// Samarium pause code; 0x78(psei),0x01(pause)
or		r0,r1


// ================================
// setup
// ================================

// ================================		// general 8 bit Tennessine codes
// 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

// check Tennessine core
srbk	sreg_bk_3
movfc	r0,sr
andi	r0,sreg_bk_3
cmpi	r0,sreg_bk_0
srbk	sreg_bk_0
$(target_ts)beq		target_cpu_ok
$(target_mn)bne		target_cpu_ok
// ERROR: not target CPU=$(target), halt
ldc		sp,iome_botm
ldbiu	r1,asc_mns
jalwr7	print_chr
$(s)// ********************************
$(s)ldwi	r0,simfail
$(s)ldwi	r7,simfnsh
$(s)stw		[r7],r0
$(s)// ********************************
pause
// ================================		// target cpu codes from here
target_cpu_ok:


// stop if cpu2 for dual core cpu edition
movfc	r0,sr
lsrwi	r0,sreg_b_id0
andi	r0,sreg_id_2>>sreg_b_id0
beq		pcnt+2
pause

// set sp to the bottom of ram area
ldwi	r6,idrgramt						// idrg: ram top address
ldw		r6,[r6]
ldwi	r7,idrgrams						// idrg: ram size
ldw		r7,[r7]
addw	r7,r6
movtc	sp,r7

// clear variables
ldvar	r7,0
ldvar	r1,static_va
ldbiu	r0,0
st_clrvar:
stw		[r7],r0
addwi	r7,2
cmpw	r7,r1
blo		st_clrvar

// port setting
ldbiu	r0,led_builtin_r|led_builtin_g|led_builtin_b
ldwi	r7,porset
stw		[r7],r0
ldwi	r7,pordir
ldw		r0,[r7]
andi	r0,~(led_builtin_r|led_builtin_g|led_builtin_b)
stw		[r7],r0

// ready
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	r5,lab_sim_str_cmnd
$(s)sim_cmnd_loop2:
$(s)ldvar	r7,lbuf
$(s)sim_cmnd_loop:
$(s)ldb		r0,[r5]
$(s)addwi	r5,1
$(s)stb		[r7],r0
$(s)addwi	r7,1
$(s)cmpi	r0,0
$(s)bne		sim_cmnd_loop
$(s)pushw	r5
$(s)jalwr7	sim_cmnd
$(s)// skip nil, check end mark (*)
$(s)popw	r5
$(s)sim_loop_1:
$(s)ldb		r0,[r5]
$(s)addwi	r5,1
$(s)cmpi	r0,0
$(s)beq		sim_loop_1
$(s)subwi	r5,1
$(s)cmpi	r0,0x2a						// asterisk(*)
$(s)bne		sim_cmnd_loop2
$(s)bra		sim_cmnd_end
$(s)sim_str_cmnd:
$(s)// rgb led-on by timled5 unit
$(s)dats	"wr,f164,00\0"				// tledpsc
$(s)dats	"wr,f166,40\0"				// tleddtyr
$(s)dats	"wr,f168,c0\0"				// tleddtyg
$(s)dats	"wr,f16a,80\0"				// tleddtyb
$(s)dats	"wr,f16c,20\0"				// tleddty1
$(s)dats	"wr,f16e,d0\0"				// tleddty2
$(s)dats	"wr,f160,3f\0"				// tledctl
$(s)dats	"who\0"
$(s)dats	"help\0"
$(s)dats	"*"							// end mark
$(s)// rgb led-on by port[2:0] with pwm
$(s)dats	"wr,f164,00\0"				// tledpsc
$(s)dats	"wr,f166,40\0"				// tleddtyr
$(s)dats	"wr,f168,c0\0"				// tleddtyg
$(s)dats	"wr,f16a,80\0"				// tleddtyb
$(s)dats	"wr,f026,f8\0"				// pordir=~led_builtin
$(s)dats	"wr,f02c,07\0"				// porclr=led_builtin
$(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
beq		no_data
jalwr7	get_line
$(s)// ********************************
$(s)sim_cmnd:
$(s)// ********************************

// check "rd," command
ldvar	r1,lbuf
ldwi	r2,lab_str_cmd_rd
ldbiu	r5,3
jalwr7	strncmp
cmpwi	r0,0
bne		rd_notid
// ================================
// rd,<adr_hex4>
// <adr_hex4>
ldvar	r1,lbuf+3
jalwr7	xtoi
ldvar	r7,acc_adr
stw		[r7],r0

// read from <adr_hex4>
ldvar	r7,acc_adr
ldw		r7,[r7]
ldw		r0,[r7]
ldvar	r7,acc_dat
stw		[r7],r0

// response
ldwi	r1,lab_str_msg_read
jalwr7	print
pushw	r1
// acc_adr
ldvar	r7,acc_adr
ldw		r1,[r7]
jalwr7	print_hex
popw	r1
jalwr7	print
pushw	r1
// acc_dat
ldvar	r7,acc_dat
ldw		r1,[r7]
jalwr7	print_hex
popw	r1
jalwr7	print
bra		no_data
rd_notid:

// check "wr," command
ldvar	r1,lbuf
ldwi	r2,lab_str_cmd_wr
ldbiu	r5,3
jalwr7	strncmp
cmpi	r0,0
bne		wr_notid
// ================================
// wr,<adr_hex4>,<dat_hex4>
// <adr_hex4>
ldvar	r1,lbuf+3
jalwr7	xtoi
ldvar	r7,acc_adr
stw		[r7],r0
// ,
ldb		r0,[r1]
cmpi	r0,asc_cma
bne		err_syntx
// <dat_hex4>
addwi	r1,1
jalwr7	xtoi
ldvar	r7,acc_dat
stw		[r7],r0

// write <dat_hex4> to <adr_hex4>
ldvar	r7,acc_dat
ldw		r0,[r7]
ldvar	r7,acc_adr
ldw		r7,[r7]
stw		[r7],r0

// response
ldwi	r1,lab_str_msg_write
jalwr7	print
pushw	r1
// acc_adr
ldvar	r7,acc_adr
ldw		r1,[r7]
jalwr7	print_hex
popw	r1
jalwr7	print
pushw	r1
// acc_dat
ldvar	r7,acc_dat
ldw		r1,[r7]
jalwr7	print_hex
popw	r1
jalwr7	print
bra		no_data
wr_notid:

// check "who" command
ldvar	r1,lbuf
ldwi	r2,lab_str_cmd_who
jalwr7	strcmp
cmpi	r0,0
bne		who_notid
// ================================
// who
cmd_who:
// idreg
ldwi	r1,lab_str_msg_idrg
// idreg, idrgcode
jalwr7	print
pushw	r1
ldwi	r1,idrgcode
ldw		r1,[r1]
jalwr7	print_hex
popw	r1
jalwr7	print
addwi	r1,1							// skip extra nil '\0'
// idreg, idrgvers
jalwr7	print
pushw	r1
ldwi	r1,idrgvers
ldw		r1,[r1]
jalwr7	print_hex
popw	r1
jalwr7	print
addwi	r1,1							// skip extra nil '\0'
// idreg, idrgfcpu
jalwr7	print
pushw	r1
ldwi	r1,idrgfcpu
ldw		r1,[r1]
jalwr7	print_hex
popw	r1
jalwr7	print
addwi	r1,1							// skip extra nil '\0'
// idreg, idrgedit
jalwr7	print
pushw	r1
ldwi	r1,idrgedit
ldw		r1,[r1]
jalwr7	print_hex
ldbiu	r1,asc_spc
jalwr7	print_chr
ldwi	r1,idrgedit
ldw		r1,[r1]
cendw	r1
jalwr7	print_chr
ldwi	r1,idrgedit
ldw		r1,[r1]
andwi	r1,0xff
jalwr7	print_chr
popw	r1
jalwr7	print
addwi	r1,1							// skip extra nil '\0'
// idreg, idrgromt
jalwr7	print
pushw	r1
ldwi	r1,idrgromt
ldw		r1,[r1]
jalwr7	print_hex
popw	r1
jalwr7	print
addwi	r1,1							// skip extra nil '\0'
// idreg, idrgroms
jalwr7	print
pushw	r1
ldwi	r1,idrgroms
ldw		r1,[r1]
jalwr7	print_hex
popw	r1
jalwr7	print
addwi	r1,1							// skip extra nil '\0'
// idreg, idrgramt
jalwr7	print
pushw	r1
ldwi	r1,idrgramt
ldw		r1,[r1]
jalwr7	print_hex
popw	r1
jalwr7	print
addwi	r1,1							// skip extra nil '\0'
// idreg, idrgrams
jalwr7	print
pushw	r1
ldwi	r1,idrgrams
ldw		r1,[r1]
jalwr7	print_hex
popw	r1
jalwr7	print
addwi	r1,1							// skip extra nil '\0'
// response
ldwi	r1,lab_str_msg_who
jalwr7	print
bra		no_data
who_notid:

// check "help" command
ldvar	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
ldvar	r1,lbuf
ldb		r0,[r1]
cmpi	r0,0
beq		no_data
// ================================
// ERROR: unsupported command
ldwi	r1,lab_str_err_unspt
jalwr7	print
pushw	r1
ldvar	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
ldvar	r7,led_stat
ldw		r0,[r7]
andwi	r0,0x06
ldwi	r7,lab_led_jmptab
addw	r7,r0
ldw		r7,[r7]
jmp		r7

led_jmptab:
datw	lab_led_st0						// msec_s[ms], led off
datw	lab_led_st1						// msec_s[ms], led on
datw	lab_led_st2						// msec_s[ms], led off, change color
datw	lab_led_st3						// msec_l[ms], led on

// ================================
// led on, msec_s[ms]
led_st0:
// check millis()
ldwi	r7,sytmmill
ldw		r0,[r7]
ldwi	r1,msec_s
cmpw	r0,r1
blo		led_end
// update led driver
ldvar	r7,led_colr
ldw		r0,[r7]
ldwi	r7,porset
stw		[r7],r0
bra		led_updt

// ================================
// led off, msec_s[ms]
led_st1:
// check millis()
ldwi	r7,sytmmill
ldw		r0,[r7]
ldwi	r1,msec_s
cmpw	r0,r1
blo		led_end
// update led driver
ldvar	r7,led_colr
ldw		r0,[r7]
ldwi	r7,porclr
stw		[r7],r0
bra		led_updt

// ================================
// led on, msec_s[ms]
led_st2:
// check millis()
ldwi	r7,sytmmill
ldw		r0,[r7]
ldwi	r1,msec_s
cmpw	r0,r1
blo		led_end
// update led driver
ldvar	r7,led_colr
ldw		r0,[r7]
ldwi	r7,porset
stw		[r7],r0
// update led_colr
ldvar	r7,led_colr
ldw		r0,[r7]
addi	r0,0x01
andi	r0,0x07
stw		[r7],r0
bra		led_updt

// ================================
// led off, msec_l[ms]
led_st3:
// check millis()
ldwi	r7,sytmmill
ldw		r0,[r7]
ldwi	r1,msec_l
cmpw	r0,r1
blo		led_end
// update led driver
ldvar	r7,led_colr
ldw		r0,[r7]
ldwi	r7,porclr
stw		[r7],r0
bra		led_updt

// update led state
led_updt:
// sytm reset
ldwi	r7,sytmctl
ldbiu	r0,sytm_rst
stw		[r7],r0
// update led_stat
ldvar	r7,led_stat
ldw		r0,[r7]
addi	r0,0x02
andi	r0,0x06
stw		[r7],r0
led_end:

// ================================
// 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


// ================================
// get line from uart ; disturbed r0,r4,r5,r7
// ================================
get_line:
ldwi	r7,uartrdat
ldwi	r5,uartctl
ldvar	r4,lbuf
gl_loop:
// polling until RAVL=1
ldw		r0,[r5]
andi	r0,uart_ravl
beq		gl_loop
// get byte
ldw		r0,[r7]
stb		[r4],r0
addwi	r4,1
// LF code check
cmpi	r0,asc_lf
beq		gl_got
// size check
ldvar	r0,lbuf+max_lbuf-1
cmpw	r4,r0
blo		gl_loop
// got line
gl_got:
// string terminate
ldbiu	r0,0
subwi	r4,1
stb		[r4],r0
// CR code check
subwi	r4,1
ldb		r0,[r4]
cmpi	r0,asc_cr
bne		gl_notcr
ldbiu	r0,0
stb		[r4],r0
gl_notcr:
rtnw

// ================================
// print r1 ; disturbed r0~r2,r5,r7
// ================================
print:
ldwi	r7,uarttdat
ldwi	r5,uartctl
pr_loop:
// get 1 byte
ldb		r2,[r1]
addwi	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,[r5]
andi	r0,uart_tful
bne		pr_poll
// send data
stw		[r7],r2
bra		pr_loop
pr_finish:
rtnw

// ================================
// print_lst r1 ; disturbed r0~r2,r5,r7
// ================================
print_lst:
jalwr7	print
ldb		r0,[r1]
cmpi	r0,0
bne		print_lst
rtnw

// ================================
// print_hex r1 ; disturbed r0~r5,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)// ********************************
push	r6
ldwi	r7,uarttdat
ldwi	r6,uartctl
ldwi	r5,lab_ph_hexdig
ph_loop:
// print nibble
movw	r0,r1
movw	r4,r5
cendw	r0
lsrwi	r0,4
andwi	r0,0x0f
addw	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
lslwi	r1,4
subi	r3,1
bne		ph_loop
pop		r6
rtnw

ph_hexdig:
dats	"0123456789abcdef"

// ================================
// 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

// ================================
// string compare: r0=strcmp (r1,r2) ; disturbed r1~r4
// ================================
strcmp:
ldb		r3,[r1]
addwi	r1,1
ldb		r4,[r2]
addwi	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]
addwi	r1,1
ldb		r4,[r2]
addwi	r2,1
mov		r0,r3
sub		r0,r4
bne		snc_finish
// check n character
subwi	r5,1
beq		snc_finish
// check nil code
cmpi	r3,0
beq		snc_finish
cmpi	r4,0
bne		strncmp
snc_finish:
rtnw

// ================================
// hexadecimal to integer: r0=xtoi (r1) ; disturbed r1,r2
// ================================
xtoi:
ldbiu	r0,0
// loop
x2i_loop:
// r2=[r1]-'0'
ldb		r2,[r1]
subi	r2,0a0
blo		x2i_break						// [r1]<'0'
cmpi	r2,(0a9+1)-0a0
blo		x2i_next						// [r1]<='9'
subi	r2,0aA-0a0
blo		x2i_break						// [r1]<'A'
addi	r2,0x0a
cmpi	r2,0x0a+(0aF+1)-0aA
blo		x2i_next						// [r1]<='F'
subi	r2,0x0a+0aa-0aA
blo		x2i_break						// [r1]<'a'
addi	r2,0x0a
cmpi	r2,0x0a+(0af+1)-0aa
bhs		x2i_break						// [r1]>'f'
x2i_next:
// hexadecimal digit
// r0=16*r0+r2
lslwi	r0,4
addw	r0,r2
// end of loop
addwi	r1,1
bra		x2i_loop
x2i_break:
// end of subroutine
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+ rd,<adr_hex4>\r\n"
dats	"OK+ wr,<adr_hex4>,<dat_hex4>\r\n"
dats	"OK+ who\r\n"
dats	"OK: help\r\n\0\0"
str_msg_idrg:
dats	"OK+ id code: \0\r\n\0"
dats	"OK+ version: \0\r\n\0"
dats	"OK+ fcpu kHz:\0\r\n\0"
dats	"OK+ edition: \0\r\n\0"
dats	"OK+ rom top: \0\r\n\0"
dats	"OK+ rom size:\0\r\n\0"
dats	"OK+ ram top: \0\r\n\0"
dats	"OK+ ram size:\0\r\n\0"
str_msg_read:
dats	"OK: read[0x\0]=0x\0\r\n\0"
str_msg_write:
dats	"OK: write[0x\0]=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_rd:
dats	"rd,\0"
str_cmd_wr:
dats	"wr,\0"
str_cmd_who:
dats	"who\0"
str_cmd_help:
dats	"help\0"

