1 ; This is a forth interpreter for x86_64 (elf64)
2 format elf64 executable
7 ;;; ============================================================
9 segment readable writable executable
11 ;;; ========================================
12 ;;; These are the core "execution semantics" words, which are placed
13 ;;; first so as to remain at the same binary address at successive
14 ;;; compilations, which is helful for declaring special debugging gdb
17 ;;; The DO* words are declared as "variables" to provide their
18 ;;; assembled address when used in FORTH.
20 ;;; The register context at entry to an "execution semantcs" code
22 ;;; rax = cfa* of word to execute
23 ;;; rsi = cell* in the calling definition, after calling cell
24 ;;; rsp = data stack pointer
25 ;;; rbp = return stack pointer
28 previous_word = 0 ; Used for chaining the words
30 WORD p_dofasm,'doFASM',dovariable
31 ;; Execution semantics for assembly words.
36 WORD p_doforth,'doFORTH',dovariable ;
37 ;; Execution semantics for FORTH defition word.
40 lea rsi, [rax+8] ; rsi = the DFA of the rax word
43 WORD p_dodoes,'doDOES',dovariable
44 ;; Execution semantics for DOES>
45 ;; [cfa-8] holds the adjustment offset ("does offset")
48 lea rsi, [rax+8] ; rsi = the DFA of the rax word
49 add rsi,qword [rax-8] ; adjust rsi by the "does offset'
52 WORD p_dovariable,'doVARIABLE',dovariable
53 ;; Execution semantics for a variable ( -- addr )
54 ;; rax points to CFA field
56 lea rax, [rax+8] ; rsi = the DFA of the rax word
60 WORD p_dovalue,'doVALUE',dovariable
61 ;; Execution semantics for a value constant ( -- v )
62 ;; rax points to CFA field
64 lea rax, [rax+8] ; rsi = the DFA of the rax word
68 WORD p_dostring,'doSTRING',dovariable
69 ;; Execution semantics for a string constant ( -- addr n )
70 ;; rax points to CFA field
72 lea rax, [rax+8] ; rsi = the DFA of the rax word
76 WORD p_calltrace,'calltrace',dovalue
77 ;; Common call point for debugging
78 ;; rax = cfa of called word
79 ;; rsi = cell* of next forth word
80 ;; [$rsp] = from where the call was
83 include 'syscalls.asm'
85 ;;; ========================================
86 ;;; The stacks are placed here.
88 ;segment readable writable
90 WORD return_stack,'RETURN-STACK',dovariable
93 rb 1048576 ; 1 Mb return stack
94 RS_TOP: ; The initial rbp
97 WORD data_stack,'DATA-STACK',dovariable
100 rb 1048576 ; 1 Mb data stack
101 DS_TOP: ; The initial rsp
104 ;;; ========================================
105 ;;; Core execution control words
107 ;segment readable executable
109 ;;; At fasm compilation: reset previous_word to make a new word list
110 ;;; Words above belong to the SYSTEM wordlist, and the following
111 ;;; belong to the FORTH wordlist.
114 WORD p_system,'SYSTEM',dovariable
116 ;; The SYSTEM word list
117 dq last_system_word ; tfa of last SYSTEM word
118 dq p_forth_DFA ; dfa of successor word list
120 WORD inline_code,'[ASM]',fasm
122 ;; This transitions execution into inline assembler in the
123 ;; calling word defintion. Note that it stops advancing rsi;
124 ;; code should use FORTH macro to reenter forth execution, or
125 ;; exit to the calling definition via "jmp exit".
128 WORD p_execute,'EXECUTE',fasm
133 jmp qword [rax] ; goto code of that FORTH word (64 bit jump)
135 WORD p_exit, 'EXIT',fasm
136 ;; ( -- ) ( R: addr -- )
137 ;; Returns execution to the calling definition as per the
143 ;; TERMINATE0 terminates the program with code 0
145 WORD p_terminate, 'TERMINATE0',fasm
151 WORD p_branch,'BRANCH',fasm
153 ;; Using subsequent inline cell as branch offset, branch
159 WORD p_zero_branch,'0BRANCH',fasm
161 ;; Using subsequent inline cell as branch offset, branch
162 ;; accordingly if the stacked value is zero, otherwise just
163 ;; skip over the branch offset
166 jne p_zero_branch_SKIP
172 ;;; ========================================
173 ;;; Core extension(s)
175 ;segment readable writable executable
177 include 'wordlists.asm'
183 include 'compile.asm'
185 WORD p_program_version,'PROGRAM_VERSION',dostring
186 STRING 'RRQ Forth version 0.1 - 2021-05-22',10
188 WORD p_stdin,'STDIN',dovalue
189 ;; Initialised to hold a STREAM for fd 0
192 WORD p_args,'ARGS',dostring
193 ;; Pointer to initial argument block
194 dq 0 ; *(int argc,(char*[argc]) argv)
196 WORD p_lparen,'(',fasm,IMMEDIATE
199 DOFORTH p_stdin, p_read_word
202 cmp rax,0 ; end of stream
217 ;;; ******** The main entry point. ********
219 ;; Initial rsp points to the arguments block of size (64 bits)
220 ;; followed by the argument pointers.
221 mov qword [p_args_DFA],rsp
222 jmp p_quit_DFA ; QUIT
224 ;;; This word is also the last word before syscalls
226 WORD p_quit,'QUIT',fasm
227 ;; QUIT is the program entry point ********************
231 cmp qword [p_stdin_DFA],0
232 jne p_quit_INITIALIZED
237 pop qword [p_stdin_DFA] ; Assign STDIN
246 BRANCH 0,p_quit_ERROR
251 STRING 10,'*** Unknown word: '
260 mov rbp,RS_TOP ; reset the return stack
263 ;;; ========================================
265 ;segment readable writable
268 rb 1048576 ; +1 Mb heap
269 rb 1048576 ; +1 Mb heap
270 rb 1048576 ; +1 Mb heap
271 rb 1048576 ; +1 Mb heap
272 rb 1048576 ; +1 Mb heap