Browse code

(uxnemu) Interrupt infinite loops with an error.

Andrew Alderwick authored on 27/03/2022 12:53:25
Showing 5 changed files
... ...
@@ -20,7 +20,8 @@ static const char *errors[] = {
20 20
 	"Working-stack overflow",
21 21
 	"Return-stack overflow",
22 22
 	"Working-stack division by zero",
23
-	"Return-stack division by zero"};
23
+	"Return-stack division by zero",
24
+	"Execution timeout"};
24 25
 
25 26
 static void
26 27
 system_print(Stack *s, char *name)
... ...
@@ -30,16 +30,25 @@ WITH REGARD TO THIS SOFTWARE.
30 30
 #define DEVW8(x, y) { dev->dat[(x) & 0xf] = y; dev->deo(dev, (x) & 0x0f); }
31 31
 #define DEVW(d, x, y) { dev = (d); if(bs) { DEVW8((x), (y) >> 8); DEVW8((x) + 1, (y)); } else { DEVW8((x), (y)) } }
32 32
 #define WARP(x) { if(bs) pc = (x); else pc += (Sint8)(x); }
33
+#define LIMIT 0x40000 /* around 3 ms */
33 34
 
34 35
 int
35 36
 uxn_eval(Uxn *u, Uint16 pc)
36 37
 {
37 38
 	unsigned int a, b, c, j, k, bs, instr, errcode;
39
+	unsigned int limit = LIMIT;
38 40
 	Uint8 kptr, *sp;
39 41
 	Stack *src, *dst;
40 42
 	Device *dev;
41 43
 	if(!pc || u->dev[0].dat[0xf]) return 0;
42 44
 	while((instr = u->ram[pc++])) {
45
+		if(!limit--) {
46
+			if(!uxn_interrupt()) {
47
+				errcode = 6;
48
+				goto timeout;
49
+			}
50
+			limit = LIMIT;
51
+		}
43 52
 		/* Return Mode */
44 53
 		if(instr & 0x40) {
45 54
 			src = &u->rst; dst = &u->wst;
... ...
@@ -101,6 +110,7 @@ err:
101 110
 	/* set 1 in errcode if it involved the return stack instead of the working stack */
102 111
 	/*        (stack overflow & ( opcode was STH / JSR )) ^ Return Mode */
103 112
 	errcode |= ((errcode >> 1 & ((instr & 0x1e) == 0x0e)) ^ instr >> 6) & 1;
113
+timeout:
104 114
 	return uxn_halt(u, errcode, pc - 1);
105 115
 }
106 116
 
... ...
@@ -47,6 +47,7 @@ typedef struct Uxn {
47 47
 
48 48
 int uxn_boot(Uxn *u, Uint8 *ram);
49 49
 int uxn_eval(Uxn *u, Uint16 pc);
50
+int uxn_interrupt(void);
50 51
 int uxn_halt(Uxn *u, Uint8 error, Uint16 addr);
51 52
 Device *uxn_port(Uxn *u, Uint8 id, Uint8 (*deifn)(Device *, Uint8), void (*deofn)(Device *, Uint8));
52 53
 #endif /* UXN_UXN_H */
... ...
@@ -101,6 +101,12 @@ load(Uxn *u, char *filepath)
101 101
 	return 1;
102 102
 }
103 103
 
104
+int
105
+uxn_interrupt(void)
106
+{
107
+	return 1;
108
+}
109
+
104 110
 static int
105 111
 start(Uxn *u)
106 112
 {
... ...
@@ -32,6 +32,7 @@ WITH REGARD TO THIS SOFTWARE.
32 32
 #define WIDTH 64 * 8
33 33
 #define HEIGHT 40 * 8
34 34
 #define PAD 4
35
+#define TIMEOUT_FRAMES 10
35 36
 
36 37
 static SDL_Window *gWindow;
37 38
 static SDL_Texture *gTexture;
... ...
@@ -43,7 +44,7 @@ static SDL_Rect gRect;
43 44
 
44 45
 static Device *devscreen, *devmouse, *devctrl, *devaudio0, *devfile0;
45 46
 static Uint8 zoom = 1;
46
-static Uint32 stdin_event, audio0_event, redraw_event;
47
+static Uint32 stdin_event, audio0_event, redraw_event, interrupt_event;
47 48
 
48 49
 static int
49 50
 error(char *msg, const char *err)
... ...
@@ -89,12 +90,19 @@ stdin_handler(void *p)
89 90
 static int
90 91
 redraw_handler(void *p)
91 92
 {
92
-	SDL_Event event;
93
+	int dropped_frames = 0;
94
+	SDL_Event event, interrupt;
93 95
 	event.type = redraw_event;
96
+	interrupt.type = interrupt_event;
94 97
 	for(;;) {
95 98
 		SDL_Delay(16);
96
-		if(SDL_HasEvent(redraw_event) == SDL_FALSE)
99
+		if(SDL_HasEvent(redraw_event) == SDL_FALSE) {
97 100
 			SDL_PushEvent(&event);
101
+			dropped_frames = 0;
102
+		}
103
+		else if(++dropped_frames == TIMEOUT_FRAMES) {
104
+			SDL_PushEvent(&interrupt);
105
+		}
98 106
 	}
99 107
 	return 0;
100 108
 	(void)p;
... ...
@@ -169,6 +177,7 @@ init(void)
169 177
 	stdin_event = SDL_RegisterEvents(1);
170 178
 	audio0_event = SDL_RegisterEvents(POLYPHONY);
171 179
 	redraw_event = SDL_RegisterEvents(1);
180
+	interrupt_event = SDL_RegisterEvents(1);
172 181
 	SDL_CreateThread(stdin_handler, "stdin", NULL);
173 182
 	SDL_CreateThread(redraw_handler, "redraw", NULL);
174 183
 	SDL_StartTextInput();
... ...
@@ -467,6 +476,12 @@ run(Uxn *u)
467 476
 	return error("SDL_WaitEvent", SDL_GetError());
468 477
 }
469 478
 
479
+int
480
+uxn_interrupt(void)
481
+{
482
+	return SDL_PeepEvents(NULL, 1, SDL_GETEVENT, interrupt_event, interrupt_event) < 1;
483
+}
484
+
470 485
 int
471 486
 main(int argc, char **argv)
472 487
 {