forth

A WIP implementation of Forth targeting UEFI x86-64.
git clone git://git.christianermann.dev/forth
Log | Files | Refs

commit 937eeaf9644e79c69f4d975c0f2025070f137fba
parent 7b25cf69ab44609948328847545e02f941436bda
Author: Christian Ermann <christianermann@gmail.com>
Date:   Sat, 15 Jun 2024 19:21:12 -0400

Add base.forth and load into dictionary at startup

Diffstat:
MDockerfile | 1+
Abase.forth | 42++++++++++++++++++++++++++++++++++++++++++
Mforth.asm | 91++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
3 files changed, 129 insertions(+), 5 deletions(-)

diff --git a/Dockerfile b/Dockerfile @@ -9,6 +9,7 @@ RUN apt-get update && apt-get -y upgrade && \ COPY forth.asm / COPY efi.asm / +COPY base.forth / COPY run.sh / RUN fasm forth.asm BOOTX64.EFI diff --git a/base.forth b/base.forth @@ -0,0 +1,42 @@ + +: [COMPILE] IMMEDIATE + WORD FIND + >CFA , +; + +: CODE + WORD CREATE + LATEST @ >CFA 8 + , + LATEST @ HIDDEN + ] +; + +: NEXT IMMEDIATE + 48 C, + AD C, + FF C, + 20 C, +; + +: ;CODE IMMEDIATE + [COMPILE] NEXT + ALIGN + LATEST @ HIDDEN + [COMPILE] [ +; + +: RAX IMMEDIATE 0 ; +: RCX IMMEDIATE 1 ; +: RDX IMMEDIATE 3 ; +: RBX IMMEDIATE 4 ; +: R8 IMMEDIATE 41 C, 0 ; +: R9 IMMEDIATE 41 C, 1 ; + +: PUSH IMMEDIATE 50 + C, ; +: POP IMMEDIATE 58 + C, ; + +: CALL-INDIRECT IMMEDIATE + FF C, + 10 + C, +; + diff --git a/forth.asm b/forth.asm @@ -268,6 +268,8 @@ main: initialize_stack mov rbp, return_stack_top mov rsi, program + mov [input_buffer], forth_base + mov [input_buffer.len], forth_base.len NEXT } @@ -343,10 +345,32 @@ set_program initialize_stack_s3, program_s3 defcode "KEY", 3, 0, KEY ; Read a character. ; - call sys_read_char + call _KEY push rax NEXT +_KEY: + cmp [input_buffer], 0 + jne .buffer + +.stdin: + call sys_read_char + ret + +.buffer: + cmp [input_buffer.len], 0 + je .buffer_empty + mov rax, [input_buffer] + movzx rax, byte [rax] + inc [input_buffer] + dec [input_buffer.len] + ret + +.buffer_empty: + mov [input_buffer], 0 + jmp .stdin + + defcode "WORD", 4, 0, WORD_ ; Read a word. ; @@ -378,7 +402,8 @@ _WORD: ; After a non-whitespace character is found, RDI is used to hold the address ; of the next character to be stored. ; - call sys_read_char + + call _KEY cmp al, ' ' je .skip_whitespace cmp al, 0xA @@ -404,7 +429,7 @@ _WORD: .next_char: ; Keep processing characters until we find the end of the word. ; - call sys_read_char + call _KEY cmp al, ' ' je .end cmp al, 0xA @@ -894,7 +919,10 @@ defcode "HERE", 4, 0, HERE defcode "CREATE", 6, 0, CREATE pop rcx ; string length pop rbx ; string address + call _CREATE + NEXT +_CREATE: mov rdi, [here] ; address of new header mov rax, [latest] ; address of last entry stosq ; add link to last entry @@ -922,7 +950,7 @@ defcode "CREATE", 6, 0, CREATE mov rax, [here] mov [latest], rax mov [here], rdi - NEXT + ret defcode ",", 1, 0, COMMA pop rax @@ -935,6 +963,13 @@ _COMMA: mov [here], rdi ret +defcode "C,", 2, 0, CHAR_COMMA + pop rax + mov rdi, [here] + stosb + mov [here], rdi + NEXT + defcode "LIT", 3, 0, LIT lodsq push rax @@ -959,6 +994,12 @@ defcode "HIDDEN", 6, 0, HIDDEN xor [rdi], rcx NEXT +defcode "IMMEDIATE", 9, FLAG_IMMEDIATE, IMMEDIATE + mov rdi, [latest] + add rdi, 8 + xor byte [rdi], FLAG_IMMEDIATE + NEXT + defcode "+", 1, 0, PLUS pop rbx pop rcx @@ -982,6 +1023,40 @@ defword ";", 1, FLAG_IMMEDIATE, SEMICOLON dq LEFT_BRACKET ; Switch to IMMEDIATE mode dq EXIT +defcode "ALIGN", 5, 0, ALIGN_ + mov rax, [here] + add rax, 7 + and rax, 0xFFFFFFFFFFFFFFF8 + mov [here], rax + NEXT + +defcode "DUP", 3, 0, DUP_ + pop rcx + push rcx + push rcx + NEXT + +defcode "DROP", 4, 0, DROP + pop rcx + NEXT + +defword "CONSTANT", 8, 0, CONSTANT + dq WORD_ + dq CREATE + dq LIT, DOCOL + dq COMMA + dq LIT, LIT + dq COMMA + dq COMMA + dq LIT, EXIT + dq COMMA + dq EXIT + +defword "FIELD", 5, 0, FIELD + dq DUP_ + dq CONSTANT + dq EXIT + ;------------------------------------------------------------------------------ ; ; Section 8 - String operations @@ -1072,7 +1147,6 @@ defcode "WORDS", 5, 0, WORDS NEXT - section '.data' data readable writable version_string db 'soup forth v0.1', 0xA @@ -1081,6 +1155,9 @@ version_string db 'soup forth v0.1', 0xA unrecognized_msg db 'unrecognized word', 0xA .length = $ - unrecognized_msg +input_buffer dq 0 +input_buffer.len dq 0 + code_EMIT.char_buffer db ? code_DOT.buffer rb 64 @@ -1108,6 +1185,10 @@ state dq 0 FLAG_IMMEDIATE = 0x40 FLAG_HIDDEN = 0x20 +forth_base: +file './base.forth' +forth_base.len = $ - forth_base + align 4096 return_stack rb 8192 return_stack_top: