blob: 5dd77a78876c0096232f70052211457925faf8e5 [file] [log] [blame]
swissChilif7f1e2b2021-12-31 14:42:43 -08001 ;; FORTH.ASM -- Forth system for Microsoft (R) DOS
2
3 BITS 16
4
5 ;; DOS loads .COM executables here
6 ORG 100h
7
8 %INCLUDE "DOS.ASM"
9
10;;; MACROS ;;;
11
12 ;; Step indirect threaded code to next word. Call this in a raw
13 ;; word to effectively return. In an interpreted word SI first
14 ;; needs to be reset to the calling value.
15 %MACRO NEXT 0
16 LODSW
17 MOV BX, AX ; [ax] is invalid in 16 bits
18 JMP [BX]
19 %ENDMACRO
20
21
22 ;; Push register operand to return stack
23 %MACRO RSPUSH 1
24 SUB BP, WORDSZ
25 MOV [BP], %1
26 %ENDMACRO
27
28
29 ;; Pop from return stack to register operand
30 %MACRO RSPOP 1
31 MOV %1, [BP]
32 ADD BP, WORDSZ
33 %ENDMACRO
34
35
swissChilif8849dc2021-12-31 23:15:57 -080036 ;; Used for the compile-time dictionary linked list. At runtime
37 ;; LATEST is used instead
swissChilif7f1e2b2021-12-31 14:42:43 -080038 %DEFINE LINK 0
39
40
41 IMMEDIATE_BIT EQU 1 << 6
42 HIDDEN_BIT EQU 1 << 5
43 LENGTH_MASK EQU 0b11111
44
45
46 ;; Define a threaded word. The arguments should be the symbol for
47 ;; the word, followed by the string version. e.g.:
48 ;;
49 ;; DEFWORD DUP, 'DUP', IMMEDIATE_BIT
50 %MACRO DEFWORD 3
51 ALIGN 2
52
53WORD_%1:
54 DW LINK
55 %DEFINE LINK WORD_%1
56 DB WORDLEN_%1 | %3 ; Length | Flags
57
58NAME_%1:
59 DB %2,
60 WORDLEN_%1 EQU $ - NAME_%1
61
62 ALIGN 2
63
64%1:
65 %ENDMACRO
66
67
68 %MACRO DEFWORD_THREADED 2
69 DEFWORD %1, %2, 0
70 DW DOCOL
71 %ENDMACRO
72
73
74 %MACRO DEFWORD_THREADED_IMMED 2
75 DEFWORD %1, %2, IMMEDIATE_BIT
76 DW DOCOL
77 %ENDMACRO
78
79
80 ;; Same as DEFWORD_THREADED but this time with raw code
81 %MACRO DEFWORD_RAW 2
82 DEFWORD %1, %2, 0
83 DW INTRAW ; Raw interpreter codeword
84
85 ;; Callable from assembly
86CODE_%1:
87 %ENDMACRO
88
89
90 %MACRO DEFWORD_RAW_IMMEDIATE 2
91 DEFWORD %1, %2, IMMEDIATE_BIT
92 DW INTRAW
93
94 ;; Callable from assembly
95CODE_%1:
96 %ENDMACRO
97
98
99 ;; DEFVAR name, 'name'
100 ;; dw 0
101 %MACRO DEFVAR 2
102 DEFWORD_RAW %1, %2
103 PUSH VAR_%1
104 NEXT
105
106VAR_%1:
107 %ENDMACRO
108
swissChilif8849dc2021-12-31 23:15:57 -0800109
swissChili7c626b92022-01-01 23:35:39 -0800110 %MACRO DEFCONST 2
swissChilif7f1e2b2021-12-31 14:42:43 -0800111 DEFWORD_RAW %1, %2
swissChili7c626b92022-01-01 23:35:39 -0800112 PUSH WORD [CONST_%1]
swissChilif7f1e2b2021-12-31 14:42:43 -0800113 NEXT
swissChili7c626b92022-01-01 23:35:39 -0800114CONST_%1:
swissChilif7f1e2b2021-12-31 14:42:43 -0800115 %ENDMACRO
116
117
swissChilif8849dc2021-12-31 23:15:57 -0800118 %MACRO INCLUDE_STRING 1
swissChilif7f1e2b2021-12-31 14:42:43 -0800119 DW LITSTRING
swissChilif8849dc2021-12-31 23:15:57 -0800120 DW %%STRINGLEN
121%%BEFORE_STRING:
122 DB %1
123 %%STRINGLEN EQU $ - %%BEFORE_STRING
swissChilif7f1e2b2021-12-31 14:42:43 -0800124 ALIGN WORDSZ
125 %ENDMACRO
126
127
swissChilif7f1e2b2021-12-31 14:42:43 -0800128 %MACRO RELATIVE_ADDRESS 1
swissChilif8849dc2021-12-31 23:15:57 -0800129 DW (%1 - $ - 2)
swissChilif7f1e2b2021-12-31 14:42:43 -0800130 %ENDMACRO
131
132
133;;; PROGRAM CODE ;;;
134
135_START:
136 ;; Progran begins
137 MOV BP, SP
swissChili7c626b92022-01-01 23:35:39 -0800138 SUB BP, 1024
139 MOV WORD [CONST_SP_INITIAL], SP
140
swissChilif7f1e2b2021-12-31 14:42:43 -0800141 MOV SI, INDIRECT_START
142 NEXT
143
144 ALIGN 2
145
146
147 ;; DO COLon definition -- Codeword for indirect threaded code
148 ;; ax: indirect execution address
149DOCOL:
150 RSPUSH si
151 ADD AX, WORDSZ ; Point to the first word address
152 MOV SI, AX ; Enter the function body (set si)
153 NEXT
154
155
156 ;; Interpret raw code (plain machine code)
157INTRAW:
158 ADD AX, WORDSZ
159 JMP AX
160
161
162INDIRECT_START:
swissChilif8849dc2021-12-31 23:15:57 -0800163 DW SETUP
swissChilif7f1e2b2021-12-31 14:42:43 -0800164 DW QUIT
165 DW BYE
166
167
168SETUP:
169 DW INTRAW
170
171 MOV DX, MSG
172 WRITESOUT
173
174 NEXT
175
176LITERAL:
177 DW INTRAW
178
179 LODSW ; Load the next word
180 PUSH AX
181
182 NEXT
183
184
185EXIT:
186 DW INTRAW
187 RSPOP SI
188 NEXT
189
190TEST_PRINTING:
191 DW INTRAW
192 MOV AX, 5723
193 JMP DOT_INT
194
195
swissChili7c626b92022-01-01 23:35:39 -0800196 DEFWORD_RAW BYE, 'BYE'
swissChilif7f1e2b2021-12-31 14:42:43 -0800197 FLUSH
198 QUIT_PROC
199
200
201 DEFWORD_RAW LIT, 'LIT'
202 LODSW ; Read next word from input to AX
203 PUSH AX
204 NEXT
205
206
207 DEFWORD_RAW DROP, 'DROP'
208 ADD SP, WORDSZ
209 NEXT
210
211
212 DEFWORD_RAW SWAP, 'SWAP'
213 POP AX
214 POP BX
215 PUSH AX
216 PUSH BX
217 NEXT
218
219
220 DEFWORD_RAW DUP, 'DUP'
221 ;; This is stupid, [SP] is invalid
222 POP AX
223 PUSH AX
224 PUSH AX
225 NEXT
226
227
228 DEFWORD_RAW PLUS, '+'
229 POP AX
230 POP BX
231 ADD AX, BX
232 PUSH AX
233 NEXT
234
235
236 DEFWORD_RAW MINUS, '-' ; ( DX AX -- DX-AX )
237 POP AX
238 POP DX
239 SUB DX, AX
240 PUSH DX
241 NEXT
242
243
swissChili7c626b92022-01-01 23:35:39 -0800244 DEFWORD_RAW SLASHMOD, '/MOD'
245 POP DX
246 POP AX
247 IDIV DX
248 PUSH DX ; Remainder
249 PUSH AX ; Quotient
250 NEXT
251
252
253 DEFWORD_RAW _TIMES, '*'
254 POP AX
255 POP DX
256 IMUL DX
257 PUSH AX
258 NEXT
259
260
swissChilif8849dc2021-12-31 23:15:57 -0800261 DEFWORD_RAW AND, 'AND'
262 POP AX
263 POP DX
264 AND AX, DX
265 PUSH AX
266 NEXT
267
268
269 DEFWORD_RAW XOR, 'XOR'
270 POP DX
271 POP AX
272 XOR AX, DX
273 PUSH AX
274 NEXT
275
276
277 DEFWORD_RAW NOT, 'NOT'
278 POP AX
279 NOT AX
280 PUSH AX
281 NEXT
282
283
swissChilif7f1e2b2021-12-31 14:42:43 -0800284 DEFWORD_RAW ADD1, '1+'
285 POP AX
286 ADD AX, 1
287 PUSH AX
288 NEXT
289
290
291 DEFWORD_RAW ADD2, '2+'
292 POP AX
293 ADD AX, 2
294 PUSH AX
295 NEXT
296
297
298 ;; This kind of sucks
299 DEFWORD_RAW _2DUP, '2DUP' ; ( a b -- a b a b )
300 POP AX
301 POP BX
302 PUSH BX
303 PUSH AX
304 PUSH BX
305 PUSH AX
306 NEXT
swissChili7c626b92022-01-01 23:35:39 -0800307
308
309 DEFWORD_RAW TEST_WRITE_FILE, 'TEST-WRITE-FILE'
310 MOV AL, F_WRITE
311 MOV DX, DUMP
312 OPENF
313 JC .OPEN
314
315 MOV BX, AX ; Handle
316 MOV CX, 4
317 MOV DX, DUMP
318 WRITEF
319 JC .WRITE
320
321 CLOSEF
322 JC .CLOSE
323
324 NEXT
325
326.OPEN:
327 MOV DX, MSG_OPENF_FAILED
328 WRITESOUT
329 NEXT
330
331.WRITE:
332 ;; 06h - invalid handle
333 PUSH AX
334 MOV DX, MSG_WRITEF_FAILED
335 WRITESOUT
336 NEXT
337
338.CLOSE:
339 MOV DX, MSG_CLOSEF_FAILED
340 WRITESOUT
341 NEXT
swissChilif7f1e2b2021-12-31 14:42:43 -0800342
343
344 %INCLUDE "IOWORDS.ASM"
345 %INCLUDE "DICTNRY.ASM"
346
347;;; LATE-INIT VARIABLES ;;;
348 DEFVAR STATE, 'STATE'
349 DW 0 ; Interpret
swissChilif8849dc2021-12-31 23:15:57 -0800350
swissChilif7f1e2b2021-12-31 14:42:43 -0800351
352 DEFVAR HERE, 'HERE'
353 DW HERE_START
swissChilif8849dc2021-12-31 23:15:57 -0800354
swissChili7c626b92022-01-01 23:35:39 -0800355
356 DEFCONST SP_INITIAL, 'S0'
357 DW 0
358
swissChilif7f1e2b2021-12-31 14:42:43 -0800359
360 ;; LATEST must be the last word defined in FORTH.ASM!
361 DEFVAR LATEST, 'LATEST'
362 DW LINK
363
364
365;;; PROGRAM DATA ;;;
366 MSG DB 'DOS FORTH', 0Dh, 0Ah, '$'
swissChili7c626b92022-01-01 23:35:39 -0800367 DUMP DB 'DUMP.COM', 0
368 DUMP_LEN EQU 8
369
370 MSG_CLOSEF_FAILED DB 'CLOSEF FAILED', 0Dh, 0Ah, '$'
371 MSG_WRITEF_FAILED DB 'WRITEF FAILED', 0Dh, 0Ah, '$'
swissChilif7f1e2b2021-12-31 14:42:43 -0800372
373
swissChilif8849dc2021-12-31 23:15:57 -0800374 ALIGN 4
swissChilif7f1e2b2021-12-31 14:42:43 -0800375;;; FREE DATA ;;;
376HERE_START: