aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2018-09-18 16:50:16 -0700
committerH. Peter Anvin <hpa@zytor.com>2018-09-18 16:50:16 -0700
commit8b942352c2bbf004eb732d583fe2b4e76a28e837 (patch)
tree370c31941909b62a34d7619afb41e51b1ce77bc4
parent61ba4fa24c18cbf476b230c374659f66644a5f6b (diff)
downloadabc80sim-8b942352c2bbf004eb732d583fe2b4e76a28e837.tar.gz
abc80sim-8b942352c2bbf004eb732d583fe2b4e76a28e837.tar.xz
abc80sim-8b942352c2bbf004eb732d583fe2b4e76a28e837.zip
abc802: enough of a DART CH-B model to support keyboard and WIDTH
Implement enough of a DART channel B model to support entering stuff on the keyboard and also support the WIDTH command and vertical retrace.
-rw-r--r--abcio.c115
-rw-r--r--abcio.h2
-rw-r--r--clock.c9
-rw-r--r--sdlscrn.c12
4 files changed, 131 insertions, 7 deletions
diff --git a/abcio.c b/abcio.c
index eb26896..0a22138 100644
--- a/abcio.c
+++ b/abcio.c
@@ -13,7 +13,7 @@ static int8_t abcbus_select = -1;
/* Keyboard IRQ vector */
static uint8_t keyb_irq = 0xff; /* = no IRQ vector set */
static uint8_t keyb_data;
-static bool keyb_new;
+static bool keyb_new, keyb_down;
extern void disk_reset(void);
extern void disk_out(int, int, int);
@@ -93,7 +93,7 @@ static void abc80_out(uint8_t port, uint8_t value)
case (57 & 0x17): /* Keyboard control port */
if (!(value & 1)) {
- keyb_irq = value >> 1;
+ keyb_irq = value;
}
break;
@@ -102,6 +102,102 @@ static void abc80_out(uint8_t port, uint8_t value)
}
}
+static bool vsync;
+void abc802_vsync(void)
+{
+ vsync = true;
+}
+
+static uint8_t dart_keyb_ctl[8];
+static bool dart_keyb_vsync;
+
+static void dart_keyb_out(uint8_t port, uint8_t value)
+{
+ /* Keyboard DART control */
+ uint8_t reg;
+
+ if ((port & 1) == 0) {
+ return; /* Data out - ignore for now */
+ }
+
+ reg = dart_keyb_ctl[0] & 7;
+ dart_keyb_ctl[0] &= ~7; /* Restore register 0 */
+
+ dart_keyb_ctl[reg] = value;
+ switch (reg) {
+ case 0:
+ switch ((value >> 3) & 7) {
+ case 2:
+ dart_keyb_vsync = vsync;
+ vsync = false;
+ break;
+ case 3:
+ keyb_irq = -1;
+ memset(dart_keyb_ctl, 0, sizeof dart_keyb_ctl);
+ return;
+ case 4:
+ break; /* Allow IRQ to be enabled */
+ default:
+ return;
+ }
+ break;
+ case 5:
+ setmode40(!!(value & 2));
+ break;
+ default:
+ break;
+ }
+
+ if ((dart_keyb_ctl[1] & 0x18) == 0) {
+ keyb_irq = 0;
+ } else {
+ if (dart_keyb_ctl[1] & 0x04) {
+ /* Status affects vector */
+ keyb_irq = (dart_keyb_ctl[2] & ~0x0f) | 0x04;
+ } else {
+ keyb_irq = (dart_keyb_ctl[1] & ~0x01);
+ }
+ }
+}
+
+static uint8_t dart_keyb_in(uint8_t port)
+{
+ uint8_t v, reg;
+
+ if ((port & 1) == 0) {
+ /* Data register */
+ keyb_new = false;
+ v = keyb_data;
+ return keyb_data;
+ }
+
+ /* Control register */
+
+ reg = dart_keyb_ctl[0] & 7;
+ dart_keyb_ctl[0] &= ~7; /* Restore register 0 */
+
+ switch (reg) {
+ case 0:
+ v = ((keyb_new) << 0) +
+ (1 << 2) + /* Transmit buffer empty */
+ (keyb_down << 3) + /* DCD -> key down */
+ (dart_keyb_vsync << 4) + /* RI -> vsync */
+ (1 << 5); /* CTS -> 60 Hz */
+ break;
+ case 1:
+ v = (1 << 0); /* All sent */
+ break;
+ case 2:
+ v = dart_keyb_ctl[2];
+ break;
+ default:
+ v = 0;
+ break;
+ }
+
+ return v;
+}
+
static void abc802_out(uint8_t port, uint8_t value)
{
port = abc800_mangle_port(port);
@@ -116,6 +212,11 @@ static void abc802_out(uint8_t port, uint8_t value)
abcbus_out(port, value);
break;
+ case 34:
+ case 35:
+ dart_keyb_out(port, value);
+ break;
+
case 56:
case 57:
crtc_out(port, value);
@@ -220,6 +321,11 @@ static uint8_t abc802_in(uint8_t port)
v = abcbus_in(port);
break;
+ case 34:
+ case 35:
+ v = dart_keyb_in(port);
+ break;
+
case 56:
case 57:
v = crtc_in(port);
@@ -250,6 +356,8 @@ int z80_in(int port)
void keyboard_down(int sym)
{
+ keyb_down = true;
+
switch (model) {
case MODEL_ABC80:
if (sym <= 127) {
@@ -268,6 +376,8 @@ void keyboard_down(int sym)
void keyboard_up(void)
{
+ keyb_down = false;
+
switch (model) {
case MODEL_ABC80:
keyb_data &= ~0x80;
@@ -289,5 +399,6 @@ void io_init(void)
case MODEL_ABC802:
do_out = abc802_out;
do_in = abc802_in;
+ keyb_data = 0xff;
}
}
diff --git a/abcio.h b/abcio.h
index 7fa60e7..b25e76c 100644
--- a/abcio.h
+++ b/abcio.h
@@ -31,4 +31,6 @@ extern void check_event(void);
extern void keyboard_down(int sym);
extern void keyboard_up(void);
+extern void abc802_vsync(void);
+
#endif
diff --git a/clock.c b/clock.c
index 78ab4a5..9f3bacc 100644
--- a/clock.c
+++ b/clock.c
@@ -30,7 +30,7 @@ struct abctimer {
uint64_t last;
uint64_t period;
};
-static struct abctimer clock_timer, blink_timer;
+static struct abctimer clock_timer, vsync_timer, blink_timer;
static void (*clock_tick)(void);
void timer_init(void)
@@ -43,15 +43,17 @@ void timer_init(void)
case MODEL_ABC802:
clock_timer.period = 10666667; /* 10.67 ms = 93.75 Hz */
clock_tick = abc800_clock_tick;
+ vsync_timer.period = 20000000;
break;
}
blink_timer.period = 400000000; /* 400 ms = 2.5 Hz */
- clock_timer.last = blink_timer.last = nstime();
+ clock_timer.last = blink_timer.last = vsync_timer.last = nstime();
}
static inline bool trigger(uint64_t now, struct abctimer *tmr)
{
+ /* This expression: a) will overflow safely, b) will never trigger for 0 */
if (likely((now - tmr->last) < tmr->period))
return false;
@@ -73,6 +75,9 @@ bool timer_poll(void)
if (trigger(now, &clock_timer))
clock_tick();
+ if (trigger(now, &vsync_timer))
+ abc802_vsync();
+
if (trigger(now, &blink_timer))
blink = !blink;
diff --git a/sdlscrn.c b/sdlscrn.c
index 800c8ee..047d0ba 100644
--- a/sdlscrn.c
+++ b/sdlscrn.c
@@ -295,7 +295,7 @@ void write_screen(uint8_t *p, uint8_t v)
update_screen();
}
-void setmode40(bool m)
+static void do_set_mode40(bool m)
{
mode40 = m;
@@ -304,6 +304,12 @@ void setmode40(bool m)
abc80_mem_mode40(m);
}
+void setmode40(bool m)
+{
+ if (m != mode40)
+ do_set_mode40(m);
+}
+
/*
* This routine switches the blink status, then goes around the screen
* and updates all characters which has any kind of blink. Returns the
@@ -405,8 +411,8 @@ void screen_init(bool width40)
/* Enable keyboard repeat */
SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
- /* Set the screen width and load the appropriate BASIC */
- setmode40(width40);
+ /* Forcibly set the screen width and load the appropriate BASIC */
+ do_set_mode40(width40);
}
/*