added
[rrq/rrqforth.git] / main.fasm
index 25e48b4f69a9aa1daf2561f2a24230d3f848a771..f06c158bd5a9879f64f804185a7292861a307d38 100644 (file)
--- a/main.fasm
+++ b/main.fasm
-; This is a forth interpreter
+; This is a forth interpreter for x86_64 (elf64)
        format elf64 executable
-       entry main_code
+       entry main
+
+;;; ========================================
+;;; 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 [rbp], x
+}
+
+macro popr x {
+       mov x, [rbp]
+       add rbp, 8
+}
+
+;;; ========================================
+;;; The next macro "moves" execution to the next FORTH instruction,
+;;; using rsi as instruction pointer. It points to the doer field of a
+;;; word, which points to the assembly code that implements the
+;;; execution effect of the word. That doer code is entered with rsi
+;;; referring to the subsequent address in the colling word, and rax
+;;; referring to the doer field of the called word.
+
+macro next {
+       lodsq                   ; mov rax, [rsi] + add rsi,8
+       jmp qword [rax]         ; goto code of that FORTH word (64 bit jump)
+}
+
+;;; ========================================
+;;; The FORTH macro transitions to inline FORTH execution.
+macro FORTH {
+       local forthcode
+       mov rsi,forthcode
+       next
+       ;; align 8
+forthcode:
+}
+
+;;; ========================================
+;;; The ENDFORTH macro transitions back to inline assembler after FORTH
+;;; ========================================
+macro ENDFORTH {
+       dq inline_code
+}
+
+;;; ========================================
+;;; The DOFORTH lays out a single FORTH call
+;;; ========================================
+macro DOFORTH label {
+       FORTH
+       dq label
+       ENDFORTH
+}
+
+;;; Macro WORD starts a FORTH word definition in this code
+;;; 
+       previous_word = 0       ; Used for chaining the words
+
+       IMMEDIATE = 1           ; optional flag
+
+macro WORD label, name, doer, flags {
+       ;; align 8
+label#_TFA:
+       ;; TFA
+       dq previous_word
+       previous_word = label#_TFA
+       ;; PFA
+label#_PFA:
+       db flags + 0
+       db label - $ - 2
+       db name
+       db 0
+       ;; align 8
+
+label#_OFF:
+       dq 0                    ; The DOES offset. Defaults to 0.
+       ;; also CFA = pointer to "doer"
+label:
+       if doer eq
+           dq doforth
+       else
+           if doer in <fasm>
+               dq label#_DFA
+           else
+               dq doer
+           end if
+       end if
+       ;; DFA
+label#_DFA:
+}
+
+;;; ============================================================
+;;; FORTH machine model
+;;; rsp = data stack pointer
+;;; rbp = return stack pointer
+;;; rsi = instruction pointer
+
+;;; ============================================================
 
-;;; ############################################################
-;;; The FORTH words
        segment readable writable executable
 
-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
+       WORD return_stack,'RS',dovariable
+       ;; The return stack
+       rb 1048576              ; 1 Mb return stack
+RS_TOP:                                ; The initial rbp
        
-       ;; 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
+       WORD data_stack,'DS',dovariable
+       ;; The data stack
+       rb 1048576              ; 1 Mb data stack
+DS_TOP:                                ; The initial rsp
 
-       ;; TERMINATE0 terminates the program with code 0
+       WORD inline_code,'[ASM]',fasm
        ;; ( -- )
-       WORD_assembler terminate0, 'TERMINATE0'
-       xor edi,edi
-       mov eax,60
-       syscall
+       ;; This transitions execution into inline assembler in the
+       ;; calling word defintion. Note that it stops advancing rsi;
+       ;; code should use FORTH macro to reenter forth execution, or
+       ;; exit to the calling definition via "jmp exit".
+       jmp qword rsi
 
-       ;; EXIT ends a forth code defintion, returning to caller
-       ;; ( -- )
-       WORD_assembler exit, 'EXIT'
+;;; Execution semantics for FORTH defition word
+;;; At entry, rsi points into the calling definition, at the cell
+;;; following the cell indicating this word, rax points to the CFA of
+;;; this word.
+doforth:
+       pushr rsi
+       lea rsi, [rax+8]        ; rsi = the DFA of the rax word
+       next
+
+       WORD p_exit, 'EXIT',fasm
+       ;; ( -- ) ( R: addr -- )
+       ;; Returns execution to the calling definition as per the
+       ;; return stack.
+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]
+
+       ;; Execution semantics for a variable ( -- addr )
+       ;; rax points to doer field
+dovariable:
+       push rax+16
+       next
+
+       ;; Execution semantics for a constant ( -- v )
+       ;; rax points to doer field
+dovalue:
+       push qword [rax+16]
        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
+       ;; Execution semantics for a string constant ( -- addr n )
+       ;; rax points to doer field
+dostring:
+       add rax,16
+       mov bl,[rax]
+       mov byte [rsp],bl
+       push rax+1
        next
 
-       ;; HERE is a variable pointing to the free heap
-       WORD here, 'HERE', marker
-       dq heap_start           ; initialise to first "free" data
+include 'wordlists.fasm'
+include 'syscalls.fasm'
+include 'memory.fasm'
+include 'stack.fasm'
+include 'math.fasm'
+include 'stdio.fasm'
 
-       ;; WORDS is the list of words
-       WORD words, 'WORDS', marker
-       dq forth_tfa            ; initialise to last forth word
+       WORD p_program_version,'PROGRAM_VERSION',dostring
+       db length
+program_version_string:        
+       db 'RRQ Forth version 0.1 - 2021-05-13',10
+       length = $ - program_version_string
 
-       ;; FORTH is the last word of the VOCABULARY 
-       WORD forth, 'FORTH', marker_get
-       dq forth_tfa
+       WORD p_stdin,'STDIN',dovalue
+       ;; Initialised to hold a STREAM for fd 0
+       dq 0
        
-heap_start:
+       WORD p_quit,'QUIT',fasm
+       ;; QUIT is the program entry point ********************
+main:
+       mov rsp,DS_TOP
+       mov rbp,RS_TOP
+       ;; Initialize STREAM STDIN
+       push 0
+       push 10000
+       DOFORTH p_stream
+       pop qword [p_stdin_DFA]
+
+       ;; read a word
+       push qword 1            ; ( fd ) =stdout
+       push qword [p_stdin_DFA]
+       FORTH
+       dq p_read_word          ; ( fd s n )
+       dq sys_write
+       ENDFORTH
+
+       push qword 1                    ; stdout
+       push qword program_version_string ; address of string
+       push qword length               ; length of string (cheating)
+       DOFORTH sys_write               ; printout
+       pop rax                         ; ignore errors
+       
+       push 0
+       DOFORTH sys_exit
 
+       ;; TERMINATE0 terminates the program with code 0
+       ;; ( v -- )
+       WORD terminate, 'TERMINATE',fasm
+       pop rdx
+terminate_special:
+       mov eax,60
+       syscall
+
+last_word:
+       ;; FORTH is the last word of VOCABULARY FORTH
+       WORD forth,'FORTH',dovalue
+       dq forth_TFA
+       dq 0
+
+       
+heap_start: