(uxnemu) Interrupt infinite loops with an error.

This commit is contained in:
Andrew Alderwick 2022-03-27 13:53:25 +01:00
parent b9ff19d857
commit 0e7ebb69e6
5 changed files with 37 additions and 4 deletions

View File

@ -20,7 +20,8 @@ static const char *errors[] = {
"Working-stack overflow", "Working-stack overflow",
"Return-stack overflow", "Return-stack overflow",
"Working-stack division by zero", "Working-stack division by zero",
"Return-stack division by zero"}; "Return-stack division by zero",
"Execution timeout"};
static void static void
system_print(Stack *s, char *name) system_print(Stack *s, char *name)

View File

@ -30,16 +30,25 @@ WITH REGARD TO THIS SOFTWARE.
#define DEVW8(x, y) { dev->dat[(x) & 0xf] = y; dev->deo(dev, (x) & 0x0f); } #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 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 WARP(x) { if(bs) pc = (x); else pc += (Sint8)(x); }
#define LIMIT 0x40000 /* around 3 ms */
int int
uxn_eval(Uxn *u, Uint16 pc) uxn_eval(Uxn *u, Uint16 pc)
{ {
unsigned int a, b, c, j, k, bs, instr, errcode; unsigned int a, b, c, j, k, bs, instr, errcode;
unsigned int limit = LIMIT;
Uint8 kptr, *sp; Uint8 kptr, *sp;
Stack *src, *dst; Stack *src, *dst;
Device *dev; Device *dev;
if(!pc || u->dev[0].dat[0xf]) return 0; if(!pc || u->dev[0].dat[0xf]) return 0;
while((instr = u->ram[pc++])) { while((instr = u->ram[pc++])) {
if(!limit--) {
if(!uxn_interrupt()) {
errcode = 6;
goto timeout;
}
limit = LIMIT;
}
/* Return Mode */ /* Return Mode */
if(instr & 0x40) { if(instr & 0x40) {
src = &u->rst; dst = &u->wst; 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 */ /* set 1 in errcode if it involved the return stack instead of the working stack */
/* (stack overflow & ( opcode was STH / JSR )) ^ Return Mode */ /* (stack overflow & ( opcode was STH / JSR )) ^ Return Mode */
errcode |= ((errcode >> 1 & ((instr & 0x1e) == 0x0e)) ^ instr >> 6) & 1; errcode |= ((errcode >> 1 & ((instr & 0x1e) == 0x0e)) ^ instr >> 6) & 1;
timeout:
return uxn_halt(u, errcode, pc - 1); return uxn_halt(u, errcode, pc - 1);
} }

View File

@ -47,6 +47,7 @@ typedef struct Uxn {
int uxn_boot(Uxn *u, Uint8 *ram); int uxn_boot(Uxn *u, Uint8 *ram);
int uxn_eval(Uxn *u, Uint16 pc); int uxn_eval(Uxn *u, Uint16 pc);
int uxn_interrupt(void);
int uxn_halt(Uxn *u, Uint8 error, Uint16 addr); int uxn_halt(Uxn *u, Uint8 error, Uint16 addr);
Device *uxn_port(Uxn *u, Uint8 id, Uint8 (*deifn)(Device *, Uint8), void (*deofn)(Device *, Uint8)); Device *uxn_port(Uxn *u, Uint8 id, Uint8 (*deifn)(Device *, Uint8), void (*deofn)(Device *, Uint8));
#endif /* UXN_UXN_H */ #endif /* UXN_UXN_H */

View File

@ -101,6 +101,12 @@ load(Uxn *u, char *filepath)
return 1; return 1;
} }
int
uxn_interrupt(void)
{
return 1;
}
static int static int
start(Uxn *u) start(Uxn *u)
{ {

View File

@ -32,6 +32,7 @@ WITH REGARD TO THIS SOFTWARE.
#define WIDTH 64 * 8 #define WIDTH 64 * 8
#define HEIGHT 40 * 8 #define HEIGHT 40 * 8
#define PAD 4 #define PAD 4
#define TIMEOUT_FRAMES 10
static SDL_Window *gWindow; static SDL_Window *gWindow;
static SDL_Texture *gTexture; static SDL_Texture *gTexture;
@ -43,7 +44,7 @@ static SDL_Rect gRect;
static Device *devscreen, *devmouse, *devctrl, *devaudio0, *devfile0; static Device *devscreen, *devmouse, *devctrl, *devaudio0, *devfile0;
static Uint8 zoom = 1; static Uint8 zoom = 1;
static Uint32 stdin_event, audio0_event, redraw_event; static Uint32 stdin_event, audio0_event, redraw_event, interrupt_event;
static int static int
error(char *msg, const char *err) error(char *msg, const char *err)
@ -89,12 +90,19 @@ stdin_handler(void *p)
static int static int
redraw_handler(void *p) redraw_handler(void *p)
{ {
SDL_Event event; int dropped_frames = 0;
SDL_Event event, interrupt;
event.type = redraw_event; event.type = redraw_event;
interrupt.type = interrupt_event;
for(;;) { for(;;) {
SDL_Delay(16); SDL_Delay(16);
if(SDL_HasEvent(redraw_event) == SDL_FALSE) if(SDL_HasEvent(redraw_event) == SDL_FALSE) {
SDL_PushEvent(&event); SDL_PushEvent(&event);
dropped_frames = 0;
}
else if(++dropped_frames == TIMEOUT_FRAMES) {
SDL_PushEvent(&interrupt);
}
} }
return 0; return 0;
(void)p; (void)p;
@ -169,6 +177,7 @@ init(void)
stdin_event = SDL_RegisterEvents(1); stdin_event = SDL_RegisterEvents(1);
audio0_event = SDL_RegisterEvents(POLYPHONY); audio0_event = SDL_RegisterEvents(POLYPHONY);
redraw_event = SDL_RegisterEvents(1); redraw_event = SDL_RegisterEvents(1);
interrupt_event = SDL_RegisterEvents(1);
SDL_CreateThread(stdin_handler, "stdin", NULL); SDL_CreateThread(stdin_handler, "stdin", NULL);
SDL_CreateThread(redraw_handler, "redraw", NULL); SDL_CreateThread(redraw_handler, "redraw", NULL);
SDL_StartTextInput(); SDL_StartTextInput();
@ -467,6 +476,12 @@ run(Uxn *u)
return error("SDL_WaitEvent", SDL_GetError()); return error("SDL_WaitEvent", SDL_GetError());
} }
int
uxn_interrupt(void)
{
return SDL_PeepEvents(NULL, 1, SDL_GETEVENT, interrupt_event, interrupt_event) < 1;
}
int int
main(int argc, char **argv) main(int argc, char **argv)
{ {