aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2018-09-18 18:20:03 -0700
committerH. Peter Anvin <hpa@zytor.com>2018-09-18 18:20:03 -0700
commitb48072bec7a7035bb8135d779ee5792e377fa057 (patch)
tree3bc846ec2c17513ebb059cb5083bcb5c8ed726ce
parent8b942352c2bbf004eb732d583fe2b4e76a28e837 (diff)
downloadabc80sim-b48072bec7a7035bb8135d779ee5792e377fa057.tar.gz
abc80sim-b48072bec7a7035bb8135d779ee5792e377fa057.tar.xz
abc80sim-b48072bec7a7035bb8135d779ee5792e377fa057.zip
abc802: make MEM: and the CTC timer interrupt work
We now can open the MEM: area correctly, and the CTC timer interrupt works, although with hard-coded time constants.
-rw-r--r--abcio.c15
-rw-r--r--abcio.h3
-rw-r--r--abcmem.c33
-rw-r--r--clock.c89
-rw-r--r--z80.c4
-rw-r--r--z80.h1
6 files changed, 118 insertions, 27 deletions
diff --git a/abcio.c b/abcio.c
index 0a22138..173fea4 100644
--- a/abcio.c
+++ b/abcio.c
@@ -143,6 +143,7 @@ static void dart_keyb_out(uint8_t port, uint8_t value)
break;
case 5:
setmode40(!!(value & 2));
+ abc802_set_mem(!!(value & 0x80));
break;
default:
break;
@@ -222,6 +223,13 @@ static void abc802_out(uint8_t port, uint8_t value)
crtc_out(port, value);
break;
+ case 96:
+ case 97:
+ case 98:
+ case 99:
+ abc800_ctc_out(port, value);
+ break;
+
default:
break;
}
@@ -331,6 +339,13 @@ static uint8_t abc802_in(uint8_t port)
v = crtc_in(port);
break;
+ case 96:
+ case 97:
+ case 98:
+ case 99:
+ v = abc800_ctc_in(port);
+ break;
+
default:
break;
}
diff --git a/abcio.h b/abcio.h
index b25e76c..5f5e3ca 100644
--- a/abcio.h
+++ b/abcio.h
@@ -22,6 +22,9 @@ extern int disk_in(int sel, int port);
extern int rtc_in(int sel, int port);
+extern void abc800_ctc_out(uint8_t, uint8_t);
+extern uint8_t abc800_ctc_in(uint8_t);
+
extern void printer_reset(void);
extern void printer_out(int sel, int port, int value);
extern int printer_in(int sel, int port);
diff --git a/abcmem.c b/abcmem.c
index 9c7b5cf..49f708c 100644
--- a/abcmem.c
+++ b/abcmem.c
@@ -27,6 +27,9 @@ extern void write_screen(uint8_t *p, uint8_t v);
#define MEM_MAPS 8
static struct mem_page memmaps[MEM_MAPS][PAGE_COUNT];
+/* Latch the last M1 address fetched, like ABC800 does */
+static uint16_t last_m1_address;
+
/*
* Currently active memory map(s)
*
@@ -37,7 +40,7 @@ static const struct mem_page *current_map[2];
static inline const struct mem_page *get_page(uint16_t addr)
{
- size_t map = (REG_PC & 0xf800) == 0x7800;
+ size_t map = (last_m1_address & 0xf800) == 0x7800;
return &current_map[map][addr >> PAGE_SHIFT];
}
@@ -119,6 +122,14 @@ uint8_t mem_fetch(uint16_t address)
return do_mem_read(address);
}
+/* This is called when fetching the first opcode byte, corresponding to M1# */
+uint8_t mem_fetch_m1(uint16_t address)
+{
+ /* Don't trace instruction fetches */
+ last_m1_address = address;
+ return do_mem_read(address);
+}
+
/*
* Words are stored with the low-order byte in the lower address.
*/
@@ -236,12 +247,18 @@ void abc802_set_mem(bool opened)
}
+#define K(x) ((x)*1024)
+#define ALL_MAPS ((1U << MEM_MAPS)-1)
+
static void
map_memory(unsigned int maps, size_t where, size_t size,
void *what, write_func wfunc)
{
size_t m;
+ assert(((where|size) & PAGE_MASK) == 0);
+ assert((maps & ~ALL_MAPS) == 0);
+
for (m = 0; maps; m++, maps >>=1) {
struct mem_page *mp;
uint8_t *datap;
@@ -264,9 +281,6 @@ map_memory(unsigned int maps, size_t where, size_t size,
}
}
-#define K(x) ((x)*1024)
-#define ALL_MAPS ((1U << MEM_MAPS)-1)
-
void mem_init(unsigned int flags)
{
/* Start by initializing all memory maps to all RAM */
@@ -302,17 +316,20 @@ void mem_init(unsigned int flags)
break;
case MODEL_ABC802:
- /* Map 0: normal execution, map 1: option ROM */
+ /* Map 0: normal execution */
if (!(flags & MEMFL_NOBASIC))
- map_memory(0x03, 0, K(24), abc802rom, write_rom);
+ map_memory(0x01, 0, K(24), abc802rom, write_rom);
if (!(flags & MEMFL_NODEV))
- map_memory(0x03, K(24), K(8), &abc802rom[K(24)], write_rom);
+ map_memory(0x01, K(24), K(8), &abc802rom[K(24)], write_rom);
map_memory(0x01, K(30), K(2), video_ram, write_screen);
- /* Map 2: MEM area open = all RAM */
+ /* Map 1: execution in option ROM - RAM other than the ROM itself */
+ map_memory(0x02, K(30), K(2), &abc802rom[K(30)], write_rom);
+
+ /* Map 2: MEM area open in its entirety */
abc802_set_mem(false); /* On start, MEM area closed */
break;
diff --git a/clock.c b/clock.c
index 9f3bacc..2de4c63 100644
--- a/clock.c
+++ b/clock.c
@@ -4,24 +4,8 @@
#include "clock.h"
#include "nstime.h"
-/*
- * ABC80: Trig a non maskable interrupt in the Z80 on the clock signal.
- */
-static void abc80_clock_tick(void)
-{
- z80_nmi();
-}
-
-static uint8_t ctc_irq = -1;
-static uint8_t ctc_cmd[4]; /*ctc_div[4] */
-
-/*
- * ABC800: Clock interrupt through the CTC
- */
-static void abc800_clock_tick(void)
-{
- z80_interrupt(ctc_irq);
-}
+static void abc80_clock_tick(void);
+static void abc800_clock_tick(void);
/*
* Initialize the time for next event
@@ -83,3 +67,72 @@ bool timer_poll(void)
return blink;
}
+
+/*
+ * ABC80: Trig a non maskable interrupt in the Z80 on the clock signal.
+ */
+static void abc80_clock_tick(void)
+{
+ z80_nmi();
+}
+
+static uint8_t ctc_ctl[4], ctc_div[4], ctc_vector;
+
+/*
+ * ABC800: Clock interrupt through the CTC
+ */
+
+static uint8_t ctc_ctl[4], ctc_div[4], ctc_vector;
+
+static void abc800_clock_tick(void)
+{
+ if ((ctc_ctl[3] & 0xc0) == 0x80)
+ z80_interrupt(ctc_vector | (3 << 1)); /* 3 = channel */
+}
+
+/*
+ * CTC I/O
+ */
+void abc800_ctc_out(uint8_t port, uint8_t v)
+{
+ if ((v & 1) == 0) {
+ ctc_vector = v;
+ return;
+ }
+
+ port &= 3; /* Get channel */
+
+ if (ctc_ctl[port] & 4) {
+ ctc_div[port] = v;
+ ctc_ctl[port] &= ~4;
+ return;
+ }
+
+ if (v & 2)
+ v = 1; /* Reset channel */
+
+ ctc_ctl[port] = v;
+}
+
+uint8_t abc800_ctc_in(uint8_t port)
+{
+ uint8_t v;
+
+ switch (port & 3) {
+ case 0:
+ case 1:
+ case 2:
+ v = 0xff;
+ break;
+
+ case 3:
+ {
+ uint64_t now = nstime();
+ v = ((clock_timer.last + clock_timer.period - now) * ctc_div[3])
+ / clock_timer.period;
+ break;
+ }
+ }
+
+ return v;
+}
diff --git a/z80.c b/z80.c
index a0f813c..f4ac870 100644
--- a/z80.c
+++ b/z80.c
@@ -2563,8 +2563,8 @@ int z80_run(bool continuous, bool halted)
ix = &z80_state.hl; /* Not an index instruction */
+ instruction = mem_fetch_m1(REG_PC++);
indexed:
- instruction = mem_fetch(REG_PC++);
inc_r();
switch(instruction)
@@ -2574,12 +2574,14 @@ int z80_run(bool continuous, bool halted)
break;
case 0xDD: /* DD.. extended instruction */
ix = &z80_state.ix;
+ instruction = mem_fetch(REG_PC++);
goto indexed;
case 0xED: /* ED.. extended instruction */
do_ED_instruction(ix);
break;
case 0xFD: /* FD.. extended instruction */
ix = &z80_state.iy;
+ instruction = mem_fetch(REG_PC++);
goto indexed;
case 0x8F: /* adc a, a */
diff --git a/z80.h b/z80.h
index f834458..558e1dd 100644
--- a/z80.h
+++ b/z80.h
@@ -174,6 +174,7 @@ extern void z80_reset(void);
extern int z80_run(bool,bool);
extern uint8_t mem_read(uint16_t);
extern uint8_t mem_fetch(uint16_t);
+extern uint8_t mem_fetch_m1(uint16_t);
extern void mem_write(uint16_t, uint8_t);
extern uint8_t *mem_rom_address(void);
extern uint8_t *mem_get_addr(uint16_t);