changeset 2716:033d8d4308e3

Fix enough issues in uPD78K/II core so that LaserActive firmware regularly polls front-panel button state
author Michael Pavone <pavone@retrodev.com>
date Sat, 12 Jul 2025 22:25:20 -0700
parents 8d4ee0c04ee0
children 04007ac9ee3b
files cpu_dsl.py upd78k2.cpu upd78k2_util.c upd78k2run.c
diffstat 4 files changed, 156 insertions(+), 25 deletions(-) [+]
line wrap: on
line diff
--- a/cpu_dsl.py	Fri Jul 11 10:55:33 2025 -0700
+++ b/cpu_dsl.py	Sat Jul 12 22:25:20 2025 -0700
@@ -2462,6 +2462,8 @@
 	info = {}
 	line_num = 0
 	cur_object = None
+	usedInstNames = set()
+	usedBitPatterns = set()
 	for line in f:
 		line_num += 1
 		line,_,comment = line.partition('#')
@@ -2530,7 +2532,15 @@
 						else:
 							fields[char] = (curbit, 1)
 					curbit -= 1
-				cur_object = Instruction(value, fields, name.strip())
+				name = name.strip()
+				if name in usedInstNames:
+					raise Exception(f'Instruction name {name} was already used!')
+				usedInstNames.add(name)
+				pattern = (table, bitpattern)
+				if pattern in usedBitPatterns:
+					raise Exception(f'Pattern {pattern} was already defined')
+				usedBitPatterns.add(pattern)
+				cur_object = Instruction(value, fields, name)
 				instructions.setdefault(table, []).append(cur_object)
 			elif line.strip() == 'regs':
 				if registers is None:
--- a/upd78k2.cpu	Fri Jul 11 10:55:33 2025 -0700
+++ b/upd78k2.cpu	Sat Jul 12 22:25:20 2025 -0700
@@ -9,7 +9,7 @@
 	body upd78k2_run_op
 	sync_cycle upd78k2_sync_cycle
 	interrupt upd78k2_interrupt
-	extra_tables sfr bit1 bit2 muldiv base sfrbit spmov indexed regind alt_base alt_indexed alt_regind mov_reg xch_reg
+	extra_tables sfr bit1 bit2 muldiv base sfrbit spmov indexed regind alt_base alt_indexed alt_regind mov_reg xch_reg shr shl
 	include upd78k2_util.c
 regs
 	main 8 x a c b e d l h
@@ -28,6 +28,7 @@
 	mem_pointers ptr8 4
 	port_data 8 8
 	port_mode 8 8
+	port_input 8 8
 	puo 8 #pull-up option register
 	pmc3 8 #port 3 pin configuration
 	cr00 16 #16-bit timer comapre register 0
@@ -51,6 +52,8 @@
 	intm0 8 #External interrupt mode register 0
 	intm1 8 #External interrupt mode register 1
 	ist 8 #Interrupt status register
+	io_read ptrupd_io_fun
+	io_write ptrupd_io_fun
 	iram 8 256
 flags
 	register psw
@@ -67,6 +70,7 @@
 	void init_upd78k2_opts(upd78k2_options *opts, memmap_chunk const *chunks, uint32_t num_chunks);
 	upd78k2_context *init_upd78k2_context(upd78k2_options *opts);
 	void upd78k2_sync_cycle(upd78k2_context *upd, uint32_t target_cycle);
+	typedef void (upd_io_fun)(upd78k2_context *upd, uint8_t offset);
 
 #Prefix bytes
 # 0000 0001 -> saddr becomes sfr, mem becomes &mem
@@ -77,6 +81,8 @@
 # 0000 1001 -> mov !addr16/stbc
 # 0000 1010 -> indexed mode
 # 0001 0110 -> register indirect
+# 0011 0000 -> shift/rotate right
+# 0011 0001 -> shift/rotate left
 
 sfr_read
 	arg offset 8
@@ -350,6 +356,14 @@
 	upd78k2_op_fetch
 	dispatch scratch1 xch_reg
 
+00110000 shr_prefix
+	upd78k2_op_fetch
+	dispatch scratch1 shr
+
+00110001 shl_prefix
+	upd78k2_op_fetch
+	dispatch scratch1 shl
+
 sfr 00000110 alt_base_prefix
 	upd78k2_op_fetch
 	dispatch scratch1 alt_base
@@ -370,13 +384,13 @@
 		dst += src
 		update_flags ZAC
 	case 1
-		adc dst src dst
+		adc src dst dst
 		update_flags ZAC
 	case 2
 		dst -= src
 		update_flags ZAC
 	case 3
-		sbc dst src dst
+		sbc src dst dst
 		update_flags ZAC
 	case 4
 		dst &= src
@@ -388,7 +402,7 @@
 		dst |= src
 		update_flags Z
 	case 7
-		cmp dst src
+		cmp src dst
 		update_flags ZAC
 	end
 
@@ -484,7 +498,28 @@
 	saddr_read offset
 	meta dst scratch1
 	aluop P immed
-	saddr_write offset scratch1
+	if P != 7
+		saddr_write offset scratch1
+	end
+
+10011PPP alu_a_saddr
+	upd78k2_op_fetch
+	saddr_read scratch1
+	meta dst a
+	aluop P scratch1
+
+01111PPP alu_saddr_saddr
+	local dst_offset 8
+	local dst_tmp 8
+	upd78k2_op_fetch
+	dst_offset = scratch1
+	saddr_read dst_offset
+	dst_tmp = scratch1
+	upd78k2_op_fetch
+	saddr_read scratch1
+	meta dst dst_tmp
+	aluop P scratch1
+	saddr_write dst_offset dst_tmp
 
 001011PP alu_ax_immed
 	invalid P 0
@@ -840,7 +875,7 @@
 	scratch2 = scratch1
 	sfr_write scratch2 a
 
-00011100 mov_ax_saddr
+00011100 movw_ax_saddr
 	local offset 8
 	upd78k2_op_fetch
 	offset = scratch1
@@ -850,7 +885,7 @@
 	saddr_read offset
 	a = scratch1
 
-00011010 mov_saddr_ax
+00011010 movw_saddr_ax
 	local offset 8
 	upd78k2_op_fetch
 	offset = scratch1
@@ -858,7 +893,7 @@
 	offset += 1
 	saddr_write offset a
 
-00010001 mov_ax_saddr
+00010001 movw_ax_sfr
 	local offset 8
 	upd78k2_op_fetch
 	offset = scratch1
@@ -868,7 +903,7 @@
 	sfr_read offset
 	a = scratch1
 
-00010011 mov_saddr_ax
+00010011 movw_sfr_ax
 	local offset 8
 	upd78k2_op_fetch
 	offset = scratch1
@@ -906,7 +941,7 @@
 	upd78k2_op_fetch
 	offset = scratch1
 	saddr_read offset
-	sub scratch1 1 scratch1 0
+	sub 1 scratch1 scratch1 0
 	update_flags ZA
 	saddr_write offset scratch1
 
@@ -944,6 +979,16 @@
 		pc += scratch1
 	end
 
+0011001R dbnz_r
+	local reg 8
+	reg = R + 2
+	upd78k2_op_fetch
+	main.reg -= 1
+	if !=
+		sext 16 scratch1 scratch1
+		pc += scratch1
+	end
+
 bit1 10100BBB bf_psw
 	local mask 8
 	upd78k2_op_fetch
@@ -1071,12 +1116,12 @@
 	local offset 8
 	offset = T << 1
 	offset += 0x40
-	mem_read_no_exp T
+	mem_read_no_exp offset
 	address = scratch1
-	scratch1 = T + 1
-	mem_read_no_exp scratch1
+	offset += 1
+	mem_read_no_exp offset
 	scratch1 <<= 8
-	address |= 8
+	address |= scratch1
 	push_word pc
 	pc = address
 
@@ -1229,6 +1274,7 @@
 	upd78k2_op_fetch
 	if offset = 0xFE
 		psw = scratch1
+		update_sync
 	else
 		sfr_write offset scratch1
 	end
@@ -1415,7 +1461,7 @@
 	scratch1 &= mask
 	sfr_write offset scratch1
 
-10110BBB set1_saddr_cy
+10110BBB set1_saddr
 	local mask 8
 	local offset 8
 	upd78k2_op_fetch
@@ -1425,7 +1471,7 @@
 	scratch1 |= mask
 	saddr_write offset scratch1
 
-10100BBB clr1_saddr_cy
+10100BBB clr1_saddr
 	local mask 8
 	local offset 8
 	upd78k2_op_fetch
@@ -1443,6 +1489,56 @@
 	psw = scratch1
 	update_sync
 
+shr 10NNNRRR shr_r
+	local cyc 32
+	main.R >>= N
+	update_flags ZA0C
+	cyc = 4 * N
+	cyc += 2
+	cycles cyc
+
+shl 10NNNRRR shl_r
+	local cyc 32
+	main.R <<= N
+	update_flags ZA0C
+	cyc = 4 * N
+	cyc += 2
+	cycles cyc
+
+shr 11NNNRRR shrw_rp
+	local cyc 32
+	local reg 8
+	local tmp 16
+	reg = R + 1
+	tmp = main.reg << 8
+	reg -= 1
+	tmp |= main.reg
+	tmp >>= N
+	update_flags ZA0C
+	main.reg = tmp
+	reg += 1
+	main.reg = tmp >> 8
+	cyc = 6 * N
+	cyc += 2
+	cycles cyc
+
+shl 11NNNRRR shlw_rp
+	local cyc 32
+	local reg 8
+	local tmp 16
+	reg = R + 1
+	tmp = main.reg << 8
+	reg -= 1
+	tmp |= main.reg
+	tmp <<= N
+	update_flags ZA0C
+	main.reg = tmp
+	reg += 1
+	main.reg = tmp >> 8
+	cyc = 6 * N
+	cyc += 2
+	cycles cyc
+
 upd78k2_interrupt
 	local vector_addr 16
 	if cycles >=U int_cycle
--- a/upd78k2_util.c	Fri Jul 11 10:55:33 2025 -0700
+++ b/upd78k2_util.c	Sat Jul 12 22:25:20 2025 -0700
@@ -188,11 +188,27 @@
 uint8_t upd78237_sfr_read(uint32_t address, void *context)
 {
 	upd78k2_context *upd = context;
-	if (address < 8) {
-		return upd->port_data[address];
-	}
 	switch (address)
 	{
+	case 0x00:
+	case 0x04:
+	case 0x05:
+	case 0x06:
+		return upd->port_data[address];
+	case 0x02:
+	case 0x07:
+		//input only
+		if (upd->io_read) {
+			upd->io_read(upd, address);
+		}
+		return upd->port_input[address];
+		break;
+	case 0x01:
+	case 0x03:
+		if (upd->io_read) {
+			upd->io_read(upd, address);
+		}
+		return (upd->port_input[address] & upd->port_mode[address]) | (upd->port_data[address] & ~upd->port_mode[address]);
 	case 0x10:
 		return upd->cr00;
 	case 0x11:
@@ -262,6 +278,9 @@
 		case 0x06:
 			printf("P%X: %02X\n", address & 7, value);
 			upd->port_data[address & 7] = value;
+			if (upd->io_write) {
+				upd->io_write(upd, address);
+			}
 			break;
 		case 0x10:
 			upd78k2_update_timer0(upd);
@@ -400,9 +419,11 @@
 			printf("ISM0: %04X\n", upd->ism0);
 			break;
 		case 0xF4:
+			printf("INTM0: %02X\n", value);
 			upd->intm0 = value;
 			break;
 		case 0xF5:
+			printf("INTM1: %02X\n", value);
 			upd->intm1 = value;
 			break;
 		case 0xF8:
--- a/upd78k2run.c	Fri Jul 11 10:55:33 2025 -0700
+++ b/upd78k2run.c	Sat Jul 12 22:25:20 2025 -0700
@@ -10,13 +10,13 @@
 {
 }
 
-uint8_t pram[384];
-uint8_t rom[0xFC80];
+uint8_t pram[768];
+uint8_t rom[0xFB00];
 
 const memmap_chunk upd_map[] = {
-	{ 0x0000, 0xFC80, 0xFFFFF, .flags = MMAP_READ, .buffer = rom},
-	{ 0xFC80, 0xFD00, 0x7F, .flags = MMAP_READ | MMAP_WRITE | MMAP_CODE, .buffer = pram},
-	{ 0xFD00, 0xFE00, 0xFF, .flags = MMAP_READ | MMAP_WRITE | MMAP_CODE, .buffer = pram + 128},
+	{ 0x0000, 0xFB00, 0xFFFFF, .flags = MMAP_READ, .buffer = rom},
+	{ 0xFB00, 0xFD00, 0x1FF, .flags = MMAP_READ | MMAP_WRITE | MMAP_CODE, .buffer = pram},
+	{ 0xFD00, 0xFE00, 0xFF, .flags = MMAP_READ | MMAP_WRITE | MMAP_CODE, .buffer = pram + 512},
 	{ 0xFF00, 0xFFFF, 0xFF, .read_8 = upd78237_sfr_read, .write_8 = upd78237_sfr_write}
 };
 
@@ -64,6 +64,10 @@
 	fclose(f);
 	init_upd78k2_opts(&opts, upd_map, 4);
 	upd = init_upd78k2_context(&opts);
+	upd->port_input[2] = 0xFF;
+	upd->port_input[3] = 0x20;
+	upd->port_input[7] = 0xF7;
+	
 	upd->pc = rom[0] | rom[1] << 8;
 	upd78k2_execute(upd, 10000000);
 	return 0;