;;; clobbers rdi rsi rdx rcx r8 r9 r11
;;; rax = syscall id
;;;
-;;; function calling
+;;; ######################################################################
+
+;;; ============================================================
+;;; FORTH machine model
+;;; rsp = data stack pointer
+;;; rbp = return stack pointer
+;;; rsi = instruction pointer
+
+;;; ========================================
+;;; The pushr macro pushes x onto the return stack
+;;; The popr macro pops x from the return stack
+macro pushr x {
+ sub rbp, 8
+ mov [rbp], x
+}
+
+macro popr x {
+ mov x, [rbp]
+ add rbp, 8
+}
+
+;;; ========================================
+;;; The next macro "moves" execution to the next FORTH instruction,
+;;; using rsi as instruction pointer. It points to the doer field of a
+;;; word, which points to the assembly code that implements the
+;;; execution effect of the word. That doer code is entered with rsi
+;;; referring to the subsequent address in the colling word, and rax
+;;; referring to the doer field of the called word.
+
+macro next {
+ lodsq ; mov rax, [rsi] + add rsi,8
+ jmp qword [rax] ; goto code of that FORTH word (64 bit jump)
+}
+
+;;; ========================================
+;;; The FORTH macro transitions to inline FORTH execution.
+macro FORTH {
+ local forthcode
+ mov rsi,forthcode
+ next
+ ;; align 8
+forthcode:
+}
+
+;;; ========================================
+;;; The ENDFORTH macro transitions back to inline assembler after FORTH
+
+macro ENDFORTH {
+ dq inline_code
+}
+
+;;; ========================================
+;;; The DOFORTH lays out a single FORTH call
+
+macro DOFORTH label {
+ FORTH
+ dq label
+ ENDFORTH
+}
+
+;;; ========================================
+;;; Macro WORD starts a FORTH word definition in this code
+;;;
+ previous_word = 0 ; Used for chaining the words
+
+ IMMEDIATE = 1 ; optional flag (symbol)
+
+macro WORD label, name, doer, flags {
+ ;; align 8
+label#_TFA:
+ ;; TFA
+ dq previous_word
+ previous_word = label#_TFA
+ ;; PFA
+label#_PFA:
+ db flags + 0
+ db label - $ - 2
+ db name
+ db 0
+ ;; align 8
+
+label#_OFF:
+ dq 0 ; The DOES offset. Defaults to 0.
+ ;; also CFA = pointer to "doer"
+label:
+ if doer eq
+ dq doforth
+ else
+ if doer in <fasm>
+ dq label#_DFA
+ else
+ dq doer
+ end if
+ end if
+ ;; DFA
+label#_DFA:
+}
+
+;;; ========================================
+;;; The BLOCK macro lays out the length for a subsequent block to the
+;;; given label.
+macro BLOCK endlabel {
+ local datastart
+ dq endlabel - datastart
+datastart:
+ }
+
+;;; ========================================
+;;; The STRING macro lays out length byte and data for s short string
+macro STRING [data] {
+common
+ local datastart, dataend
+ db dataend - datastart
+datastart:
+forward
+ db data
+common
+dataend:
+ }