adding TELL and EMIT
[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         lodsq                   ; mov rax, [rsi] + add rsi,8
77         jmp qword [rax]         ; goto code of that FORTH word (64 bit jump)
78 }
79
80 ;;; ========================================
81 ;;; The FORTH macro transitions to inline FORTH execution.
82 macro FORTH {
83         local forthcode
84         mov rsi,forthcode
85         next
86         ;; align 8
87 forthcode:
88 }
89
90 ;;; ========================================
91 ;;; The ENDFORTH macro transitions back to inline assembler after FORTH
92
93 macro ENDFORTH {
94         dq inline_code
95 }
96
97 ;;; ========================================
98 ;;; The DOFORTH lays out a single FORTH call
99
100 macro DOFORTH label {
101         FORTH
102         dq label
103         ENDFORTH
104 }
105
106 ;;; ========================================
107 ;;; Macro WORD starts a FORTH word definition in this code
108 ;;; 
109         previous_word = 0       ; Used for chaining the words
110
111         IMMEDIATE = 1           ; optional flag (symbol)
112
113 macro WORD label, name, doer, flags {
114         ;; align 8
115 label#_TFA:
116         ;; TFA
117         dq previous_word
118         previous_word = label#_TFA
119         ;; PFA
120 label#_PFA:
121         db flags + 0
122         db label - $ - 2
123         db name
124         db 0
125         ;; align 8
126
127 label#_OFF:
128         dq 0                    ; The DOES offset. Defaults to 0.
129         ;; also CFA = pointer to "doer"
130 label:
131         if doer eq
132             dq doforth
133         else
134             if doer in <fasm>
135                 dq label#_DFA
136             else
137                 dq doer
138             end if
139         end if
140         ;; DFA
141 label#_DFA:
142 }
143
144 ;;; ========================================
145 ;;; The BLOCK macro lays out the length for a subsequent block to the
146 ;;; given label.
147 macro BLOCK endlabel {
148         local datastart
149         dq endlabel - datastart
150 datastart:
151         }
152
153 ;;; ========================================
154 ;;; The STRING macro lays out length byte and data for s short string
155 macro STRING [data] {
156 common
157         local datastart, dataend
158         db dataend - datastart
159 datastart:
160 forward
161         db data
162 common
163 dataend:
164         }
165