Implement TYPE
[rrq/jonasforth.git] / main.asm
1 format ELF64 executable
2
3 ;; The code in this macro is placed at the end of each Forth word. When we are
4 ;; executing a definition, this code is what causes execution to resume at the
5 ;; next word in that definition.
6 macro next {
7   ;; RSI points to the address of the definition of the next word to execute.
8   lodsq                   ; Load value at RSI into RAX and increment RSI
9   ;; Now RAX contains the location of the next word to execute. The first 8
10   ;; bytes of this word is the address of the codeword, which is what we want
11   ;; to execute.
12   jmp qword [rax]         ; Jump to the codeword of the current word
13 }
14
15 ;; pushr and popr work on the return stack, whose location is stored in the
16 ;; register RBP.
17 macro pushr x {
18   sub rbp, 8
19   mov qword [rbp], x
20 }
21 macro popr x {
22   mov x, [rbp]
23   add rbp, 8
24 }
25
26 segment readable executable
27
28 main:
29   cld                        ; Clear direction flag so LODSQ does the right thing.
30   mov rbp, return_stack_top  ; Initialize return stack
31
32   mov rsi, program
33   next
34
35 program: dq MAIN
36
37 ;; The codeword is the code that will be executed at the beginning of a forth
38 ;; word. It needs to save the old RSI and update it to point to the next word to
39 ;; execute.
40 docol:
41   pushr rsi            ; Save old value of RSI on return stack; we will continue execution there after we are done executing this word
42   lea rsi, [rax + 8]   ; RAX currently points to the address of the codeword, so we want to continue at RAX+8
43   next                 ; Execute word pointed to by RSI
44
45 ;; This word is called at the end of a Forth definition. It just needs to
46 ;; restore the old value of RSI (saved by 'docol') and resume execution.
47 EXIT:
48   dq .start
49 .start:
50   popr rsi
51   next
52
53 EMIT:
54   dq .start
55 .start:
56   pushr rsi
57   pushr rax
58   mov rax, 1
59   mov rdi, 1
60   lea rsi, [rsp]
61   mov rdx, 1
62   syscall
63   add rsp, 8
64   popr rax
65   popr rsi
66   next
67
68 TYPE:
69   dq .start
70 .start:
71   mov rbx, rsi
72   mov rcx, rax
73
74   mov rax, 1
75   mov rdi, 1
76   pop rdx     ; Length
77   pop rsi     ; Buffer
78   syscall
79
80   mov rax, rcx
81   mov rsi, rbx
82   next
83
84 PUSH_HELLO_CHARS:
85   dq .start
86 .start:
87   push $A
88   push 'o'
89   push 'l'
90   push 'l'
91   push 'e'
92   push 'H'
93   next
94
95 PUSH_TEST_STRING:
96   dq .start
97 .start:
98   push test_string
99   push test_string.length
100   next
101
102 HELLO:
103   dq docol
104   dq PUSH_HELLO_CHARS
105   dq EMIT
106   dq EMIT
107   dq EMIT
108   dq EMIT
109   dq EMIT
110   dq EMIT
111   dq EXIT
112
113 TERMINATE:
114   dq .start
115   .start:
116   mov rax, $3C
117   mov rdi, 0
118   syscall
119
120 MAIN:
121   dq docol
122   dq HELLO
123   dq PUSH_TEST_STRING
124   dq PUSH_TEST_STRING
125   dq TYPE
126   dq TYPE
127   dq HELLO
128   dq HELLO
129   dq TERMINATE
130
131 segment readable writable
132
133 test_string db 'Hi, this is a test.',$A
134 .length = $ - test_string
135
136 ;; Return stack
137 rq $2000
138 return_stack_top: