cleanup makefile
[rrq/rrqforth.git] / rrqforth.asm
1 ; This is a forth interpreter for x86_64 (elf64)
2         format elf64 executable
3         entry main
4
5 ;;; ========================================
6 ;;; The pushr macro pushes x onto the return stack
7 ;;; The popr macro pops x from the return stack
8 macro pushr x {
9         sub rbp, 8
10         mov [rbp], x
11 }
12
13 macro popr x {
14         mov x, [rbp]
15         add rbp, 8
16 }
17
18 ;;; ========================================
19 ;;; The next macro "moves" execution to the next FORTH instruction,
20 ;;; using rsi as instruction pointer. It points to the doer field of a
21 ;;; word, which points to the assembly code that implements the
22 ;;; execution effect of the word. That doer code is entered with rsi
23 ;;; referring to the subsequent address in the colling word, and rax
24 ;;; referring to the doer field of the called word.
25
26 macro next {
27         lodsq                   ; mov rax, [rsi] + add rsi,8
28         jmp qword [rax]         ; goto code of that FORTH word (64 bit jump)
29 }
30
31 ;;; ========================================
32 ;;; The FORTH macro transitions to inline FORTH execution.
33 macro FORTH {
34         local forthcode
35         mov rsi,forthcode
36         next
37         ;; align 8
38 forthcode:
39 }
40
41 ;;; ========================================
42 ;;; The ENDFORTH macro transitions back to inline assembler after FORTH
43 ;;; ========================================
44 macro ENDFORTH {
45         dq inline_code
46 }
47
48 ;;; ========================================
49 ;;; The DOFORTH lays out a single FORTH call
50 ;;; ========================================
51 macro DOFORTH label {
52         FORTH
53         dq label
54         ENDFORTH
55 }
56
57 ;;; Macro WORD starts a FORTH word definition in this code
58 ;;; 
59         previous_word = 0       ; Used for chaining the words
60
61         IMMEDIATE = 1           ; optional flag
62
63 macro WORD label, name, doer, flags {
64         ;; align 8
65 label#_TFA:
66         ;; TFA
67         dq previous_word
68         previous_word = label#_TFA
69         ;; PFA
70 label#_PFA:
71         db flags + 0
72         db label - $ - 2
73         db name
74         db 0
75         ;; align 8
76
77 label#_OFF:
78         dq 0                    ; The DOES offset. Defaults to 0.
79         ;; also CFA = pointer to "doer"
80 label:
81         if doer eq
82             dq doforth
83         else
84             if doer in <fasm>
85                 dq label#_DFA
86             else
87                 dq doer
88             end if
89         end if
90         ;; DFA
91 label#_DFA:
92 }
93
94 ;;; ============================================================
95 ;;; FORTH machine model
96 ;;; rsp = data stack pointer
97 ;;; rbp = return stack pointer
98 ;;; rsi = instruction pointer
99
100 ;;; ============================================================
101
102         segment readable writable executable
103
104         WORD return_stack,'RS',dovariable
105         ;; The return stack
106         rb 1048576              ; 1 Mb return stack
107 RS_TOP:                         ; The initial rbp
108         
109         WORD data_stack,'DS',dovariable
110         ;; The data stack
111         rb 1048576              ; 1 Mb data stack
112 DS_TOP:                         ; The initial rsp
113
114         WORD inline_code,'[ASM]',fasm
115         ;; ( -- )
116         ;; This transitions execution into inline assembler in the
117         ;; calling word defintion. Note that it stops advancing rsi;
118         ;; code should use FORTH macro to reenter forth execution, or
119         ;; exit to the calling definition via "jmp exit".
120         jmp qword rsi
121
122 ;;; Execution semantics for FORTH defition word
123 ;;; At entry, rsi points into the calling definition, at the cell
124 ;;; following the cell indicating this word, rax points to the CFA of
125 ;;; this word.
126 doforth:
127         pushr rsi
128         lea rsi, [rax+8]        ; rsi = the DFA of the rax word
129         next
130
131         WORD p_exit, 'EXIT',fasm
132         ;; ( -- ) ( R: addr -- )
133         ;; Returns execution to the calling definition as per the
134         ;; return stack.
135 exit:
136         popr rsi
137         next
138
139         ;; Execution semantics for a variable ( -- addr )
140         ;; rax points to doer field
141 dovariable:
142         push rax+16
143         next
144
145         ;; Execution semantics for a constant ( -- v )
146         ;; rax points to doer field
147 dovalue:
148         push qword [rax+16]
149         next
150
151         ;; Execution semantics for a string constant ( -- addr n )
152         ;; rax points to doer field
153 dostring:
154         add rax,16
155         mov bl,[rax]
156         mov byte [rsp],bl
157         push rax+1
158         next
159
160 include 'wordlists.asm'
161 include 'syscalls.asm'
162 include 'memory.asm'
163 include 'stack.asm'
164 include 'math.asm'
165 include 'stdio.asm'
166
167         WORD p_program_version,'PROGRAM_VERSION',dostring
168         db length
169 program_version_string: 
170         db 'RRQ Forth version 0.1 - 2021-05-13',10
171         length = $ - program_version_string
172
173         WORD p_stdin,'STDIN',dovalue
174         ;; Initialised to hold a STREAM for fd 0
175         dq 0
176         
177         WORD p_quit,'QUIT',fasm
178         ;; QUIT is the program entry point ********************
179 main:
180         mov rsp,DS_TOP
181         mov rbp,RS_TOP
182         ;; Initialize STREAM STDIN
183         push 0
184         push 10000
185         DOFORTH p_stream
186         pop qword [p_stdin_DFA]
187
188         ;; read a word
189         push qword 1            ; ( fd ) =stdout
190         push qword [p_stdin_DFA]
191         FORTH
192         dq p_read_word          ; ( fd s n )
193         dq sys_write
194         ENDFORTH
195
196         push qword 1                    ; stdout
197         push qword program_version_string ; address of string
198         push qword length               ; length of string (cheating)
199         DOFORTH sys_write               ; printout
200         pop rax                         ; ignore errors
201         
202         push 0
203         DOFORTH sys_exit
204
205         ;; TERMINATE0 terminates the program with code 0
206         ;; ( v -- )
207         WORD terminate, 'TERMINATE',fasm
208         pop rdx
209 terminate_special:
210         mov eax,60
211         syscall
212
213 last_word:
214         ;; FORTH is the last word of VOCABULARY FORTH
215         WORD forth,'FORTH',dovalue
216         dq forth_TFA
217         dq 0
218
219         
220 heap_start: