diff --git a/blk/091 b/blk/091 index 0e9bde4..dc6eb36 100644 --- a/blk/091 +++ b/blk/091 @@ -5,12 +5,12 @@ sets that don't change (well, not without some binary manipu- lation). Here's the complete list of these references: 04 BOOT addr 06 (uflw) addr 08 LATEST -2b (s) wordref 33 2>R wordref 42 EXIT wordref -53 (br) wordref 67 (?br) wordref 80 (loop) wordref -bf (n) wordref +13 (oflw) addr 2b (s) wordref 33 2>R wordref +42 EXIT wordref 53 (br) wordref 67 (?br) wordref +80 (loop) wordref bf (n) wordref -BOOT and (uflw) exist because they are referred to before those -words are defined (in core words). LATEST is a critical part -of the initialization sequence. +BOOT, (uflw) and (oflw) exist because they are referred to +before those words are defined (in core words). LATEST is a +critical part of the initialization sequence. (cont.) diff --git a/blk/381 b/blk/381 index 002cfe4..8df37ff 100644 --- a/blk/381 +++ b/blk/381 @@ -7,4 +7,6 @@ : NL 0x0a RAM+ @ ( NLPTR ) ?DUP IF EXECUTE ELSE CRLF THEN ; : (uflw) LIT" stack underflow" ERR ; XCURRENT @ _xapply ORG @ 0x06 ( stable ABI uflw ) + ! +: (oflw) LIT" stack overflow" ERR ; +XCURRENT @ _xapply ORG @ 0x13 ( stable ABI oflw ) + ! : (wnf) (print) SPC LIT" word not found" ERR ; diff --git a/cvm/forth.bin b/cvm/forth.bin index 8d84cef..c5cdc0e 100644 Binary files a/cvm/forth.bin and b/cvm/forth.bin differ diff --git a/cvm/vm.c b/cvm/vm.c index 021a404..33ffa63 100644 --- a/cvm/vm.c +++ b/cvm/vm.c @@ -76,23 +76,33 @@ static void sw(word addr, word val) { // pop word from SP static word pop() { if (vm.uflw) return 0; - if (vm.SP >= SP_ADDR) { vm.uflw = true; } + if (vm.SP >= SP_ADDR) { vm.uflw = true; return 0; } return vm.mem[vm.SP++] | vm.mem[vm.SP++] << 8; } // push word to SP static void push(word x) { - vm.SP -= 2; sw(vm.SP, x); + vm.SP -= 2; + if (vm.SP <= vm.RS) { + vm.oflw = true; vm.SP = SP_ADDR; vm.RS = RS_ADDR; + return; + } + sw(vm.SP, x); if (vm.SP < vm.minSP) { vm.minSP = vm.SP; } } // pop word from RS static word popRS() { if (vm.uflw) return 0; - if (vm.RS <= RS_ADDR) { vm.uflw = true; } + if (vm.RS <= RS_ADDR) { vm.uflw = true; return 0; } word x = gw(vm.RS); vm.RS -= 2; return x; } // push word to RS static void pushRS(word val) { - vm.RS += 2; sw(vm.RS, val); + vm.RS += 2; + if (vm.SP <= vm.RS) { + vm.oflw = true; vm.SP = SP_ADDR; vm.RS = RS_ADDR; + return; + } + sw(vm.RS, val); if (vm.RS > vm.maxRS) { vm.maxRS = vm.RS; } } @@ -358,6 +368,7 @@ VM* VM_init() { sw(SYSVARS+0x02, gw(0x08)); // CURRENT sw(SYSVARS+0x04, gw(0x08)); // HERE vm.uflw = false; + vm.oflw = false; vm.running = true; return &vm; } @@ -380,6 +391,10 @@ bool VM_steps(int n) { vm.uflw = false; execute(gw(0x06)); /* uflw */ } + if (vm.oflw) { + vm.oflw = false; + execute(gw(0x13)); /* oflw */ + } n--; } return vm.running; diff --git a/cvm/vm.h b/cvm/vm.h index b14834b..215bd9e 100644 --- a/cvm/vm.h +++ b/cvm/vm.h @@ -39,6 +39,11 @@ typedef struct { // execute cycle. The goal is to avoid over-popping in native words that // pop more than once and thus corrupt memory. bool uflw; + // Same as uflw, but for stack overflow. However, we behave differently with + // oflw than with uflw. We can't prevent push() and pushRS() because it + // would prevent us from calling (oflw). Instead, we clear both stacks on + // oflw conditions, which gives us the room to maneuver. + bool oflw; } VM; VM* VM_init();