cvm: implement stack overflow error condition

This commit is contained in:
Virgil Dupras 2020-08-07 21:57:25 -04:00
parent 25f4312523
commit 78d4d15fcf
5 changed files with 32 additions and 10 deletions

12
blk/091
View File

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

View File

@ -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 ;

Binary file not shown.

View File

@ -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;

View File

@ -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();