-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathforth.asm
231 lines (188 loc) · 4.67 KB
/
forth.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
section .text
extern printf ;include C printf function
global _start ;must be declared for linker (ld)
_start: ;tell linker the entry point
mov [SP0],esp ;store stack pointer in SP0
mov esi,PROGRAM ;set the fPC
mov DWORD [STACK_P], RSTACK
;insert INIT_D in here
jmp NEXT ;go!
INIT_D:
NEXT:
mov eax,[esi] ;*fPC into eax
add esi,0x4 ;inc address by 8 due to 32bit
cmp DWORD[esi],0
je N_J
;composite word
mov ebx,[eax]
mov eax, ebx
N_J: add esi,0x4
jmp eax
DOTESS:
;ebx is base-stack-pointer
;ecx is size, and then decrements to zero
mov ebx, [SP0]
sub ebx, esp ;find stack size (in 32b)
mov ecx, ebx ;copy size
sar ecx, 2 ;bytes in 32b
; print size
push ecx ;push size to stack
push ds_sz ;format "<size>"
call printf
add esp, 8 ;remove msg from stack
; print contents
DS_ITER:jbe DS_ENDR ;close print if size == 0
mov ecx, esp ;save stack pointer
add ecx, ebx ;move toward base from top
sub ecx, 4
mov edx, [ecx] ;derefence val and store in edx
push edx
push ds_num ;end printf message (\n\r)
call printf
add esp, 8 ;remove msg from stack pointer
sub ebx, 4 ;decrement counter (set flags!)
jmp DS_ITER ;iterate through stack
;print end of msg
DS_ENDR:push ds_end ;end printf message (\n\r)
call printf
add esp, 4 ;remove msg from stack pointer
jmp NEXT
DOT:
push message
call printf
add esp, 8 ;restore stack?! shouldn't be -ve?
jmp NEXT
DUP:
push DWORD [esp]
jmp NEXT
STAR:
pop ebx
pop eax
imul eax, ebx
push eax
jmp NEXT
SEVEN:
push 0x7
jmp NEXT
FIVE:
push 0x5
jmp NEXT
;MATH ops
; CROSS:
; DASH:
; STAR:
; SLASH:
; PERCENT:
;STACK ops
; DUP: ;( a -- a a )
; SWAP: ;( a b -- b a )
; DROP: ;( a -- )
; OVER: ;( a b -- a b a )
; ROT: ;( a b c -- b c a )
;FLOW control
; IF:
; ELSE:
; THEN:
; BEGIN: ;( -- )
; WHILE: ;( b -- _)
; REPEAT: ;( -- )
; DO: ;( j i -- )
; LOOP: ;( -- )
; +LOOP: ;( n -- )
;COMPARE ops
; LESS: ;( a b -- f )
; LEQ: ;( a b -- f )
; EQ: ;( a b -- f )
; GREATER: ;( a b -- f )
; GEQ: ;( a b -- f )
;HELPERS
; COLON: ;starts new word definition
; WORDS: ;( -- ) prints list of all words in system
; SEE: ;( "word" -- ) prints definition of given word
;INTERPRETER
; BL: ;( -- 32 ) pushes a "BLank" char (null token)
; CHAR: ;( "c" -- char ) push value of char to input stream
; FIND: ;( str -- str 0 | xt 1 | xt -1 ); search for word <str>
;if not found, leave str on stack, push 0
;if found, replace <str> w exec token
;if immediate push 1
;else push -1
; WORD: ;( ch "token" -- str ) consume stream to <ch>
; and push pointer to this token
BYE:
mov eax,1 ;system call number (sys_exit)
int 0x80 ;call kernel
NEXT:
mov eax,[esi] ;*fPC into eax
add esi,0x4 ;inc address by 8 due to 32bit
cmp DWORD[esi],0
je N_J
;composite word
mov ebx,[eax]
mov eax, ebx
N_J: add esi,0x4
jmp eax
JUMP:
sub esi, 0x4 ;go to previous PC (this call!)
mov ecx, [esi] ;deref PC into sub-fn
add ecx, 0x8 ;this is 1st inst, go to 2nd
mov esi, ecx
mov eax,[esi] ;*fPC into eax
add esi,0x4 ;inc address by 8 due to 32bit
cmp DWORD[esi],0
add esi,0x4
jmp eax
ENTER:
;push
mov eax, [STACK_P] ;deref TOS into eax
mov [eax], esi ;save prog counter's address
add DWORD [STACK_P],0x4 ;inc stack pointer
;
sub esi, 0x8 ;go to previous PC location
mov ecx, [esi] ;deref PC into sub-fn
add ecx, 0x8 ;this is 1st inst, go to 2nd
mov esi, ecx
;set PC to 2nd command in metafn
jmp NEXT
EXIT:
sub DWORD [STACK_P], 0x4
mov eax, [STACK_P]
mov esi, [eax]
jmp NEXT
; program map
PROGRAM:;
;dd ENTER
dd FIVE, SQUARE, DUP, DOTESS, BYE
SQUARE:
dd ENTER, 0
dd DUP, 0, STAR, 0, EXIT, 0
;"name", address, flag(JUMP/ENTER), next-entry
DICTIONARY:
;native words
dd 'NEXT' ,JUMP,NEXT ,dict[1]
dd '.S' ,JUMP,DOTESS ,?
dd '.' ,JUMP,DOT ,
dd 'DUP' ,JUMP,DUP ,
dd '*' ,JUMP,STAR ,
dd '7' ,JUMP,SEVEN ,
dd '5' ,JUMP,FIVE ,
dd 'BYE' ,JUMP,BYE ,
dd 'ENTER' ,JUMP,ENTER ,
dd 'EXIT' ,JUMP,EXIT ,0x0
;composite words (only for eg)
dd 'SQUARE',ENTER,DUP,STAR,EXIT ,0x0
;rather than having a flag at each address
;the dict just has an index which says "last imm. word"
;if
;NOPE: this can't work bc the composite words are
;a linked list and thus not related to any absolute ix
;vars called above have to be in .data!! otherwise no access!
section .data
SP0 dd 0x0 ;var to hold stack base pointer
RSTACK TIMES 0xF dd 0x0
STACK_P dd 0x0
ds_sz db '<0x%x> ',0x0 ;no new line!
ds_num db '0x%x ',0x0 ;print a hex num
ds_end db 'nice stack ;)',0xA,0x0 ;close printf statement
message db 'the number: 0x%x', 0xA, 0x0
;len equ $ - msg ;length of our dear string