// ================================
// Mandelbrot set for MCOC115 (Moscovium)
//		(c) 2021	1YEN Toru
//
//
//		2021/06/12	ver.1.00
//
// ================================
asm		"mcoc_irom.mif"
#asm		"mcoc_irom.mem"
#asm		"mcoc_irom.dat2",bit16,list
incl	"mcoc115.incl"
# ================================
# constants
equ		max_lbuf,64						// size of lbuf
equ		baud,115200						// 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		mdbr_NITR,32					// mdbr: maximum iteration
equ		mdbr_SIZE,140					// mdbr: size [dot]
equh	mdbr_NCOL_h,32.					// mdbr: color scale
equh	mdbr_NINF_h,10000.				// mdbr: threshold lim/inf
equh	mdbr_REAL_h,-1.5				// mdbr: real range left
equh	mdbr_REAR_h,0.5					// mdbr: real range right
equh	mdbr_IMAB_h,-1					// mdbr: imaginary range bottom
equh	mdbr_IMAT_h,1					// mdbr: imaginary range top
# variables
equ		va,ramtop
equ		rtncod,va
equ		va,va+2
equ		mdbr_idx,va
equ		va,va+2
equ		mdbr_kk,va
equ		va,va+2
equ		mdbr_ix,va
equ		va,va+2
equ		mdbr_iy,va
equ		va,va+2
equ		mdbr_zr,va
equ		va,va+2
equ		mdbr_zi,va
equ		va,va+2
equ		mdbr_cr,va
equ		va,va+2
equ		mdbr_ci,va
equ		va,va+2
equ		mdbr_tr,va
equ		va,va+2
equ		mdbr_ti,va
equ		va,va+2
equ		mdbr_usec,va					// mdbr: elapsed time [us]
equ		va,va+4
equ		hue6q,va
equ		va,va+2
equ		hue6r,va
equ		va,va+2
equ		mdbr_ptr,va						// mdbr: pointer to mdbr_buf
equ		va,va+2
equ		static_va,va
# array variables
equ		lbuf,va							// receive data buffer
equ		va,va+max_lbuf
equ		mdbr_buf,va						// mdbr: buffer (2*sq (mdbr_SIZE))
equ		va,va+2*sq(mdbr_SIZE)
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

// send RDY
ldwi	r1,lab_str_msg_rdy
jalwr7	print

// ================================
// loop
// ================================
loop:

// ================================
// serial monitor handling
// check uartctl.RAVL
ldwi	r7,uartctl
ldw		r0,[r7]
andi	r0,uart_ravl
beq		no_data
jalwr7	get_line

// check "mdbr" command
ldwi	r1,lbuf
ldwi	r2,lab_str_cmd_mdbr
ldbiu	r5,4
jalwr7	strncmp
mov		r0,r0
bne		mdbr_notid
// ================================
// mdbr
jalwr7	mandelbrot
// response
ldwi	r1,lab_str_msg_mdbr
jalwr7	print
ldwi	r7,mdbr_usec
ldw		r1,[r7]
jalwr7	print_hex
ldwi	r7,mdbr_usec+2
ldw		r1,[r7]
jalwr7	print_hex
ldwi	r1,lab_str_msg_mdbr_us
jalwr7	print
bra		no_data
mdbr_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
ldwi	r1,lbuf
jalwr7	print
ldwi	r1,lab_str_crlf
jalwr7	print
bra		no_data

// ERROR: syntax
err_syntx:
ldwi	r1,lab_str_err_syntx
jalwr7	print
bra		no_data

no_data:

// ================================
// end of loop
bra		loop


// ================================
// mandelbrot
// ================================
mandelbrot:
// reset system timer
ldwi	r7,sytmctl
ldbiu	r0,sytm_rst
stw		[r7],r0
// initialize
ldbiu	r0,0
ldwi	r7,mdbr_ptr
stw		[r7],r0
ldwi	r7,rtncod
stw		[r7],r0

//	for (mdbr_iy=0; mdbr_iy<mdbr_SIZE; mdbr_iy++)
ldbiu	r0,0
ldwi	r7,mdbr_iy
stw		[r7],r0
mdbr_for_iy:
//	{
ldwi	r1,mdbr_SIZE
cmp		r0,r1
bhs		mdbr_for_iy_brk

//		mdbr_kk=float (mdbr_SIZE - mdbr_iy)/mdbr_SIZE;
mov		r2,r1
sub		r2,r0
hhalf	r2,r2
hhalf	r1,r1
hdiv	r2,r1
ldwi	r7,mdbr_kk
stw		[r7],r2

//		mdbr_ci=IMAB*(1. - mdbr_kk) + IMAT*mdbr_kk;
ldwi	r0,mdbr_IMAT_h
ldwi	r1,mdbr_IMAB_h
hldi	r3,1
hsub	r3,r2
hmul	r1,r3
hmul	r0,r2
hadd	r0,r1
ldwi	r7,mdbr_ci
stw		[r7],r0

//		for (mdbr_ix=0; mdbr_ix<mdbr_SIZE; mdbr_ix++)
ldbiu	r0,0
ldwi	r7,mdbr_ix
stw		[r7],r0
//		{
mdbr_for_ix:
ldwi	r1,mdbr_SIZE
cmp		r0,r1
bhs		mdbr_for_ix_brk

//			mdbr_kk=float (mdbr_ix)/mdbr_SIZE;
hhalf	r0,r0
hhalf	r1,r1
hdiv	r0,r1
ldwi	r7,mdbr_kk
stw		[r7],r0

//			mdbr_cr=REAL*(1. - mdbr_kk) + REAR*mdbr_kk;
ldwi	r1,mdbr_REAL_h
ldwi	r2,mdbr_REAR_h
hldi	r3,1
hsub	r3,r0
hmul	r1,r3
hmul	r2,r0
hadd	r1,r2
ldwi	r7,mdbr_cr
stw		[r7],r1

//			mdbr_zr=0;
//			mdbr_zi=0;
ldbiu	r0,0
ldwi	r7,mdbr_zr
stw		[r7],r0
addi	r7,2							// mdbr_zi
stw		[r7],r0

//			for (mdbr_idx=0; mdbr_idx<mdbr_NITR; mdbr_idx++)
ldbiu	r0,0
ldwi	r7,mdbr_idx
stw		[r7],r0
//			{
mdbr_for_idx:
ldwi	r1,mdbr_NITR
cmp		r0,r1
bhs		mdbr_for_idx_brk

// t=sq (z) + c
//	=(r + i*j)*(r + i*j) + c=sq (r) + 2*r*i*j - sq (i) + c
//				mdbr_tr=sq (mdbr_zr) - sq (mdbr_zi) + mdbr_cr;
ldwi	r7,mdbr_zr
ldw		r0,[r7]
addi	r7,2							// mdbr_zi
ldw		r1,[r7]
ldwi	r7,mdbr_cr
ldw		r2,[r7]
addi	r7,2							// mdbr_ci
ldw		r3,[r7]
mov		r4,r0
hmul	r4,r4
mov		r5,r1
hmul	r5,r5
hsub	r4,r5
hadd	r4,r2
ldwi	r7,mdbr_tr
stw		[r7],r4
//				mdbr_ti=2.*mdbr_zr*mdbr_zi + mdbr_ci;
hmul	r0,r1
hadd	r0,r0
hadd	r0,r3
addi	r7,2							// mdbr_ti
stw		[r7],r0

//				mdbr_zr=mdbr_tr;
//				mdbr_zi=mdbr_ti;
mov		r1,r4
ldwi	r7,mdbr_zr
stw		[r7],r1
addi	r7,2							// mdbr_zi
stw		[r7],r0

// judge
//				if (sq (mdbr_zr) + sq (mdbr_zi)>mdbr_NINF_h)
//					break;
hmul	r0,r0
hmul	r1,r1
hadd	r0,r1
ldwi	r1,mdbr_NINF_h
hsub	r1,r0
mov		r1,r1
bmi		mdbr_for_idx_brk

//			}
ldwi	r7,mdbr_idx
ldw		r0,[r7]
addi	r0,1
stw		[r7],r0
bra		mdbr_for_idx

mdbr_for_idx_brk:

// draw
//			if (mdbr_idx<mdbr_NITR)
//			{
ldwi	r7,mdbr_idx
ldw		r0,[r7]
ldwi	r1,mdbr_NITR
cmp		r0,r1
bhs		mdbr_else_idx_lo

//				rgb_hue2rgb (240*mdbr_idx/mdbr_NCOL_h, rr,gg,bb);
hldi	r1,240
hhalf	r0,r0
hmul	r0,r1
ldwi	r1,mdbr_NCOL_h
hdiv	r0,r1
huint	r0,r0
jalwr7	rgb_hue2rgb
//				mdbr_pix=((bb<<8)&0xf800) | ((gg<<3)&0x07e0) | ((rr>>3)&0x001f);
lsfti	r1,-3
lsfti	r2,3
lsfti	r3,8
ldbiu	r0,0x1f
and		r1,r0
lsfti	r0,11
and		r3,r0
ldwi	r0,0x07e0
and		r2,r0
or		r1,r2
or		r1,r3
bra		mdbr_endif_idx_lo

//			}
//			else
mdbr_else_idx_lo:
//				mdbr_pix=0;
ldbiu	r1,0
mdbr_endif_idx_lo:

//			if (mdbr_opt)
//				tft_putpix (mdbr_pix);
ldwi	r7,mdbr_ptr
ldw		r0,[r7]
ldwi	r6,mdbr_buf
add		r6,r0
add		r6,r0
stw		[r6],r1
addi	r0,1
stw		[r7],r0

//		}
ldwi	r7,mdbr_ix
ldw		r0,[r7]
addi	r0,1
stw		[r7],r0
bra		mdbr_for_ix

mdbr_for_ix_brk:

//		if (Serial.available ()>0)
//		{
ldwi	r7,uartctl
ldw		r0,[r7]
andi	r0,uart_ravl
beq		mdbr_no_rdat
//			rtncod=ErrCancel;
ldbiu	r0,0xff
ldwi	r7,rtncod
stw		[r7],r0
//			break;
bra		mdbr_for_iy_brk

//		}
mdbr_no_rdat:

//	}
ldwi	r7,mdbr_iy
ldw		r0,[r7]
addi	r0,1
stw		[r7],r0
bra		mdbr_for_iy

mdbr_for_iy_brk:

// elapsed time
ldwi	r6,mdbr_usec
ldwi	r7,sytmmcrh
ldw		r0,[r7]
stw		[r6],r0
addi	r7,2
addi	r6,2
ldw		r0,[r7]
stw		[r6],r0

// send data to the Serial
//		Serial.println (mdbr_SIZE);
ldwi	r1,lab_str_0x
jalwr7	print
ldwi	r1,mdbr_SIZE
jalwr7	print_hex
ldwi	r1,lab_str_crlf
jalwr7	print

//		for (mdbr_idx=0; mdbr_idx<mdbr_SIZE*mdbr_SIZE; mdbr_idx++)
ldwi	r7,mdbr_buf
ldwi	r0,2*mdbr_SIZE*mdbr_SIZE
add		r0,r7
//		{
mdbr_send_loop:
pushw	r0
//			sprintf (fbuf,"%04x",mdbr_buf[mdbr_idx]);
//			Serial.println (fbuf);
pushw	r7
ldw		r1,[r7]
jalwr7	print_hex
ldwi	r1,lab_str_crlf
jalwr7	print
popw	r7
//		}
popw	r0
addi	r7,2
cmp		r7,r0
bne		mdbr_send_loop
rtnw

// ================================
// hue to rgb conversion; disturbed r0,r5~r7
//		r0=hue (0~359) --> r1=red, r2=green, r3=blue (0~255)
// ================================
rgb_hue2rgb:
// parameter
//	hue%=360;
//	if (hue<0)
//		hue += 360;
ldwi	r1,360
add		r0,r1
bmi		pcnt-4
sub		r0,r1
bpl		pcnt-4
add		r0,r1
// hue to rgb
//	hue6q=hue/60;
hhalf	r1,r0
hldi	r2,60
hdiv	r1,r2
huint	r1,r1
ldwi	r7,hue6q
stw		[r7],r1
//	hue6r=hue - hue6q*60;
hhalf	r1,r1
hmul	r1,r2
huint	r1,r1
sub		r0,r1
ldwi	r7,hue6r
stw		[r7],r0
// r5=half (256/60), r6=hue6r
hldi	r5,256/60
ldwi	r6,hue6r
ldw		r6,[r6]
//	switch (hue6q)
//	{
ldwi	r7,hue6q
ldw		r1,[r7]
ldwi	r7,lab_h2r_jmp_tab
add		r7,r1
add		r7,r1
ldw		r7,[r7]
jmp		r7

h2r_jmp_tab:
datw	lab_h2r_cas_0
datw	lab_h2r_cas_1
datw	lab_h2r_cas_2
datw	lab_h2r_cas_3
datw	lab_h2r_cas_4
datw	lab_h2r_cas_5

h2r_cas_0:
//		default:
//		case 0:
//			ir=59*256/60;
ldbiu	r1,59*256/60
//			ig=hue6r*256/60;
hhalf	r2,r6
hmul	r2,r5
huint	r2,r2
//			ib=0;
ldbiu	r3,0
//			break;
bra		h2r_cas_brk

h2r_cas_1:
//		case 1:
//			ir=(59 - hue6r)*256/60;
ldbiu	r1,59
sub		r1,r6
hhalf	r1,r1
hmul	r1,r5
huint	r1,r1
//			ig=59*256/60;
ldbiu	r2,59*256/60
//			ib=0;
ldbiu	r3,0
//			break;
bra		h2r_cas_brk

h2r_cas_2:
//		case 2:
//			ir=0;
ldbiu	r1,0
//			ig=59*256/60;
ldbiu	r2,59*256/60
//			ib=hue6r*256/60;
hhalf	r3,r6
hmul	r3,r5
huint	r3,r3
//			break;
bra		h2r_cas_brk

h2r_cas_3:
//		case 3:
//			ir=0;
ldbiu	r1,0
//			ig=(59 - hue6r)*256/60;
ldbiu	r2,59
sub		r2,r6
hhalf	r2,r2
hmul	r2,r5
huint	r2,r2
//			ib=59*256/60;
ldbiu	r3,59*256/60
//			break;
bra		h2r_cas_brk

h2r_cas_4:
//		case 4:
//			ir=hue6r*256/60;
hhalf	r1,r6
hmul	r1,r5
huint	r1,r1
//			ig=0;
ldbiu	r2,0
//			ib=59*256/60;
ldbiu	r3,59*256/60
//			break;
bra		h2r_cas_brk

h2r_cas_5:
//		case 5:
//			ir=59*256/60;
ldbiu	r1,59*256/60
//			ig=0;
ldbiu	r2,0
//			ib=(59 - hue6r)*256/60;
ldbiu	r3,59
sub		r3,r6
hhalf	r3,r3
hmul	r3,r5
huint	r3,r3
//			break;
bra		h2r_cas_brk

//	}
h2r_cas_brk:
rtnw


// ================================
// 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
// 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_hex r1 ; disturbed r0~r7
//		print r1 as 4 digits hexadecimal number
// ================================
print_hex:
ldbiu	r3,4
ldwi	r7,uarttdat
ldwi	r6,uartctl
ldwi	r5,lab_ph_hexdig
ph_loop:
// print nibble
mov		r0,r1
mov		r4,r5
lsfti	r0,-12
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
lsfti	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
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

// ================================
// c string data
// ================================
str_msg_who:
dats	"OK: mandelbrot ver.1.00\r\n\0"
str_msg_rdy:
dats	"RDY\r\n\0"
str_msg_help:
dats	"OK+ mdbr\r\n"
dats	"OK+ who\r\n"
dats	"OK: help\r\n\0\0"
str_msg_mdbr:
dats	"OK: Mandelbrot (half) 0x\0"
str_msg_mdbr_us:
dats	"[us]\r\n\0"
str_err_unspt:
dats	"ERR: unsupported command: \0"
str_err_syntx:
dats	"ERR: syntax\r\n\0"
str_cmd_mdbr:
dats	"mdbr\0"
str_cmd_who:
dats	"who\0"
str_cmd_help:
dats	"help\0"
str_crlf:
dats	"\r\n\0"
str_0x:
dats	"0x\0"

