Skip to content

Commit 9c755ab

Browse files
committed
Better error handling, bounds check, bug fixes. Fixes #7, #8, #13, #14
1 parent 7fe14c7 commit 9c755ab

11 files changed

Lines changed: 149 additions & 86 deletions

README.md

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ Development progress has been logged regularly in the [devlogs](https://aw.githu
2121

2222
The quickest way to get started is to download and flash one of the firmware binaries listed below:.
2323

24-
* [fiveforths-longan-nano-lite.bin](https://github.com/aw/fiveforths/releases/download/v0.2/fiveforths-longan-nano-lite.bin) (64K Flash, 20K RAM)
25-
* [fiveforths-longan-nano.bin](https://github.com/aw/fiveforths/releases/download/v0.2/fiveforths-longan-nano.bin) (128K Flash, 32K RAM)
24+
* [fiveforths-longan-nano-lite.bin](https://github.com/aw/fiveforths/releases/download/v0.3/fiveforths-longan-nano-lite.bin) (64K Flash, 20K RAM)
25+
* [fiveforths-longan-nano.bin](https://github.com/aw/fiveforths/releases/download/v0.3/fiveforths-longan-nano.bin) (128K Flash, 32K RAM)
2626

2727
See the [TUTORIALS](docs/TUTORIALS.md) for detailed download and flashing information.
2828

@@ -35,8 +35,6 @@ See the [TUTORIALS](docs/TUTORIALS.md) for detailed download and flashing inform
3535

3636
# TODO
3737

38-
- [ ] Implement bounds checks for stacks and dictionary
39-
- [ ] Add example Forth code to turn it into a "real" Forth (ex: `[`, `]`, `branch`, etc)
4038
- [ ] Code cleanup and optimizations
4139

4240
# Contributing
@@ -45,6 +43,17 @@ Please create a pull-request or [open an issue](https://github.com/aw/picolisp-k
4543

4644
# Changelog
4745

46+
## 0.3 (2023-01-19)
47+
48+
* Fix issue #7 - Implement bounds checks for stacks
49+
* Fix issue #8 - Implement bounds checks for user dictionary
50+
* Fix issue #13 - `TOIN` should not be an address
51+
* Fix issue #14 - `STORE` primitive is incorrect
52+
* Add better error messages
53+
* Add detailed documentation in [docs](docs/)
54+
* Add `djb2.c` to generate a word's hash locally
55+
* Add RAM zerofill of unused dictionary space on reset
56+
4857
## 0.2 (2023-01-10)
4958

5059
* Fix issue #9 - Handling of carriage return

docs/HOWTO.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ Accessing _FiveForths_ through the terminal should look similar to this:
9595
```
9696
--- Miniterm on /dev/ttyUSB0 115200,8,N,1 ---
9797
--- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
98-
FiveForths v0.2, Copyright (c) 2021~ Alexander Williams, https://a1w.ca
98+
FiveForths v0.3, Copyright (c) 2021~ Alexander Williams, https://a1w.ca
9999
100100
```
101101

docs/REFERENCE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ Below is a list of specifications for _FiveForths_, most can be changed in the s
3434
* Return character newline: `\n`
3535
* Maximum word length: `32 characters`
3636
* Stack effects comments support `( x -- x )`: **yes**
37+
* Stack and memory overflow/underflow protection: **yes**
3738
* Backslash comments support `\ comment`: **yes**
3839
* Multiline code definitions support: **no**
3940
* OK message: `" ok\n"`
@@ -167,7 +168,6 @@ The hash is a 32-bit hash with the last 8 bits (from the LSB) used for the Flags
167168
| FLAGS | LENGTH | HASH |
168169
+-------+--------+------------------+
169170
3-bits 5-bits 24-bits
170-
171171
```
172172

173173
### Other Forths

docs/TUTORIALS.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ It is possible to download a pre-built firmware binary, or build the firmware ma
5454

5555
Download one of the firmware binaries from the [releases page](https://github.com/aw/fiveforths/releases).
5656

57-
* [fiveforths-longan-nano-lite.bin](https://github.com/aw/fiveforths/releases/download/v0.2/fiveforths-longan-nano-lite.bin) (64K Flash, 20K RAM)
58-
* [fiveforths-longan-nano.bin](https://github.com/aw/fiveforths/releases/download/v0.2/fiveforths-longan-nano.bin) (128K Flash, 32K RAM)
57+
* [fiveforths-longan-nano-lite.bin](https://github.com/aw/fiveforths/releases/download/v0.3/fiveforths-longan-nano-lite.bin) (64K Flash, 20K RAM)
58+
* [fiveforths-longan-nano.bin](https://github.com/aw/fiveforths/releases/download/v0.3/fiveforths-longan-nano.bin) (128K Flash, 32K RAM)
5959

6060
### Build it
6161

@@ -87,7 +87,7 @@ $ make
8787

8888
Additional build options are explained in the [HOWTO](HOWTO.md) section.
8989

90-
The firmware file is called `fiveforths.bin` and is **under 2 KBytes** as of _release v0.1_ since _January 08, 2023_.
90+
The firmware file is called `fiveforths.bin` and is **nearly 2.5 KBytes** as of _release v0.3_ since _January 19, 2023_.
9191

9292
### Flash it
9393

src/01-variables-constants.s

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# Variables and constants
33
##
44

5-
.equ FORTH_VERSION, 2
5+
.equ FORTH_VERSION, 3
66

77
##
88
# Memory map

src/02-macros.s

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,25 +18,27 @@
1818

1919
# push register to top of stack and move DSP
2020
.macro PUSH reg
21-
sw \reg, -CELL(sp) # store the value in the register to the top of the DSP
22-
addi sp, sp, -CELL # move the DSP down by 1 cell
23-
.endm
21+
li t0, RSP_TOP+CELL # load address of bottom of stack + 1 CELL
22+
blt sp, t0, err_overflow # jump to error handler if stack overflow
2423

25-
# push variable to top of stack
26-
.macro PUSHVAR var
27-
li t0, \var # load variable into temporary
28-
sw t0, -CELL(sp) # store the variable value to the top of the DSP
24+
sw \reg, -CELL(sp) # store the value in the register to the top of the DSP
2925
addi sp, sp, -CELL # move the DSP down by 1 cell
3026
.endm
3127

3228
# push register to return stack
3329
.macro PUSHRSP reg
30+
li t0, TIB_TOP+CELL # load address of bottom of stack + 1 CELL
31+
blt s2, t0, err_overflow # jump to error handler if stack overflow
32+
3433
sw \reg, -CELL(s2) # store value from register into RSP
3534
addi s2, s2, -CELL # decrement RSP by 1 cell
3635
.endm
3736

3837
# pop top of return stack to register
3938
.macro POPRSP reg
39+
li t0, RSP_TOP # load address of top of RSP
40+
bge s2, t0, err_underflow # jump to error handler if stack underflow
41+
4042
lw \reg, 0(s2) # load value from RSP into register
4143
addi s2, s2, CELL # increment RSP by 1 cell
4244
.endm
@@ -67,3 +69,31 @@
6769
li t0, \char # load character into temporary
6870
beq a0, t0, \dest # jump to the destination if the char matches
6971
.endm
72+
73+
# print a message
74+
.macro print_error name, size, jump
75+
.balign CELL
76+
err_\name :
77+
la a1, msg_\name # load string message
78+
addi a2, a1, \size # load string length
79+
call uart_print # call uart print function
80+
j \jump # jump when print returns
81+
.endm
82+
83+
# restore HERE and LATEST variables
84+
.macro restorevars reg
85+
# update HERE
86+
li t0, HERE # load HERE variable into temporary
87+
sw \reg, 0(t0) # store the address of LATEST back into HERE
88+
89+
# update LATEST
90+
li t0, LATEST # load LATEST variable into temporary
91+
lw t1, 0(\reg) # load LATEST variable value into temporary
92+
sw t1, 0(t0) # store LATEST word into LATEST variable
93+
.endm
94+
95+
# check for stack underflow
96+
.macro checkunderflow stacktop
97+
li t0, DSP_TOP-\stacktop # load address of top of stack
98+
bge sp, t0, err_underflow # jump to error handler if stack underflow
99+
.endm

src/05-internal-functions.s

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -97,32 +97,24 @@ lookup_loop:
9797
lw t0, 4(a1) # load the hash of the word from the X working register
9898

9999
# check if the word is hidden
100-
li t1, F_HIDDEN # load the HIDDEN flag into temporary
101-
and t1, t0, t1 # read the hidden flag bit
102-
bnez t1, lookup_next # skip the word if it's hidden
100+
li t1, F_HIDDEN # load the HIDDEN flag into temporary
101+
and t1, t0, t1 # read the hidden flag bit
102+
bnez t1, lookup_next # skip the word if it's hidden
103103

104104
# remove the 3-bit flags using a mask
105-
li t1, ~FLAGS_MASK # load the inverted 3-bit flags mask into temporary
106-
and t0, t0, t1 # ignore flags when comparing the hashes
107-
beq t0, a0, lookup_done # done if the hashes match
105+
li t1, ~FLAGS_MASK # load the inverted 3-bit flags mask into temporary
106+
and t0, t0, t1 # ignore flags when comparing the hashes
107+
beq t0, a0, lookup_done # done if the hashes match
108108
lookup_next:
109-
lw a1, 0(a1) # follow link to next word in dict
109+
lw a1, 0(a1) # follow link to next word in dict
110110
j lookup_loop
111111
lookup_error:
112112
# check the STATE
113113
li t0, STATE # load the address of the STATE variable into temporary
114114
lw t0, 0(t0) # load the current state into a temporary
115-
beqz t0, error # if in execute mode (STATE = 0), jump to error handler to reset
115+
beqz t0, err_error # if in execute mode (STATE = 0), jump to error handler to reset
116116

117-
# update HERE since we're in compile mode
118-
li t0, HERE # load HERE variable into temporary
119-
sw t2, 0(t0) # store the address of LATEST back into HERE
120-
121-
# update LATEST since we're in compile mode
122-
li t0, LATEST # load LATEST variable into temporary
123-
lw t1, 0(t2) # load LATEST variable value into temporary
124-
sw t1, 0(t0) # store LATEST word into LATEST variable
125-
126-
j error # jump to error handler
117+
restorevars t2 # restore HERE and LATEST (t2)
118+
j err_error # jump to error handler
127119
lookup_done:
128120
ret

src/06-initialization.s

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,29 @@ reset:
4141
li t0, STATE # load STATE variable
4242
sw zero, 0(t0) # initialize STATE variable (0 = execute)
4343

44+
.balign CELL
45+
# reset the RAM from the last defined word
46+
ram_init:
47+
li t0, HERE # load HERE memory address
48+
lw t0, 0(t0) # load HERE value
49+
li t1, PAD # load PAD variable
50+
ram_zerofill:
51+
# initialize the memory cells
52+
beq t0, t1,ram_done # loop until counter (HERE) == PAD
53+
sw zero, 0(t0) # zero-fill the memory address
54+
addi t0, t0, CELL # increment counter by 1 CELL
55+
j ram_zerofill # repeat
56+
ram_done:
57+
# continue to tib_init
58+
59+
.balign CELL
4460
# reset the terminal input buffer
4561
tib_init:
4662
# initialize TOIN variable
4763
li t0, TIB # load TIB memory address
4864
li t1, TOIN # load TOIN variable
4965
li t2, TIB_TOP # load TIB_TOP variable
50-
sw t0, 0(t1) # initialize TOIN variable to contain TIB start address
66+
sw zero, 0(t1) # initialize TOIN variable to contain zero
5167
tib_zerofill:
5268
# initialize the TIB
5369
beq t2, t0,tib_done # loop until TIB_TOP == TIB
@@ -57,4 +73,4 @@ tib_zerofill:
5773
tib_done:
5874
j interpreter_start # jump to the main interpreter REPL
5975

60-
msg_boot: .ascii "FiveForths v0.2, Copyright (c) 2021~ Alexander Williams, https://a1w.ca \n\n"
76+
msg_boot: .ascii "FiveForths v0.3, Copyright (c) 2021~ Alexander Williams, https://a1w.ca \n\n"

src/07-error-handling.s

Lines changed: 14 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,30 +2,20 @@
22
# Error handling
33
##
44

5-
.balign CELL
6-
# print an error message to the UART
7-
error:
8-
la a1, msg_error # load string message
9-
addi a2, a1, 4 # load string length
10-
call uart_print # call uart print function
11-
j reset # jump to reset the stack pointers, variables, etc before jumping to the interpreter
12-
13-
.balign CELL
14-
# print an OK message to the UART
15-
ok:
16-
la a1, msg_ok # load string message
17-
addi a2, a1, 6 # load string length
18-
call uart_print # call uart print function
19-
j tib_init # jump to reset the terminal input buffer before jumping to the interpreter
20-
21-
.balign CELL
22-
# print a REBOOTING message to the UART
23-
reboot:
24-
la a1, msg_reboot # load string message
25-
addi a2, a1, 12 # load string length
26-
call uart_print # call uart print function
27-
j _start # reboot when print returns
5+
print_error error, 4, reset
6+
print_error ok, 6, tib_init
7+
print_error reboot, 16, _start
8+
print_error tib, 14, reset
9+
print_error mem, 16, reset
10+
print_error token, 14, reset
11+
print_error underflow, 20, reset
12+
print_error overflow, 20, reset
2813

2914
msg_error: .ascii " ?\n"
3015
msg_ok: .ascii " ok\n"
31-
msg_reboot: .ascii " rebooting\n"
16+
msg_reboot: .ascii " ok rebooting\n"
17+
msg_tib: .ascii " ? tib full\n"
18+
msg_mem: .ascii " ? memory full\n"
19+
msg_token: .ascii " ? big token\n"
20+
msg_underflow: .ascii " ? stack underflow\n"
21+
msg_overflow: .ascii " ? stack overflow\n"

0 commit comments

Comments
 (0)