blob: 25324fe86a467c9d45d537b3f881358453010b74 [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
swissChilie1abd072022-04-22 22:07:42 -0700133 %MACRO DOS_STRING 1
134 DB %1, 0Dh, 0Ah, '$'
135 %ENDMACRO
136
137
138 ;; Move the address of the PAD into %1
139 ;; Pad starts at 256 bytes above LATEST
140 %MACRO GET_PAD 1
141 MOV %1, [VAR_LATEST]
142 ADD %1, 256
143 %ENDMACRO
144
145
swissChilif7f1e2b2021-12-31 14:42:43 -0800146;;; PROGRAM CODE ;;;
147
148_START:
149 ;; Progran begins
150 MOV BP, SP
swissChili7c626b92022-01-01 23:35:39 -0800151 SUB BP, 1024
152 MOV WORD [CONST_SP_INITIAL], SP
153
swissChilif7f1e2b2021-12-31 14:42:43 -0800154 MOV SI, INDIRECT_START
155 NEXT
156
157 ALIGN 2
158
159
160 ;; DO COLon definition -- Codeword for indirect threaded code
161 ;; ax: indirect execution address
162DOCOL:
swissChilie1abd072022-04-22 22:07:42 -0700163 RSPUSH SI
swissChilif7f1e2b2021-12-31 14:42:43 -0800164 ADD AX, WORDSZ ; Point to the first word address
165 MOV SI, AX ; Enter the function body (set si)
166 NEXT
167
168
169 ;; Interpret raw code (plain machine code)
170INTRAW:
171 ADD AX, WORDSZ
172 JMP AX
173
174
175INDIRECT_START:
swissChilif8849dc2021-12-31 23:15:57 -0800176 DW SETUP
swissChilif7f1e2b2021-12-31 14:42:43 -0800177 DW QUIT
swissChilif7f1e2b2021-12-31 14:42:43 -0800178
179
180SETUP:
181 DW INTRAW
182
183 MOV DX, MSG
184 WRITESOUT
185
186 NEXT
187
188LITERAL:
189 DW INTRAW
190
191 LODSW ; Load the next word
192 PUSH AX
193
194 NEXT
195
196
197EXIT:
198 DW INTRAW
199 RSPOP SI
200 NEXT
201
swissChilif7f1e2b2021-12-31 14:42:43 -0800202
swissChili7c626b92022-01-01 23:35:39 -0800203 DEFWORD_RAW BYE, 'BYE'
swissChilib921e822022-04-20 19:47:33 -0700204 MOV DX, .BYE_MSG
205 WRITESOUT
swissChilif7f1e2b2021-12-31 14:42:43 -0800206 QUIT_PROC
207
swissChili7156d512022-04-22 22:19:55 -0700208.BYE_MSG DOS_STRING 'Bye'
swissChilib921e822022-04-20 19:47:33 -0700209
swissChilif7f1e2b2021-12-31 14:42:43 -0800210
211 DEFWORD_RAW LIT, 'LIT'
212 LODSW ; Read next word from input to AX
213 PUSH AX
214 NEXT
215
216
217 DEFWORD_RAW DROP, 'DROP'
218 ADD SP, WORDSZ
219 NEXT
220
221
222 DEFWORD_RAW SWAP, 'SWAP'
223 POP AX
224 POP BX
225 PUSH AX
226 PUSH BX
227 NEXT
228
229
swissChilie1abd072022-04-22 22:07:42 -0700230 ;; a b -- a b a
swissChili7156d512022-04-22 22:19:55 -0700231 DEFWORD_THREADED OVER, 'OVER'
232 DW TO_RET, DUP, FROM_RET, SWAP, EXIT
swissChilie1abd072022-04-22 22:07:42 -0700233
234
swissChilif7f1e2b2021-12-31 14:42:43 -0800235 DEFWORD_RAW DUP, 'DUP'
236 ;; This is stupid, [SP] is invalid
237 POP AX
238 PUSH AX
239 PUSH AX
240 NEXT
241
242
swissChilie1abd072022-04-22 22:07:42 -0700243 DEFWORD_RAW TO_RET, '>R'
244 POP AX
245 RSPUSH AX
246 NEXT
247
248
249 DEFWORD_RAW FROM_RET, 'R>'
250 RSPOP AX
251 PUSH AX
252 NEXT
253
254
255 ;; ( a b c -- b c a )
swissChili7156d512022-04-22 22:19:55 -0700256 DEFWORD_THREADED ROT, 'ROT'
257 DW TO_RET, SWAP, FROM_RET, SWAP, EXIT
swissChilie1abd072022-04-22 22:07:42 -0700258
259
swissChilif7f1e2b2021-12-31 14:42:43 -0800260 DEFWORD_RAW PLUS, '+'
261 POP AX
262 POP BX
263 ADD AX, BX
264 PUSH AX
265 NEXT
266
267
268 DEFWORD_RAW MINUS, '-' ; ( DX AX -- DX-AX )
269 POP AX
270 POP DX
271 SUB DX, AX
272 PUSH DX
273 NEXT
274
275
swissChili7c626b92022-01-01 23:35:39 -0800276 DEFWORD_RAW SLASHMOD, '/MOD'
swissChili7c626b92022-01-01 23:35:39 -0800277 POP AX
swissChili94f1e762022-01-29 21:55:45 -0800278 POP DX
swissChili7c626b92022-01-01 23:35:39 -0800279 IDIV DX
280 PUSH DX ; Remainder
281 PUSH AX ; Quotient
282 NEXT
283
284
285 DEFWORD_RAW _TIMES, '*'
286 POP AX
287 POP DX
288 IMUL DX
289 PUSH AX
290 NEXT
291
292
swissChilif8849dc2021-12-31 23:15:57 -0800293 DEFWORD_RAW AND, 'AND'
294 POP AX
295 POP DX
296 AND AX, DX
297 PUSH AX
298 NEXT
299
300
301 DEFWORD_RAW XOR, 'XOR'
302 POP DX
303 POP AX
304 XOR AX, DX
305 PUSH AX
306 NEXT
307
308
309 DEFWORD_RAW NOT, 'NOT'
310 POP AX
311 NOT AX
312 PUSH AX
313 NEXT
314
315
swissChilif7f1e2b2021-12-31 14:42:43 -0800316 DEFWORD_RAW ADD1, '1+'
317 POP AX
318 ADD AX, 1
319 PUSH AX
320 NEXT
321
322
323 DEFWORD_RAW ADD2, '2+'
324 POP AX
325 ADD AX, 2
326 PUSH AX
327 NEXT
328
329
330 ;; This kind of sucks
331 DEFWORD_RAW _2DUP, '2DUP' ; ( a b -- a b a b )
332 POP AX
333 POP BX
334 PUSH BX
335 PUSH AX
336 PUSH BX
337 PUSH AX
338 NEXT
swissChili7c626b92022-01-01 23:35:39 -0800339
340
swissChilif7f1e2b2021-12-31 14:42:43 -0800341 %INCLUDE "IOWORDS.ASM"
342 %INCLUDE "DICTNRY.ASM"
343
344;;; LATE-INIT VARIABLES ;;;
345 DEFVAR STATE, 'STATE'
swissChilice85f572022-04-20 16:54:34 -0700346 DW 0 ; Interpret; ( cfa )
swissChilif8849dc2021-12-31 23:15:57 -0800347
swissChilif7f1e2b2021-12-31 14:42:43 -0800348
349 DEFVAR HERE, 'HERE'
350 DW HERE_START
swissChilif8849dc2021-12-31 23:15:57 -0800351
swissChili7c626b92022-01-01 23:35:39 -0800352
353 DEFCONST SP_INITIAL, 'S0'
354 DW 0
355
swissChilif7f1e2b2021-12-31 14:42:43 -0800356
357 ;; LATEST must be the last word defined in FORTH.ASM!
358 DEFVAR LATEST, 'LATEST'
359 DW LINK
360
361
362;;; PROGRAM DATA ;;;
363 MSG DB 'DOS FORTH', 0Dh, 0Ah, '$'
364
365
swissChilif7f1e2b2021-12-31 14:42:43 -0800366;;; FREE DATA ;;;
swissChilie4d2e282022-01-04 22:22:27 -0800367 ALIGN 4
swissChilif7f1e2b2021-12-31 14:42:43 -0800368HERE_START: