Skip to content

Commit

Permalink
Better error handling, bounds check, bug fixes. Fixes #7, #8, #13, #14
Browse files Browse the repository at this point in the history
  • Loading branch information
aw committed Jan 19, 2023
1 parent 7fe14c7 commit 9c755ab
Show file tree
Hide file tree
Showing 11 changed files with 149 additions and 86 deletions.
17 changes: 13 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ Development progress has been logged regularly in the [devlogs](https://aw.githu

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

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

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

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

# TODO

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

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

# Changelog

## 0.3 (2023-01-19)

* Fix issue #7 - Implement bounds checks for stacks
* Fix issue #8 - Implement bounds checks for user dictionary
* Fix issue #13 - `TOIN` should not be an address
* Fix issue #14 - `STORE` primitive is incorrect
* Add better error messages
* Add detailed documentation in [docs](docs/)
* Add `djb2.c` to generate a word's hash locally
* Add RAM zerofill of unused dictionary space on reset

## 0.2 (2023-01-10)

* Fix issue #9 - Handling of carriage return
Expand Down
2 changes: 1 addition & 1 deletion docs/HOWTO.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ Accessing _FiveForths_ through the terminal should look similar to this:
```
--- Miniterm on /dev/ttyUSB0 115200,8,N,1 ---
--- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
FiveForths v0.2, Copyright (c) 2021~ Alexander Williams, https://a1w.ca
FiveForths v0.3, Copyright (c) 2021~ Alexander Williams, https://a1w.ca
```

Expand Down
2 changes: 1 addition & 1 deletion docs/REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ Below is a list of specifications for _FiveForths_, most can be changed in the s
* Return character newline: `\n`
* Maximum word length: `32 characters`
* Stack effects comments support `( x -- x )`: **yes**
* Stack and memory overflow/underflow protection: **yes**
* Backslash comments support `\ comment`: **yes**
* Multiline code definitions support: **no**
* OK message: `" ok\n"`
Expand Down Expand Up @@ -167,7 +168,6 @@ The hash is a 32-bit hash with the last 8 bits (from the LSB) used for the Flags
| FLAGS | LENGTH | HASH |
+-------+--------+------------------+
3-bits 5-bits 24-bits
```

### Other Forths
Expand Down
6 changes: 3 additions & 3 deletions docs/TUTORIALS.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ It is possible to download a pre-built firmware binary, or build the firmware ma

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

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

### Build it

Expand Down Expand Up @@ -87,7 +87,7 @@ $ make

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

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

### Flash it

Expand Down
2 changes: 1 addition & 1 deletion src/01-variables-constants.s
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# Variables and constants
##

.equ FORTH_VERSION, 2
.equ FORTH_VERSION, 3

##
# Memory map
Expand Down
44 changes: 37 additions & 7 deletions src/02-macros.s
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,27 @@

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

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

# push register to return stack
.macro PUSHRSP reg
li t0, TIB_TOP+CELL # load address of bottom of stack + 1 CELL
blt s2, t0, err_overflow # jump to error handler if stack overflow

sw \reg, -CELL(s2) # store value from register into RSP
addi s2, s2, -CELL # decrement RSP by 1 cell
.endm

# pop top of return stack to register
.macro POPRSP reg
li t0, RSP_TOP # load address of top of RSP
bge s2, t0, err_underflow # jump to error handler if stack underflow

lw \reg, 0(s2) # load value from RSP into register
addi s2, s2, CELL # increment RSP by 1 cell
.endm
Expand Down Expand Up @@ -67,3 +69,31 @@
li t0, \char # load character into temporary
beq a0, t0, \dest # jump to the destination if the char matches
.endm

# print a message
.macro print_error name, size, jump
.balign CELL
err_\name :
la a1, msg_\name # load string message
addi a2, a1, \size # load string length
call uart_print # call uart print function
j \jump # jump when print returns
.endm

# restore HERE and LATEST variables
.macro restorevars reg
# update HERE
li t0, HERE # load HERE variable into temporary
sw \reg, 0(t0) # store the address of LATEST back into HERE

# update LATEST
li t0, LATEST # load LATEST variable into temporary
lw t1, 0(\reg) # load LATEST variable value into temporary
sw t1, 0(t0) # store LATEST word into LATEST variable
.endm

# check for stack underflow
.macro checkunderflow stacktop
li t0, DSP_TOP-\stacktop # load address of top of stack
bge sp, t0, err_underflow # jump to error handler if stack underflow
.endm
28 changes: 10 additions & 18 deletions src/05-internal-functions.s
Original file line number Diff line number Diff line change
Expand Up @@ -97,32 +97,24 @@ lookup_loop:
lw t0, 4(a1) # load the hash of the word from the X working register

# check if the word is hidden
li t1, F_HIDDEN # load the HIDDEN flag into temporary
and t1, t0, t1 # read the hidden flag bit
bnez t1, lookup_next # skip the word if it's hidden
li t1, F_HIDDEN # load the HIDDEN flag into temporary
and t1, t0, t1 # read the hidden flag bit
bnez t1, lookup_next # skip the word if it's hidden

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

# update HERE since we're in compile mode
li t0, HERE # load HERE variable into temporary
sw t2, 0(t0) # store the address of LATEST back into HERE

# update LATEST since we're in compile mode
li t0, LATEST # load LATEST variable into temporary
lw t1, 0(t2) # load LATEST variable value into temporary
sw t1, 0(t0) # store LATEST word into LATEST variable

j error # jump to error handler
restorevars t2 # restore HERE and LATEST (t2)
j err_error # jump to error handler
lookup_done:
ret
20 changes: 18 additions & 2 deletions src/06-initialization.s
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,29 @@ reset:
li t0, STATE # load STATE variable
sw zero, 0(t0) # initialize STATE variable (0 = execute)

.balign CELL
# reset the RAM from the last defined word
ram_init:
li t0, HERE # load HERE memory address
lw t0, 0(t0) # load HERE value
li t1, PAD # load PAD variable
ram_zerofill:
# initialize the memory cells
beq t0, t1,ram_done # loop until counter (HERE) == PAD
sw zero, 0(t0) # zero-fill the memory address
addi t0, t0, CELL # increment counter by 1 CELL
j ram_zerofill # repeat
ram_done:
# continue to tib_init

.balign CELL
# reset the terminal input buffer
tib_init:
# initialize TOIN variable
li t0, TIB # load TIB memory address
li t1, TOIN # load TOIN variable
li t2, TIB_TOP # load TIB_TOP variable
sw t0, 0(t1) # initialize TOIN variable to contain TIB start address
sw zero, 0(t1) # initialize TOIN variable to contain zero
tib_zerofill:
# initialize the TIB
beq t2, t0,tib_done # loop until TIB_TOP == TIB
Expand All @@ -57,4 +73,4 @@ tib_zerofill:
tib_done:
j interpreter_start # jump to the main interpreter REPL

msg_boot: .ascii "FiveForths v0.2, Copyright (c) 2021~ Alexander Williams, https://a1w.ca \n\n"
msg_boot: .ascii "FiveForths v0.3, Copyright (c) 2021~ Alexander Williams, https://a1w.ca \n\n"
38 changes: 14 additions & 24 deletions src/07-error-handling.s
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,20 @@
# Error handling
##

.balign CELL
# print an error message to the UART
error:
la a1, msg_error # load string message
addi a2, a1, 4 # load string length
call uart_print # call uart print function
j reset # jump to reset the stack pointers, variables, etc before jumping to the interpreter

.balign CELL
# print an OK message to the UART
ok:
la a1, msg_ok # load string message
addi a2, a1, 6 # load string length
call uart_print # call uart print function
j tib_init # jump to reset the terminal input buffer before jumping to the interpreter

.balign CELL
# print a REBOOTING message to the UART
reboot:
la a1, msg_reboot # load string message
addi a2, a1, 12 # load string length
call uart_print # call uart print function
j _start # reboot when print returns
print_error error, 4, reset
print_error ok, 6, tib_init
print_error reboot, 16, _start
print_error tib, 14, reset
print_error mem, 16, reset
print_error token, 14, reset
print_error underflow, 20, reset
print_error overflow, 20, reset

msg_error: .ascii " ?\n"
msg_ok: .ascii " ok\n"
msg_reboot: .ascii " rebooting\n"
msg_reboot: .ascii " ok rebooting\n"
msg_tib: .ascii " ? tib full\n"
msg_mem: .ascii " ? memory full\n"
msg_token: .ascii " ? big token\n"
msg_underflow: .ascii " ? stack underflow\n"
msg_overflow: .ascii " ? stack overflow\n"
Loading

0 comments on commit 9c755ab

Please sign in to comment.