aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2019-12-09 22:11:06 -0800
committerH. Peter Anvin <hpa@zytor.com>2019-12-09 22:11:06 -0800
commitc20338e17250c88c024b04aa15be185189d5692f (patch)
tree93b24f426fed7d0f24459731f3a24e7424e2f449
parent1214ac7ae82615f8cd2465374d00205739031cad (diff)
downloadabc80sim-c20338e17250c88c024b04aa15be185189d5692f.tar.gz
abc80sim-c20338e17250c88c024b04aa15be185189d5692f.tar.xz
abc80sim-c20338e17250c88c024b04aa15be185189d5692f.zip
Use C11 <stdatomic.h>; enable script files
The only really portable way to do lockless atomics is <stdatomic.h>, so use it even though it is C11. It is almost 2020 after all... This hopefully will work better on non-x86 platforms? Add support for an auto-typed script file. Idea by Mikael Bonnier.
-rw-r--r--abc80.c9
-rw-r--r--abcio.c109
-rw-r--r--abcio.h4
-rw-r--r--clib/inttypes.h201
-rw-r--r--compiler.h57
-rw-r--r--configure.ac1
-rw-r--r--screen.h2
-rw-r--r--sdlscrn.c96
-rw-r--r--z80.c2
-rw-r--r--z80.h4
-rw-r--r--z80dis.c6
-rw-r--r--z80irq.c7
-rw-r--r--z80irq.h6
13 files changed, 165 insertions, 339 deletions
diff --git a/abc80.c b/abc80.c
index f06e276..f93bc73 100644
--- a/abc80.c
+++ b/abc80.c
@@ -27,6 +27,7 @@ const char *program_name;
static const char *tracefile = NULL;
static const char *memfile = NULL;
static const char *console_filename = NULL;
+static const char *script_filename = NULL;
enum tracing traceflags;
FILE *tracef;
@@ -129,6 +130,7 @@ static no_return help(void)
" -Fc, --casfile file input file for cassette (CAS:)\n"
" -Lc, --caslist file read list of files for the cassette from a file\n"
" -Dc, --casdir dir set directory for named cassette files [= filedir]\n"
+ " -Fs, --scriptfile file script file to auto-type on startup\n"
" -e, --console enable console output device (PRC:)\n"
" -Fe, --consolefile file enable console output device to a file\n"
" --detach detach from console if run from a command line\n"
@@ -257,6 +259,7 @@ static const struct path_option path_options[] = {
{{"Fc", "-casfile"}, NULL, add_casfile},
{{"Lc", "-caslist"}, NULL, add_caslist},
{{"Dc", "-casdir"}, &cas_path, NULL},
+ {{"Fs", "-scriptfile"}, &script_filename, NULL},
};
static int set_path(const char *opt, const char *what)
@@ -551,6 +554,12 @@ int main(int argc, char **argv)
mem_init(opts.memflags, memfile);
io_init();
+ if (script_filename)
+ scriptfile = open_host_file(HF_BINARY, NULL, script_filename, O_RDONLY);
+
+ if (!scriptfile)
+ enable_real_keyboard();
+
/*
* Load any other program files the
* user gave on the command line.
diff --git a/abcio.c b/abcio.c
index 3e93942..462846e 100644
--- a/abcio.c
+++ b/abcio.c
@@ -8,19 +8,20 @@
#include "trace.h"
/* Keyboard IRQ vector */
-static volatile unsigned int keyb_data;
+static atomic_uint keyb_data;
static uint8_t keyb_fakedata;
/* These constants are designed to make dart_keyb_in() as simple as possible */
#define KEYB_NEW 0x100
#define KEYB_DOWN 0x800
-static int keyb_intack_fake(struct z80_irq *irq);
+struct host_file *scriptfile;
+
+static void script_next_char(void);
+static int keyb_intack_80(struct z80_irq *irq);
static struct z80_irq *keyb_irq;
-static struct z80_irq keyb_irq_80 = IRQ(IRQ80_PIOA, NULL, NULL, NULL);
-static struct z80_irq keyb_irq_fake =
-IRQ(IRQ80_PIOA, keyb_intack_fake, NULL, NULL);
+static struct z80_irq keyb_irq_80 = IRQ(IRQ80_PIOA, keyb_intack_80, NULL, NULL);
static struct z80_irq keyb_irq_800 = IRQ(IRQ800_DARTB, NULL, NULL, NULL);
struct in_port {
@@ -243,11 +244,13 @@ static uint8_t abc80_pioa_in(uint16_t port)
return 0xff;
/* Data port */
- if (opts.faketype) {
+ if (opts.faketype || scriptfile) {
v = keyb_fakedata;
keyb_fakedata &= ~0x80;
+ if (!(v & 0x80) && scriptfile)
+ script_next_char();
} else {
- unsigned int kbd = keyb_data;
+ unsigned int kbd = atomic_load(&keyb_data);
v = (kbd & 0x7f) | ((kbd & KEYB_DOWN) ? 0x80 : 0);
}
return v;
@@ -310,6 +313,7 @@ static void dart_keyb_out(uint16_t port, uint8_t value)
{
/* Keyboard DART control */
uint8_t reg;
+ int16_t old_vector = keyb_irq->vector;
if ((port & 1) == 0) {
return; /* Data out - ignore for now */
@@ -352,26 +356,41 @@ static void dart_keyb_out(uint16_t port, uint8_t value)
/* Fixed vector */
keyb_irq->vector = (dart_keyb_ctl[2] & ~0x01);
}
+
+ if (scriptfile && old_vector != keyb_irq->vector)
+ z80_interrupt(keyb_irq);
}
/* Get the keyboard data, clearing the KEYB_NEW flag */
static unsigned int get_key(void)
{
- unsigned int rv, kbd;
-
- rv = kbd = keyb_data;
- cmpxchg(&keyb_data, &kbd, kbd & ~KEYB_NEW);
-
- return rv;
+ unsigned int mask = scriptfile ? KEYB_NEW|KEYB_DOWN : KEYB_NEW;
+ return atomic_fetch_and(&keyb_data, ~mask);
}
-static int keyb_intack_fake(struct z80_irq *irq)
+static int keyb_intack_80(struct z80_irq *irq)
{
- unsigned int data = get_key();
+ if (opts.faketype || scriptfile) {
+ unsigned int data = get_key();
+ keyb_fakedata = (data & 0x7f) | ((data & KEYB_NEW) ? 0x80 : 0x00);
+ }
+ return irq->vector;
+}
- keyb_fakedata = (data & 0x7f) | ((data & KEYB_NEW) ? 0x80 : 0x00);
+void cursor_enable_hook(void)
+{
+ if (!is_abc800())
+ return;
- return irq->vector;
+ /*
+ * On ABC800, typing ahead will just cause characters to be lost
+ * in the buffer, so only do ghost typing when the cursor gets
+ * enabled.
+ */
+ if (scriptfile) {
+ if (!(atomic_load(&keyb_data) & KEYB_NEW))
+ script_next_char();
+ }
}
static uint8_t dart_keyb_in(uint16_t port)
@@ -389,9 +408,10 @@ static uint8_t dart_keyb_in(uint16_t port)
switch (reg) {
case 0:
- v = (keyb_data >> 8) + (1 << 2) + /* Transmit buffer empty */
- (dart_keyb_vsync << 4) + /* RI -> vsync */
- (1 << 5); /* CTS -> 60 Hz */
+ v = (atomic_load(&keyb_data) >> 8) +
+ (1 << 2) + /* Transmit buffer empty */
+ (dart_keyb_vsync << 4) + /* RI -> vsync */
+ (1 << 5); /* CTS -> 60 Hz mode */
break;
case 1:
v = (1 << 0); /* All sent */
@@ -428,6 +448,36 @@ static void abc802_register_ioports(void)
}
/*
+ * Script keyboard handling
+ */
+static void script_next_char(void)
+{
+ int nextchar;
+
+ if (!scriptfile)
+ return;
+
+ do {
+ nextchar = fgetc(scriptfile->f);
+ } while (nextchar == '\r'); /* Drop CR */
+
+ if (nextchar == EOF) {
+ close_file(&scriptfile);
+ atomic_store(&keyb_data, 0); /* Nothing there */
+ enable_real_keyboard();
+ return;
+ }
+
+ if (nextchar == '\n' + 128)
+ nextchar = '\n';
+ else if (nextchar == '\n')
+ nextchar = '\r';
+
+ atomic_store(&keyb_data, (uint8_t)nextchar | KEYB_NEW | KEYB_DOWN);
+ z80_interrupt(keyb_irq);
+}
+
+/*
* Keyboard callins from the screen-handling code
*/
@@ -435,25 +485,22 @@ static void abc802_register_ioports(void)
/* Need to handle ABC800 up/down mode! */
-void keyboard_down(int sym)
+void keyboard_down(int key)
{
- if (opts.model == is_abc80()) {
+ uint8_t sym = key;
+
+ if (is_abc80()) {
if (sym & ~127)
return;
}
- keyb_data = sym | KEYB_NEW | KEYB_DOWN;
+ atomic_store(&keyb_data, sym | KEYB_NEW | KEYB_DOWN);
z80_interrupt(keyb_irq);
}
-unsigned int keyboard_up(void)
+void keyboard_up(void)
{
- unsigned int rv, kbd;
-
- rv = kbd = keyb_data;
- cmpxchg(&keyb_data, &kbd, kbd & ~KEYB_DOWN);
-
- return rv;
+ atomic_fetch_and(&keyb_data, ~KEYB_DOWN);
}
/*
@@ -500,7 +547,7 @@ void io_init(void)
abc80_register_ioports();
keyb_data = 0;
abc80_cas_init();
- keyb_irq = opts.faketype ? &keyb_irq_fake : &keyb_irq_80;
+ keyb_irq = &keyb_irq_80;
break;
case MODEL_ABC802:
diff --git a/abcio.h b/abcio.h
index f02b96f..8454cbd 100644
--- a/abcio.h
+++ b/abcio.h
@@ -58,8 +58,9 @@ extern void dart_pr_out(uint16_t port, uint8_t v);
extern uint8_t dart_pr_in(uint16_t port);
extern void keyboard_down(int sym);
-extern unsigned int keyboard_up(void);
+extern void keyboard_up(void);
extern bool faketype;
+extern void cursor_enable_hook(void);
extern void abc802_vsync(void);
@@ -96,6 +97,7 @@ enum abc800_irq {
extern const char *fileop_path, *disk_path, *screen_path, *memdump_path,
*cas_path;
extern struct file_list cas_files;
+extern struct host_file *scriptfile;
/* Program name for error messages */
extern const char *program_name;
diff --git a/clib/inttypes.h b/clib/inttypes.h
deleted file mode 100644
index 5063d06..0000000
--- a/clib/inttypes.h
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * inttypes.h
- *
- * Small ersatz subset of <inttypes.h>, deriving the types from
- * <limits.h>.
- *
- * Important: the preprocessor may truncate numbers too large for it.
- * Therefore, test the signed types only ... truncation won't generate
- * a 01111111... bit pattern.
- */
-
-#ifndef INTTYPES_H
-#define INTTYPES_H
-
-#include <limits.h>
-
-/*** 64-bit type: long or long long ***/
-
-/* Some old versions of gcc <limits.h> omit LLONG_MAX */
-#ifndef LLONG_MAX
-#ifdef __LONG_LONG_MAX__
-#define LLONG_MAX __LONG_LONG_MAX__
-#else
-#define LLONG_MAX 0 /* Assume long long is unusable */
-#endif
-#endif
-
-#if LONG_MAX == 9223372036854775807L
-
-/* long is 64 bits */
-typedef signed long int64_t;
-typedef unsigned long uint64_t;
-#define _scn64 "l"
-#define _pri64 "l"
-#define INT64_C(x) x ## L
-#define UINT64_C(x) x ## UL
-
-#elif LLONG_MAX == 9223372036854775807LL
-
-/* long long is 64 bits */
-typedef signed long long int64_t;
-typedef unsigned long long uint64_t;
-#define _scn64 "ll"
-#define _pri64 "ll"
-#define INT64_C(x) x ## LL
-#define UINT64_C(x) x ## ULL
-
-#else
-
-#error "Neither long nor long long is 64 bits in size"
-
-#endif
-
-/*** 32-bit type: int or long ***/
-
-#if INT_MAX == 2147483647
-
-/* int is 32 bits */
-typedef signed int int32_t;
-typedef unsigned int uint32_t;
-#define _scn32 ""
-#define _pri32 ""
-#define INT32_C(x) x
-#define UINT32_C(x) x ## U
-
-#elif LONG_MAX == 2147483647L
-
-/* long is 32 bits */
-typedef signed long int32_t;
-typedef unsigned long uint32_t;
-#define _scn32 "l"
-#define _pri32 "l"
-#define INT32_C(x) x ## L
-#define UINT32_C(x) x ## UL
-
-#else
-
-#error "Neither int nor long is 32 bits in size"
-
-#endif
-
-/*** 16-bit size: int or short ***/
-
-#if INT_MAX == 32767
-
-/* int is 16 bits */
-typedef signed int int16_t;
-typedef unsigned int uint16_t;
-#define _scn16 ""
-#define _pri16 ""
-#define INT16_C(x) x
-#define UINT16_C(x) x ## U
-
-#elif SHRT_MAX == 32767
-
-/* short is 16 bits */
-typedef signed short int16_t;
-typedef unsigned short uint16_t;
-#define _scn16 "h"
-#define _pri16 ""
-#define INT16_C(x) x
-#define UINT16_C(x) x ## U
-
-#else
-
-#error "Neither short nor int is 16 bits in size"
-
-#endif
-
-/*** 8-bit size: char ***/
-
-#if SCHAR_MAX == 127
-
-/* char is 8 bits */
-typedef signed char int8_t;
-typedef unsigned char uint8_t;
-#define _scn8 "hh"
-#define _pri8 ""
-#define INT8_C(x) x
-#define UINT8_C(x) x ## U
-
-#else
-
-#error "char is not 8 bits in size"
-
-#endif
-
-/* The rest of this is common to all models */
-
-#define PRId8 _pri8 "d"
-#define PRId16 _pri16 "d"
-#define PRId32 _pri32 "d"
-#define PRId64 _pri64 "d"
-
-#define PRIi8 _pri8 "i"
-#define PRIi16 _pri16 "i"
-#define PRIi32 _pri32 "i"
-#define PRIi64 _pri64 "i"
-
-#define PRIo8 _pri8 "o"
-#define PRIo16 _pri16 "o"
-#define PRIo32 _pri32 "o"
-#define PRIo64 _pri64 "o"
-
-#define PRIu8 _pri8 "u"
-#define PRIu16 _pri16 "u"
-#define PRIu32 _pri32 "u"
-#define PRIu64 _pri64 "u"
-
-#define PRIx8 _pri8 "x"
-#define PRIx16 _pri16 "x"
-#define PRIx32 _pri32 "x"
-#define PRIx64 _pri64 "x"
-
-#define PRIX8 _pri8 "X"
-#define PRIX16 _pri16 "X"
-#define PRIX32 _pri32 "X"
-#define PRIX64 _pri64 "X"
-
-#define SCNd8 _scn8 "d"
-#define SCNd16 _scn16 "d"
-#define SCNd32 _scn32 "d"
-#define SCNd64 _scn64 "d"
-
-#define SCNi8 _scn8 "i"
-#define SCNi16 _scn16 "i"
-#define SCNi32 _scn32 "i"
-#define SCNi64 _scn64 "i"
-
-#define SCNo8 _scn8 "o"
-#define SCNo16 _scn16 "o"
-#define SCNo32 _scn32 "o"
-#define SCNo64 _scn64 "o"
-
-#define SCNu8 _scn8 "u"
-#define SCNu16 _scn16 "u"
-#define SCNu32 _scn32 "u"
-#define SCNu64 _scn64 "u"
-
-#define SCNx8 _scn8 "x"
-#define SCNx16 _scn16 "x"
-#define SCNx32 _scn32 "x"
-#define SCNx64 _scn64 "x"
-
-#define INT8_MIN INT8_C(-128)
-#define INT8_MAX INT8_C(127)
-#define UINT8_MAX UINT8_C(255)
-
-#define INT16_MIN INT16_C(-32768)
-#define INT16_MAX INT16_C(32767)
-#define UINT16_MAX UINT16_C(65535)
-
-#define INT32_MIN INT32_C(-2147483648)
-#define INT32_MAX INT32_C(2147483647)
-#define UINT32_MAX UINT32_C(4294967295)
-
-#define INT64_MIN INT64_C(-9223372036854775808)
-#define INT64_MAX INT64_C(9223372036854775807)
-#define UINT64_MAX UINT64_C(18446744073709551615)
-
-#endif /* INTTYPES_H */
diff --git a/compiler.h b/compiler.h
index e704bc5..a859478 100644
--- a/compiler.h
+++ b/compiler.h
@@ -14,11 +14,6 @@
/* On Microsoft platforms we support multibyte character sets in filenames */
#define _MBCS 1
-#ifdef HAVE_INTTYPES_H
-#include <inttypes.h>
-#else
-#include "clib/inttypes.h" /* Ersatz header file */
-#endif
/* These header files should pretty much always be included... */
#include <assert.h>
@@ -30,6 +25,8 @@
#include <errno.h>
#include <time.h>
#include <math.h>
+#include <inttypes.h>
+#include <stdatomic.h>
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
@@ -203,54 +200,4 @@ typedef unsigned __int128 uint128_t;
#define is_constant(x) false
#endif
-/* Simple atomic operations */
-#ifdef __GNUC__
-#define atomic_load(p) __atomic_load_n((p), __ATOMIC_ACQUIRE)
-#define atomic_store(p,v) __atomic_store_n((p), (v), __ATOMIC_RELEASE)
-#define cmpxchg(p, e, d) \
- likely(__atomic_compare_exchange_n((p), (e), (d), false, \
- __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE))
-#define xchg(p, v) \
- __atomic_exchange_n((p), (v), __ATOMIC_ACQ_REL)
-#define barrier() __atomic_thread_fence(__ATOMIC_ACQ_REL)
-
-#if defined(__i386__) || defined(__x86_64__)
-static inline bool atomic_test_set_bit(volatile unsigned int *p, unsigned int v)
-{
- bool b;
- asm volatile ("lock btsl %2,%0":"+m" (*p), "=@ccc"(b)
- :"rN"(v)
- :"memory");
- return b;
-}
-
-static inline bool
-atomic_test_clear_bit(volatile unsigned int *p, unsigned int v)
-{
- bool b;
- asm volatile ("lock btrl %2,%0":"+m" (*p), "=@ccc"(b)
- :"rN"(v)
- :"memory");
- return b;
-}
-#else
-static inline bool atomic_test_set_bit(volatile unsigned int *p, unsigned int v)
-{
- return (__atomic_fetch_or(p, 1U << v, __ATOMIC_ACQ_REL) >> v) & 1;
-}
-
-static inline bool
-atomic_test_clear_bit(volatile unsigned int *p, unsigned int v)
-{
- return (__atomic_fetch_and(p, ~(1U << v), __ATOMIC_ACQ_REL) >> v) & 1;
-}
-#endif
-
-#define atomic_set_bit(p,v) ((void)atomic_test_set_bit(p,v))
-#define atomic_clear_bit(p,v) ((void)atomic_test_clear_bit(p,v))
-
-#else /* __GNUC__ */
-#error "Define atomic operations for your compiler here"
-#endif
-
#endif /* COMPILER_H */
diff --git a/configure.ac b/configure.ac
index 939b5b4..c471b79 100644
--- a/configure.ac
+++ b/configure.ac
@@ -41,6 +41,7 @@ AC_HEADER_STDC
AC_HEADER_STDBOOL
AC_CHECK_HEADERS(inttypes.h)
AC_CHECK_HEADERS(stdnoreturn.h)
+AC_CHECK_HEADERS(stdatomic.h)
dnl Force gcc and gcc-compatible compilers treat signed integers
dnl as 2's complement
diff --git a/screen.h b/screen.h
index ae1bbca..7ede006 100644
--- a/screen.h
+++ b/screen.h
@@ -20,6 +20,8 @@ Uint32 post_periodic(Uint32 interval, void *param);
extern void crtc_out(uint16_t, uint8_t);
extern uint8_t crtc_in(uint16_t);
+extern void enable_real_keyboard(void);
+
/* Pointer into video RAM */
extern uint8_t *const video_ram;
diff --git a/sdlscrn.c b/sdlscrn.c
index bda5e58..11580a4 100644
--- a/sdlscrn.c
+++ b/sdlscrn.c
@@ -4,10 +4,7 @@
* ABC80/802 screen emulation (40x24/80x24)
*/
-#include <stdarg.h>
-#include <stdlib.h>
-#include <inttypes.h>
-#include <string.h>
+#include "compiler.h"
#include "screen.h"
#include "screenshot.h"
#include "z80.h"
@@ -221,7 +218,9 @@ put_screen(struct surface *s, unsigned int tx, unsigned int ty, bool blink)
curmask = 0;
if (unlikely(voffs == vdu.curaddr)) {
- if (blink | (vdu.crtc.r.curstart & 0x40)) {
+ uint8_t curmode = vdu.crtc.r.curstart & 0x60;
+
+ if ((curmode == 0) || (blink && (curmode & 0x40))) {
curmask = (~0U << (vdu.crtc.r.curstart & 0x1f));
curmask &= (2U << (vdu.crtc.r.curend & 0x1f)) - 1;
}
@@ -413,12 +412,18 @@ enum dump_memory_type {
DUMP_RAM
};
-static volatile enum dump_memory_type dump_memory_now;
+static atomic_uint dump_memory_now;
+
+enum user_event {
+ UEV_REFRESH_SCREEN,
+ UEV_ENABLE_KEYBOARD
+};
void event_loop(void)
{
SDL_Event event;
- static int keyboard_scan = -1; /* No key currently down */
+ int keyboard_scan = -1; /* No key currently down */
+ static bool keyboard_enabled = false;
enum kshift {
KSH_SHIFT = 1,
KSH_CTRL = 2,
@@ -428,25 +433,9 @@ void event_loop(void)
while (SDL_WaitEvent(&event)) {
switch (event.type) {
case SDL_KEYDOWN:
- kshift =
- ((event.key.keysym.
- mod & (KMOD_LALT | KMOD_RALT)) ? KSH_ALT : 0) | ((event.key.
- keysym.
- mod &
- (KMOD_LCTRL
- |
- KMOD_RCTRL))
- ? KSH_CTRL :
- 0) | ((event.
- key.
- keysym.
- mod &
- (KMOD_LSHIFT
- |
- KMOD_RSHIFT))
- ?
- KSH_SHIFT
- : 0);
+ kshift = ((event.key.keysym.mod & (KMOD_LALT | KMOD_RALT)) ? KSH_ALT : 0)
+ | ((event.key.keysym.mod & (KMOD_LCTRL | KMOD_RCTRL)) ? KSH_CTRL : 0)
+ | ((event.key.keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT)) ? KSH_SHIFT : 0);
if (kshift & KSH_ALT) {
/* Alt+key are special functions */
@@ -483,7 +472,7 @@ void event_loop(void)
default:
break;
}
- } else {
+ } else if (keyboard_enabled) {
int mysym = -1;
switch (event.key.keysym.sym) {
@@ -705,12 +694,24 @@ void event_loop(void)
}
break;
case SDL_KEYUP:
- if (event.key.keysym.scancode == keyboard_scan)
- keyboard_up();
+ if (keyboard_enabled) {
+ if (event.key.keysym.scancode == keyboard_scan)
+ keyboard_up();
+ }
break;
case SDL_USEREVENT:
- /* Time to update the screen */
- refresh_screen(&rscreen, false);
+ switch (event.user.code) {
+ case UEV_REFRESH_SCREEN:
+ /* Time to update the screen */
+ refresh_screen(&rscreen, false);
+ break;
+ case UEV_ENABLE_KEYBOARD:
+ /* Script file done */
+ keyboard_enabled = true;
+ break;
+ default:
+ break;
+ }
break;
case SDL_QUIT:
return; /* Return to main(), terminate */
@@ -738,7 +739,7 @@ void vsync_screen(void)
trigger_refresh();
if (unlikely(dump_memory_now)) {
- dm = xchg(&dump_memory_now, DUMP_NONE);
+ dm = atomic_exchange(&dump_memory_now, DUMP_NONE);
if (dm)
dump_memory(dm == DUMP_RAM);
}
@@ -747,18 +748,31 @@ void vsync_screen(void)
fflush(tracef); /* So we don't buffer indefinitely */
}
+/* Post a user event */
+static void push_user_event(enum user_event ev)
+{
+ SDL_Event event;
+
+ memset(&event, 0, sizeof event);
+ event.type = SDL_USEREVENT;
+ event.user.code = ev;
+ SDL_PushEvent(&event);
+}
+
/* Used from the CPU thread context to cause a screen redraw */
static void trigger_refresh(void)
{
- SDL_Event trigger_redraw;
-
SDL_mutexP(screen_mutex);
xfr = cpu;
SDL_mutexV(screen_mutex);
- memset(&trigger_redraw, 0, sizeof trigger_redraw);
- trigger_redraw.type = SDL_USEREVENT;
- SDL_PushEvent(&trigger_redraw);
+ push_user_event(UEV_REFRESH_SCREEN);
+}
+
+/* Called by the CPU thread once any script file is fully consumed */
+void enable_real_keyboard(void)
+{
+ push_user_event(UEV_ENABLE_KEYBOARD);
}
/* Called in the CPU thread context */
@@ -766,6 +780,8 @@ static uint8_t crtc_addr;
void crtc_out(uint16_t port, uint8_t data)
{
+ uint8_t old_data;
+
if (!(port & 1)) {
crtc_addr = data;
return;
@@ -776,11 +792,17 @@ void crtc_out(uint16_t port, uint8_t data)
SDL_mutexP(screen_mutex);
+ old_data = cpu.crtc.regs[crtc_addr];
cpu.crtc.regs[crtc_addr] = data;
cpu.startaddr = ((cpu.crtc.r.starth & 0x3f) << 8) + cpu.crtc.r.startl;
cpu.curaddr = ((cpu.crtc.r.curh & 0x3f) << 8) + cpu.crtc.r.curl;
SDL_mutexV(screen_mutex);
+
+ if (crtc_addr == 0x0a &&
+ (old_data & 0x60) == 0x20 && (data & 0x60) != 0x20) {
+ cursor_enable_hook();
+ }
}
uint8_t crtc_in(uint16_t port)
diff --git a/z80.c b/z80.c
index fbd5aa7..b69a9f6 100644
--- a/z80.c
+++ b/z80.c
@@ -1169,7 +1169,7 @@ static void do_im2(void)
static void do_nmi(void)
{
- bool nminterrupt = xchg(&z80_state.nminterrupt, false);
+ bool nminterrupt = atomic_exchange(&z80_state.nminterrupt, false);
if (!nminterrupt)
return;
diff --git a/z80.h b/z80.h
index c1930f4..d758e8e 100644
--- a/z80.h
+++ b/z80.h
@@ -67,7 +67,7 @@ struct z80_state_struct {
bool iff1, iff2, ei_shadow, signal_eoi;
bool nmi_in_progress; /* to prevent multiple simultaneous NMIs */
- volatile bool nminterrupt; /* used to signal a non maskable interrupt */
+ atomic_bool nminterrupt; /* used to signal a non maskable interrupt */
uint64_t tc; /* T-state (clock cycle) counter */
};
@@ -166,7 +166,7 @@ extern struct z80_state_struct z80_state;
/* Signal an NMI */
static inline void z80_nmi(void)
{
- z80_state.nminterrupt = true;
+ atomic_store(&z80_state.nminterrupt, true);
}
extern void z80_reset(void);
diff --git a/z80dis.c b/z80dis.c
index 8aad224..99904fe 100644
--- a/z80dis.c
+++ b/z80dis.c
@@ -1,8 +1,4 @@
-#include <inttypes.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <ctype.h>
+#include "compiler.h"
#include "z80.h"
static const char *const Mnemonics[256] = {
diff --git a/z80irq.c b/z80irq.c
index c3d9502..0635d08 100644
--- a/z80irq.c
+++ b/z80irq.c
@@ -2,7 +2,7 @@
#include "z80.h"
#include "z80irq.h"
-volatile unsigned int irq_pending; /* Quick way to poll */
+atomic_uint irq_pending; /* Quick way to poll */
unsigned int irq_mask = ~0U;
static struct z80_irq *irqs[MAX_IRQ];
@@ -23,7 +23,7 @@ int z80_intack(void)
{
unsigned int prio;
int vector = -1;
- unsigned int irqpend, irqmasked;
+ unsigned int irqpend, irqmasked, thisirq;
struct z80_irq *irq;
do {
@@ -35,7 +35,8 @@ int z80_intack(void)
return vector; /* All interrupts went away... */
prio = __builtin_ctz(irqmasked);
- if (unlikely(!atomic_test_clear_bit(&irq_pending, prio)))
+ thisirq = 1U << prio;
+ if (unlikely(!(atomic_fetch_and(&irq_pending, ~thisirq) & thisirq)))
continue; /* This particular interrupt went away on us? */
irq = irqs[prio];
diff --git a/z80irq.h b/z80irq.h
index 3a04a5b..f43f278 100644
--- a/z80irq.h
+++ b/z80irq.h
@@ -20,7 +20,7 @@ struct z80_irq {
#define MAX_IRQ 32
-extern volatile unsigned int irq_pending;
+extern atomic_uint irq_pending;
extern unsigned int irq_mask; /* 0 = inside handler (irq->handled == true) */
static inline bool poll_irq(void)
@@ -33,12 +33,12 @@ int z80_intack(void);
void z80_eoi(void);
static inline void z80_interrupt(struct z80_irq *irq)
{
- atomic_set_bit(&irq_pending, irq->prio);
+ atomic_fetch_or(&irq_pending, 1U << irq->prio);
}
static inline void z80_clear_interrupt(struct z80_irq *irq)
{
- atomic_clear_bit(&irq_pending, irq->prio);
+ atomic_fetch_and(&irq_pending, ~(1U << irq->prio));
}
#endif /* Z80IRQ_H */