cvm: implement stack overflow error condition
This commit is contained in:
parent
25f4312523
commit
78d4d15fcf
12
blk/091
12
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:
|
lation). Here's the complete list of these references:
|
||||||
|
|
||||||
04 BOOT addr 06 (uflw) addr 08 LATEST
|
04 BOOT addr 06 (uflw) addr 08 LATEST
|
||||||
2b (s) wordref 33 2>R wordref 42 EXIT wordref
|
13 (oflw) addr 2b (s) wordref 33 2>R wordref
|
||||||
53 (br) wordref 67 (?br) wordref 80 (loop) wordref
|
42 EXIT wordref 53 (br) wordref 67 (?br) wordref
|
||||||
bf (n) wordref
|
80 (loop) wordref bf (n) wordref
|
||||||
|
|
||||||
BOOT and (uflw) exist because they are referred to before those
|
BOOT, (uflw) and (oflw) exist because they are referred to
|
||||||
words are defined (in core words). LATEST is a critical part
|
before those words are defined (in core words). LATEST is a
|
||||||
of the initialization sequence.
|
critical part of the initialization sequence.
|
||||||
|
|
||||||
(cont.)
|
(cont.)
|
||||||
|
2
blk/381
2
blk/381
@ -7,4 +7,6 @@
|
|||||||
: NL 0x0a RAM+ @ ( NLPTR ) ?DUP IF EXECUTE ELSE CRLF THEN ;
|
: NL 0x0a RAM+ @ ( NLPTR ) ?DUP IF EXECUTE ELSE CRLF THEN ;
|
||||||
: (uflw) LIT" stack underflow" ERR ;
|
: (uflw) LIT" stack underflow" ERR ;
|
||||||
XCURRENT @ _xapply ORG @ 0x06 ( stable ABI uflw ) + !
|
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 ;
|
: (wnf) (print) SPC LIT" word not found" ERR ;
|
||||||
|
BIN
cvm/forth.bin
BIN
cvm/forth.bin
Binary file not shown.
23
cvm/vm.c
23
cvm/vm.c
@ -76,23 +76,33 @@ static void sw(word addr, word val) {
|
|||||||
// pop word from SP
|
// pop word from SP
|
||||||
static word pop() {
|
static word pop() {
|
||||||
if (vm.uflw) return 0;
|
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;
|
return vm.mem[vm.SP++] | vm.mem[vm.SP++] << 8;
|
||||||
}
|
}
|
||||||
// push word to SP
|
// push word to SP
|
||||||
static void push(word x) {
|
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; }
|
if (vm.SP < vm.minSP) { vm.minSP = vm.SP; }
|
||||||
}
|
}
|
||||||
// pop word from RS
|
// pop word from RS
|
||||||
static word popRS() {
|
static word popRS() {
|
||||||
if (vm.uflw) return 0;
|
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;
|
word x = gw(vm.RS); vm.RS -= 2; return x;
|
||||||
}
|
}
|
||||||
// push word to RS
|
// push word to RS
|
||||||
static void pushRS(word val) {
|
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; }
|
if (vm.RS > vm.maxRS) { vm.maxRS = vm.RS; }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -358,6 +368,7 @@ VM* VM_init() {
|
|||||||
sw(SYSVARS+0x02, gw(0x08)); // CURRENT
|
sw(SYSVARS+0x02, gw(0x08)); // CURRENT
|
||||||
sw(SYSVARS+0x04, gw(0x08)); // HERE
|
sw(SYSVARS+0x04, gw(0x08)); // HERE
|
||||||
vm.uflw = false;
|
vm.uflw = false;
|
||||||
|
vm.oflw = false;
|
||||||
vm.running = true;
|
vm.running = true;
|
||||||
return &vm;
|
return &vm;
|
||||||
}
|
}
|
||||||
@ -380,6 +391,10 @@ bool VM_steps(int n) {
|
|||||||
vm.uflw = false;
|
vm.uflw = false;
|
||||||
execute(gw(0x06)); /* uflw */
|
execute(gw(0x06)); /* uflw */
|
||||||
}
|
}
|
||||||
|
if (vm.oflw) {
|
||||||
|
vm.oflw = false;
|
||||||
|
execute(gw(0x13)); /* oflw */
|
||||||
|
}
|
||||||
n--;
|
n--;
|
||||||
}
|
}
|
||||||
return vm.running;
|
return vm.running;
|
||||||
|
5
cvm/vm.h
5
cvm/vm.h
@ -39,6 +39,11 @@ typedef struct {
|
|||||||
// execute cycle. The goal is to avoid over-popping in native words that
|
// execute cycle. The goal is to avoid over-popping in native words that
|
||||||
// pop more than once and thus corrupt memory.
|
// pop more than once and thus corrupt memory.
|
||||||
bool uflw;
|
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* VM_init();
|
VM* VM_init();
|
||||||
|
Loading…
Reference in New Issue
Block a user