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