forth-riscv

My forth
git clone git://git.electrosoup.com/forth-riscv
Log | Files | Refs

commit ee279aeafca810f2aa70e63a6a29bbc5624fc767
parent 21588fcba332d565b2140bff48cfd019d6badc6f
Author: Christian Ermann <christianermann@gmail.com>
Date:   Thu, 21 Nov 2024 13:05:08 -0800

Add core test suite

Diffstat:
Msrc/bootstrap.fs | 2++
Msrc/forth.s | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/riscv32-virt.ld | 2++
Asrc/tests.fs | 291++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 346 insertions(+), 0 deletions(-)

diff --git a/src/bootstrap.fs b/src/bootstrap.fs @@ -19,6 +19,8 @@ : char parse-word if c@ else 0 then ; : [char] char postpone literal ; immediate +: bl 32 ; + : ')' [char] ) ; : '"' [char] " ; : '\' [char] \ ; diff --git a/src/forth.s b/src/forth.s @@ -576,6 +576,12 @@ defword "bootstrap", bootstrap, 0x15C160D9 jal evaluate exit +defword "run-tests", run_tests, 0xC7C52582 + push w + li w, 2 + jal evaluate + exit + defword "evaluate", evaluate, 0xACE4360A jal source_id jal store @@ -706,6 +712,13 @@ defcode "cell+", cell_plus, 0xB14A8CBA addi w, w, cell next +defcode "chars", chars, 0x5DA9662A + next + +defcode "char+", char_plus, 0x25A90E02 + addi w, w, 1 + next + # ----------------------------------------------------------------------------- # dictionary management # ----------------------------------------------------------------------------- @@ -808,6 +821,11 @@ defcode "r>", from_ret, 0x135408B1 pop_ret w next +defcode "r@", fetch_ret, 0x3D544ACF + push w + load_cell w, 0(rsp) + next + defcode "2>r" two_to_ret, 0x69F5D439 pop x push_ret x @@ -883,11 +901,27 @@ defcode "-", minus, 0x280C9438 sub w, x, w next +defcode "abs", abs, 0x2A48023B + bgtz w, _abs_positive + not w, w + addi w, w, 1 +_abs_positive: + next + +defcode "negate", negate, 0x757CBB5B + not w, w + addi w, w, 1 + next + defcode "*", times, 0x2F0C9F3D pop x mul w, x, w next +defcode "not", not_, 0x29B19C8A + not w, w + next + defcode "or", or_, 0x5D342984 pop x or w, x, w @@ -898,6 +932,11 @@ defcode "and", and_, 0x0F29C2A6 and w, x, w next +defcode "xor", xor_, 0xCC6BDB7E + pop x + xor w, x, w + next + defcode "lshift", lshift, 0x8DA53719 pop x sll w, x, w @@ -973,6 +1012,13 @@ defcode "min", min, 0xC98F4557 _min_greater_than: next +defcode "max", max, 0xD7A2E319 + pop x + blt x, w, _max_less_than + mv w, x +_max_less_than: + next + # ----------------------------------------------------------------------------- # compiler # ----------------------------------------------------------------------------- @@ -1251,6 +1297,7 @@ defword "read-line", read_line, 0xAF1308A2 # ( addr len id -- ? ) load_cell x, 3 * cell(x) # offset # apply offset add y, y, x + sub w, w, x # len = min(buffer, file) jal min @@ -1291,6 +1338,10 @@ _file_table: .int __file_start # addr .int __file_end - __file_start # len .int 0 # offset + .int 0x98CD7A4F + .int __tests_start + .int __tests_end - __tests_start + .int 0 .section ".text" program: diff --git a/src/riscv32-virt.ld b/src/riscv32-virt.ld @@ -1,6 +1,7 @@ TARGET(binary) INPUT("src/bootstrap.fs") +INPUT("src/tests.fs") OUTPUT_FORMAT("elf32-littleriscv", "elf32-littleriscv", "elf32-littleriscv") OUTPUT_ARCH(riscv) @@ -18,6 +19,7 @@ SECTIONS { . = ORIGIN(RAM); .text : { *(.text.boot); *(.text); *(.text.*) } >RAM .text : { __file_start = .; "src/bootstrap.fs" ; __file_end = .; } >RAM + .text : { __tests_start = .; "src/tests.fs" ; __tests_end = .; } >RAM .rodata : { *(.rodata) } >RAM . = ALIGN(4); __here_start = .; diff --git a/src/tests.fs b/src/tests.fs @@ -0,0 +1,291 @@ +\ this test suite is adapted from the forth standard test suite. not all tests +\ are included. + +\ f.3.1 - basic assumptions +t{ -> }t \ this test should pass +t{ -> 1 }t \ this test should fail + +t{ ( a comment)1234 -> 1234 }t +t{ : pc1 ( a comment)1234 ; pc1 -> 1234 }t + +\ f.3.2 - booleans +t{ false not -> true }t +t{ true not -> false }t + +t{ false false and -> false }t +t{ false true and -> false }t +t{ true false and -> false }t +t{ true true and -> true }t + +t{ false false or -> false }t +t{ false true or -> true }t +t{ true false or -> true }t +t{ true true or -> true }t + +t{ false false xor -> false }t +t{ false true xor -> true }t +t{ true false xor -> true }t +t{ true true xor -> false }t + +\ f.3.3 - shifts +hex +t{ 1 0 lshift -> 1 }t +t{ 1 1 lshift -> 2 }t +t{ 1 2 lshift -> 4 }t +t{ 1 F lshift -> 8000 }t +t{ true 1 lshift 1 xor -> true }t + +t{ 1 0 rshift -> 1 }t +t{ 1 1 rshift -> 0 }t +t{ 2 1 rshift -> 1 }t +t{ 4 2 rshift -> 1 }t +t{ 8000 F rshift -> 1 }t + +\ f.3.5 - comparisons +0 not constant max-uint +0 not 1 rshift constant max-int +0 not 1 rshift not constant min-int + +t{ 0 0= -> true }t +t{ 1 0= -> false }t +t{ 2 0= -> false }t +t{ -1 0= -> false }t +t{ max-uint 0= -> false }t +t{ min-int 0= -> false }t +t{ max-int 0= -> false }t + +t{ 0 0 = -> true }t +t{ 1 1 = -> true }t +t{ -1 -1 = -> true }t +t{ 1 0 = -> false }t +t{ -1 0 = -> false }t +t{ 0 1 = -> false }t +t{ 0 -1 = -> false }t +t{ 1 -1 = -> false }t +t{ -1 1 = -> false }t + +t{ 0 1 < -> true }t +t{ 1 2 < -> true }t +t{ -1 0 < -> true }t +t{ -1 1 < -> true }t +t{ 1 0 < -> false }t +t{ 2 1 < -> false }t +t{ 0 -1 < -> false }t +t{ 1 -1 < -> false }t +t{ 0 0 < -> false }t +t{ 1 1 < -> false }t +t{ min-int 0 < -> true }t +t{ min-int max-int < -> true }t +t{ 0 max-int < -> true }t +t{ 0 min-int < -> false }t +t{ max-int min-int < -> false }t +t{ max-int 0 < -> false }t + +t{ 0 1 > -> false }t +t{ 1 2 > -> false }t +t{ -1 0 > -> false }t +t{ -1 1 > -> false }t +t{ 1 0 > -> true }t +t{ 2 1 > -> true }t +t{ 0 -1 > -> true }t +t{ 1 -1 > -> true }t +t{ 0 0 > -> false }t +t{ 1 1 > -> false }t +t{ min-int 0 > -> false }t +t{ min-int max-int > -> false }t +t{ 0 max-int > -> false }t +t{ 0 min-int > -> true }t +t{ max-int min-int > -> true }t +t{ max-int 0 > -> true }t + +t{ 0 1 min -> 0 }t +t{ 1 2 min -> 1 }t +t{ -1 0 min -> -1 }t +t{ -1 1 min -> -1 }t +t{ 1 0 min -> 0 }t +t{ 2 1 min -> 1 }t +t{ 0 -1 min -> -1 }t +t{ 1 -1 min -> -1 }t +t{ 0 0 min -> 0 }t +t{ 1 1 min -> 1 }t +t{ min-int 0 min -> min-int }t +t{ min-int max-int min -> min-int }t +t{ 0 max-int min -> 0 }t +t{ 0 min-int min -> min-int }t +t{ max-int min-int min -> min-int }t +t{ max-int 0 min -> 0 }t + +t{ 0 1 max -> 1 }t +t{ 1 2 max -> 2 }t +t{ -1 0 max -> 0 }t +t{ -1 1 max -> 1 }t +t{ 1 0 max -> 1 }t +t{ 2 1 max -> 2 }t +t{ 0 -1 max -> 0 }t +t{ 1 -1 max -> 1 }t +t{ 0 0 max -> 0 }t +t{ 1 1 max -> 1 }t +t{ min-int 0 max -> 0 }t +t{ min-int max-int max -> max-int }t +t{ 0 max-int max -> max-int }t +t{ 0 min-int max -> 0 }t +t{ max-int min-int max -> max-int }t +t{ max-int 0 max -> max-int }t + +\ f.3.6 - stack operators +t{ 1 2 drop -> 1 }t +t{ 0 drop -> }t +t{ 1 dup -> 1 1 }t +t{ 1 2 over -> 1 2 1 }t +t{ 1 2 swap -> 2 1 }t +t{ 1 2 nip -> 2 }t +t{ 1 2 tuck -> 2 1 2 }t +t{ 1 2 3 2drop -> 1 }t +t{ 1 2 2drop -> }t +t{ 1 2 2dup -> 1 2 1 2 }t + +\ f.3.7 - return stack operators +t{ : gr1 >r r> ; -> }t +t{ : gr2 >r r@ r> drop ; -> }t +t{ 123 gr1 -> 123 }t +t{ 123 gr2 -> 123 }t +t{ true gr1 -> true }t + +\ f.3.8 - addition and subtraction (and other math operators) +t{ 0 5 + -> 5 }t +t{ 5 0 + -> 5 }t +t{ 0 -5 + -> -5 }t +t{ -5 0 + -> -5 }t +t{ 1 2 + -> 3 }t +t{ 1 -2 + -> -1 }t +t{ -1 2 + -> 1 }t +t{ -1 -2 + -> -3 }t +t{ -1 1 + -> 0 }t + +t{ 0 5 - -> -5 }t +t{ 5 0 - -> 5 }t +t{ 0 -5 - -> 5 }t +t{ -5 0 - -> -5 }t +t{ 1 2 - -> -1 }t +t{ 1 -2 - -> 3 }t +t{ -1 2 - -> -3 }t +t{ -1 -2 - -> 1 }t +t{ 1 1 - -> 0 }t + +t{ 0 abs -> 0 }t +t{ 1 abs -> 1 }t +t{ -1 abs -> 1 }t +t{ min-int abs -> mid-uint+1 }t + +t{ 0 negate -> 0 }t +t{ 1 negate -> -1 }t +t{ -1 negate -> 1 }t +t{ 2 negate -> -2 }t +t{ -2 negate -> 2 }t + +\ f.3.9 - multiplication +t{ 0 0 * -> 0 }t +t{ 0 1 * -> 0 }t +t{ 1 0 * -> 0 }t +t{ 1 2 * -> 2 }t +t{ 2 1 * -> 2 }t +t{ 3 3 * -> 9 }t +t{ -3 3 * -> -9 }t +t{ 3 -3 * -> -9 }t +t{ -3 -3 * -> 9 }t + +\ f.3.11 memory +here 1 , +here 2 , +constant 2nd +constant 1st + +t{ 1st 2nd < -> true }t +t{ 1st cell+ -> 2nd }t +t{ 1st 1 cells + -> 2nd }t +t{ 1st @ 2nd @ -> 1 2 }t +t{ 5 1st ! -> }t +t{ 1st @ 2nd @ -> 5 2 }t +t{ 6 2nd ! -> }t +t{ 1st @ 2nd @ -> 5 6 }t +t{ 1st 2@ -> 6 5 }t +t{ 2 1 1st 2! -> }t +t{ 1st 2@ -> 2 1 }t +t{ true 1st ! 1st @ -> true }t + +t{ 0 1st ! -> }t +t{ 1 1st +! -> }t +t{ 1st @ -> 1 }t +t{ -1 1st +! 1st @ -> 0 }t + +here 1 c, +here 2 c, +align +constant 2nd-c +constant 1st-c + +t{ 1st-c 2nd-c < -> true }t +t{ 1st-c char+ -> 2nd-c }t +t{ 1st-c 1 chars + -> 2nd-c }t +t{ 1st-c c@ 2nd-c c@ -> 1 2 }t +t{ 3 1st-c c! -> }t +t{ 1st-c c@ 2nd-c c@ -> 3 2 }t +t{ 4 2nd-c c! -> }t +t{ 1st-c c@ 2nd-c c@ -> 3 4 }t + +\ f.3.12 characters +t{ bl -> hex 20 }t + +t{ char x -> hex 78 }t +t{ char hello -> hex 68 }t + +t{ : gc1 [char] x ; -> }t +t{ : gc2 [char] hello ; -> }t +t{ gc1 -> hex 78 }t +t{ gc2 -> hex 68 }t + +t{ : gc3 [ gc1 ] literal ; -> }t +t{ gc3 -> hex 78 }t + +t{ : gc4 " xy" ; -> }t +t{ gc4 nip -> 2 }t +t{ gc4 drop dup c@ swap char+ c@ -> hex 78 79 }t +t{ : gc5 " a string"2drop ; -> }t +t{ gc5 -> }t + +\ f.3.14 flow control +t{ : gi1 if 123 then ; -> }t +t{ : gi2 if 123 else 234 then ; -> }t +t{ 0 gi1 -> }t +t{ 1 gi1 -> 123 }t +t{ -1 gi1 -> 123 }t +t{ 0 gi2 -> 234 }t +t{ 1 gi2 -> 123 }t +t{ -1 gi2 -> 123 }t + +t{ : gi3 begin dup 5 < while dup 1 + repeat ; -> }t +t{ 0 gi3 -> 0 1 2 3 4 5 }t +t{ 4 gi3 -> 4 5 }t +t{ 5 gi3 -> 5 }t +t{ 6 gi3 -> 6 }t + +\ f.3.16 defining words +t{ : nop : postpone ; ; -> }t +t{ nop nop1 nop nop2 -> }t +t{ nop1 -> }t +t{ nop2 -> }t + +t{ : gdx 123 ; -> }t +t{ : gdx gdx 234 ; -> }t +t{ gdx -> 123 234 }t + +t{ 123 constant x123 -> }t +t{ x123 -> 123 }t +t{ : equ constant ; -> }t +t{ x123 equ y123 -> }t +t{ y123 -> 123 }t + +t{ variable v1 -> }t +t{ 123 v1 ! -> }t +t{ v1 @ -> 123 }t +