Skip to content

Commit

Permalink
Add bounds check for stacks and user dictionary. Fixes #7 and fixes #8
Browse files Browse the repository at this point in the history
  • Loading branch information
aw committed Jan 16, 2023
1 parent 5fc1186 commit f4b83f1
Show file tree
Hide file tree
Showing 8 changed files with 94 additions and 42 deletions.
10 changes: 8 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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,14 @@ Please create a pull-request or [open an issue](https://github.com/aw/picolisp-k

# Changelog

## 0.3 (TIB)

* Implement bounds checks for stacks
* Implement bounds checks for user dictionary
* Add better error messages
* Add detailed documentation in [docs](docs/)
* Add `djb2.c` to generate a word's hash locally

## 0.2 (2023-01-10)

* Fix issue #9 - Handling of carriage return
Expand Down
2 changes: 1 addition & 1 deletion docs/TUTORIALS.md
Original file line number Diff line number Diff line change
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 **slightly over 2 KBytes** as of _release v0.3_ since _January 16, 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
22 changes: 22 additions & 0 deletions src/02-macros.s
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,37 @@

# push register to top of stack and move DSP
.macro PUSH reg
li t0, RSP_TOP+(1*CELL) # load address of top of DSP with -4 offset (needs 1 CELL)
blt sp, t0, err_overflow # jump to error handler if stack overflow

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 variable to top of stack
.macro PUSHVAR var
li t0, RSP_TOP+(1*CELL) # load address of top of DSP with -4 offset (needs 1 CELL)
blt sp, t0, err_overflow # jump to error handler if stack overflow

li t0, \var # load variable into temporary
sw t0, -CELL(sp) # store the variable value 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, RSP_TOP+(1*CELL) # load address of top of RSP with -4 offset (needs 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-(1*CELL) # load address of top of RSP with -4 offset (needs 1 CELL)
bgt 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 +79,13 @@
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
4 changes: 2 additions & 2 deletions src/05-internal-functions.s
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ 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
Expand All @@ -123,6 +123,6 @@ lookup_error:
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
j err_error # jump to error handler
lookup_done:
ret
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"
28 changes: 19 additions & 9 deletions src/08-forth-primitives.s
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

# reboot ( -- ) # Reboot the entire system and initialize memory
defcode "reboot", 0x06266b70, REBOOT, NULL
j reboot # jump to reboot
j err_reboot # jump to reboot

# @ ( addr -- x ) Fetch memory at addr
defcode "@", 0x0102b5e5, FETCH, REBOOT
Expand All @@ -17,6 +17,9 @@ defcode "@", 0x0102b5e5, FETCH, REBOOT

# ! ( x addr -- ) Store x at addr
defcode "!", 0x0102b5c6, STORE, FETCH
li t0, DSP_TOP-(2*CELL) # load address of top of DSP with -8 offset (needs 2 CELLs)
bgt sp, t0, err_underflow # jump to error handler if stack underflow

lw t0, 0(sp) # load the DSP value (x) into temporary
lw t1, CELL(sp) # load the DSP value (addr) into temporary
sw t0, 0(t1) # store x into addr
Expand All @@ -43,6 +46,9 @@ defcode "0=", 0x025970b2, ZEQU, RSPFETCH

# + ( x1 x2 -- n ) Add the two values at the top of the stack
defcode "+", 0x0102b5d0, ADD, ZEQU
li t0, DSP_TOP-(2*CELL) # load address of top of DSP with -8 offset (needs 2 CELLs)
bgt sp, t0, err_underflow # jump to error handler if stack underflow

POP t0 # pop DSP value (x1) into temporary
lw t1, 0(sp) # load DSP value (x2) into temporary
add t0, t0, t1 # add the two values
Expand All @@ -51,6 +57,9 @@ defcode "+", 0x0102b5d0, ADD, ZEQU

# nand ( x1 x2 -- n ) Bitwise NAND the two values at the top of the stack
defcode "nand", 0x049b0c66, NAND, ADD
li t0, DSP_TOP-(2*CELL) # load address of top of DSP with -8 offset (needs 2 CELLs)
bgt sp, t0, err_underflow # jump to error handler if stack underflow

POP t0 # pop DSP value (x1) into temporary
lw t1, 0(sp) # load DSP value (x2) into temporary
and t0, t0, t1 # perform bitwise AND of the two values
Expand Down Expand Up @@ -130,9 +139,9 @@ defcode ":", 0x0102b5df, COLON, LATEST
sw t0, 0(t3) # move TOIN to process the next word in the TIB

# bounds checks on token size
beqz a1, ok # ok if token size is 0
beqz a1, err_ok # ok if token size is 0
li t0, 32 # load max token size (2^5 = 32) in temporary
bgtu a1, t0, error # error if token size is greater than 32
bgtu a1, t0, err_token # error if token size is greater than 32

call djb2_hash # hash the token

Expand All @@ -151,8 +160,8 @@ defcode ":", 0x0102b5df, COLON, LATEST

# bounds check on new word memory location
addi t4, t2, 3*CELL # prepare to move the HERE pointer to the end of the word
li t5, PAD # load out of bounds memory address (PAD)
bgt t4, t5, error # error if the memory address is out of bounds
li t5, PAD-4 # load out of bounds memory address (PAD)
bgt t4, t5, err_mem # error if the memory address is out of bounds

# update LATEST variable
sw t2, 0(t1) # store the current value of HERE into the LATEST variable
Expand Down Expand Up @@ -192,13 +201,14 @@ defcode ";", 0x8102b5e0, SEMI, COLON
# update HERE variable
li t0, HERE # copy the memory address of HERE into temporary
lw t2, 0(t0) # load the HERE value into temporary
la t1, code_EXIT # load the codeword address into temporary
sw t1, 0(t2) # store the codeword address into HERE

# bounds check on the exit memory location
li t3, PAD-4 # load out of bounds memory address (PAD)
bgt t2, t3, compile_error # error if the memory address is out of bounds

la t1, code_EXIT # load the codeword address into temporary
sw t1, 0(t2) # store the codeword address into HERE
addi t2, t2, CELL # prepare to move the HERE pointer by 1 CELL
li t3, PAD # load out of bounds memory address (PAD)
bgt t2, t3, error # error if the memory address is out of bounds

# move HERE pointer
sw t2, 0(t0) # store the new address of HERE into the HERE variable
Expand Down
30 changes: 27 additions & 3 deletions src/09-interpreter.s
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ skip_send:
interpreter_tib:
# add the character to the TIB
li t4, TIB_TOP # load TIB_TOP memory address
bge a1, t4, error # error if the terminal input buffer is full # FIXME: handle this better
bge a1, t4, err_tib # error if the terminal input buffer is full
sb a0, 0(a1) # store the character from W register in the TIB
addi a1, a1, 1 # increment TOIN value by 1
li t0, CHAR_NEWLINE # load newline into temporary
Expand Down Expand Up @@ -82,9 +82,9 @@ process_token:
sw t0, 0(t3) # move TOIN to process the next word in the TIB

# bounds checks on token size
beqz a1, ok # ok if token size is 0
beqz a1, err_ok # ok if token size is 0
li t0, 32 # load max token size (2^5 = 32) in temporary
bgtu a1, t0, error # error if token size is greater than 32
bgtu a1, t0, err_token # error if token size is greater than 32

# check if the token is a number
mv t5, a0 # save a0 temporarily
Expand Down Expand Up @@ -131,22 +131,46 @@ compile:
addi t0, a1, 2*CELL # increment the address of the found word by 8 to get the codeword address
li t1, HERE # load HERE variable into temporary
lw t2, 0(t1) # load HERE value into temporary

# bounds check on codeword memory location
li t3, PAD-4 # load out of bounds memory address (PAD)
bgt t2, t3, compile_error # error if the memory address is out of bounds

sw t0, 0(t2) # write the address of the codeword to the current definition

addi t0, t2, CELL # increment HERE by 4
sw t0, 0(t1) # store new HERE address
compile_done:
j process_token
compile_error:
li t0, HERE # load HERE variable into temporary
li t1, LATEST # load LATEST variable into temporary
lw t2, 0(t1) # load the address of the previous word into temporary (LATEST)

# update HERE
sw t2, 0(t0) # store the address of LATEST back into HERE

# update LATEST
lw t0, 0(t2) # load LATEST variable value into temporary
sw t0, 0(t1) # store LATEST word into LATEST variable

j err_mem # jump to error handler

push_number:
# push to stack if STATE = 0 (execute)
li t1, STATE # load the address of the STATE variable into temporary
lw t1, 0(t1) # load the current state into a temporary
beqz t1, push_stack # if in execute mode, push the number to the stack

# push to memory if STATE = 1 (compile)
la t0, code_LIT # load the codeword address of LIT into temporary
li t1, HERE # load HERE variable into temporary
lw t2, 0(t1) # load HERE value into temporary

# bounds check on codeword memory location
li t3, PAD-8 # load out of bounds memory address (PAD)
bgt t2, t3, compile_error # error if the memory address is out of bounds

sw t0, 0(t2) # write the codeword address of LIT to memory (HERE)
sw a0, 4(t2) # write the number from W to the next memory cell (HERE+4)
addi t0, t2, 2*CELL # increment HERE by 2 CELLs
Expand Down

0 comments on commit f4b83f1

Please sign in to comment.