update
[rrq/rrqforth.git] / machine.asm
1 ;;; This file define/describes the "machine"
2 ;;;
3 ;;; Abstract Machine:
4 ;;; https://en.wikibooks.org/wiki/X86_Assembly/X86_Architecture
5 ;;; 
6 ;;; General Purpose Registers ( * marks those used in syscalls )
7 ;;;  *rax = ( -, eax = ( -, ax = ( ah, al) )) "accumulator"
8 ;;;   rbx = ( -, ebx = ( -, bx = ( bh, bl) )) "base"
9 ;;;  *rcx = ( -, ecx = ( -, cx = ( ch, cl) )) "counter"
10 ;;;  *rdx = ( -, edx = ( -, dx = ( dh, dl) )) "data"
11 ;;;   rsp = ( -, esp = ( -, sp = ( -, spl) )) "stack pointer"
12 ;;;   rbp = ( -, ebp = ( -, bp = ( -, bpl) )) "stack base pointer"
13 ;;;  *rsi = ( -, esi = ( -, si = ( -, sil) )) "source"
14 ;;;  *rdi = ( -, edi = ( -, di = ( -, dil) )) "destination"
15 ;;;  *r8
16 ;;;  *r9
17 ;;;   r10
18 ;;;  *r11
19 ;;;   r12
20 ;;;   r13
21 ;;;   r14
22 ;;;   r15
23 ;;; clobbers rdi rsi rdx rcx r8 r9 r11
24 ;;; rax = syscall id
25 ;;;
26 ;;; Segment Registers
27 ;;;   SS "Stack Segment"
28 ;;;   CS "Code Segment"
29 ;;;   DS "Data Segment"
30 ;;;   ES "Extra Segment"
31 ;;;   FS "more Extra Segment"
32 ;;;   GS "more more Extra Segment"
33 ;;;
34 ;;; EFLAGS Register
35 ;;;   0,0,0,0,0,0,0,0,0,0,ID,VIP,VIF,AC,VM,RF,
36 ;;;   0,NT,[IOPL,IOPL],OF,DF,IF,TF,SF,ZF,0,AF,0,PF,1,CF
37 ;;; 
38 ;;; Instruction pointer
39 ;;;   EIP
40 ;;; 
41 ;;; Syscall allocations
42 ;;; clobbers rdi rsi rdx rcx r8 r9 r11
43 ;;; rax = syscall id
44 ;;;
45
46 ;;; ######################################################################
47
48 ;;; ============================================================
49 ;;; FORTH machine model
50 ;;; rsp = data stack pointer
51 ;;; rbp = return stack pointer
52 ;;; rsi = instruction pointer
53
54 ;;; ========================================
55 ;;; The pushr macro pushes x onto the return stack
56 ;;; The popr macro pops x from the return stack
57 macro pushr x {
58         sub rbp, 8
59         mov [rbp], x
60 }
61
62 macro popr x {
63         mov x, [rbp]
64         add rbp, 8
65 }
66
67 ;;; ========================================
68 ;;; The next macro "moves" execution to the next FORTH instruction,
69 ;;; using rsi as instruction pointer. It points to the doer field of a
70 ;;; word, which points to the assembly code that implements the
71 ;;; execution effect of the word. That doer code is entered with rsi
72 ;;; referring to the subsequent address in the colling word, and rax
73 ;;; referring to the doer field of the called word.
74
75 macro next {
76         call p_calltrace_DFA
77         lodsq                   ; mov rax, [rsi] + add rsi,8
78         jmp qword [rax]         ; goto code of that FORTH word (64 bit jump)
79 }
80
81 ;;; ========================================
82 ;;; The FORTH macro transitions to inline FORTH execution.
83 macro FORTH {
84         local forthcode
85         mov rsi,forthcode
86         next
87         ;; align 8
88 forthcode:
89 }
90
91 ;;; ========================================
92 ;;; The ENDFORTH macro transitions back to inline assembler after FORTH
93
94 macro ENDFORTH {
95         dq inline_code
96 }
97
98 ;;; ========================================
99 ;;; The DOFORTH lays out a single FORTH call
100
101 macro DOFORTH [label] {
102 common
103         FORTH
104 forward
105         dq label
106 common
107         ENDFORTH
108 }
109
110 ;;; ========================================
111 ;;; Macro WORD starts a FORTH word definition in this code.
112 ;;; The layout of a word is as follows:
113 ;;; TFA: [8 bytes] pointer to previous word in the word list
114 ;;;      [8 bytes] pointer to the word's CFA
115 ;;;      [8 bytes] a flags field
116 ;;;      [8 bytes] the length of the word's pname
117 ;;;      [varying] the word's pname
118 ;;;      [1 byte]  NUL -- making an asciiz of the pname
119 ;;;      ;;[? bytes] 0-7 bytes for address alignment to [disabled]
120 ;;;      [8 bytes] pointer to the word's TFA
121 ;;; OFF: [8 bytes] the DOES offset for the word
122 ;;; CFA: [8 bytes] pointer to the word's "doer" code
123 ;;; DFA: [? bytes] the word's data field
124
125 IMMEDIATE = 1           ; optional flag (symbol)
126
127 macro WORD label, name, doer, flags, previous, offset {
128         local pname
129         ;; align 8
130 label#_TFA:
131         ;; TFA
132         if previous eq
133             dq previous_word
134         else
135             dq previous
136         end if
137         previous_word = label#_TFA
138         ;; PFA
139 label#_pCFA:
140         dq label#_CFA           ; link to CFA of word
141         dq flags + 0
142 label#_PFA:
143         dq pname - $ - 8
144         db name
145 pname:  db 0                    ; extra NUL byte
146         ;; align 8
147 label#_pTFA:
148         dq label#_TFA           ; link to TFA of word
149 label#_OFF:
150         dq offset + 0           ; The DOES offset. Defaults to 0.
151         ;; also CFA = pointer to "doer"
152 label#_CFA:
153 label:
154         if doer eq
155             dq doforth
156         else
157             if doer in <fasm>
158                 dq dofasm ; label#_DFA
159             else
160                 dq doer
161             end if
162         end if
163         ;; DFA
164 label#_DFA:
165 }
166
167 macro tfa2cfa reg {
168         mov reg,qword [reg+8]
169 }
170 macro tfa2does reg {
171         tfa2cfa reg
172         sub reg,8
173 }
174 macro tfa2dfa reg {
175         tfa2cfa reg
176         add reg,8
177 }
178 macro tfa2flags reg {
179         add reg,16
180 }
181 macro tfa2pfa reg {
182         add reg,24
183 }
184 macro tfa2pname reg {
185         add reg,32
186 }
187 macro cfa2tfa reg {
188         sub reg,16
189         mov reg,qword [reg]
190 }
191 macro cfa2dfa reg {
192         add reg,8
193 }
194 macro dfa2cfa reg {
195         sub reg,8
196 }
197 macro dfa2tfa reg {
198         sub reg,24
199         mov reg,qword [reg]
200 }
201 ;;; Code snippet to push a pname string with address and 64-bit length field.
202 ;;; The register is advanced to point at the text part.
203 macro pushpname reg {
204         add reg,8
205         push reg
206         push qword [reg-8]
207 }
208 ;;; ========================================
209 ;;; The BLOCK macro lays out the length for a subsequent block to the
210 ;;; given label.
211 macro BLOCK endlabel {
212         local datastart
213         dq endlabel - datastart
214 datastart:
215         }
216
217 ;;; ========================================
218 ;;; The STRING macro lays out length cell and data for several string
219 ;;; components.
220 macro STRING [data] {
221 common
222         local datastart, dataend
223         dq dataend - datastart
224 datastart:
225 forward
226         db data
227 common
228         db 0
229 dataend:
230         }
231
232 ;;; ========================================
233 ;;; The BRANCH macro lays out FORTH words BRANCH and 0BRANCH with offset
234 macro BRANCH zero,label {
235         if zero in <0>
236             dq p_zero_branch
237         else if zero in <1>
238             dq p_true_branch
239         else
240             dq p_branch
241         end if
242         dq label - $ - 8
243 }
244
245 ;;; ========================================
246 ;;; The STREAM macro starts an in-core FORTH STREAM area. See WORD
247 ;;; STREAM for details.
248         macro STREAM endlabel {
249         local datastart
250         dq $+32
251         dq -1
252         dq endlabel - datastart
253         dq 0
254 datastart:
255         }