... | ... |
@@ -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 */ |
... | ... |
@@ -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 |
{ |