changeset 46:51672bd41cdd

Rework data segment setup to allow a stack segment and to add space for push and pop instructions
author Michael Pavone <pavone@retrodev.com>
date Tue, 30 Aug 2016 20:50:54 -0700
parents 5338b9affd09
children 506b531cf570
files simple_console.txt src/asm.c src/cpu.c src/cpu.h src/mnemonics.c
diffstat 5 files changed, 78 insertions(+), 44 deletions(-) [+]
line wrap: on
line diff
--- a/simple_console.txt	Mon Aug 29 21:17:41 2016 -0700
+++ b/simple_console.txt	Tue Aug 30 20:50:54 2016 -0700
@@ -63,36 +63,44 @@
 
 0: reti - return from interrupt, D = register to restore from uer
 1: trapi
-2: getepc
-3: setepc
-4: getepch
-5: setepch
-6: getesr
-7: setesr
-8: getenum
-9: setenum
+2: push
+3: pop
+4: getpch
+5: setpch
+6: getepc
+7: setepc
+8: getesr
+9: setesr
 A: getuer
 B: setuer
-C: getvbr
-D: setvbr
-E: getdatabanks
-F: setdatabanks
+C: getenum
+D: setenum
+E: getvbr
+F: setvbr
 
 
 Registers:
 
-r0 - r12 : general purpose
-r13 : technically general purpose, but canonically the stack register
+r0 - r11 : general purpose
+r12 : Data Banks - Holds the upper bytes used for data accesses (MSB = byte for lower half of memory space, LSB = byte for upper half of memory space)
+r13 : stack register
 r14 : PC
-r15 : status register
+r15 : status register, Stack MSB
+	Layout: XSSS SSSS XXXN CZ10
+		S = Stack most significant bits
+		N = Negaitve flag
+		C = Carry flag
+		Z = Zero flag
+		1 = Interrupt 1 enable
+		0 = Interrupt 0 enable
 
 Special Registers
+pch - PC High - Low byte stores current PC High value, Upper byte stores saved PC High value when entering an exception handler
 epc - Exception PC - Stores PC value to resume to when entering an exception handler
-epch - High 7-bits of PC
 esr - Exception SR - same as above, but for SR
 eur - Exceptuion User Reg - reg for temporary storage of a reg in a handler, intended to be used for the stack pointer
 enum - Exception Number - holds the number of the most recent exception
-databanks - Holds the upper bytes used for data accesses (MSB = byte for upper half of memory space, LSB = byte for lower half of memory space)
+vbr - Vector Base Register - Base address in page 0 of vector table
 
 IO: Ports
 
@@ -151,8 +159,22 @@
 	$400000 - $4FFFFF - 128K RAM, mirrored every 128KB
 	$500000 - $6FFFFF - Reserved
 	$700000 - $7FFFFF - 64KB VRAM back buffer, mirrored every 64KB
+	
+Banking/Segments:
+	Code Segment: 64KB, used for instruction fetch and PC-relative load/stores
+	Stack Segment: 64KB, used for push/pop and SP-relative load/stores
+	Upper Data Segment: 32KB, used for load/stores to addresses in the upper half of the 16-bit address space
+	Lower Data Segment: 32KB, used for load/stores to addresses in the lower half of the 16-bit address space
 
-
+	23-bit address generation details:
+		Code segment
+			r14 (aka PC) is used for the low 16 bits of the address and PCH is used for the upper 7 bits
+		Stack Segment
+			r13 (aka SP) is used for the low 16 bits of the address and the upper byte of SR is used for
+			the upper 7-bits. Note that for a load/store that uses both PC and SP, the code segment is used
+		Data segments
+			The low 15-bits of the computed 16-bit address are used directly. The most significant bit
+			selects a data segment and then the relevant byte of r12 is used for the upper 8 bits
 26.112 MHZ Clock
 Dot Clock Divider 4
 CPU Clock Divider 4 (assuming 1 cycle/instruction, 1 for 4 cycles/instruction)
--- a/src/asm.c	Mon Aug 29 21:17:41 2016 -0700
+++ b/src/asm.c	Tue Aug 30 20:50:54 2016 -0700
@@ -120,8 +120,8 @@
 		}
 		return ret;
 	}
-	index = find_string_arr(mnemonics_single_reg, mnemonic, SETDATABANKS+1);
-	if (index > SETDATABANKS) {
+	index = find_string_arr(mnemonics_single_reg, mnemonic, SETVBR+1);
+	if (index > SETVBR) {
 		ret.base = 0xFFFF;
 		return ret;
 	}
@@ -308,6 +308,14 @@
 			return 1;
 		}
 	}
+	if (!strcmp(arg, "db")) {
+		*inst |= REG_DB << arg_shift;
+		return 1;
+	}
+	if (!strcmp(arg, "sp")) {
+		*inst |= REG_SP << arg_shift;
+		return 1;
+	}
 	if (!strcmp(arg, "pc")) {
 		*inst |= REG_PC << arg_shift;
 		return 1;
--- a/src/cpu.c	Mon Aug 29 21:17:41 2016 -0700
+++ b/src/cpu.c	Tue Aug 30 20:50:54 2016 -0700
@@ -127,10 +127,10 @@
 void vector_fetch(cpu *context)
 {
 	context->exception_pc = context->regs[REG_PC] - 2;
-	context->exception_pch = context->pc_msb >> 16;
+	context->exception_pc_msb = context->pc_msb;
 	context->exception_sr = context->regs[REG_SR];
 	context->regs[REG_SR] &= ~(STATUS_INT0_ENABLE | STATUS_INT1_ENABLE);
-	context->regs[REG_PC] = cpu_read_16(context, context->vector_base + context->exception * 2);
+	context->regs[REG_PC] = cpu_read_16(context, (context->vector_base + context->exception * 2) & 0xFFFF);
 	context->pc_msb = 0;
 	context->state = STATE_NEED_FETCH;
 }
@@ -236,12 +236,25 @@
 		context->regs[dst] = context->exception_ur;
 		context->regs[REG_PC] = context->exception_pc;
 		context->regs[REG_SR] = context->exception_sr;
+		context->pc_msb = context->exception_pc_msb;
 		context->state = STATE_NEED_FETCH;
 		return;
 	case TRAPI:
 		context->state = STATE_EXCEPTION_START;
 		context->exception = dst;
-		return;	
+		return;
+	case PUSH:
+		break;
+	case POP:
+		break;
+	case GETPCH:
+		context->regs[dst] = context->exception_pc_msb >> 8 | context->pc_msb >> 16;
+		break;
+	case SETPCH:
+		context->exception_pc_msb = context->regs[dst] << 8 & 0x7F0000;
+		context->pc_msb = context->regs[dst] << 16 & 0x7F0000;
+		context->state = STATE_NEED_FETCH;
+		return;
 	case GETEPC:
 		context->regs[dst] = context->exception_pc;
 		break;
@@ -272,17 +285,6 @@
 	case SETVBR:
 		context->vector_base = context->regs[dst];
 		break;
-	case GETDATABANKS:
-		context->regs[dst] = context->data_high_msb >> 7 | context->data_low_msb >> 15;
-		break;
-	case SETDATABANKS:
-		context->data_high_msb = (context->regs[dst] & 0xFF00) << 7;
-		context->data_low_msb = (context->regs[dst] & 0xFF) << 15;
-		break;
-	default:
-		context->state = STATE_EXCEPTION_START;
-		context->exception = EXCEPTION_INVALID_INSTRUCTION;
-		return;
 	}
 	if (dst == REG_PC) {
 		context->state = STATE_NEED_FETCH;
@@ -390,10 +392,12 @@
 	uint32_t address = context->regs[a] + context->regs[b];
 	if (a == REG_PC || b == REG_PC) {
 		address |= context->pc_msb;
+	} else if (a == REG_SP || b == REG_SP) {
+		address |= context->regs[REG_SR] << 8 & 0x7F0000;
 	} else if (address & 0x8000) {
-		address = (address & 0x7FFF) | context->data_high_msb;
+		address = (address & 0x7FFF) | (context->regs[REG_DB] << 15 & 0x7F8000);
 	} else {
-		address |= context->data_low_msb;
+		address |= context->regs[REG_DB] << 7 & 0x7F8000;
 	}
 	return address;
 }
--- a/src/cpu.h	Mon Aug 29 21:17:41 2016 -0700
+++ b/src/cpu.h	Tue Aug 30 20:50:54 2016 -0700
@@ -34,13 +34,11 @@
 	uint16_t regs[16];
 	uint16_t exception;
 	uint16_t exception_pc;
-	uint16_t exception_pch;
 	uint16_t exception_sr;
 	uint16_t exception_ur;
 	uint16_t vector_base;
 	uint32_t pc_msb;
-	uint32_t data_low_msb;
-	uint32_t data_high_msb;
+	uint32_t exception_pc_msb;
 	
 	uint16_t prefetch;
 	
@@ -103,10 +101,12 @@
 enum {
 	RETI,
 	TRAPI,
+	PUSH,
+	POP,
+	GETPCH,
+	SETPCH,
 	GETEPC,
 	SETEPC,
-	GETEPCH,
-	SETEPCH,
 	GETESR,
 	SETESR,
 	GETEUR,
@@ -115,8 +115,6 @@
 	SETENUM,
 	GETVBR,
 	SETVBR,
-	GETDATABANKS,
-	SETDATABANKS,
 };
 
 enum {
@@ -132,6 +130,8 @@
 	COND_LEQ
 };
 
+#define REG_DB 12
+#define REG_SP 13
 #define REG_PC 14
 #define REG_SR 15
 
--- a/src/mnemonics.c	Mon Aug 29 21:17:41 2016 -0700
+++ b/src/mnemonics.c	Tue Aug 30 20:50:54 2016 -0700
@@ -8,5 +8,5 @@
 };
 
 char * mnemonics_single_reg[] = {
-	"reti", "trapi", "getepc", "setepc", "getepch", "setepch", "getesr", "setesr", "getenum", "setenum", "getuer", "setuer", "getvbr", "setvbr", "getdatabanks", "setdatabanks"
+	"reti", "trapi", "push", "pop", "getpch", "setpch", "getepc", "setepc", "getesr", "setesr", "getuer", "setuer", "getenum", "setenum", "getvbr", "setvbr"
 };