Skip to content

Commit

Permalink
Make emu_keypad_event thread-safe, refactor CPU aborts into generic s…
Browse files Browse the repository at this point in the history
…ignals. Fixes #486.
  • Loading branch information
calc84maniac committed Jul 10, 2024
1 parent c8dd990 commit 096f80c
Show file tree
Hide file tree
Showing 9 changed files with 170 additions and 80 deletions.
60 changes: 58 additions & 2 deletions core/atomics.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,73 @@
#ifndef __cplusplus
#if !defined(__STDC_NO_ATOMICS__) || (defined(_MSC_VER) && _MSC_VER >= 1935)
#include <stdatomic.h>
#define atomic8_fetch_and atomic_fetch_and
#define atomic32_fetch_and atomic_fetch_and
#define atomic8_fetch_and_explicit atomic_fetch_and_explicit
#define atomic32_fetch_and_explicit atomic_fetch_and_explicit
#define atomic8_fetch_or atomic_fetch_or
#define atomic32_fetch_or atomic_fetch_or
#define atomic8_fetch_or_explicit atomic_fetch_or_explicit
#define atomic32_fetch_or_explicit atomic_fetch_or_explicit
#else
#define _Atomic(X) volatile X /* doesn't do anything, but makes me feel better... although if you are trying to do multithreading glhf */
#define atomic_compare_exchange_strong(object, expected, desired) (*(object) == *(expected) ? (*(object) = (desired)) : (*(expected) = (desired)))
#define atomic_load_explicit(object, order) (*(object))
static inline atomic8_fetch_and(volatile uint8_t *obj, uint8_t arg) {
uint8_t result = *obj;
*obj = result & arg;
return result;
}
static inline atomic32_fetch_and(volatile uint32_t *obj, uint8_t arg) {
uint32_t result = *obj;
*obj = result & arg;
return result;
}
static inline atomic8_fetch_or(volatile uint8_t *obj, uint8_t arg) {
uint8_t result = *obj;
*obj = result | arg;
return result;
}
static inline atomic32_fetch_or(volatile uint32_t *obj, uint8_t arg) {
uint32_t result = *obj;
*obj = result | arg;
return result;
}
#define atomic8_fetch_and_explicit(object, arg, order) atomic8_fetch_and(object, arg)
#define atomic32_fetch_and_explicit(object, arg, order) atomic32_fetch_and(object, arg)
#define atomic8_fetch_or_explicit(object, arg, order) atomic8_fetch_or(object, arg)
#define atomic32_fetch_or_explicit(object, arg, order) atomic32_fetch_or(object, arg)
#endif
#else
#include <atomic>
#define _Atomic(X) std::atomic<X>
#endif
#else
#define _Atomic(X) X
#define atomic_compare_exchange_strong(object, expected, desired) (*(object) == *(expected) ? (*(object) = (desired)) : (*(expected) = (desired)))
#define atomic_load_explicit(object, order) (*(object))
static inline atomic8_fetch_and(uint8_t *obj, uint8_t arg) {
uint8_t result = *obj;
*obj = result & arg;
return result;
}
static inline atomic32_fetch_and(uint32_t *obj, uint8_t arg) {
uint32_t result = *obj;
*obj = result & arg;
return result;
}
static inline atomic8_fetch_or(uint8_t *obj, uint8_t arg) {
uint8_t result = *obj;
*obj = result | arg;
return result;
}
static inline atomic32_fetch_or(uint32_t *obj, uint8_t arg) {
uint32_t result = *obj;
*obj = result | arg;
return result;
}
#define atomic8_fetch_and_explicit(object, arg, order) atomic8_fetch_and(object, arg)
#define atomic32_fetch_and_explicit(object, arg, order) atomic32_fetch_and(object, arg)
#define atomic8_fetch_or_explicit(object, arg, order) atomic8_fetch_or(object, arg)
#define atomic32_fetch_or_explicit(object, arg, order) atomic32_fetch_or(object, arg)
#endif

#endif
26 changes: 13 additions & 13 deletions core/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@
eZ80cpu_t cpu;

typedef struct eZ80atomics {
_Atomic(uint8_t) abort;
_Atomic(uint8_t) signals;
} eZ80atomics_t;

static eZ80atomics_t atomics;
static eZ80atomics_t cpu_atomics;

static void cpu_clear_context(void) {
cpu.PREFIX = cpu.SUFFIX = 0;
Expand Down Expand Up @@ -814,7 +814,7 @@ static void cpu_execute_bli() {

void cpu_init(void) {
memset(&cpu, 0, sizeof(eZ80cpu_t));
atomics.abort = CPU_ABORT_NONE;
cpu_atomics.signals = CPU_SIGNAL_ON_KEY | CPU_SIGNAL_ANY_KEY;
gui_console_printf("[CEmu] Initialized CPU...\n");
}

Expand All @@ -841,20 +841,20 @@ void cpu_nmi(void) {
#endif
}

void cpu_transition_abort(uint8_t from, uint8_t to) {
atomic_compare_exchange_strong(&atomics.abort, &from, to);
void cpu_set_signal(uint8_t signal) {
atomic8_fetch_or_explicit(&cpu_atomics.signals, signal, memory_order_release);
}

uint8_t cpu_check_abort(void) {
return atomics.abort;
uint8_t cpu_check_signals(void) {
return atomic_load_explicit(&cpu_atomics.signals, memory_order_relaxed);
}

void cpu_exit(void) {
atomics.abort = CPU_ABORT_EXIT;
uint8_t cpu_clear_signals(void) {
return atomic8_fetch_and_explicit(&cpu_atomics.signals, CPU_SIGNAL_EXIT, memory_order_acquire);
}

void cpu_crash(const char *msg) {
cpu_transition_abort(CPU_ABORT_NONE, CPU_ABORT_RESET);
cpu_set_signal(CPU_SIGNAL_RESET);
gui_console_printf("[CEmu] Reset caused by %s.\n", msg);
#ifdef DEBUG_SUPPORT
if (debug_get_flags() & DBG_OPEN_ON_RESET) {
Expand All @@ -880,7 +880,7 @@ static void cpu_halt(void) {
}

void cpu_restore_next(void) {
if (cpu.NMI || (cpu.IEF1 && (intrpt->status & intrpt->enabled)) || atomics.abort != CPU_ABORT_NONE) {
if (cpu.NMI || (cpu.IEF1 && (intrpt->status & intrpt->enabled)) || cpu_check_signals() != CPU_SIGNAL_NONE) {
cpu.next = 0; /* always applies, even after cycle rewind during port writes */
} else if (cpu.IEF_wait) {
cpu.next = cpu.eiDelay; /* execute one instruction */
Expand Down Expand Up @@ -943,7 +943,7 @@ void cpu_execute(void) {
} else {
cpu_restore_next();
}
if (cpu.cycles >= cpu.next || atomics.abort != CPU_ABORT_NONE) {
if (cpu.cycles >= cpu.next) {
break;
}
if (cpu.inBlock) {
Expand Down Expand Up @@ -1135,7 +1135,7 @@ void cpu_execute(void) {
break;
}
if (context.z < 4) {
if (cpu.SUFFIX && atomics.abort != CPU_ABORT_NONE) { /* suffix can infinite loop */
if (cpu.SUFFIX && (cpu_check_signals() & (CPU_SIGNAL_RESET | CPU_SIGNAL_EXIT))) { /* suffix can infinite loop */
return;
}
cpu.L = context.s;
Expand Down
18 changes: 10 additions & 8 deletions core/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,13 @@ extern "C" {

#define cpu_mask_mode(address, mode) ((uint32_t)((address) & ((mode) ? 0xFFFFFF : 0xFFFF)))

typedef enum eZ80abort {
CPU_ABORT_NONE,
CPU_ABORT_RESET,
CPU_ABORT_EXIT,
} eZ80abort_t;
typedef enum eZ80signal {
CPU_SIGNAL_NONE = 0,
CPU_SIGNAL_EXIT = 1 << 0,
CPU_SIGNAL_RESET = 1 << 1,
CPU_SIGNAL_ON_KEY = 1 << 2,
CPU_SIGNAL_ANY_KEY = 1 << 3
} eZ80signal_t;

typedef union eZ80context {
uint8_t opcode;
Expand Down Expand Up @@ -112,9 +114,9 @@ void cpu_flush(uint32_t, bool);
void cpu_nmi(void);
void cpu_execute(void);
void cpu_restore_next(void);
void cpu_transition_abort(uint8_t from, uint8_t to);
uint8_t cpu_check_abort(void);
void cpu_exit(void);
void cpu_set_signal(uint8_t signal);
uint8_t cpu_check_signals(void);
uint8_t cpu_clear_signals(void);
void cpu_crash(const char *msg);
bool cpu_restore(FILE *image);
bool cpu_save(FILE *image);
Expand Down
18 changes: 9 additions & 9 deletions core/debug/debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ typedef struct debug_atomics {
_Atomic(bool) open;
} debug_atomics_t;

static debug_atomics_t atomics;
static debug_atomics_t debug_atomics;

void debug_init(void) {
debug_clear_step();
Expand All @@ -28,7 +28,7 @@ void debug_init(void) {
debug.addr = (uint8_t*)calloc(DBG_ADDR_SIZE, sizeof(uint8_t));
debug.port = (uint8_t*)calloc(DBG_PORT_SIZE, sizeof(uint8_t));
debug.bufPos = debug.bufErrPos = 0;
atomics.open = false;
debug_atomics.open = false;
debug_disable_basic_mode();
gui_console_printf("[CEmu] Initialized Debugger...\n");
}
Expand All @@ -41,15 +41,15 @@ void debug_free(void) {
}

bool debug_is_open(void) {
return atomics.open;
return atomic_load_explicit(&debug_atomics.open, memory_order_relaxed);
}

int debug_get_flags(void) {
return atomics.flags;
return atomic_load_explicit(&debug_atomics.flags, memory_order_relaxed);
}

void debug_open(int reason, uint32_t data) {
if (cpu_check_abort() == CPU_ABORT_EXIT || atomics.open || ((atomics.flags & DBG_IGNORE) && (reason >= DBG_BREAKPOINT && reason <= DBG_PORT_WRITE))) {
if ((cpu_check_signals() & CPU_SIGNAL_EXIT) || debug_is_open() || ((debug_get_flags() & DBG_IGNORE) && (reason >= DBG_BREAKPOINT && reason <= DBG_PORT_WRITE))) {
return;
}

Expand Down Expand Up @@ -97,9 +97,9 @@ void debug_open(int reason, uint32_t data) {
debug.flashWaitStates = flash.waitStates;
debug.flashDelayCycles = cpu.flashDelayCycles;

atomics.open = true;
debug_atomics.open = true;
gui_debug_open(reason, data);
atomics.open = false;
debug_atomics.open = false;

cpu.next = debug.cpuNext;
cpu.cycles = debug.cpuCycles;
Expand Down Expand Up @@ -132,9 +132,9 @@ void debug_ports(uint16_t addr, int mask, bool set) {

void debug_flag(int mask, bool set) {
if (set) {
atomics.flags |= mask;
debug_atomics.flags |= mask;
} else {
atomics.flags &= ~mask;
debug_atomics.flags &= ~mask;
}
}

Expand Down
15 changes: 11 additions & 4 deletions core/emu.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "asic.h"
#include "cpu.h"
#include "cert.h"
#include "keypad.h"
#include "os/os.h"
#include "defines.h"
#include "schedule.h"
Expand All @@ -20,7 +21,7 @@
#define IMAGE_VERSION 0xCECE0017

void EMSCRIPTEN_KEEPALIVE emu_exit(void) {
cpu_exit();
cpu_set_signal(CPU_SIGNAL_EXIT);
}

void EMSCRIPTEN_KEEPALIVE emu_reset(void) {
Expand Down Expand Up @@ -239,12 +240,18 @@ emu_state_t emu_load(emu_data_t type, const char *path) {
}

void emu_run(uint64_t ticks) {
uint8_t signals;
sched.run_event_triggered = false;
sched_repeat(SCHED_RUN, ticks);
while (cpu_check_abort() != CPU_ABORT_EXIT) {
while (!((signals = cpu_clear_signals()) & CPU_SIGNAL_EXIT)) {
if (signals & CPU_SIGNAL_ON_KEY) {
keypad_on_check();
}
if (signals & CPU_SIGNAL_ANY_KEY) {
keypad_any_check();
}
sched_process_pending_events();
if (cpu_check_abort() == CPU_ABORT_RESET) {
cpu_transition_abort(CPU_ABORT_RESET, CPU_ABORT_NONE);
if (signals & CPU_SIGNAL_RESET) {
gui_console_printf("[CEmu] Reset triggered.\n");
asic_reset();
#ifdef DEBUG_SUPPORT
Expand Down
Loading

0 comments on commit 096f80c

Please sign in to comment.