baseline
authorRalph Ronnquist <ralph.ronnquist@gmail.com>
Thu, 13 May 2021 02:25:13 +0000 (12:25 +1000)
committerRalph Ronnquist <ralph.ronnquist@gmail.com>
Thu, 13 May 2021 02:25:13 +0000 (12:25 +1000)
Makefile
machine.fasm [new file with mode: 0644]
main.fasm

index 39e68f2b2adf940a953fa6520b32b14fc9ad48c7..1e629b944805f77bbfc05ffac20ea21f2b3e7819 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,9 +2,13 @@ BINARY = rrqforth
 
 default: rrqforth
 
+VFMT := "RRQ Forth version %h at %aI"
+VERSION := $(shell git log -1 --pretty=format:'$(VFMT)' main.fasm)
+
+main.fasm: machine.fasm stdio.fasm
+
 version: main.fasm
-       git log --pretty=format:"msg db 'RRQ Forth version %h at %aI'" $< > $@
-       echo "\ndb 10" >> $@
+       @echo "db '$(VERSION)'\ndb 10" > $@
 
 rrqforth: main.fasm | version
        fasm $^ $@
diff --git a/machine.fasm b/machine.fasm
new file mode 100644 (file)
index 0000000..92f51a1
--- /dev/null
@@ -0,0 +1,101 @@
+;;; This file define/describes the "machine"
+;;;
+;;; Abstract Machine:
+;;; https://en.wikibooks.org/wiki/X86_Assembly/X86_Architecture
+;;; 
+;;; General Purpose Registers ( * marks those used in syscalls )
+;;;  *rax = ( -, eax = ( -, ax = ( ah, al) )) "accumulator"
+;;;   rbx = ( -, ebx = ( -, bx = ( bh, bl) )) "base"
+;;;  *rcx = ( -, ecx = ( -, cx = ( ch, cl) )) "counter"
+;;;  *rdx = ( -, edx = ( -, dx = ( dh, dl) )) "data"
+;;;   rsp = ( -, esp = ( -, sp = ( -, spl) )) "stack pointer"
+;;;   rbp = ( -, ebp = ( -, bp = ( -, bpl) )) "stack base pointer"
+;;;  *rsi = ( -, esi = ( -, si = ( -, sil) )) "source"
+;;;  *rdi = ( -, edi = ( -, di = ( -, dil) )) "destination"
+;;;  *r8
+;;;  *r9
+;;;   r10
+;;;  *r11
+;;;   r12
+;;;   r13
+;;;   r14
+;;;   r15
+;;; clobbers rdi rsi rdx rcx r8 r9 r11
+;;; rax = syscall id
+;;;
+;;; Segment Registers
+;;;   SS "Stack Segment"
+;;;   CS "Code Segment"
+;;;   DS "Data Segment"
+;;;   ES "Extra Segment"
+;;;   FS "more Extra Segment"
+;;;   GS "more more Extra Segment"
+;;;
+;;; EFLAGS Register
+;;;   0,0,0,0,0,0,0,0,0,0,ID,VIP,VIF,AC,VM,RF,
+;;;   0,NT,[IOPL,IOPL],OF,DF,IF,TF,SF,ZF,0,AF,0,PF,1,CF
+;;; 
+;;; Instruction pointer
+;;;   EIP
+;;; 
+;;; Syscall allocations
+;;; clobbers rdi rsi rdx rcx r8 r9 r11
+;;; rax = syscall id
+;;;
+;;; function calling
+
+;;; FORTH model
+;;; rsp = data stack pointer
+;;; rbp = frame pointer
+;;; rdi = frame stack
+;;; rsi = instruction pointer
+
+;;; ========================================
+;;; The next macro "moves" execution to the next FORTH instruction,
+;;; using rsi as instruction pointer.
+
+       macro next {
+       lodsq                   ; mov rax, qword [rsi]
+                               ; add rsi,8
+       jmp qword [rax]         ; goto code of that FORTH word
+       }
+
+;;; ========================================
+;;; The pushr macro pushes x onto the return stack
+;;; The popr macro pops x from the return stack
+       macro pushr x {
+       sub rbp, 8
+       mov qword [rbp], x
+       }
+
+       macro popr x {
+       mov x, [rbp]
+       add rbp, 8
+       }
+
+;;; ========================================
+;;; 
+
+       previous_word = 0
+
+       ;; Macro WORD starts a FORTH word definition in this code
+       macro WORD label, name, doer, flags {
+label#_tfa:
+       ;; TFA
+       dq previous_word
+       ;; PFA
+label#_word:
+       previous_word = label#_word
+       db flags + 0
+       db label - $ - 1
+       db name
+       ;; CFA = pointer to "interpreter"
+label:
+       dq doer
+       }
+
+       ;; Macro WORD_assembler begins an assembler implementation
+       macro WORD_assembler label, name, flags {
+       WORD label, name, label#_code, flags
+label#_code:
+       }
index dd4f30de6e0fdcc9b9625768d9b0ab67a419c237..25e48b4f69a9aa1daf2561f2a24230d3f848a771 100644 (file)
--- a/main.fasm
+++ b/main.fasm
@@ -1,20 +1,79 @@
-; This is a program
+; This is a forth interpreter
        format elf64 executable
-       entry main
+       entry main_code
 
-       segment readable executable
-       include 'version'
-       length = $ - msg
+;;; ############################################################
+;;; The FORTH words
+       segment readable writable executable
 
-main:
-       lea rsi,[msg]           ; address of message
-       mov edx,length          ; length od trdting
+include 'machine.fasm'
+       
+       ;; PROGRAM_VERSION is the program version string
+       WORD program_version, 'PROGRAM_VERSION', marker
+       db length
+program_version_string:        
+       include 'version'
+       length = $ - program_version_string
+       
+       ;; MAIN is the program entry point
+       ;; ( -- )
+       WORD_assembler main, "MAIN"
+       mov rsi,program_version_string ; address of string
+       mov edx,length          ; length of string (cheating)
        mov edi,1               ; stdout
        mov eax,1               ; sys_write
        syscall
+       jmp terminate0_code
 
-fini:
+       ;; TERMINATE0 terminates the program with code 0
+       ;; ( -- )
+       WORD_assembler terminate0, 'TERMINATE0'
        xor edi,edi
        mov eax,60
        syscall
+
+       ;; EXIT ends a forth code defintion, returning to caller
+       ;; ( -- )
+       WORD_assembler exit, 'EXIT'
+       popr rsi
+       next
        
+       ;; MARKER is a word that pushes the address after itself, then exits
+       ;; ( -- p )
+       WORD_assembler marker, 'MARKER'
+       push qword rsi
+       jmp exit_code
+
+       ;; MARKER@ is a word that pushes a the value after itself, then exits
+       ;; ( -- v )
+       WORD_assembler marker_get, 'MARKER@'
+       push qword [rsi]
+       jmp exit_code
+
+       ;; DOFORTH begins a FORTH defintion
+       WORD_assembler doforth, 'DOFORTH'
+       pushr rsi
+       lea rsi, [rax + 8]
+       next
+
+       ;; LIT is a word that pushes a the value after itself, then continues
+       ;; ( -- v )
+       WORD_assembler lit, 'LIT'
+       push qword [rsi]
+       add rsi, 8
+       next
+
+       ;; HERE is a variable pointing to the free heap
+       WORD here, 'HERE', marker
+       dq heap_start           ; initialise to first "free" data
+
+       ;; WORDS is the list of words
+       WORD words, 'WORDS', marker
+       dq forth_tfa            ; initialise to last forth word
+
+       ;; FORTH is the last word of the VOCABULARY 
+       WORD forth, 'FORTH', marker_get
+       dq forth_tfa
+       
+heap_start:
+