da94d056d7ca7da435815ab01f465ab39b64e380
[rrq/rrqforth.git] / rrqforth.asm
1 ; This is a forth interpreter for x86_64 (elf64)
2         format elf64 executable
3         entry main
4
5 include 'machine.asm'
6
7 ;;; ============================================================
8
9         segment readable writable executable
10         
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
15 ;;; aliases.
16 ;;; 
17 ;;; The DO* words are declared as "variables" to provide their
18 ;;; assembled address when used in FORTH.
19 ;;;
20 ;;; The register context at entry to an "execution semantcs" code
21 ;;; snippets is:
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
26 ;;; 
27
28 previous_word = 0       ; Used for chaining the words
29
30         WORD p_dofasm,'doFASM',dovariable
31         ;; Execution semantics for assembly words.
32 dofasm:
33         add rax,8
34         jmp rax
35
36         WORD p_doforth,'doFORTH',dovariable ;
37         ;; Execution semantics for FORTH defition word.
38 doforth:
39         pushr rsi
40         lea rsi, [rax+8]        ; rsi = the DFA of the rax word
41         next
42
43         WORD p_dodoes,'doDOES',dovariable
44         ;; Execution semantics for DOES>
45         ;; [cfa-8] holds the adjustment offset ("does offset")
46 dodoes:
47         pushr rsi
48         lea rsi, [rax+8]        ; rsi = the DFA of the rax word
49         add rsi,qword [rax-8]   ; adjust rsi by the "does offset'
50         next
51
52         WORD p_dovariable,'doVARIABLE',dovariable
53         ;; Execution semantics for a variable ( -- addr )
54         ;; rax points to CFA field
55 dovariable:
56         lea rax, [rax+8]        ; rsi = the DFA of the rax word
57         push rax
58         next
59
60         WORD p_dovalue,'doVALUE',dovariable
61         ;; Execution semantics for a value constant ( -- v )
62         ;; rax points to CFA field
63 dovalue:
64         lea rax, [rax+8]        ; rsi = the DFA of the rax word
65         push qword [rax]
66         next
67
68         WORD p_dostring,'doSTRING',dovariable
69         ;; Execution semantics for a string constant ( -- addr n )
70         ;; rax points to CFA field
71 dostring:
72         lea rax, [rax+8]        ; rsi = the DFA of the rax word
73         pushpname rax
74         next
75
76 include 'syscalls.asm'
77
78 ;;; ========================================
79 ;;; The stacks are placed here.
80         
81         ;segment readable writable
82
83         WORD return_stack,'RETURN-STACK',dovariable
84         ;; The return stack
85         BLOCK RS_TOP
86         rb 1048576              ; 1 Mb return stack
87 RS_TOP:                         ; The initial rbp
88         
89 last_system_word:
90         WORD data_stack,'DATA-STACK',dovariable
91         ;; The data stack
92         BLOCK DS_TOP
93         rb 1048576              ; 1 Mb data stack
94 DS_TOP:                         ; The initial rsp
95
96
97 ;;; ========================================
98 ;;; Core execution control words
99
100         ;segment readable executable
101
102 ;;; At fasm compilation: reset previous_word to make a new word list
103 ;;; Words above belong to the SYSTEM wordlist, and the following
104 ;;; belong to the FORTH wordlist.
105 previous_word = 0
106
107         WORD p_system,'SYSTEM',dovariable
108         ;; ( -- dfa )
109         ;; The SYSTEM word list
110         dq last_system_word     ; tfa of last SYSTEM word
111         dq p_forth_DFA          ; dfa of successor word list
112
113         WORD inline_code,'[ASM]',fasm
114         ;; ( -- )
115         ;; This transitions execution into inline assembler in the
116         ;; calling word defintion. Note that it stops advancing rsi;
117         ;; code should use FORTH macro to reenter forth execution, or
118         ;; exit to the calling definition via "jmp exit".
119         jmp qword rsi
120
121         WORD p_execute,'EXECUTE',fasm
122         ;; ( tfa -- )
123         ;; Execute the word
124         pop rax
125         tfa2cfa rax
126         jmp qword [rax]         ; goto code of that FORTH word (64 bit jump)
127         
128         WORD p_exit, 'EXIT',fasm
129         ;; ( -- ) ( R: addr -- )
130         ;; Returns execution to the calling definition as per the
131         ;; return stack.
132 exit:
133         popr rsi
134         next
135
136         ;; TERMINATE0 terminates the program with code 0
137         ;; ( -- )
138         WORD p_terminate, 'TERMINATE0',fasm
139         pop rdx
140 terminate_special:
141         mov eax,60
142         syscall
143
144         WORD p_branch,'BRANCH',fasm
145         ;; ( -- )
146         ;; Using subsequent inline cell as branch offset, branch
147         ;; accordingly
148         add rsi,qword [rsi]     
149         add rsi,8
150         next
151         
152         WORD p_zero_branch,'0BRANCH',fasm
153         ;; ( v -- )
154         ;; Using subsequent inline cell as branch offset, branch
155         ;; accordingly if the stacked value is zero, otherwise just
156         ;; skip over the branch offset
157         pop rax
158         cmp rax,0
159         jne p_zero_branch_SKIP
160         add rsi,qword [rsi]
161 p_zero_branch_SKIP:
162         add rsi,8
163         next
164
165 ;;; ========================================
166 ;;; Core extension(s)
167
168         ;segment readable writable executable
169         
170 include 'wordlists.asm'
171 include 'memory.asm'
172 include 'stack.asm'
173 include 'math.asm'
174 include 'logic.asm'
175 include 'stdio.asm'
176 include 'compile.asm'
177
178         WORD p_program_version,'PROGRAM_VERSION',dostring
179         STRING 'RRQ Forth version 0.1 - 2021-05-13',10
180
181         WORD p_stdin,'STDIN',dovalue
182         ;; Initialised to hold a STREAM for fd 0
183         dq 0
184
185 ;;; The main entry point.
186 ;;; This word is also the last word before syscalls
187 last_forth_word:
188         WORD p_quit,'QUIT',fasm
189         ;; QUIT is the program entry point ********************
190 main:
191         mov rsp,DS_TOP
192         mov rbp,RS_TOP
193         cmp qword [p_stdin_DFA],0
194         jne p_quit_INITIALIZED
195         ;; Initialize STDIN
196         push 0
197         push 10000
198         DOFORTH p_stream
199         pop qword [p_stdin_DFA] ; Assign STDIN
200
201 p_quit_INITIALIZED:
202         ;; Initial blurb
203         FORTH
204         dq p_program_version
205         dq p_tell
206         dq p_stdin
207         dq p_clear_stream
208         dq p_stdin
209         dq p_evaluate_stream
210         BRANCH 0,p_quit_ERROR
211         dq p_false
212         dq sys_exit
213 p_quit_ERROR:
214         dq p_literal_string
215         STRING 10,'*** Unknown word: '
216         dq p_tell
217         dq p_this_word
218         dq p_2get
219         dq p_tell
220         dq p_literal_string
221         STRING 10
222         dq p_tell
223         ENDFORTH
224         mov rbp,RS_TOP          ; reset the return stack
225         jmp main
226
227 ;;; ========================================
228
229         ;segment readable writable
230         
231 heap_start:
232         rb 1048576              ; +1 Mb heap
233         rb 1048576              ; +1 Mb heap
234         rb 1048576              ; +1 Mb heap
235         rb 1048576              ; +1 Mb heap
236         rb 1048576              ; +1 Mb heap