commit 0e7ebb69e61107dc17282339d0696baee582dbd4
parent b9ff19d857a0451cf4a4024fca17a163169c284d
Author: Andrew Alderwick <andrew@alderwick.co.uk>
Date: Sun, 27 Mar 2022 13:53:25 +0100
(uxnemu) Interrupt infinite loops with an error.
Diffstat:
5 files changed, 37 insertions(+), 4 deletions(-)
diff --git a/src/devices/system.c b/src/devices/system.c
@@ -20,7 +20,8 @@ static const char *errors[] = {
"Working-stack overflow",
"Return-stack overflow",
"Working-stack division by zero",
- "Return-stack division by zero"};
+ "Return-stack division by zero",
+ "Execution timeout"};
static void
system_print(Stack *s, char *name)
diff --git a/src/uxn.c b/src/uxn.c
@@ -30,16 +30,25 @@ WITH REGARD TO THIS SOFTWARE.
#define DEVW8(x, y) { dev->dat[(x) & 0xf] = y; dev->deo(dev, (x) & 0x0f); }
#define DEVW(d, x, y) { dev = (d); if(bs) { DEVW8((x), (y) >> 8); DEVW8((x) + 1, (y)); } else { DEVW8((x), (y)) } }
#define WARP(x) { if(bs) pc = (x); else pc += (Sint8)(x); }
+#define LIMIT 0x40000 /* around 3 ms */
int
uxn_eval(Uxn *u, Uint16 pc)
{
unsigned int a, b, c, j, k, bs, instr, errcode;
+ unsigned int limit = LIMIT;
Uint8 kptr, *sp;
Stack *src, *dst;
Device *dev;
if(!pc || u->dev[0].dat[0xf]) return 0;
while((instr = u->ram[pc++])) {
+ if(!limit--) {
+ if(!uxn_interrupt()) {
+ errcode = 6;
+ goto timeout;
+ }
+ limit = LIMIT;
+ }
/* Return Mode */
if(instr & 0x40) {
src = &u->rst; dst = &u->wst;
@@ -101,6 +110,7 @@ err:
/* set 1 in errcode if it involved the return stack instead of the working stack */
/* (stack overflow & ( opcode was STH / JSR )) ^ Return Mode */
errcode |= ((errcode >> 1 & ((instr & 0x1e) == 0x0e)) ^ instr >> 6) & 1;
+timeout:
return uxn_halt(u, errcode, pc - 1);
}
diff --git a/src/uxn.h b/src/uxn.h
@@ -47,6 +47,7 @@ typedef struct Uxn {
int uxn_boot(Uxn *u, Uint8 *ram);
int uxn_eval(Uxn *u, Uint16 pc);
+int uxn_interrupt(void);
int uxn_halt(Uxn *u, Uint8 error, Uint16 addr);
Device *uxn_port(Uxn *u, Uint8 id, Uint8 (*deifn)(Device *, Uint8), void (*deofn)(Device *, Uint8));
#endif /* UXN_UXN_H */
diff --git a/src/uxncli.c b/src/uxncli.c
@@ -101,6 +101,12 @@ load(Uxn *u, char *filepath)
return 1;
}
+int
+uxn_interrupt(void)
+{
+ return 1;
+}
+
static int
start(Uxn *u)
{
diff --git a/src/uxnemu.c b/src/uxnemu.c
@@ -32,6 +32,7 @@ WITH REGARD TO THIS SOFTWARE.
#define WIDTH 64 * 8
#define HEIGHT 40 * 8
#define PAD 4
+#define TIMEOUT_FRAMES 10
static SDL_Window *gWindow;
static SDL_Texture *gTexture;
@@ -43,7 +44,7 @@ static SDL_Rect gRect;
static Device *devscreen, *devmouse, *devctrl, *devaudio0, *devfile0;
static Uint8 zoom = 1;
-static Uint32 stdin_event, audio0_event, redraw_event;
+static Uint32 stdin_event, audio0_event, redraw_event, interrupt_event;
static int
error(char *msg, const char *err)
@@ -89,12 +90,19 @@ stdin_handler(void *p)
static int
redraw_handler(void *p)
{
- SDL_Event event;
+ int dropped_frames = 0;
+ SDL_Event event, interrupt;
event.type = redraw_event;
+ interrupt.type = interrupt_event;
for(;;) {
SDL_Delay(16);
- if(SDL_HasEvent(redraw_event) == SDL_FALSE)
+ if(SDL_HasEvent(redraw_event) == SDL_FALSE) {
SDL_PushEvent(&event);
+ dropped_frames = 0;
+ }
+ else if(++dropped_frames == TIMEOUT_FRAMES) {
+ SDL_PushEvent(&interrupt);
+ }
}
return 0;
(void)p;
@@ -169,6 +177,7 @@ init(void)
stdin_event = SDL_RegisterEvents(1);
audio0_event = SDL_RegisterEvents(POLYPHONY);
redraw_event = SDL_RegisterEvents(1);
+ interrupt_event = SDL_RegisterEvents(1);
SDL_CreateThread(stdin_handler, "stdin", NULL);
SDL_CreateThread(redraw_handler, "redraw", NULL);
SDL_StartTextInput();
@@ -468,6 +477,12 @@ run(Uxn *u)
}
int
+uxn_interrupt(void)
+{
+ return SDL_PeepEvents(NULL, 1, SDL_GETEVENT, interrupt_event, interrupt_event) < 1;
+}
+
+int
main(int argc, char **argv)
{
SDL_DisplayMode DM;