X-Git-Url: https://git.rrq.au/?a=blobdiff_plain;f=machine.asm;h=31db9ce305a77eec54ffc77f7834ac780cd838db;hb=60057839785134cd60545fa503c31ab50d4056d2;hp=ddfb9711fe18abd89b514d3ccffd2989a18140c8;hpb=f3bc3b97f37dd7bc012c152374d4185c734b3a7e;p=rrq%2Frrqforth.git diff --git a/machine.asm b/machine.asm index ddfb971..31db9ce 100644 --- a/machine.asm +++ b/machine.asm @@ -42,6 +42,213 @@ ;;; 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 { + call p_calltrace_DFA + 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] { +common + FORTH +forward + dq label +common + ENDFORTH +} + +;;; ======================================== +;;; Macro WORD starts a FORTH word definition in this code. +;;; The layout of a word is as follows: +;;; TFA: [8 bytes] pointer to previous word in the word list +;;; [8 bytes] pointer to the word's CFA +;;; [8 bytes] a flags field +;;; [8 bytes] the length of the word's pname +;;; [varying] the word's pname +;;; [1 byte] NUL -- making an asciiz of the pname +;;; ;;[? bytes] 0-7 bytes for address alignment to [disabled] +;;; [8 bytes] pointer to the word's TFA +;;; OFF: [8 bytes] the DOES offset for the word +;;; CFA: [8 bytes] pointer to the word's "doer" code +;;; DFA: [? bytes] the word's data field + +IMMEDIATE = 1 ; optional flag (symbol) + +macro WORD label, name, doer, flags, previous, offset { + local pname + ;; align 8 +label#_TFA: + ;; TFA + if previous eq + dq previous_word + else + dq previous + end if + previous_word = label#_TFA + ;; PFA +label#_pCFA: + dq label#_CFA ; link to CFA of word + dq flags + 0 +label#_PFA: + dq pname - $ - 8 + db name +pname: db 0 ; extra NUL byte + ;; align 8 +label#_pTFA: + dq label#_TFA ; link to TFA of word +label#_OFF: + dq offset + 0 ; The DOES offset. Defaults to 0. + ;; also CFA = pointer to "doer" +label#_CFA: +label: + if doer eq + dq doforth + else + if doer in + dq dofasm ; label#_DFA + else + dq doer + end if + end if + ;; DFA +label#_DFA: +} + +macro tfa2cfa reg { + mov reg,qword [reg+8] +} +macro tfa2does reg { + tfa2cfa reg + sub reg,8 +} +macro tfa2dfa reg { + tfa2cfa reg + add reg,8 +} +macro tfa2flags reg { + add reg,16 +} +macro tfa2pfa reg { + add reg,24 +} +macro tfa2pname reg { + add reg,32 +} +macro cfa2tfa reg { + sub reg,16 + mov reg,qword [reg] +} +macro cfa2dfa reg { + add reg,8 +} +macro dfa2cfa reg { + sub reg,8 +} +macro dfa2tfa reg { + sub reg,24 + mov reg,qword [reg] +} +;;; Code snippet to push a pname string with address and 64-bit length field. +;;; The register is advanced to point at the text part. +macro pushpname reg { + add reg,8 + push reg + push qword [reg-8] +} +;;; ======================================== +;;; 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 cell and data for several string +;;; components. +macro STRING [data] { +common + local datastart, dataend + dq dataend - datastart +datastart: +forward + db data +common +dataend: + } + +;;; ======================================== +;;; The BRANCH macro lays out FORTH words BRANCH and 0BRANCH with offset +macro BRANCH zero,label { + if zero in <0> + dq p_zero_branch + else if zero in <1> + dq p_true_branch + else + dq p_branch + end if + dq label - $ - 8 +} + +;;; ======================================== +;;; The STREAM macro starts an in-core FORTH STREAM area. See WORD +;;; STREAM for details. + macro STREAM endlabel { + local datastart + dq $+32 + dq -1 + dq endlabel - datastart + dq 0 +datastart: + }