blob: 65f93073820e223109028dc8fe3d8eb24136552c [file] [log] [blame]
swissChilif7f1e2b2021-12-31 14:42:43 -08001;;; Assembly definitions of built-in Forth words
2;;; Assume this is included after all the relevant macros
3
4
5;;; INPUT & OUTPUT ROUTINES ;;;
6 ;; Read a key from the input. If STDIN is blank wait for a key
7 ;; press.
8 ;;
9 ;; TODO: Keep an internal buffer until RETURN is pressed, allow
10 ;; some line editing.
11 ;;
12 ;; Actually, that could be implemented in Forth for simplicity.
13 DEFWORD_RAW KEY, 'KEY'
14 CALL READ_KEY
15 PUSH AX
16 NEXT
17
18 ;; This routine returns the key in AL, but Forth wants it on the
19 ;; stack, so we have a helper function.
20READ_KEY:
21 GETSTDINSTATUS
22 TEST AL, AL
23 JZ .EOF
24
25 READCIN
26 XOR AH, AH ; We get the result in AL but we want
27 ; the whole word to be the correct
28 ; char.
29 RET
30
31.EOF: ; End of STDIN
32 ;; Check if line buffer is empty
33 READCIN
34 XOR AH, AH ; We don't care about the scan code
35 RET
36
37
38 %MACRO WHITESPACE 2
39 CMP %1, ' '
40 JE %2
41
42 CMP %1, 09h ; \t
43 JE %2
44
45 CMP %1, 0Ah ; \n
46 JE %2
47
48 CMP %1, 0Dh ; \r
49 JE %2
50 %ENDMACRO
51
52
53 ;; Read a word from the input, max 32 bytes. WORD is reserved in
54 ;; NASM sadly.
55 DEFWORD_RAW _WORD, 'WORD'
56READ_WORD:
57 MOV DI, WORD_BUFFER
58
59.START:
60 ;; First skip whitespace
61 CALL READ_KEY ; Char in AL
62
63 WHITESPACE AL, .START
64 CMP AL, '\'
65 JE .COMMENT
66
67.LOOP:
68 CMP AL, 'a'
69 JL .STORE
70 CMP AL, 'z'
71 JG .STORE
72
73 SUB AL, ('a' - 'A') ; To upper case
74
75.STORE:
76 STOSB ; Buffer char
77
78 CALL READ_KEY
79 WHITESPACE AL, .DONE
80 JMP .LOOP
81
82.COMMENT:
83 CALL READ_KEY
84 CMP AL, ASCII_RETURN
85 JNE .COMMENT
86 JE .START
87
88.DONE:
89 SUB DI, WORD_BUFFER ; Length
90 PUSH WORD_BUFFER
91 PUSH DI
92
93 NEXT
94
95
96 ;; ( string len -- num unparsed )
97 DEFWORD_RAW NUMBER, 'NUMBER'
98 POP DX ; Length
99 POP BX ; Index
100 ADD DX, BX ; End pointer
101 XOR AX, AX ; The number
102
103 XOR CX, CX ; CL - used for char
104
105.LOOP:
106 MOV CL, BYTE [BX]
107 CMP CL, '0'
108 JL .DONE
109 CMP CL, '9'
110 JG .DONE
111
112 SUB CL, '0'
113 MOV CH, 10 ; This needs to be reset each time
114 ; which is annoying
115 IMUL CH ; 8-bit IMUL operand means that the
116 ; result is just in AX, not extended
117 ; by DX. Perfect
118 XOR CH, CH
119 ADD AX, CX
120 INC BX
121 CMP BX, DX
122 JL .LOOP
123
124.DONE:
125 SUB DX, BX ; Number of chars unread
126 PUSH AX
127 PUSH DX
128 NEXT
129
130
131 ;; Emit a char from the stack
132 DEFWORD_RAW EMIT, 'EMIT'
133 POP DX
134 WRITECOUT
135 NEXT
136
137
138 DEFWORD_RAW CR, 'CR'
139 MOV DX, CRLF_MSG
140 WRITESOUT
141 NEXT
142
143
144 DEFWORD_RAW TYPE, 'TYPE'
145TYPE_STRING:
146 POP CX ; Length
147 POP BX ; Index
148 ADD CX, BX ; End pointer
149
150.LOOP:
151 MOV DL, BYTE [BX]
152 WRITECOUT
153
154 INC BX
155 CMP BX, CX
156 JNE .LOOP
157
158.DONE:
159 NEXT
160
161
162 ;; ( n -- )
163 DEFWORD_RAW DOT, '.'
164 POP AX ; The number
165
166DOT_INT:
167 TEST AX, AX
168 JNZ .START
169
170 MOV DX, '0'
171 WRITECOUT
172 NEXT
173
174.START:
175 MOV BX, 10 ; The base
176
177 ;; TODO: BUG: Depending on this value there is a maximum number
178 ;; that this routine will format, which is weird. For the value of
179 ;; 7 it is 1280.
180 MOV CX, 7
181.LOOP:
182 XOR DX, DX
183 DIV BX ; AX = quotient; DX = remainder
184 PUSH DX
185
186 LOOP .LOOP
187
188 MOV CX, 7
189 XOR BX, BX ; At start
190.REVERSE:
191 POP DX
192 OR BL, DL
193 JZ .END
194
195 ADD DL, '0'
196 WRITECOUT
197
198.END:
199 LOOP .REVERSE
200
201 NEXT
202
203
204;;; DATA ;;;
205 CRLF_MSG DB ASCII_RETURN, ASCII_NEWLINE, '$'
206
207 WORD_BUFFER TIMES 32 DB 0
208WORD_BUFFER_END: