--- /dev/null
+;;; 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:
+ }
-; 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:
+