diff options
author | H. Peter Anvin <hpa@zytor.com> | 2019-12-09 22:11:06 -0800 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2019-12-09 22:11:06 -0800 |
commit | c20338e17250c88c024b04aa15be185189d5692f (patch) | |
tree | 93b24f426fed7d0f24459731f3a24e7424e2f449 | |
parent | 1214ac7ae82615f8cd2465374d00205739031cad (diff) | |
download | abc80sim-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.c | 9 | ||||
-rw-r--r-- | abcio.c | 109 | ||||
-rw-r--r-- | abcio.h | 4 | ||||
-rw-r--r-- | clib/inttypes.h | 201 | ||||
-rw-r--r-- | compiler.h | 57 | ||||
-rw-r--r-- | configure.ac | 1 | ||||
-rw-r--r-- | screen.h | 2 | ||||
-rw-r--r-- | sdlscrn.c | 96 | ||||
-rw-r--r-- | z80.c | 2 | ||||
-rw-r--r-- | z80.h | 4 | ||||
-rw-r--r-- | z80dis.c | 6 | ||||
-rw-r--r-- | z80irq.c | 7 | ||||
-rw-r--r-- | z80irq.h | 6 |
13 files changed, 165 insertions, 339 deletions
@@ -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. @@ -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: @@ -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 */ @@ -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 @@ -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; @@ -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) @@ -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; @@ -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); @@ -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] = { @@ -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]; @@ -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 */ |