changeset 2714:d30e7f605ff8

Get uPD78k/II timer interrupts actually working and implement instructions needed for them to run to completion
author Michael Pavone <pavone@retrodev.com>
date Thu, 10 Jul 2025 20:27:49 -0700
parents a88eff3fb5d8
children 8d4ee0c04ee0
files cpu_dsl.py upd78k2.cpu upd78k2_util.c
diffstat 3 files changed, 179 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- a/cpu_dsl.py	Thu Jul 10 16:07:04 2025 -0700
+++ b/cpu_dsl.py	Thu Jul 10 20:27:49 2025 -0700
@@ -1253,7 +1253,12 @@
 	return ret
 	
 def _updateSyncCImpl(prog, params):
-	return '\n\t{sync}(context, target_cycle);'.format(sync=prog.sync_cycle)
+	ret = ''
+	if prog.needFlagDisperse:
+		ret += prog.flags.disperseFlags(prog, 'c')
+		prog.needFlagDispserse = False
+	ret += f'\n\t{prog.sync_cycle}(context, target_cycle);'
+	return ret
 
 _opMap = {
 	'mov': Op(lambda val: val).cUnaryOperator(''),
--- a/upd78k2.cpu	Thu Jul 10 16:07:04 2025 -0700
+++ b/upd78k2.cpu	Thu Jul 10 20:27:49 2025 -0700
@@ -280,24 +280,28 @@
 	end
 	mem_write_no_exp full_address value
 
+push_byte
+	arg value 8
+	sp -= 1
+	mem_write_no_exp sp value
+
 push_word
 	arg value 16
 	local tmp 8
 	tmp = value >> 8
-	sp -= 1
-	mem_write_no_exp sp tmp
-	tmp = value
-	sp -= 1
-	mem_write_no_exp sp tmp
+	push_byte tmp
+	push_byte value
+
+pop_byte
+	mem_read_no_exp sp
+	sp += 1
 
 pop_word
-	mem_read_no_exp sp
+	pop_byte
 	dst = scratch1
-	sp += 1
-	mem_read_no_exp sp
+	pop_byte
 	scratch1 <<= 8
 	dst |= scratch1
-	sp += 1
 
 00000000 nop
 	cycles 2 #minimum cycle time appears to be 4 (ignoring internal divider)
@@ -401,6 +405,26 @@
 		#TODO: what happens in these invalid cases
 	end
 
+aluop16_ax
+	local tmp 16
+	arg op 8
+	arg src 16
+	tmp = a << 8
+	tmp |= x
+	switch op
+	case 1
+		tmp += src
+		update_flags ZAC
+	case 2
+		tmp -= src
+		update_flags ZAC
+	case 3
+		tmp -= src
+		update_flags ZAC
+	end
+	x = tmp
+	a = tmp >> 8
+
 10001PPP alu_r_r
 	local tmp_src 16
 	local tmp_dst 16
@@ -457,6 +481,39 @@
 	meta dst scratch1
 	aluop P immed
 	saddr_write offset scratch1
+
+001011PP alu_ax_immed
+	invalid P 0
+	upd78k2_op_fetch_word
+	aluop16_ax P scratch1
+
+000111PP alu_ax_saddr
+	invalid P 0
+	local offset 8
+	local tmp 8
+	upd78k2_op_fetch
+	offset = scratch1
+	saddr_read offset
+	tmp = scratch1
+	offset += 1
+	saddr_read offset
+	scratch1 <<= 16
+	scratch1 |= tmp
+	aluop16_ax P scratch1
+
+sfr 000111PP alu_ax_sfr
+	invalid P 0
+	local offset 8
+	local tmp 8
+	upd78k2_op_fetch
+	offset = scratch1
+	sfr_read offset
+	tmp = scratch1
+	offset += 1
+	sfr_read offset
+	scratch1 <<= 16
+	scratch1 |= tmp
+	aluop16_ax P scratch1
 	
 calc_addr_base
 	arg regpair 8
@@ -733,6 +790,62 @@
 	scratch2 = scratch1
 	mem_write_no_exp scratch2 a
 
+00100000 mov_a_saddr
+	upd78k2_op_fetch
+	saddr_read scratch1
+	a = scratch1
+
+00100010 mov_saddr_a
+	upd78k2_op_fetch
+	scratch2 = scratch1
+	saddr_write scratch2 a
+
+00010000 mov_a_sfr
+	upd78k2_op_fetch
+	sfr_read scratch1
+	a = scratch1
+
+00010010 mov_sfr_a
+	upd78k2_op_fetch
+	scratch2 = scratch1
+	sfr_write scratch2 a
+
+00011100 mov_ax_saddr
+	local offset 8
+	upd78k2_op_fetch
+	offset = scratch1
+	saddr_read offset
+	x = scratch1
+	offset += 1
+	saddr_read offset
+	a = scratch1
+
+00011010 mov_saddr_ax
+	local offset 8
+	upd78k2_op_fetch
+	offset = scratch1
+	saddr_write offset x
+	offset += 1
+	saddr_write offset a
+
+00010001 mov_ax_saddr
+	local offset 8
+	upd78k2_op_fetch
+	offset = scratch1
+	sfr_read offset
+	x = scratch1
+	offset += 1
+	sfr_read offset
+	a = scratch1
+
+00010011 mov_saddr_ax
+	local offset 8
+	upd78k2_op_fetch
+	offset = scratch1
+	sfr_write offset x
+	offset += 1
+	sfr_write offset a
+
 11000RRR inc_r
 	cycles 2
 	main.R += 1
@@ -743,6 +856,24 @@
 	main.R -= 1
 	update_flags ZA
 
+00100110 inc_saddr
+	local offset 8
+	upd78k2_op_fetch
+	offset = scratch1
+	saddr_read offset
+	add scratch1 1 scratch1 0
+	update_flags ZA
+	saddr_write offset scratch1
+
+00100111 dec_saddr
+	local offset 8
+	upd78k2_op_fetch
+	offset = scratch1
+	saddr_read offset
+	sub scratch1 1 scratch1 0
+	update_flags ZA
+	saddr_write offset scratch1
+
 11010RRR mov_a_r
 	a = main.R
 
@@ -1241,16 +1372,32 @@
 	scratch1 &= mask
 	saddr_write offset scratch1
 
+01010111 reti
+	meta dst pc
+	pop_word
+	pop_byte
+	psw = scratch1
+	update_sync
+
 upd78k2_interrupt
+	local vector_addr 16
 	if cycles >=U int_cycle
 		update_sync
 		if int_enable
 			scratch1 = ~mk0
 			scratch1 &= if0
 			if !=
+				push_byte psw
+				push_word pc
 				ocall calc_vector
-				mem_read_no_exp scratch1
+				vector_addr = scratch1
+				mem_read_no_exp vector_addr
 				pc = scratch1
+				vector_addr += 1
+				mem_read_no_exp vector_addr
+				scratch1 <<= 8
+				pc |= scratch1
+				int_enable = 0
 			end
 		end
 	end
--- a/upd78k2_util.c	Thu Jul 10 16:07:04 2025 -0700
+++ b/upd78k2_util.c	Thu Jul 10 20:27:49 2025 -0700
@@ -193,6 +193,18 @@
 	}
 	switch (address)
 	{
+	case 0x10:
+		return upd->cr00;
+	case 0x11:
+		return upd->cr00 >> 8;
+	case 0x12:
+		return upd->cr01;
+	case 0x13:
+		return upd->cr01 >> 8;
+	case 0x14:
+		return upd->cr10;
+	case 0x1C:
+		return upd->cr11;
 	case 0x21:
 	case 0x26:
 		return upd->port_mode[address & 0x7];
@@ -269,7 +281,7 @@
 			upd78k2_update_timer0(upd);
 			upd->cr01 &= 0xFF00;
 			upd->cr01 |= value;
-			printf("CR01: %04X\n", upd->cr00);
+			printf("CR01: %04X\n", upd->cr01);
 			upd78k2_calc_next_int(upd);
 			break;
 		case 0x13:
@@ -438,12 +450,15 @@
 {
 	uint32_t pending_enabled = upd->scratch1;
 	uint32_t vector = 0x6;
+	uint32_t bit = 1;
 	while (pending_enabled)
 	{
 		if (pending_enabled & 1) {
+			upd->if0 &= ~bit;
 			upd->scratch1 = vector;
 			return;
 		}
+		bit <<= 1;
 		pending_enabled >>= 1;
 		vector += 2;
 		if (vector == 0xE) {