OSDN Git Service

some functioning flattening, buggy division work
[fig-forth-68000/fig-forth-68000.git] / FIG68KFL.S
1         OPT LIST,SYMTAB\r
2         MACHINE MC68000\r
3         OPT DEBUG\r
4         OUTPUT\r
5 * fig-FORTH FOR 68000\r
6 * ASSEMBLY SOURCE LISTING\r
7 \r
8 * RELEASE 0\r
9 * JAN-FEB 2023\r
10 * WITH COMPILER SECURITY\r
11 * AND VARIABLE LENGTH NAMES\r
12 * Flattening the RTS mode\r
13 *\r
14 * When I got to BUILDS/DOES in FIG68KSB.S,\r
15 * I realized that the far branch kludge\r
16 * is more of a paradigm-breaker than I had been expecting.\r
17 * So I came back to FIG68KRT.S to flatten\r
18 * the indirect-threading, subroutine-call inner interpreter.\r
19 * Subroutine-call inner interpreter should allow\r
20 * seamless interface with CPU native runtime libraries,\r
21 *\r
22 * Adapted by Joel Matthew Rees \r
23 * from fig-FORTH for 6800 (via buggy fig-FORTH for 6809) by Dave Lion, et. al.\r
24 \r
25 * This free/libre/open source publication is provided\r
26 * through the courtesy of:\r
27 * FORTH\r
28 * INTEREST\r
29 * GROUP\r
30 * fig\r
31 * and other interested parties.\r
32 \r
33 * Ancient address:\r
34 * P.O. Box 8231 - San Jose, CA 95155 - (408) 277-0668\r
35 * URL: http://www.forth.org\r
36 * Further distribution must include this notice.\r
37         PAGE\r
38         TTL     Copyright: FORTH Interest Group, original authors, and Joel Matthew Rees\r
39 *       OPT     NOG,PAG\r
40 * filename fig-forth-hand68000.asm\r
41 * === FORTH-68000 {date} {time}\r
42 \r
43 \r
44 * Permission is hereby granted, free of charge, to any person obtaining a copy\r
45 * of this software and associated documentation files (the "Software"), to deal\r
46 * in the Software without restriction, including without limitation the rights\r
47 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r
48 * copies of the Software, and to permit persons to whom the Software is\r
49 * furnished to do so, subject to the following conditions:\r
50 *\r
51 * The above copyright notice and this permission notice shall be included in\r
52 * all copies or substantial portions of the Software.\r
53 \r
54 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
55 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
56 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r
57 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
58 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
59 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r
60 * THE SOFTWARE.\r
61 *\r
62 * "Associated documentation" for this declaration of license\r
63 * shall be interpreted to include only the comments in this file,\r
64 * or, if the code is split into multiple files,\r
65 * all files containing the complete source.\r
66\r
67 * This is the MIT model license, as published by the Open Source Consortium,\r
68 * with associated documentation defined.\r
69 * It was chosen to reflect the spirit of the original \r
70 * terms of use, which used archaic legal terminology.\r
71 *\r
72 * Authors of the 6800 model:\r
73 * === Primary: Dave Lion,\r
74 * ===  with help from\r
75 * === Bob Smith,\r
76 * === LaFarr Stuart,\r
77 * === The Forth Interest Group\r
78 * === PO Box 1105\r
79 * === San Carlos, CA 94070\r
80 * ===  and\r
81 * === Unbounded Computing\r
82 * === 1134-K Aster Ave.\r
83 * === Sunnyvale, CA 94086\r
84 *\r
85         PAGE\r
86 \r
87 *********\r
88 * NOTICE! the fig Forth model has problems, \r
89 * including known bugs and unknown, \r
90 * and including vulnerabilities.\r
91 *\r
92 * While it might be used to bootstrap more correct and secure systems,\r
93 * it should be primarily used for study, practice, and research.\r
94 *********\r
95 \r
96 * Some processor-specific stuff:\r
97 NATWID  EQU     4       ; bytes per natural integer/pointer\r
98 * The assembler ought to have defined these, but I don't see them in the manual:\r
99 * User program condition codes:\r
100 F_CARY  EQU     $0001\r
101 F_OVER  EQU     $0002\r
102 F_ZERO  EQU     $0004\r
103 F_NEG   EQU     $0008\r
104 F_EXT   EQU     $0010\r
105 * System status flags (68000/68010/CPU32):\r
106 F_SYS   EQU     $2000\r
107 F_TRAC  EQU     $8000\r
108 * Ignoring the interrupt flags for now\r
109 *\r
110 *  The original version was developed on an AMI EVK 300 PROTO\r
111 *  system using an ACIA for the I/O.\r
112 *  This version is developed targeting the Atari ST.\r
113 \r
114 *  All terminal 1/0\r
115 *  is done in three subroutines:\r
116 *   PEMIT  ( word # 182 )\r
117 *   PKEY   (        183 )\r
118 *   PQTERM (        184 )\r
119 *\r
120 *  The FORTH words for disc related I/O follow the model\r
121 *  of the FORTH Interest Group, but have not yet been\r
122 *  tested using a real disc.\r
123 *\r
124 *  Addresses in the 6800 implementation reflect the fact that,\r
125 *  on the development system, it was convenient to\r
126 *  write-protect memory at hex 1000, and leave the first\r
127 *  4K bytes write-enabled. As a consequence, code from\r
128 *  location $1000 to label ZZZZ could be put in ROM.\r
129 *  Minor deviations from the model were made in the\r
130 *  initialization and words ?STACK and FORGET\r
131 *  in order to do this.\r
132 *\r
133 *  Those definitions will be altered somewhat in this \r
134 *  implementation for the 68000 -- Atari ST.\r
135 *  \r
136         PAGE\r
137 *  MEMORY MAP for this approximately 128K system:\r
138 *  ( arranged for systems with high-memory ROM/write-protect )\r
139 *\r
140 * Won't be using the ACIA directly, no need to define addresses.\r
141 * ACIAC EQU     $XXXXXXXX       the ACIA control address and\r
142 * ACIAD EQU     ACIAC+1 data address for PROTO\r
143 *\r
144 * Moving the definitions of the memory area since the usual 68000 assemblers are \r
145 * so kind as to make sure that definitions dependent on negative offsets and such\r
146 * are not supported as ORG arguments, etc.\r
147 *\r
148 * These will be defined elsewhere:\r
149 * Except the buffers must be defined before being used.\r
150 *\r
151 \r
152 * The following buffered I/O definitions must be resolved before being used in the first pass,\r
153 * for assemblers that insist.\r
154 *\r
155 * Traditional SCREEN size is 1024.\r
156 * But it must be a power of 2 multiple of BLOCK size.\r
157 * The model I/O routines from fig Forth may work better at 8 BLOCKs per SCREEN,\r
158 * but only 4 buffers (half a SCREEN) in memory\r
159 * -- because of certain tightly-coupled design features (bugs).\r
160 *\r
161 * * If your block I/O works directly on sector buffers, \r
162 * BLOCK size should be SECTOR size.\r
163 * * If your sector buffer memory is not in Forth-controlled memory,\r
164 * BLOCK size can be decoupled from SECTOR size. But your low-level routines\r
165 * have to handle the copying between correctly.\r
166 *\r
167 * This version of the model does not handle BLOCK 0 buffering well.\r
168 *\r
169 * And, of course, this should be in a table with entries for each block I/O device.\r
170 *\r
171 NBLK    EQU     4       ; # of disc buffer blocks for "virtual memory"\r
172 *\r
173 SCRSZ   EQU     1024    \r
174 *\r
175 RSECSZ  EQU     256             ; size of the RAM-resident emulated block I/O sector\r
176 RBLKSZ  EQU     SCRSZ/NBLK      ; \r
177 *  each block buffer is RBLKSZ+SECTRL bytes in size,\r
178 *  holding RBLKSZ characters\r
179 SECTRL  EQU     2*NATWID        ; Currently held sector number, etc.\r
180 BUFSZ   EQU     (RBLKSZ+SECTRL)*NBLK\r
181 *\r
182 \r
183 \r
184 * MEMEND        EQU     132*NBLK+ENDofCODE end of ram\r
185 *  each block is 132 bytes in size,\r
186 *  holding 128 characters\r
187 *\r
188 * MEMTOP        EQU     $WAYupHIGH      absolute end of all ram\r
189 *  MEMORY MAP for this 16K system:\r
190 *  ( positioned so that systems with 4k byte write-\r
191 *   protected segments can write protect FORTH )\r
192 *\r
193 * addr.         contents                pointer init by\r
194 * ****  ******************************* ******* ******\r
195 * MEMTOP                                        HI\r
196 *       substitute for disc mass memory\r
197 * MEMEND                                        LO\r
198 * MEMEND-1\r
199 *       4 buffer sectors of VIRTUAL MEMORY\r
200 * ENDofCODE+1                                   FIRST\r
201 * >>>>>> memory from here up must be RAM <<<<<<\r
202 *\r
203 * ENDofCODE\r
204 * >>>>>>--------Two words to start RAMmable dictionary--------<<<<<<\r
205 *\r
206 *       ~12k of romable "FORTH"         <== IP  ABORT\r
207 *                                       <== W\r
208 *       the VIRTUAL FORTH MACHINE\r
209 *\r
210 * ENTRY+4 <<< WARM START ENTRY >>>\r
211 * ENTRY <<< COLD START ENTRY >>>\r
212 *\r
213 * >>>>>> memory from here down must be RAM <<<<<<\r
214 *  IRP  RETURN STACK base               <== RP  RINIT\r
215 *\r
216 *  SFTBND\r
217 *       INPUT LINE BUFFER\r
218 *       holds up to 132 characters\r
219 *       and is scanned upward by IN\r
220 *       starting at TIB\r
221 *  ITIB                                 <== IN  TIB\r
222 *  IPSP DATA STACK                      <== SP  SP0,SINIT\r
223 *    |  grows downward from here\r
224 *    v\r
225 *  - -\r
226 *    ^\r
227 *    |  DICTIONARY grows upward\r
228\r
229 * These two entries will be copied from the end of the "ROMmable" dictionary\r
230 * into the bottom of the "RAMmable" dictionary area to link the two parts together.\r
231\r
232 *       end of ram-dictionary.          <== DP  DPINIT\r
233 *       "TASK"\r
234 *\r
235 *       "FORTH" ( a word )              <=, <== CONTEXT\r
236 *                                       `==== CURRENT\r
237 *       start of RAM dictionary area.\r
238 *\r
239 *  RTDICT+(something)   "FORTH" ( definition )          <=, <== CONTEXT\r
240 *                                       `==== CURRENT\r
241 *  RTDICT       start of ram-dictionary.\r
242 *\r
243 *  USERSP       user #1 table of variables      <= UP   DPINIT\r
244 *   --- No need for registers & pointers for the virtual machine\r
245 *       No need for scratch area used by various words\r
246 *   --- lowest address used by FORTH\r
247 * Linker/loader structures produced by assembler and linker\r
248 * CODEBEG\r
249 * >>>>>> memory from here down left alone <<<<<<\r
250 * >>>>>> so we can safely call ROM routines <<<<<<\r
251 *\r
252 * UNK    don't care stuff, if anything\r
253 *\r
254 * $400\r
255 * EXCVCT 68000 exception vectors\r
256 * 0000==RSTVCT\r
257 \r
258         PAGE\r
259 \r
260 *       ORG $30000      ; Not on the Atari ST under EMUTOS.\r
261 \r
262 * Edit this according to the desired size for the dictionary.\r
263 RTDCSZ  EQU     8*1024  ; Must be even on 68000. For now, keep total size under 32K.\r
264 \r
265 * This should be adjusted to the target:\r
266 * CODEBG        EQU $800\r
267 CODEBG  EQU     *       ; On the Atari ST, the assembler should determine this.\r
268 *\r
269 *       per-task (per-user) tables\r
270 USERAL  EQU     64*NATWID       ; allocatable\r
271 USERCT  EQU     4               ; maybe, someday?\r
272 *\r
273 * USERSP        EQU     *       ; (task-local variable space, addressable by UP)        ; NOPE!\r
274 USERSP  EQU     USERAL*USERCT   ; (task-local variable space, addressable by UP)\r
275 * IUP   EQU     USERSP  ; USERSZ*USERCT ; Nope!\r
276 * The per-user (or task-local) table definitions are moved to the end \r
277 * to avoid using BSS segments, because I don't know how well they are \r
278 * supported in various 68K assemblers.\r
279 \r
280 *       This system is built for one "user", or task, \r
281 *       but additional users (tasks) may be added\r
282 *       by allocating additional user tables.\r
283 *\r
284 *       Some of this stuff gets initialized during\r
285 *       COLD start and WARM start:\r
286 *       [ names correspond to FORTH words of similar (no X) name ]\r
287 *\r
288 *               A few useful VM variables --\r
289 * Will be removed when they are no longer needed.\r
290 * All are replaced by 68000 registers.\r
291 \r
292 * The Atari apparently wants the beginning of the image to be a jump to the entry point.\r
293 * Put a jump around stuff here, anyway.\r
294 START:\r
295 *       MOVE.L  #ORIG-SURPRISE,D7\r
296 * SURPRISE:\r
297 *       JMP     (PC,D7) ; monku monku mutter mutter mumble mumble butsu butsu\r
298         JMP     ORIG    ; In case the distance is greater than 32K.\r
299 * And this is why people don't understand true position independent coding.\r
300 RSRV    DS.L    8\r
301 N       DS.L    8       ; might be used as scratch if we really needed it.\r
302 \r
303 *       These locations could be used by a TRACE routine :\r
304 TRLIM   DS.W    1       ; the count for tracing without user intervention\r
305 TRACEM  DS.W    1       ; non-zero = trace mode\r
306 BRKPT   DS.L    1       ; the breakpoint address at which\r
307 *                         the program will go into trace mode\r
308 VECT    DS.L    1       ; vector to machine code\r
309 *       (only needed if the TRACE routine is resident)\r
310 \r
311 *       Registers used by the FORTH virtual machine:\r
312 *       Starting at $OOFO in the 6800, unneeded here:\r
313 *\r
314 * All of these are defined below, with explanation.\r
315 * W     RMB     NATWID  ; the instruction register remembers IP.\r
316 * IP    RMB     NATWID  ; the instruction pointer points to pointer to 6800 code\r
317 * RP    RMB     NATWID  ; the return stack pointer\r
318 * PSP   RMB     NATWID  ; the parameter stack pointer (Forth SP)\r
319 * UP    RMB     NATWID  ; the pointer to base of current user's 'USER' table\r
320 *               ( altered by a task switch )\r
321 *\r
322 GAP     EQU     *\r
323         DS.B    USERAL-(GAP-START)\r
324 *\r
325 UORIG   DS.L    3       ; 3 reserved variables\r
326 XSPZER  DS.L    1       ; initial top of data stack for this user\r
327 XRZERO  DS.L    1       ; initial top of return stack\r
328 XTIB    DS.L    1       ; start of terminal input buffer\r
329 XWIDTH  DS.L    1       ; name field width ****** could be byte\r
330 XWARN   DS.L    1       ; warning message mode (0 = no disc) ****** could be byte\r
331 XFENCE  DS.L    1       ; fence for FORGET\r
332 XDICTP  DS.L    1       ; dictionary pointer\r
333 XVOCL   DS.L    1       ; vocabulary linking\r
334 XBLK    DS.L    1       ; disc block being accessed\r
335 XIN     DS.L    1       ; scan pointer into the block ****** could be 16-bit\r
336 XOUT    DS.L    1       ; cursor position ****** could be 16-bit\r
337 XSCR    DS.L    1       ; disc screen being accessed ( O=terminal )\r
338 XOFSET  DS.L    1       ; disc sector offset for multi-disc\r
339 XCONT   DS.L    1       ; last word in primary search vocabulary\r
340 XCURR   DS.L    1       ; last word in extensible vocabulary\r
341 XSTATE  DS.L    1       ; flag for 'interpret' or 'compile' modes ****** could be byte?\r
342 XBASE   DS.L    1       ; number base for I/O numeric conversion ****** could be byte\r
343 XDPL    DS.L    1       ; decimal point place ****** could be 16-bit\r
344 XFLD    DS.L    1       ; conversion field ****** could be 16-bit\r
345 XCSP    DS.L    1       ; current stack position, for compile checks\r
346 XRNUM   DS.L    1       ; ****** could be 16-bit? \r
347 XHLD    DS.L    1       ; ****** could be 16-bit?\r
348 XDELAY  DS.L    1       ; carriage return delay count ****** could be byte\r
349 XCOLUM  DS.L    1       ; carriage width ****** could be 16-bit\r
350 IOSTAT  DS.L    1       ; last acia status from write/read ****** could be byte or 16-bit\r
351 *\r
352 *   end of user table, start of (theoretical) common system variables\r
353 *\r
354 * These need to be moved to where they will be \r
355 * initialized globals in variable space, not in the USER table.\r
356 * Or, more accurately, need to be turned into monitored or semaphored resources.\r
357 XUSE    DS.L    1\r
358 XPREV   DS.L    1\r
359         DS.L    2       ( spares )\r
360 *\r
361 XUCURR  DS.L    1       ; user table current allocation\r
362 *\r
363 XDEF    EQU     *\r
364         DS.B    USERAL-(XDEF-UORIG)     ; allocatable\r
365 *\r
366 *USERSZ EQU     *-UORIG\r
367         DS.B    USERAL*(USERCT-1)\r
368 *\r
369         PAGE\r
370 VOCFLG  EQU     $832020A0       ; flag (dummy) entry to switch vocabularies by.\r
371 *  These things, up through the label 'REND', are overwritten\r
372 *  at time of cold load and should have the same contents\r
373 *  as shown here:\r
374 *\r
375         EVEN\r
376 RBEG    EQU     *\r
377         DC.B    $C5     immediate\r
378         DC.B    'FORT'  ; 'FORTH'\r
379         DC.B    'H'|$80\r
380         DC.L    NOOP-5-NATWID\r
381 FORTH:  DC.L    DODOES,DOVOC,VOCFLG,TASK-5-NATWID\r
382         DC.L    0\r
383 *\r
384         DC.B    "Copyright 1979 Forth Interest Group, David Lion,"\r
385         DC.B    $0D\r
386         DC.B    "Parts Copyright 2019 Joel Matthew Rees"\r
387         DC.B    $0D\r
388 *\r
389         EVEN\r
390         DC.B    0\r
391         DC.B    $84\r
392         DC.B    'TAS'   ; 'TASK'\r
393         DC.B    'K'|$80\r
394         DC.L    FORTH-6-NATWID\r
395 TASK:   DC.L    DOCOL,SEMIS\r
396\r
397 REND    EQU     *       ( first empty location in dictionary )\r
398 RSIZE   EQU     *-RBEG  ; So we can look at it.\r
399         PAGE\r
400 ***\r
401 *\r
402 * CONVENTIONS USED IN THIS PROGRAM ARE AS FOLLOWS :\r
403 *\r
404 * IP points to the next FORTH VM instruction ( pre-increment mode )\r
405 IP      EQUR    A5      ; post-inc mode, as opposed to 6800 model.\r
406 * RP points to last return address pushed on return stack\r
407 RP      EQUR    A7      ; Yes, we are going to break with fig false traditions.\r
408 * PSP points to last item pushed on data (parameter) stack\r
409 PSP     EQUR    A6      ; SP is already defined as A7 on 68K.\r
410 * may conflict with using A6 as frame pointer? Not really.\r
411 * Note that 6800 S points one below last byte pushed. We don't have to do that.\r
412 *\r
413 * A5 must be IP when NEXT is entered (when using the inner loop).\r
414 *\r
415 *       D0 handles all of what is A:B on 6801/6809.\r
416 *\r
417 * UP (could be DP on 6809) is the base of per-task ("user") variables.\r
418 UP      EQUR    A3\r
419 * (Be careful of the stray semantics of "user".)\r
420 *\r
421 * W (hardware X) is the pointer to the "code field" address of native CPU\r
422 W       EQUR    A4 \r
423 * Points to pointer to machine code to be executed for the definition \r
424 * of the dictionary word to be executed/currently executing.\r
425 * The following natural integer (word) begins any "parameter section" \r
426 * (body) -- similar to a "this" pointer, but not the same.\r
427 * It may be native CPU machine code, or it may be a global variable, \r
428 * or it may be a list of Forth definition words (addresses).\r
429 *\r
430 * Since we have it, give it a handle. The execute vector:\r
431 * (Only valid until used elsewhere.)\r
432 VEC     EQUR    A2\r
433 *\r
434 * A0 and A1 used as scratch indexes.\r
435 * D0 through D7 used as scratch registers.\r
436 * Some related routines (for example, LOOP) use D0 as a shared parameter.\r
437 *\r
438 * Except that I want to keep this close to the fig model:\r
439 ** We've got the registers, might as well use 'em.\r
440 ** Defined for the I-level loop variables:\r
441 * LUPLIM        EQUR    D5      ; limit was pushed first, \r
442 * LUPCT EQUR    D4      ; then index/count\r
443 ** J-level is on the return stack.\r
444 *\r
445 * ======\r
446 * This implementation uses the indirect subroutine architecture \r
447 * -- a postponed-push call that the 6800 model VM also uses\r
448 * to save code and time in leaf routines. \r
449 *\r
450 * It won't allow mixing assembly language directly into Forth word lists.\r
451 * ======\r
452 *\r
453 * boolean flags:\r
454 * 0 is false, anything else is true.\r
455 * Most places in this model that set a boolean flag set true as 1.\r
456 * This is in contrast to many models that set a boolean flag as -1.\r
457 *\r
458 ***\r
459 \r
460 * The run-time dictionary allocation area begins here, \r
461 * initialized with the FORTH and TASK definitions that will be \r
462 * actually used.\r
463 \r
464 RTDICT  DS.B    RTDCSZ          ; dictionary allocation space\r
465 *\r
466 PSPSPC  EQU     256*NATWID      ; for the parameter stack\r
467         DS.B    PSPSPC\r
468 SPBUMP  EQU     4*NATWID\r
469 IPSP    DS.L    SPBUMP          ; initial PSP below, bumper zone above\r
470 *\r
471 * Don't want terminal input and parameter underflow collisions\r
472 TIBSZ   EQU     80              ; bytes of input buffer, must be even on 68000.\r
473 ITIB    DS.B    TIBSZ           ; Also, must match terminal width. (Bad design.)\r
474 *\r
475 * *** This is quite clearly a vulnerability! ***\r
476 SFTBND  EQU     *               ; (pseudo boundary between TIB and return stack)\r
477 *\r
478 RPSPAC  EQU     128*NATWID      ; for the return stack\r
479         DS.B    RPSPAC\r
480 RPBUMP  EQU     4*NATWID\r
481 IRP     DS.B    RPBUMP          ; initial RP below, bumper zone above\r
482 \r
483         PAGE\r
484 * Expecting 8K to 12K for the kernel, because pointers are 4 bytes.\r
485 VMBASE  EQU     *\r
486 \r
487 *   "ROMmable" init tables and pre-compiled dictionary\r
488 *\r
489 *    The FORTH interpreter will be organized\r
490 *    so that it can be in a ROM, or write-protected if desired,\r
491 * but right now we're just getting it running.\r
492 \r
493 * ######>> screen 3 <<\r
494 *\r
495 ***************************\r
496 **  C O L D   E N T R Y  **\r
497 ***************************\r
498 *\r
499 ORIG    NOP\r
500         BRA.W   CENT            ; ROMmable dictionary size is less than 32K\r
501 ***************************\r
502 **  W A R M   E N T R Y  **\r
503 ***************************\r
504         NOP\r
505         BRA.W   WENT    warm-start code, keeps current dictionary intact\r
506 \r
507 *\r
508 MAXNML  EQU     32      ; max name length of words (symbols) in the dictionary\r
509 NMLMSK  EQU     MAXNML-1        ; MAXNML must be a power of 2.\r
510 ******* startup parmeters **************************\r
511 *\r
512         DC.L    $68000,00000000 ; cpu & revision\r
513         DC.L    0               ; topmost word in FORTH vocabulary\r
514 * BACKSP        DC.L    $7F     ; backspace character for editing \r
515 BACKSP  DC.L    $08     ; backspace character for editing \r
516 UPINIT  DC.L    UORIG   ; initial user area\r
517 SINIT   DC.L    IPSP    ; initial top of data stack\r
518 RINIT   DC.L    IRP     ; initial top of return stack\r
519         DC.L    ITIB    ; terminal input buffer\r
520 IWIDTH  DC.L    MAXNML  ; initial name field width\r
521         DC.L    0       ; initial warning mode (0 = no disc)\r
522 FENCIN  DC.L    REND    ; initial fence\r
523 DPINIT  DC.L    REND    ; cold start value for DICTPT\r
524 BUFINT  DC.L    BUFBAS  ; Start of the disk buffers area        \r
525 VOCINT  DC.L    FORTH+4*NATWID  \r
526 COLINT  DC.L    TIBSZ   ; initial terminal carriage width\r
527 DELINT  DC.L    4       ; initial carriage return delay\r
528 ****************************************************\r
529 *\r
530 *\r
531         PAGE\r
532 *\r
533 * ######>> screen 13 <<\r
534 * These are of questionable use anyway, \r
535 * and are too much trouble to use with native subroutine call anyway.\r
536 *POPD0X MOVE.L  (PSP)+,D0       ; These may actually not end up being used.\r
537 *STD0X  MOVE.L  D0,(A0)\r
538 *       BRA.S   NEXT\r
539 *GETX   MOVE.L  (A0),D0\r
540 PUSHD0  MOVE.L  D0,-(PSP)       ; fall through to NEXT\r
541 \r
542 * "NEXT" takes ?? cycles if TRACE is removed,\r
543 *\r
544 * and ?? cycles if trace is present and NOT tracing.\r
545 *\r
546 * = = = = = = =   t h e   v i r t u a l   m a c h i n e   = = = = =\r
547 *                                                                 =\r
548 * NEXT itself might just completely go away.\r
549 * About the only reason to keep it is to allow executing a list\r
550 * which allows a cheap TRACE routine.\r
551 *\r
552 * NEXT is a loop which implements the Forth VM.\r
553 * It basically cycles through calling the code out of code lists,\r
554 * one at a time.\r
555 * Using a native CPU return for this uses a few extra cycles per call,\r
556 * compared to simply jumping to each definition and jumping back \r
557 * to the known beginning of the loop,\r
558 * but the loop itself is really only there for convenience,\r
559 * in the first place.\r
560\r
561 * This implementation uses indirect threading,\r
562 * leaving a wall between Forth VM code and non-Forth VM code.\r
563 *\r
564 NEXT:   ; IP is a register.\r
565 NEXT2   MOVE.L  (IP)+,W ; get W which points to CFA of word to be done\r
566 NEXT3   MOVE.L  (W)+,VEC        ; get characteristic address, point to Parameter Field.\r
567 * These NOPs can be patched at run-time to JMP TRACE              =\r
568 * if a TRACE routine is available:                                =\r
569 *       NOP                                                       =     \r
570 *       NOP                                                       =\r
571 *       NOP                                                       =\r
572 *       NOP                                                       =\r
573 *       NOP                                                       =\r
574         TST.W   TRACEM-UORIG(UP)                                  =\r
575         BEQ.S   NEXTJ                                             =\r
576         BSR.W   PTRACE                                            =\r
577 NEXTJ:  JSR     (VEC)                                             =\r
578         BRA.S   NEXT                                              =\r
579 * In other words, with the call and the NOP,\r
580 * there is room to patch the loop with a call to your TRACE \r
581 * routine, which you have to provide.\r
582 *                                                                 =\r
583 * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =\r
584 \r
585         PAGE\r
586 *\r
587 * ======>>  1  <<\r
588 * ( --- n )\r
589 * Pushes the following natural width integer from the instruction stream\r
590 * as a literal, or immediate value.\r
591 *\r
592 *       DC.L {OP}\r
593 *       DC.L {OP}\r
594 *       DC.L LIT\r
595 *       DC.L LITERAL-TO-BE-PUSHED\r
596 *       DC.L {OP}\r
597 *\r
598 * In native processor code, there should be a better way, use that instead.\r
599 * More specifically, DO NOT CALL THIS from assembly language code.\r
600 * (Note that there is no compile-only flag in the fig model.)\r
601 *\r
602 * See (FIND), or PFIND , for layout of the header format.\r
603 *\r
604         EVEN\r
605         DC.B    $83\r
606         DC.B    'LI'    ; 'LIT' :       NOTE: this is different from LITERAL\r
607         DC.B    'T'|$80 ; character code for T, with high bit set.\r
608         DC.L    0       ; link of zero to terminate dictionary scan\r
609 LIT     DC.L    *+NATWID        ; Note also that LIT is meaningless in native code.\r
610         MOVE.L  (IP)+,-(PSP)\r
611         RTS\r
612 *\r
613 * ######>> screen 14 <<\r
614 * ======>>  2  <<\r
615 * ( --- n )\r
616 * Save a little dictionary space by pushing a half-width value as a full-width value.\r
617 * LIT8 won't really work with the 68000 because of alignment problems,\r
618 * but LIT16 will save a little space.\r
619 * Pushes the following 16-bit word from the instruction stream\r
620 * as a literal, or immediate value.\r
621 *\r
622 * If this is kept, it should have a header for TRACE to read.\r
623 * If the data bus is wider than a byte, consider whether you want to do this.\r
624 * Byte shaving like this is often counter-productive anyway.\r
625 * Changing the name to LIT16, hoping that will be more understandable.\r
626 * Also, see comments for LIT: DO NOT CALL THIS from assembly language code.\r
627 * (Note that there is no compile-only flag in the fig model.)\r
628         EVEN\r
629         DC.B    $85\r
630         DC.B    'LIT1'  ; 'LIT16'       ; half a LIT\r
631         DC.B    '6'|$80\r
632         DC.L    LIT-4-NATWID\r
633 LIT16   DC.L    *+NATWID        ; (this was an invisible word, with no header)\r
634         CLR.L   -(PSP)          ; The fig model does not sign extend.\r
635         MOVE.W  (IP)+,NATWID/2(PSP)\r
636         RTS\r
637 *       CLR.L   D0              ; The fig model does not sign extend.\r
638 *       MOVE.W  (IP)+,D0\r
639 **NOT this:     BRA.W   PUSHD0\r
640 *       MOVE.L  D0,-(PSP)\r
641 *       RTS\r
642 *\r
643 * ======>>  3  <<\r
644 * ( adr --- )\r
645 * Jump to address on stack.  Used by the "outer" interpreter to\r
646 * interactively invoke routines.  \r
647 * Might be useful to have EXECUTE test the pointer, as done in BIF-6809.\r
648         EVEN\r
649         DC.B    $87\r
650         DC.B    'EXECUT'        ; 'EXECUTE'\r
651         DC.B    'E'|$80 ; $C5\r
652         DC.L    LIT16-6-NATWID\r
653 EXEC    DC.L    *+NATWID\r
654         MOVE.L  (PSP)+,W        ; Get the adr parameter.\r
655 *       LEA     NATWID(RP),RP   ; Dump the return\r
656 *       BRA.S   NEXT3           ; Sub it.\r
657         MOVE.L  (W)+,VEC        ; Or, pretend we are the inner interpreter\r
658         JMP     (VEC)           ; tail return\r
659 *       \r
660 *\r
661 * ######>> screen 15 <<\r
662 * ======>>  4  <<\r
663 * ( --- )                                                 C\r
664 * Add the following word from the instruction stream to the\r
665 * instruction pointer (Y++).  Causes a program branch in Forth code stream.\r
666 *\r
667 * In native processor code, there should be a better way, use that instead.\r
668 * More specifically, DO NOT CALL THIS from assembly language code.\r
669 * This is only for Forth code stream.\r
670 * Also, see comments for LIT.\r
671         EVEN\r
672         DC.B    0\r
673         DC.B    $86\r
674         DC.B    'BRANC' ; 'BRANCH'\r
675         DC.B    'H'|$80\r
676         DC.L    EXEC-8-NATWID\r
677 BRAN    DC.L    ZBYES   ; Go steal code in ZBRANCH\r
678 \r
679 * Moving code around to optimize the branch taking case in 0BRANCH.\r
680 ZBNO    LEA     NATWID(IP),IP ; No branch.\r
681         RTS\r
682 * ======>>  5  <<\r
683 * ( f --- )                                               C\r
684 * BRANCH if flag is zero.\r
685 *\r
686 * In native processor code, there should be a better way, use that instead.\r
687 * More specifically, DO NOT CALL THIS from assembly language code.\r
688 * This is only for Forth code stream.\r
689 * Also, see comments for LIT.\r
690         EVEN\r
691         DC.B    $87\r
692         DC.B    '0BRANC'        ; '0BRANCH'\r
693         DC.B    'H'|$80\r
694         DC.L    BRAN-7-NATWID\r
695 ZBRAN   DC.L    *+NATWID\r
696         TST.L   (PSP)+\r
697         BNE.S   ZBNO\r
698 ZBYES   MOVE.L  (IP)+,D0\r
699         LEA     (IP,D0.L),IP    ; IP is postinc\r
700         RTS\r
701 *\r
702 \r
703 * ######>> screen 16 <<\r
704 \r
705 * ======>>  6  <<\r
706 * ( --- )         ( limit index *** limit index+1)        C\r
707 *                 ( limit index *** )\r
708 * Counting loop primitive.  The counter and limit are the top two\r
709 * words on the return stack.  If the updated index/counter does\r
710 * not exceed the limit, a branch occurs.  If it does, the branch\r
711 * does not occur, and the index and limit are dropped from the\r
712 * return stack.\r
713 *\r
714 * Loop words share the counter increment via D0.\r
715 *\r
716 * In native processor code, there should be a better way, use that instead.\r
717 * More specifically, DO NOT CALL THIS from assembly language code.\r
718 * This is only for Forth code stream.\r
719 * Also, see comments for LIT.\r
720 * D0 and various code paths are shared with XPLOOP.\r
721 * Having to dodge the return address on the stack might be reason\r
722 * for loop variables in registers, but not yet.\r
723 LUPLIM  EQU     NATWID*2        ; limit was pushed first, \r
724 LUPCT   EQU     NATWID          ; then index/count\r
725\r
726         EVEN\r
727         DC.B    0\r
728         DC.B    $86\r
729         DC.B    '(LOOP' ; '(LOOP)'\r
730         DC.B    ')'|$80\r
731         DC.L    ZBRAN-8-NATWID\r
732 XLOOP   DC.L    *+NATWID\r
733         MOVEQ   #1,D0   ; Loop counter and limit in registers.\r
734 XLOOPA  ADD.L   LUPCT(RP),D0\r
735         MOVE.L  D0,LUPCT(RP)\r
736         CMP.L   LUPLIM(RP),D0\r
737         BMI.S   ZBYES   ; pseudo-signed-unsigned\r
738 XLOOPN  LEA     NATWID(IP),IP\r
739         MOVE.L  (RP),A0 ; Get the return to NEXT.\r
740         LEA     LUPLIM+NATWID(RP),RP    ; drop loop control variables\r
741         JMP     (A0)\r
742 *\r
743 * Notes for loop counter and limit in registers:\r
744 *       MOVEQ   #1,D0   ; Loop counter and limit in registers.\r
745 * XLOOPA        ADD.L   D0,LUPCT\r
746 *       CMP.L   LUPLIM,LUPCT\r
747 *       BMI.S   ZBYES   ; pseudo-signed-unsigned\r
748 * XLOOPN        LEA     NATWID(IP),IP\r
749 *       MOVEM.L (RP)+,LUPLIM/LUPCT      ; restore possible outer loop controls\r
750 *       RTS     \r
751 *\r
752 * ======>>  7  <<\r
753 * ( n --- )       ( limit index *** limit index+n )       C\r
754 *                 ( limit index *** )\r
755 * Loop with a variable increment.  Terminates when the index\r
756 * crosses the boundary from one below the limit to the limit.  A\r
757 * positive n will cause termination if the result index equals the\r
758 * limit.  A negative n must cause the index to become less than\r
759 * the limit to cause loop termination.\r
760 *\r
761 * Note that the end conditions are not symmetric around zero.\r
762 *\r
763 * In native processor code, there should be a better way, use that instead.\r
764 * More specifically, DO NOT CALL THIS from assembly language code.\r
765 * This is only for Forth code stream.\r
766 * Also, see comments for LIT.\r
767 * D0 and various code paths are shared with XLOOP.\r
768         EVEN\r
769         DC.B    $87\r
770         DC.B    '(+LOOP'        ; '(+LOOP)'\r
771         DC.B    ')'|$80\r
772         DC.L    XLOOP-7-NATWID\r
773 XPLOOP  DC.L    *+NATWID        ; Loop counter and limit in registers.\r
774         MOVE.L  (PSP)+,D0       ; inc val\r
775         BPL.S   XLOOPA          ; Steal plain loop code for forward count.\r
776         ADD.L   LUPCT(RP),D0\r
777         MOVE.L  D0,LUPCT(RP)\r
778         CMP.L   LUPLIM(RP),D0\r
779         BPL.S   ZBYES           ; pseudo-signed-unsigned\r
780         BRA.S   XLOOPN          ; This path might be less time-sensitive.\r
781 *\r
782 * Notes for loop counter and limit in registers:\r
783 *       MOVE.L  (PSP)+,D0       ; inc val\r
784 *       BPL.S   XLOOPA          ; Steal plain loop code for forward count.\r
785 *       ADD.L   D0,LUPCT\r
786 *       CMP.L   LUPLIM,LUPCT\r
787 *       BPL.S   ZBYES           ; pseudo-signed-unsigned\r
788 *       BRA.S   XLOOPN          ; This path might be less time-sensitive.\r
789 *\r
790 * ######>> screen 17 <<\r
791 * ======>>  8  <<\r
792 * ( limit index --- )     ( *** outerlimit outerindex )\r
793 * Save whatever is in limit and index registers, Load the loop parameters. \r
794 * This would NOT be a synonym for D>R (2>R) if we were keeping the control variables in registers.\r
795         EVEN\r
796         DC.B    0\r
797         DC.B    $84\r
798         DC.B    '(DO'   ; '(DO)'\r
799         DC.B    ')'|$80\r
800         DC.L    XPLOOP-8-NATWID\r
801 XDO     DC.L    *+NATWID        ; This is the RUNTIME DO, not the COMPILING DO\r
802         MOVEM.L (PSP)+,D0/D1    ; MOVEM preserves the order.\r
803         MOVE.L  (RP)+,A0        ; get the return to NEXT out of the way.\r
804         MOVEM.L D0/D1,-(RP)     ; Control variables are now on the return stack.\r
805         JMP     (A0)            ; Back to NEXT\r
806 *\r
807 * Notes for loop counter and limit in registers:\r
808 *       MOVE.L  (RP)+,A0        ; Get the reurn to NEXT out of the way\r
809 *       MOVEM.L LUPLIM/LUPCT,-(RP)      ; save possible outer loop limit and count\r
810 *       MOVEM.L (PSP)+,LUPLIM/LUPCT     ; limit must be higher register number to be deeper in stack. \r
811 *       JMP     (A0)    ; Back to NEXT\r
812 *\r
813 * ======>>  9  <<\r
814 * ( --- index )           ( limit index *** limit index )\r
815 * Copy the loop index from the index register. \r
816 * This would NOT be a synonym for R if we were keeping the control variables in registers.\r
817         EVEN\r
818         DC.B    $81\r
819         DC.B    'I'|$80 ; I\r
820         DC.L    XDO-5-NATWID    \r
821 I       DC.L    *+NATWID\r
822         MOVE.L  LUPCT(RP),-(PSP)        ; hide dodge in LUPCT\r
823         RTS\r
824 *\r
825 * Notes for loop counter and limit in registers:\r
826 *       MOVE.L  LUPCT,-(PSP)    ; nothing to dodge\r
827 *       RTS\r
828 *\r
829 * ######>> screen 18 <<\r
830 * ======>>  10  <<\r
831 * ( c base --- false )\r
832 * ( c base --- n true )\r
833 * Translate C in base, yielding a translation valid flag.  \r
834 * If the translation is not valid in the specified base,\r
835 * only the false flag is returned.\r
836         EVEN\r
837         DC.B    $85\r
838         DC.B    'DIGI'  ; 'DIGIT'\r
839         DC.B    'T'|$80\r
840         DC.L    I-2-NATWID\r
841 DIGIT   DC.L    *+NATWID        ; NOTE: legal input range is 0-9, A-Z\r
842         MOVE.L  NATWID(PSP),D0  ; Check the whole 32 bits.\r
843         CMP.L   #'Z',D0         ; Allow byte width from here.\r
844         BHI.S   DIGITN\r
845         SUB.L   #'0',D0         ; ascii zero\r
846         BLO.S   DIGITN          ; IF LESS THAN '0', ILLEGAL\r
847         CMP.B   #9,D0\r
848         BLS.S   DIGITB          ; IF '9' OR LESS\r
849         SUB.B   #'A'-('9'+1),D0 ; translate 'A' thru 'Z'\r
850         CMP.B   #$A,D0          ; between '9' and 'A'?\r
851         BLO.S   DIGITN          ; if less than 'A'\r
852 DIGITB  CMP.B   NATWID-1(PSP),D0        ; Check the base.\r
853         BHS.S   DIGITN          ; error if not less than the base\r
854         MOVE.L  D0,NATWID(PSP)  ; Store converted digit. (High bytes known zero.)\r
855         MOVE.L  #1,(PSP)        ; store valid flag \r
856         RTS\r
857 DIGITN  LEA     NATWID(PSP),PSP ; pop base\r
858         MOVE.L  #0,(PSP)        ; set not valid flag\r
859         RTS\r
860 *\r
861 * ######>> screen 19 <<\r
862 *\r
863 * The word definition format in the dictionary:\r
864 *\r
865 * (Symbol names are bracketed by bytes with the high bit set, rather than linked.)\r
866 *\r
867 * EVEN address alignment on 68K.\r
868 * Optional byte of zero for odd name fields on 68K.\r
869 * NFA (name field address):\r
870 * char-count + $80      Length of symbol name, flagged with high bit set.\r
871 * char 1                Characters of symbol name.\r
872 * char 2\r
873 * ...\r
874 * char n  + $80      symbol termination flag (char set < 128 code points)\r
875 * LFA (link field address):\r
876 * link high byte \\r
877 * ... inner byte  \___pointer to previous word in list\r
878 * ... inner byte  /   (List is combined allocation/dictionary list.)\r
879 * link low byte  /\r
880 * CFA (code field address):\r
881 * CFLD high byte \\r
882 * ... inner byte  \___pointer to native CPU machine code\r
883 * ... inner byte  /   -- Consider this the characteristic code. --\r
884 * CFLD low byte  /\r
885 * PFA (parameter field address):\r
886 * parameter fields   -- Machine code for low-level native machine CPU code,\r
887 *    "                  instruction list for high-level Forth code,\r
888 *    "                  constant data for constants, pointers to per task variables,\r
889 *    "                  space for variables, for global variables, etc.\r
890 *\r
891 * In the case of native CPU machine code, the address at CFA (the code field) will be PFA.\r
892 \r
893 * Definition attributes:\r
894 FIMMED  EQU     $40     ; Immediate word flag.\r
895 FSMUDG  EQU     $20     ; Smudged => definition not ready.\r
896 CTMASK  EQU     ($FF&(~($80|FIMMED)))   ; For unmasking the length byte.\r
897 * Note that the SMUDGE bit is not masked out.\r
898 *\r
899 * But we really want more flags (Thinking for a new model, need one more byte):\r
900 * FCOMPI        EQU     $10     ; Compile-time-only.\r
901 * FASSEM        EQU     $08     ; Assembly-language code only.\r
902 * F4THLV        EQU     $04     ; Must not be called from assembly language code.\r
903 * These would require some significant adjustments to the model.\r
904 * We also want to put the low-level VM stuff in its own vocabulary, eventually.\r
905 *\r
906 * ======>>  11  <<\r
907 * (FIND)  ( name vocptr --- locptr length true )\r
908 *         ( name vocptr --- false )\r
909 * Search vocabulary for a symbol called name. \r
910 * name is a pointer to a high-bit bracketed string with length head.\r
911 * vocptr is a pointer to the NFA of the tail-end (LATEST) definition \r
912 * in the vocabulary to be searched.\r
913 * Hidden (SMUDGEd) definitions are lexically not equal to their name strings.\r
914 * Use the stack and registers instead of temp area N.\r
915 PA0     EQU     NATWID  ; pointer to the length byte of name being searched against\r
916 YPA0    EQUR    A2      ; ditto\r
917 PD      EQU     0       ; pointer to NFA of dict word being checked\r
918 XPD     EQUR    A1      ; ditto\r
919         EVEN\r
920         DC.B    0\r
921         DC.B    $86\r
922         DC.B    '(FIND' ; '(FIND)'\r
923         DC.B    ')'|$80\r
924         DC.L    DIGIT-6-NATWID\r
925 PFIND   DC.L    *+NATWID\r
926         MOVE.L  PD(PSP),XPD     ; Start in on the vocabulary (NFA).\r
927 PFNDLP  MOVE.L  PA0(PSP),YPA0   ; Point to the name to check against.\r
928         MOVE.B  (XPD)+,D1       ; get dict name length byte\r
929         MOVE.B  D1,D0           ; Save it in case it matches.\r
930         AND.B   #CTMASK,D1 \r
931         CMP.B   (YPA0)+,D1      ; Compare lengths\r
932         BNE.S   PFNDUN\r
933 PFNDBR  MOVE.B  (XPD)+,D1       ; Is high bit of character in dictionary entry set?\r
934         BPL.S   PFNDCH\r
935         AND.B   #$7F,D1         ; Clear high bit in char from dictionary.\r
936         CMP.B   (YPA0)+,D1      ; Compare "last" characters.\r
937         BEQ.S   PFOUND          ; Matches even if dictionary actual length is shorter.\r
938 PFNDLN  MOVE.L  (XPD)+,D0       ; Get previous link in vocabulary. (Note flag entry to switch vocabularies by.)\r
939         MOVE.L  D0,XPD          ; On 68K, flags not in effect for MOVEA, TST not available, and this is what we wanted.\r
940         BNE.S   PFNDLP          ; Continue if link not=0\r
941 *\r
942 *       not found :\r
943         LEA     NATWID(PSP),PSP ; Return only false flag.\r
944         CLR.L   (PSP)\r
945         RTS\r
946 *\r
947 PFNDCH  CMP.B   (YPA0)+,D1      ; Compare characters.\r
948         BEQ.S   PFNDBR\r
949 PFNDUN:\r
950 PFNDSC  MOVE.B  (XPD)+,D1       ; scan forward to end of this name in dictionary\r
951         BPL.S   PFNDSC\r
952         BRA.S   PFNDLN\r
953 *\r
954 *       found :\r
955 *\r
956 PFOUND  LEA     2*NATWID(XPD),XPD       ; point to parameter field\r
957         MOVE.L  XPD,NATWID(PSP)\r
958         CLR.L   D1              ; make sure count is valid\r
959         MOVE.B  D0,D1\r
960         MOVE.L  D1,(PSP)\r
961         MOVEQ   #1,D1           ; set a true flag\r
962         MOVE.L  D1,-(PSP)\r
963         RTS\r
964 *\r
965 * ######>> screen 20 <<\r
966 * ======>>  12  <<\r
967 * ( buffer ch --- buffer symboloffset delimiteroffset scancount )\r
968 * ( buffer ch --- buffer symboloffset nuloffset scancount ) ( Scan count == nuloffset )\r
969 * ( buffer ch --- buffer nuloffset onepast scancount )\r
970 * Scan buffer for a symbol delimited by ch or ASCII NUL, \r
971 * return the length of the buffer region scanned,\r
972 * the offset to the trailing delimiter,\r
973 * and the offset of the first character of the symbol. \r
974 * Leave the buffer on the stack.\r
975 * Scancount is also offset to first character not yet looked at.\r
976 * If no symbol in buffer, scancount and symboloffset point to NUL\r
977 * and delimiteroffset points one beyond for some reason. \r
978 * On trailing NUL, delimiteroffset == scancount.\r
979 * (Buffer is the address of the buffer array to scan.)\r
980 * (This is a bit too tricky, really.)\r
981 * NOTE :\r
982 * FC means offset (bytes) to First Character of next word\r
983 * EW  "     "   to End of Word\r
984 * NC  "     "   to Next Character to start next enclose at\r
985         EVEN\r
986         DC.B    $87\r
987         DC.B    'ENCLOS'        ; 'ENCLOSE'\r
988         DC.B    'E'|$80\r
989         DC.L    PFIND-7-NATWID\r
990 ENCLOS  DC.L    *+NATWID\r
991         MOVE.B  NATWID-1(PSP),D0        ; Delimiter character to match against in D0.\r
992         MOVE.L  NATWID(PSP),A0  ; Buffer to scan in.\r
993         CLR.L   D1              ; Initialize offset. (No particular limit on Buffer width.)\r
994 *       Scan to a non-delimiter or a NUL\r
995 ENCDEL  TST.B   (A0,D1.W)               ; NUL ?\r
996         BEQ.S   ENCNUL\r
997         CMP.B   (A0,D1.W),D0    ; Delimiter?\r
998         BNE.S   ENC1ST\r
999         ADDQ.L  #1,D1           ; count character\r
1000         BRA.S   ENCDEL\r
1001 *       Found first character. Save the offset.\r
1002 ENC1ST  MOVE.L  D1,(PSP)        ; Found first non-delimiter character -- store the count.\r
1003 *       Scan to a delimiter or a NUL\r
1004 ENCSYM  TST.B   (A0,D1.W)       ; NUL ?\r
1005         BEQ.S   ENC0TR\r
1006         CMP.B   (A0,D1.W),D0    ; delimiter?\r
1007         BEQ.S   ENCEND\r
1008         ADDQ.L  #1,D1\r
1009         BRA.S   ENCSYM\r
1010 *       Found end of symbol. Push offset to delimiter found.\r
1011 ENCEND  MOVE.L  D1,-(PSP)       ; Offset to seen delimiter.\r
1012 *       Advance and push address of next character to check.\r
1013         ADDQ.L  #1,D1   ; one past \r
1014         MOVE.L  D1,-(PSP)\r
1015         RTS\r
1016 *       Found NUL before non-delimiter, therefore there is no word\r
1017 ENCNUL  MOVE.L  D1,(PSP)        ; offset to NUL.\r
1018         ADDQ.L  #1,D1           ; Point after NUL to allow (FIND) to match it.\r
1019         MOVE.L  D1,-(PSP)       ;\r
1020         SUBQ.L  #1,D1           ; Next is not passed NUL.\r
1021         MOVE.L  D1,-(PSP)       ; Stealing code will save only one byte.\r
1022         RTS\r
1023 *       Found NUL following the word instead of delimiter.\r
1024 ENC0TR\r
1025         MOVE.L  D1,-(PSP)       ; Save offset to first after symbol (NUL)\r
1026         MOVE.L  D1,-(PSP)       ; and count scanned.\r
1027         RTS\r
1028 *\r
1029         PAGE\r
1030 *\r
1031 * ######>> screen 21 <<\r
1032 * The next 4 words call system dependant I/O routines\r
1033 * which are listed after word "-->" ( label: "arrow" )\r
1034 * in the dictionary.\r
1035 *\r
1036 * ======>>  13  <<\r
1037 * ( c --- )\r
1038 * Write c to the output device (screen or printer).\r
1039 ******* Need to write this for the ST ROM BIOS.\r
1040 ******* Probably want to go ahead and define PEMIT, PKEY, PQTER, and PCR.\r
1041 ******* Also might want to tune UORIG variable sizes.\r
1042 ******* Need to find a way to set default operand size to Long.\r
1043 * ROM Uses the ECB device number at address $6F,\r
1044 * -2 is printer, 0 is screen.\r
1045         EVEN\r
1046         DC.B    0\r
1047         DC.B    $84\r
1048         DC.B    'EMI'   ; 'EMIT'\r
1049         DC.B    'T'|$80\r
1050         DC.L    ENCLOS-8-NATWID\r
1051 EMIT    DC.L    *+NATWID\r
1052         MOVE.L  (PSP)+,D1\r
1053         BSR.W   PEMIT   ; PEMIT expects the character in D1.\r
1054         ADDQ.L  #1,XOUT-UORIG(UP)       ; Bump the output count.\r
1055 EMITDN  RTS\r
1056 *\r
1057 * ======>>  14  <<\r
1058 * ( --- c )\r
1059 * ( --- BREAK )\r
1060 * Wait for a key from the keyboard. \r
1061 * If the key is BREAK, set the high byte (result $FF03).\r
1062         EVEN\r
1063         DC.B    $83\r
1064         DC.B    'KE'    ; 'KEY'\r
1065         DC.B    'Y'|$80\r
1066         DC.L    EMIT-5-NATWID\r
1067 KEY     DC.L    *+NATWID\r
1068         BSR.W   PKEY    ; PKEY leaves the scancode|key/break in D1.\r
1069         AND.L   #$000000FF,D1\r
1070         MOVE.L  D1,-(PSP)\r
1071         RTS\r
1072 *\r
1073 * ======>>  15  <<\r
1074 * ( --- f )\r
1075 * Scan keyboard, but do not wait.  \r
1076 * Return 0 if no key,\r
1077 * BREAK ($ff03) if BREAK is pressed,\r
1078 * or key currently pressed.     \r
1079         EVEN\r
1080         DC.B    $89\r
1081         DC.B    '?TERMINA'      ; '?TERMINAL'\r
1082         DC.B    $CC\r
1083         DC.L    KEY-4-NATWID\r
1084 QTERM   DC.L    *+NATWID\r
1085         BSR.W   PQTER   ; PQTER leaves the flag/key in D1.\r
1086         MOVE.L  D1,-(PSP)\r
1087         RTS\r
1088 *\r
1089 * ======>>  16  <<\r
1090 * ( --- )\r
1091 * EMIT a Carriage Return (ASCII CR).\r
1092         EVEN\r
1093         DC.B    0\r
1094         DC.B    $82\r
1095         DC.B    'C'     ; 'CR'\r
1096         DC.B    'R'|$80\r
1097         DC.L    QTERM-10-NATWID\r
1098 CR      DC.L    *+NATWID\r
1099         BSR.W   PCR     ; Nothing really to do here.\r
1100         RTS\r
1101 *\r
1102 * ######>> screen 22 <<\r
1103 * ======>>  17  <<\r
1104 * ( source target count --- )\r
1105 * Copy/move count bytes from source to target.  \r
1106 * Moves ascending addresses,\r
1107 * so that overlapping only works if the source is above the destination.\r
1108 * CMOVE provides a nice testbed for the intersection between clever and real.\r
1109 * It also raises questions about why one might want to move all of memory.\r
1110 * The 68000 DBF instruction only does up to 2^16 moves, which is probably a reasonable limit;\r
1111 * but, rather than answer that question and/or the logic of split count, use a straight count.\r
1112         EVEN\r
1113         DC.B    $85\r
1114         DC.B    'CMOV'  ; 'CMOVE' :     source, destination, count\r
1115         DC.B    'E'|$80\r
1116         DC.L    CR-3-NATWID\r
1117 CMOVE   DC.L    *+NATWID\r
1118         MOVEM.L (PSP)+,D1/A0/A1 ; No effect in flags.\r
1119         TST.L   D1      ; Don't let zero count equal 2^32.\r
1120 *NOT    BEQ.W   NEXT    ; Stack clean.\r
1121         BEQ.S   CMOVEX  ; Stack clean.\r
1122 CMOVEL  MOVE.B  (A1)+,(A0)+\r
1123         SUBQ.L  #1,D1\r
1124         BNE.S   CMOVEL\r
1125 CMOVEX  RTS\r
1126 *\r
1127 **      One possible way to use DBcc (untested):\r
1128 *       MOVEM.L (PSP)+,D1/A0/A1 ; No effect in flags.\r
1129 *       TST.L   D1      ; Don't let zero count equal 2^32.\r
1130 *       BEQ.L   CMOVEX  ; Stack clean.\r
1131 *       SUBQ.W  #1,D1   ; Adjust for DBcc\r
1132 *CMOVEL MOVE.B  (A1)+,(A0)+\r
1133 *       DBF     D1,CMOVEL\r
1134 *       SUB.L   #$10000,D1\r
1135 *       BCC.S   CMOVEL\r
1136 *CMOVEX RTS     ;\r
1137 *\r
1138 * ( source target count --- )\r
1139 * Copy/move count bytes from source to target.  \r
1140 * Moves descending addresses,\r
1141 * so that overlapping does work if the source is below the destination.\r
1142 * And, conversely, does not work if the source is above the destination.\r
1143 * Not in fig, provided here for aligning header names in CREATE.\r
1144         EVEN\r
1145         DC.B    0\r
1146         DC.B    $86\r
1147         DC.B    'CMOVE' ; 'CMOVED' :    source, destination, count\r
1148         DC.B    'D'|$80\r
1149         DC.L    CMOVE-6-NATWID\r
1150 CMOVD   DC.L    *+NATWID\r
1151         MOVEM.L (PSP)+,D1/A0/A1 ; No effect in flags.\r
1152         TST.L   D1      ; Don't let zero count equal 2^32.\r
1153 *NOT    BEQ.W   NEXT    ; Stack clean.\r
1154         BEQ.S   CMOVDX  ; Stack clean.\r
1155         LEA     (A1,D1.L),A1    ; Point to (one past) the ends.\r
1156         LEA     (A0,D1.L),A0\r
1157 CMOVDL  MOVE.B  -(A1),-(A0)\r
1158         SUBQ.L  #1,D1\r
1159         BNE.S   CMOVDL\r
1160 CMOVDX  RTS\r
1161 * Could use MOVE.B      (A1,D0.L),(A0,D0.L), too, but that would take extra cycles.\r
1162 *\r
1163 * ######>> screen 23 <<\r
1164 * ======>>  18  <<\r
1165 * ( u1 u2 --- ud )\r
1166 * Multiplies the top two unsigned integers,\r
1167 * yielding a double integer product.\r
1168 * Word at a time, but significantly faster than bit-at-a-time.\r
1169         EVEN\r
1170         DC.B    0\r
1171         DC.B    $82\r
1172         DC.B    'U'     ; 'U*'\r
1173         DC.B    '*'|$80\r
1174         DC.L    CMOVD-7-NATWID\r
1175 USTAR   DC.L    *+NATWID\r
1176         MOVEM.W (PSP),D0/D1/D2/D3       ; MOVEM is a cheap way to split the low and high words.\r
1177         MULU.W  D3,D1           ; U2 low by U1 low, and it's in place\r
1178         MULU.W  D2,D0           ; U2 high by U1 high, and it's in place\r
1179         MULU.W  NATWID/2(PSP),D2        ; U1 high by U2 low\r
1180         MULU.W  (PSP),D3        ; U1 low by U2 high\r
1181         ADD.L   D3,D2           ; sum of inner products\r
1182         CLR.L   D3              ; X-carry is not affected\r
1183         ADDX.L  D3,D3           ; grab the X-carry (no ADDX #0!)\r
1184         SWAP    D3              ; move the carry into place\r
1185         SWAP    D2              ; fast 16 bit rotate\r
1186         MOVE.W  D2,D3           ; high half of inner product, carry in place\r
1187         AND.L   #$FFFF0000,D2   ; low half of inner product\r
1188         ADD.L   D2,D1\r
1189         ADDX.L  D3,D0           ; along with both carries!\r
1190         MOVEM.L D0/D1,(PSP)     ; stack is as we want it.\r
1191         RTS\r
1192 *\r
1193 *\r
1194 * ######>> screen 24 <<\r
1195 * ======>>  19  <<\r
1196 * ( ud u --- uremainder uquotient )\r
1197 * Divides the top unsigned integer\r
1198 * into the second and third words on the stack\r
1199 * as a single unsigned double integer,\r
1200 * leaving the remainder and quotient (quotient on top)\r
1201 * as unsigned integers.\r
1202 *\r
1203 * The reason for this oddity is that U/ was intended to be the inverse of U* :\r
1204 * in other words, \r
1205 * U/ can only divide without overflow if the dividend is the result of \r
1206 * the divisor multiplied by the quotient using U* , \r
1207 * with an added constant less than the divisor (the remainder portion).\r
1208 *\r
1209 * This is particularly useful in columnar division,\r
1210 * when the divisor fits within the defined column:\r
1211 *               \r
1212 *    The smaller the divisor, the more likely dropping the high word \r
1213 *    of the quotient loses significant bits. See M/MOD .\r
1214 *\r
1215 * An example of a dividend/divisor pair that would not work:\r
1216 * HEX 200000000 2 U/\r
1217 * -- The largest multiple of 2 that U* could produce in a 32-bit environment would be\r
1218 * HEX 1FFFFFFFE\r
1219 * Thus, HEX 1FFFFFFFF would be the maximum 64-bit number\r
1220 * that U/ would divide by 2 without overflow.\r
1221 *\r
1222 * Note (from M/MOD) that U/ can be chained, as long as the divisor is single-width.\r
1223 *\r
1224 * For a library routine, I would probably want to run-time optimize the divide,\r
1225 * following four paths:\r
1226 * If divisor is zero, (1) give saturation result of max quotient, max remainder --\r
1227 * else if divisor fits in 16 bits, \r
1228 *   if dividend fits in 16 bits, (2) use native DIVU --\r
1229 *   else (3) use chained native DIVU (can be one less than full divide);\r
1230 * else, (4) for each 16-bit column,\r
1231 *   use native DIVU to guess high word of quotient\r
1232 *   multiply and subtract intermediate product\r
1233 *   if too guess too large, decrement guess and add divisor to get remainder\r
1234 *   shift to the next right column\r
1235 * But light testing would not be sufficient.\r
1236 * Each path would need to be tested against its next more optimal path.\r
1237 * And the resulting routine could be full M/MOD, if paths 3 and 4 are fully worked out.\r
1238 *\r
1239 * For now, for the fig model --\r
1240         EVEN\r
1241         DC.B    0\r
1242         DC.B    $82\r
1243         DC.B    'U'     ; 'U/'\r
1244         DC.B    '/'|$80\r
1245         DC.L    USTAR-3-NATWID\r
1246 USLASH:\r
1247         DC.L    *+NATWID\r
1248         MOVEM.L (PSP),D0/D1/D2  ; divisor in D0\r
1249         TST.L   D0              ; divisor 0?\r
1250         BEQ.S   USL0            ; dodge divide-by-zero exception\r
1251         CMP.L   #$10000,D0      ; 16-bit divisor?\r
1252         BHS.S   USLD32          ; no, can't use the easy way\r
1253         TST.L   D1              ; dividend greater than 32-bit?\r
1254         BNE.S   USLH64          ; handle the high word\r
1255         DIVU.W  D0,D2           ; result remainder in high 16 bits ; about ~140\r
1256         MOVE.L  D2,D1           ; Move the results into place.\r
1257         SWAP    D1\r
1258         AND.L   #$FFFF,D1       ; only the remainder\r
1259         AND.L   #$FFFF,D2       ; only the quotient\r
1260         BRA.S   BSLR\r
1261 USLH64:\r
1262 USLD32:\r
1263         BRA.S   BSLENT          ; bail for now\r
1264 USL0    MOVE.L  D2,D1           ; dividend low word as remainder\r
1265         MOVEQ.L #-1,D2          ; saturated quotient\r
1266         BRA.S   BSLR\r
1267         \r
1268 \r
1269 *\r
1270         EVEN\r
1271         DC.B    0\r
1272         DC.B    $82\r
1273         DC.B    'B'     ; 'B/'\r
1274         DC.B    '/'|$80\r
1275         DC.L    USLASH-3-NATWID\r
1276 * Using the bit divide to reduce testing burden, working in registers.\r
1277 BSLASH:\r
1278         DC.L    *+NATWID\r
1279         MOVEM.L (PSP),D0/D1/D2  ; D1:D2 by D0   (40~ ignore attempts to count cycles)\r
1280 BSLENT:\r
1281         MOVE.W  #32,D3  ; bit ct for DBcc       (8~)\r
1282 BSLDIV:\r
1283         CMP.L   D0,D1   ; divisor               (6~)\r
1284         BHS.S   BSLSUB                          (8/10~)\r
1285         AND     #~F_EXT,CCR     ; X-carry clear         (20~)\r
1286         BRA.S   BSLBIT                          (10~)\r
1287 BSLSUB:\r
1288         SUB.L   D0,D1                           (6~)\r
1289         OR      #F_EXT,CCR      ; quotient, (X-carry set)       (20~)\r
1290 BSLBIT:\r
1291         ROXL.L  #1,D2   ; save it               (8~)\r
1292         DBF     D3,BSLMOR       ; more bits? Don't mess with CCR        ((12/14)/10~)\r
1293 BSLR:\r
1294         LEA     NATWID(PSP),PSP                 (8~)\r
1295         MOVE.L  D1,NATWID(PSP)                  (16~)\r
1296         MOVE.L  D2,(PSP)                        (12~)\r
1297         RTS\r
1298 BSLMOR\r
1299         ROXL.L  #1,D1   ; remainder             (8~)\r
1300         BCC.S   BSLDIV                          (8/10~)\r
1301         BRA.S   BSLSUB                          (10~)   (~90*32=~2880+entry+exit, about 800 Î¼S at 4 MHz)\r
1302 \r
1303 * The following is not yet functional, only here to help me remember:\r
1304 * cUSLASH       DC.L    *+NATWID\r
1305 *       MOVE.W  (PSP)+,D0\r
1306 *       BNE     USL32\r
1307 *       MOVE.W  (PSP)+,D0       ; stack pre-adjusted\r
1308 *       BNE     USL16   ; avoid DIV by 0 exception\r
1309 *       MOVE.L  #-1,(PSP)       ; quotient too large\r
1310 *       MOVE.L  #-1,NATWID(PSP) ; remainder too large\r
1311 *       RTS\r
1312 * cUSL16        CLR.L   D1\r
1313 *       MOVE.W  (PSP),D1        ; start with highest half\r
1314 *       DIVU.W  D0,D1           ; can't overflow\r
1315 *       MOVE.W  D1,(PSP)        ; remainder in high half\r
1316 *       MOVE.W  NATWID/2(PSP),D1        ; 2nd half\r
1317 *       DIVU.W  D0,D1\r
1318 *       MOVE.W  D1,NATWID/2(PSP)\r
1319 *       MOVE.W  NATWID(PSP),D1          ; 3rd half\r
1320 *       DIVU.W  D0,D1\r
1321 *       MOVE.W  D1,NATWID(PSP)\r
1322 *       MOVE.W  3*NATWID/2(PSP),D1      ; lowest half\r
1323 *       DIVU.W  D0,D1                   ; (140~) (~140*4=560+smallstuff)\r
1324 *       MOVE.W  D1,3*NATWID/2(PSP)      \r
1325 *       CLR.W   D1\r
1326 *       SWAP.W  D1\r
1327 *       RTS\r
1328 * cUSL32\r
1329 *\r
1330 * Following the 6809 code, working on the stack.\r
1331 * Untested:\r
1332 * B0USLASH:\r
1333 *       DC.L    *+NATWID\r
1334 *       MOVE.W  #33,D3  ; bit ct\r
1335 *       MOVE.L  NATWID(PSP),D2  ; dividend\r
1336 * B0USLDIV:\r
1337 *       CMP.L   (PSP),D2        ; divisor\r
1338 *       BHS.S   B0USLSUB\r
1339 *       AND     #~F_EXT,CCR     ; X-carry clear\r
1340 *       BRA.S   B0USLBIT\r
1341 * B0USLSUB:\r
1342 *       SUB.L   (PSP),D2\r
1343 *       OR      #F_EXT,CCR      ; quotient, (X-carry set)\r
1344 * B0USLBIT:\r
1345 *       ROXL.W  2*NATWID+NATWID/2(PSP)  ; save it\r
1346 *       ROXL.W  2*NATWID(PSP)           ; in memory has only 16-bit by 1 bit form\r
1347 *       SUBQ.W  #1,D3   ; more bits?\r
1348 *       BEQ.S   B0USLR\r
1349 *       ROXL.L  D2      ; remainder\r
1350 *       BCC.S   B0USLDIV\r
1351 *       BRA.S   B0USLSUB\r
1352 * B0USLR:\r
1353 *       LEA     NATWID(PSP),PSP\r
1354 *       MOVE.L  NATWID(PSP),D1\r
1355 *       MOVEM.L D1/D2,(PSP)\r
1356 *       RTS\r
1357 *\r
1358 \r
1359         PAGE\r
1360 * ######>> screen 25 <<\r
1361 * ======>>  20  <<\r
1362 * ( n1 n2 --- n )\r
1363 * Bitwise and the top two integers.\r
1364         EVEN\r
1365         DC.B    $83\r
1366         DC.B    'AN'    ; 'AND'\r
1367         DC.B    "D"|$80\r
1368 *       DC.L    I-2-NATWID      ; ***** debug link *****\r
1369         DC.L    BSLASH-3-NATWID ; correct link\r
1370 AND     DC.L    *+NATWID\r
1371         MOVE.L  (PSP)+,D0\r
1372         AND.L   D0,(PSP)\r
1373         RTS\r
1374 *\r
1375 * ======>>  21  <<\r
1376 * ( n1 n2 --- n )\r
1377 * Bitwise or the top two integers.\r
1378         EVEN\r
1379         DC.B    0\r
1380         DC.B    $82\r
1381         DC.B    'O'     ; 'OR'\r
1382         DC.B    'R'|$80\r
1383         DC.L    AND-4-NATWID\r
1384 OR      DC.L    *+NATWID\r
1385         MOVE.L  (PSP)+,D0\r
1386         OR.L    D0,(PSP)\r
1387         RTS\r
1388 *       \r
1389 * ======>>  22  <<\r
1390 * ( n1 n2 --- n )\r
1391 * Bitwise exclusive or the top two integers.\r
1392         EVEN\r
1393         DC.B    $83\r
1394         DC.B    'XO'    ; 'XOR'\r
1395         DC.B    'R'|$80\r
1396         DC.L    OR-3-NATWID\r
1397 XOR     DC.L    *+NATWID\r
1398         MOVE.L  (PSP)+,D0\r
1399         EOR.L   D0,(PSP)\r
1400         RTS\r
1401 *\r
1402 * Not in fig,\r
1403 * for CPUs that don't like odd addresses.\r
1404 * Test whether top of stack is odd, push flag: 0 => even, 1 => odd.\r
1405 * ( n --- n f )\r
1406         EVEN\r
1407         DC.B    0\r
1408         DC.B    $84\r
1409         DC.B    '?OD'   ; '?ODD'\r
1410         DC.B    'D'|$80\r
1411         DC.L    XOR-4-NATWID\r
1412 QODD    DC.L    *+NATWID\r
1413         MOVE.L  (PSP),-(PSP)\r
1414         AND.L   #1,(PSP)\r
1415         RTS\r
1416 *       MOVE.L  (PSP),D0\r
1417 *       AND.L   #1,D0\r
1418 **NOT   BRA.W   PUSHD0  ; Save the test result as the flag.\r
1419 *       MOVE.L  D0,-(PSP)\r
1420 *       RTS\r
1421 *\r
1422 * Not in fig --\r
1423 * Calculate the bump adjustment necessary for odd or even alignment.\r
1424 * Odd for odd alignment, even for even.\r
1425 * bump is 0 (no adjustment) or 1 (adjustment needed)\r
1426 * ( n alignment --- n bump )\r
1427         EVEN\r
1428         DC.B    0\r
1429         DC.B    $8A\r
1430         DC.B    'ALIGN-BUM'     ; 'ALIGN-BUMP'\r
1431         DC.B    'P'|$80\r
1432         DC.L    QODD-5-NATWID\r
1433 ALGNB   DC.L    *+NATWID\r
1434         MOVE.L  (PSP),D0\r
1435         AND.L   #1,D0   ; Even or odd alignment?\r
1436         MOVE.L  NATWID(PSP),D1\r
1437         AND.W   #1,D1   ; Even address or odd?\r
1438         EOR.W   D0,D1   ; odd on even or even on odd is 1, else 0\r
1439         MOVE.L  D1,(PSP)\r
1440         RTS\r
1441 *\r
1442 ** Not in fig,\r
1443 ** for CPUs that don't like odd addresses.\r
1444 ** Floor top of stack even.\r
1445 ** ( n --- even )\r
1446 *       EVEN\r
1447 *       DC.B    0\r
1448 *       DC.B    $86\r
1449 *       DC.B    'FLOOR' ; 'FLOOR2'\r
1450 *       DC.B    '2'|$80\r
1451 *       DC.L    ALGNB-11-NATWID\r
1452 * FLOOR2        DC.L    *+NATWID\r
1453 *       AND.W   #$FFFE,NATWID/2(PSP)\r
1454 *       RTS\r
1455 **\r
1456 ** Not in fig,\r
1457 ** for CPUs that don't like odd addresses.\r
1458 ** Make top of stack even by adjusting it up.\r
1459 ** ( n --- even )\r
1460 *       EVEN\r
1461 *       DC.B    0\r
1462 *       DC.B    $88\r
1463 *       DC.B    'CIELING'       ; 'CIELING2'\r
1464 *       DC.B    '2'|$80\r
1465 *       DC.L    FLOOR2-7-NATWID\r
1466 * CIEL2 DC.L    *+NATWID\r
1467 *       BCLR    #0,NATWID-1(PSP)\r
1468 *       BEQ.S   CIEL2X\r
1469 *       ADDQ.L  #2,(PSP)\r
1470 * CIEL2X        RTS\r
1471 *\r
1472 * ######>> screen 26 <<\r
1473 * ======>>  23  <<\r
1474 * ( anything --- anything adr )\r
1475 * Fetch the parameter stack pointer (before it is pushed).\r
1476 * This points at whatever was on the top of stack before.\r
1477         EVEN\r
1478         DC.B    $83\r
1479         DC.B    'SP'    ; 'SP@'\r
1480         DC.B    '@'|$80\r
1481         DC.L    ALGNB-11-NATWID\r
1482 SPAT    DC.L    *+NATWID\r
1483         MOVE.L  PSP,-(PSP)\r
1484         RTS\r
1485 *\r
1486 * ======>>  24  <<\r
1487 * ( whatever --- nothing )\r
1488 * Initialize the parameter stack pointer from the USER variable S0. \r
1489 * Effectively clears the stack.\r
1490         EVEN\r
1491         DC.B    $83\r
1492         DC.B    'SP'    ; 'SP!'\r
1493         DC.B    '!'|$80\r
1494         DC.L    SPAT-4-NATWID\r
1495 SPSTOR  DC.L    *+NATWID\r
1496         MOVE.L  XSPZER-UORIG(UP),PSP\r
1497         RTS\r
1498 *\r
1499         PAGE\r
1500 *\r
1501 * ======>>  25  <<\r
1502 * ( whatever *** nothing )\r
1503 * Initialize the return stack pointer from the initialization table\r
1504 * instead of the user variable R0, for some reason.\r
1505 * Quite possibly, this should be from R0.\r
1506 * Effectively aborts all in-process definitions, except the active one. \r
1507 * An emergency measure, to be sure.\r
1508 * The routine that calls this must never execute a return.\r
1509 * So this should never be executed from the terminal, I guess.\r
1510 * This is another that should be compile-time only, and in a separate vocabulary.\r
1511         EVEN\r
1512         DC.B    $83\r
1513         DC.B    'RP'    ; 'RP!'\r
1514         DC.B    '!'|$80\r
1515         DC.L    SPSTOR-4-NATWID\r
1516 RPSTOR  DC.L    *+NATWID\r
1517         MOVE.L  RINIT(PC),RP\r
1518         BRA.W   NEXT    ; This is correct here.\r
1519 *\r
1520 * ======>>  26  <<\r
1521 * ( ip *** )\r
1522 * Pop IP from return stack (return from high-level definition).\r
1523 * Can be used in a screen to force interpretion to terminate.\r
1524 * Must not be executed when temporaries are saved on top of the return stack.\r
1525         EVEN\r
1526         DC.B    0\r
1527         DC.B    $82\r
1528         DC.B    ';'     ; ';S'\r
1529         DC.B    'S'|$80\r
1530         DC.L    RPSTOR-4-NATWID\r
1531 SEMIS   DC.L    *+NATWID\r
1532         MOVEM.L (RP)+,A0/IP     ; A0 will be TOS\r
1533         JMP     (A0)    ; return to NEXT\r
1534 *       MOVE.L  (RP)+,A0\r
1535 *       MOVE.L  (RP)+,IP\r
1536 *       JMP     (A0)\r
1537 *\r
1538 * ######>> screen 27 <<\r
1539 * ======>>  27  <<\r
1540 * ( limit index *** index index )\r
1541 * Force the terminating condition for the innermost loop by\r
1542 * copying its index to its limit. \r
1543 * Termination is postponed until the next\r
1544 * LOOP or +LOOP instruction is executed. \r
1545 * The index remains available for use until\r
1546 * the LOOP or +LOOP instruction is encountered.\r
1547 * Note that the assumption is that the current count is the correct count \r
1548 * to end at, rather than pushing the count to the final count.\r
1549         EVEN\r
1550         DC.B    $85\r
1551         DC.B    'LEAV'  ; 'LEAVE'\r
1552         DC.B    'E'|$80\r
1553         DC.L    SEMIS-3-NATWID\r
1554 LEAVE   DC.L    *+NATWID\r
1555         MOVE.L  LUPCT(RP),LUPLIM(RP)    ; Return address hidden in offset EQUs.\r
1556         RTS\r
1557 *\r
1558 * Notes for loop counter and limit in registers:\r
1559 *       MOVE.L  LUPCT,LUPLIM    ; No return address to dodge.\r
1560 *       RTS\r
1561 *\r
1562 * ======>>  28  <<\r
1563 * ( n --- )              \r
1564 * ( *** n ) \r
1565 * Move top of parameter stack to top of return stack.\r
1566         EVEN\r
1567         DC.B    0\r
1568         DC.B    $82\r
1569         DC.B    '>'     ; '>R'\r
1570         DC.B    'R'|$80\r
1571         DC.L    LEAVE-6-NATWID\r
1572 TOR     DC.L    *+NATWID\r
1573         MOVE.L  (RP),A0\r
1574         MOVE.L  (PSP)+,(RP)\r
1575         JMP     (A0)\r
1576 *\r
1577 * ======>>  29  <<\r
1578 * ( --- n )              \r
1579 * ( n *** )  \r
1580 * Move top of return stack to top of parameter stack.\r
1581         EVEN\r
1582         DC.B    0\r
1583         DC.B    $82\r
1584         DC.B    'R'     ; 'R>'\r
1585         DC.B    '>'|$80\r
1586         DC.L    TOR-3-NATWID\r
1587 FROMR   DC.L    *+NATWID\r
1588 *       MOVEM.L (RP)+,A0/A1     ; A0 will be TOS\r
1589 *       MOVE.L  A1,-(PSP)\r
1590 *       JMP     (A0)\r
1591         MOVE.L  (RP)+,A0\r
1592         MOVE.L  (RP)+,-(PSP)\r
1593         JMP     (A0)\r
1594 *\r
1595 * ======>>  30  <<\r
1596 * ( --- n )             \r
1597 * ( n *** n )\r
1598 * Copy the top of return stack to top of parameter stack. \r
1599 * This would NOT be a synonym for I if we were keeping the control variables in registers.\r
1600         EVEN\r
1601         DC.B    $81     ; R\r
1602         DC.B    'R'|$80\r
1603         DC.L    FROMR-3-NATWID\r
1604 R       DC.L    I+NATWID        ; synonym\r
1605 *\r
1606         PAGE\r
1607 *\r
1608 * ######>> screen 28 <<\r
1609 * ======>>  31  <<\r
1610 * ( n --- ~n )\r
1611 * Bit-invert top.\r
1612 * Not part of fig model.\r
1613         EVEN\r
1614         DC.B    $83\r
1615         DC.B    'NO'    ; 'NOT'\r
1616         DC.B    'T'|$80\r
1617         DC.L    R-2-NATWID\r
1618 LNOT    DC.L    *+NATWID\r
1619         NOT     (PSP)\r
1620         RTS\r
1621 *\r
1622 * ( n --- n=0 )\r
1623 * Logically invert top of stack;\r
1624 * or flag true if top is zero, otherwise false.\r
1625         EVEN\r
1626         DC.B    0\r
1627         DC.B    $82\r
1628         DC.B    '0'     ; '0='\r
1629         DC.B    '='|$80\r
1630         DC.L    LNOT-4-NATWID\r
1631 ZEQU    DC.L    *+NATWID\r
1632         CLR.L   D0\r
1633         TST.L   (PSP)\r
1634         SEQ     D0      ; faster than branch\r
1635 ZEQMSK  AND.W   #1,D0\r
1636         MOVE.L  D0,(PSP)\r
1637         RTS\r
1638 *\r
1639 * Option using branch and increment:\r
1640 * ZEQU  DC.L    *+NATWID\r
1641 *       CLR.L   D0\r
1642 *       TST.L   (PSP)\r
1643 *       BEQ.S   ZEQUS\r
1644 *       MOVEQ   #1,D0   ; ADDQ.W would work. ADDQ.L takes 8 cycles instead of 4.\r
1645 * ZEQUS MOVE.L  D0,(PSP)\r
1646 *       RTS\r
1647 *\r
1648 * If TRUE were -1:\r
1649 * ZEQU  DC.L    *+NATWID\r
1650 *       TST.L   (PSP)\r
1651 *       SEQ     D0\r
1652 *       EXT.B   D0\r
1653 *       EXT.W   D0\r
1654 *       MOVE.L  D0,(PSP)\r
1655 *       RTS\r
1656 *\r
1657 * ======>>  32  <<\r
1658 * ( n --- n<0 )\r
1659 * Flag true if top is negative (MSbit set), otherwise false.\r
1660         EVEN\r
1661         DC.B    0\r
1662         DC.B    $82\r
1663         DC.B    '0'     ; '0<'\r
1664         DC.B    '<'|$80\r
1665         DC.L    ZEQU-3-NATWID\r
1666 ZLESS   DC.L    *+NATWID\r
1667 *       CLR.L   D0\r
1668         TST.L   (PSP)\r
1669         SMI     D0\r
1670 *       BRA.S   ZEQMSK  ; don't trade a few cycles for several bytes\r
1671 *       AND.W   #1,D0   ; flatten it, instead.\r
1672         AND.L   #1,D0   ; flatten it, instead.\r
1673         MOVE.L  D0,(PSP)\r
1674         RTS\r
1675 *\r
1676 * ######>> screen 29 <<\r
1677 * ======>>  33  <<\r
1678 * ( n1 n2 --- n1+n2 )\r
1679 * Add top two words.\r
1680         EVEN\r
1681         DC.B    $81     ; '+'\r
1682         DC.B    '+'|$80\r
1683         DC.L    ZLESS-3-NATWID\r
1684 PLUS    DC.L    *+NATWID\r
1685         MOVE.L  (PSP)+,D0       ; Addition is commutative.\r
1686         ADD.L   D0,(PSP)        ; This order will not work for subtraction.\r
1687         RTS             ; Remember, my son --\r
1688 *                               ; the left hand operator is one deeper in the stack,\r
1689 *                               ; and it is the target.\r
1690 *\r
1691 * ======>>  34  <<\r
1692 * ( d1 d2 --- d1+d2 )\r
1693 * Add top two double integers.\r
1694         EVEN\r
1695         DC.B    0\r
1696         DC.B    $82\r
1697         DC.B    'D'     ; 'D+'\r
1698         DC.B    '+'|$80\r
1699         DC.L    PLUS-2-NATWID\r
1700 DPLUS   DC.L    *+NATWID\r
1701         MOVEM.L (PSP)+,D0/D1/D2/D3      ; ADDX memory requires too much setup\r
1702         ADD.L   D1,D3                   ; This order will work for subtraction, too.\r
1703         ADDX.L  D0,D2\r
1704         MOVEM.L D2/D3,-(PSP)\r
1705         RTS\r
1706 *\r
1707 * ======>>  35  <<\r
1708 * ( n --- -n )\r
1709 * Negate (two's complement) top of stack.\r
1710         EVEN\r
1711         DC.B    $85\r
1712         DC.B    'MINU'  ; 'MINUS'\r
1713         DC.B    'S'|$80\r
1714         DC.L    DPLUS-3-NATWID\r
1715 MINUS   DC.L    *+NATWID\r
1716         NEG.L   (PSP)\r
1717         RTS\r
1718 *\r
1719 * ======>>  36  <<\r
1720 * ( d --- -d )\r
1721 * Negate (two's complement) top two words on stack as a double integer.\r
1722         EVEN\r
1723         DC.B    0\r
1724         DC.B    $86\r
1725         DC.B    'DMINU' ; 'DMINUS'\r
1726         DC.B    'S'|$80\r
1727         DC.L    MINUS-6-NATWID\r
1728 DMINUS  DC.L    *+NATWID\r
1729         NEG.L   NATWID(PSP)\r
1730         NEGX.L  (PSP)\r
1731         RTS\r
1732 *\r
1733 * ######>> screen 30 <<\r
1734 * ======>>  37  <<\r
1735 * ( n1 n2 --- n1 n2 n1 )\r
1736 * Push a copy of the second word on stack.\r
1737         EVEN\r
1738         DC.B    0\r
1739         DC.B    $84\r
1740         DC.B    'OVE'   ; 'OVER'\r
1741         DC.B    'R'|$80\r
1742         DC.L    DMINUS-7-NATWID\r
1743 OVER    DC.L    *+NATWID\r
1744         MOVE.L  NATWID(PSP),-(PSP)\r
1745         RTS\r
1746 *\r
1747 * ======>>  38  <<\r
1748 * ( n --- )\r
1749 * Discard the top word on stack.\r
1750         EVEN\r
1751         DC.B    0\r
1752         DC.B    $84\r
1753         DC.B    'DRO'   ; 'DROP'\r
1754         DC.B    'P'|$80\r
1755         DC.L    OVER-5-NATWID\r
1756 DROP    DC.L    *+NATWID\r
1757         LEA     NATWID(PSP),PSP\r
1758         RTS\r
1759 *\r
1760 * ======>>  39  <<\r
1761 * ( n1 n2 --- n2 n1 )\r
1762 * Swap the top two words on stack.\r
1763         EVEN\r
1764         DC.B    0\r
1765         DC.B    $84\r
1766         DC.B    'SWA'   ; 'SWAP'\r
1767         DC.B    'P'|$80\r
1768         DC.L    DROP-5-NATWID\r
1769 SWAP    DC.L    *+NATWID\r
1770         MOVEM.L (PSP),D0/D1\r
1771         EXG     D0,D1\r
1772         MOVEM.L D0/D1,(PSP)\r
1773         RTS\r
1774 *       MOVE.L  (PSP),D0\r
1775 *       MOVE.L  NATWID(PSP),(PSP)\r
1776 *       MOVE.L  D0,NATWID(POS)\r
1777 *       RTS\r
1778 *\r
1779 * ======>>  40  <<\r
1780 * ( n1 --- n1 n1 )\r
1781 * Push a copy of the top word on stack.\r
1782         EVEN\r
1783         DC.B    $83\r
1784         DC.B    'DU'    ; 'DUP'\r
1785         DC.B    'P'|$80\r
1786         DC.L    SWAP-5-NATWID\r
1787 DUP     DC.L    *+NATWID\r
1788         MOVE.L  (PSP),-(PSP)\r
1789         RTS\r
1790 *\r
1791 * ######>> screen 31 <<\r
1792 * ======>>  41  <<\r
1793 * ( n adr --- )\r
1794 * Add the second word on stack to the word at the adr on top of stack.\r
1795         EVEN\r
1796         DC.B    0\r
1797         DC.B    $82\r
1798         DC.B    '+'     ; '+!'\r
1799         DC.B    '!'|$80\r
1800         DC.L    DUP-4-NATWID\r
1801 PSTORE  DC.L    *+NATWID\r
1802         MOVEM.L (PSP)+,D0/A0\r
1803         EXG     D0,A0\r
1804         ADD.L   D0,(A0)\r
1805         RTS\r
1806 *\r
1807 * ======>>  42  <<\r
1808 * ( adr b --- )\r
1809 * Exclusive or byte at adr with low byte of top word.\r
1810         EVEN\r
1811         DC.B    0\r
1812         DC.B    $86\r
1813         DC.B    'TOGGL' ; 'TOGGLE'\r
1814         DC.B    'E'|$80\r
1815         DC.L    PSTORE-3-NATWID\r
1816 TOGGLE  DC.L    *+NATWID\r
1817         MOVEM.L (PSP)+,D0/A0\r
1818         EOR.B   D0,(A0)\r
1819         RTS\r
1820 * Using the model code would be less likely to introduce bugs, \r
1821 * but that would sort-of defeat my purposes here.\r
1822 * Anyway, I can imitate known good bif-6809 code\r
1823 * and it's fewer bytes and much faster code this way.\r
1824 * TOGGLE\r
1825 *       DC.L    DOCOL,OVER,CAT,XOR,SWAP,CSTORE\r
1826 *       DC.L    SEMIS\r
1827 *\r
1828 * ######>> screen 32 <<\r
1829 * ======>>  43  <<\r
1830 * ( adr --- n )\r
1831 * Replace address on stack with the word at the address.\r
1832         EVEN\r
1833         DC.B    $81     ; @\r
1834         DC.B    '@'|$80\r
1835         DC.L    TOGGLE-7-NATWID\r
1836 AT      DC.L    *+NATWID\r
1837         MOVE.L  (PSP),A0\r
1838         MOVE.L  (A0),(PSP)\r
1839         RTS\r
1840 *\r
1841 * ======>>  44  <<\r
1842 * ( adr --- b )\r
1843 * Replace address on top of stack with the byte at the address.\r
1844 * High byte of result is clear.\r
1845 * Unfortunate naming. 8 bits doth not a character code point make.\r
1846         EVEN\r
1847         DC.B    0\r
1848         DC.B    $82\r
1849         DC.B    'C'     ; 'C@'\r
1850         DC.B    '@'|$80\r
1851         DC.L    AT-2-NATWID\r
1852 CAT     DC.L    *+NATWID\r
1853         MOVE.L  (PSP),A0        ; Memory indirect is 68020 and after, but not CPU32.\r
1854         CLR.L   D0              ; Reduce bus activity and un-aligned access.\r
1855         MOVE.B  (A0),D0\r
1856         MOVE.L  D0,(PSP)\r
1857         RTS\r
1858 * Another way:\r
1859 *       MOVE.L  (PSP),A0\r
1860 *       CLR.L   (A0)\r
1861 *       MOVE.B  (A0),NATWID-1(PSP)\r
1862 *       RTS\r
1863 * But optimization is not my primary purpose here, \r
1864 * so I'm not going to count bytes and cycles and compare.\r
1865 *\r
1866 * ( adr --- h )\r
1867 * Yeah, we're gonna need this.\r
1868 * Replace address on top of stack with the 16-bit half-word at the address.\r
1869 * High half-word of result is clear.\r
1870         EVEN\r
1871         DC.B    0\r
1872         DC.B    $82\r
1873         DC.B    'H'     ; 'H@'\r
1874         DC.B    '@'|$80\r
1875         DC.L    CAT-3-NATWID\r
1876 HAT     DC.L    *+NATWID\r
1877         MOVE.L  (PSP),A0        ; Memory indirect is 68020 and after, but not CPU32.\r
1878         CLR.L   D0              ; Reduce bus activity.\r
1879         MOVE.W  (A0),D0\r
1880         MOVE.L  D0,(PSP)\r
1881         RTS\r
1882 * See alternate approach for CAT\r
1883 *\r
1884 * ======>>  45  <<\r
1885 * ( n adr --- )\r
1886 * Store second word on stack at address on top of stack.\r
1887         EVEN\r
1888         DC.B    $81     ; !\r
1889         DC.B    '!'|$80\r
1890         DC.L    HAT-3-NATWID\r
1891 STORE   DC.L    *+NATWID\r
1892         MOVEM.L (PSP)+,D0/A0\r
1893         EXG     D0,A0\r
1894         MOVE.L  D0,(A0)\r
1895         RTS\r
1896 * Aaaaaand,\r
1897 *       MOVE.L  (PSP)+,A0\r
1898 *       MOVE.L  (PSP)+,(A0)\r
1899 *       RTS\r
1900 *\r
1901 * ======>>  46  <<\r
1902 * ( b adr --- )\r
1903 * Store low byte of second word on stack at address on top of stack. \r
1904 * High byte is ignored.\r
1905 * Unfortunate naming. 8 bits doth not a character code point make.\r
1906         EVEN\r
1907         DC.B    0\r
1908         DC.B    $82\r
1909         DC.B    'C'     ; 'C!'\r
1910         DC.B    '!'|$80\r
1911         DC.L    STORE-2-NATWID\r
1912 CSTORE  DC.L    *+NATWID\r
1913         MOVEM.L (PSP)+,D0/A0\r
1914         EXG     D0,A0\r
1915         MOVE.B  D0,(A0)\r
1916         RTS\r
1917 *\r
1918 * ( b adr --- )\r
1919 * Yeah, we're gonna need this.\r
1920 * Store low 16-bit half-word of second word on stack at address on top of stack. \r
1921 * High half-word is ignored.\r
1922         EVEN\r
1923         DC.B    0\r
1924         DC.B    $82\r
1925         DC.B    'H'     ; 'H!'\r
1926         DC.B    '!'|$80\r
1927         DC.L    CSTORE-3-NATWID\r
1928 HSTORE  DC.L    *+NATWID\r
1929         MOVEM.L (PSP)+,D0/A0\r
1930         EXG     D0,A0\r
1931         MOVE.W  D0,(A0)\r
1932         RTS\r
1933 *\r
1934         PAGE\r
1935 *\r
1936 * ######>> screen 33 <<\r
1937 * ======>>  47  <<\r
1938 * ( --- )                                                 P\r
1939 * { : name sundry-activities ; } typical input\r
1940 * ( Termination of recursive definition, or eating our own dogfood --\r
1941 *   lots of forward references here.)\r
1942 * If executing (not compiling), \r
1943 * record the data stack mark in CSP,\r
1944 * Set the CONTEXT vocabulary to CURRENT,\r
1945 * CREATE a header,\r
1946 * set state to compile,\r
1947 * and compile the call to the trailing native CPU machine code DOCOL.\r
1948 *\r
1949 * This would not be hard to flatten to native code,\r
1950 * especially in the 6809 or 68000.\r
1951 * But that's not the purpose of a model.\r
1952 * Except that's the purpose of this model, now.\r
1953 * So we will start flattening here, to see how it goes.\r
1954 * First need to flatten certain of the called words.\r
1955         EVEN\r
1956         DC.B    $C1     ; : immediate\r
1957         DC.B    ':'|$80\r
1958         DC.L    HSTORE-3-NATWID\r
1959 COLON   DC.L    DOCOL,QEXEC,SCSP,CURENT,AT,CONTXT,STORE\r
1960         DC.L    CREATE,RBRAK\r
1961         DC.L    PSCODE\r
1962 \r
1963 * What was I thinking?\r
1964 *COLON  DC.L    *+NATWID\r
1965 *       BSR.W   QEXEC+NATWID\r
1966 **      BSR.W   SCSP+NATWID\r
1967 *       MOVE.L  PSP,XCSP-UORIG(UP)              ; SCSP\r
1968 *       MOVE.L  XCURR-UORIG(UP),XCONT-UORIG(UP)\r
1969 *       BSR.W   CREATE+NATWID\r
1970 *       BSR.W   RBRAK+NATWID\r
1971 *       MOVE.L  #STCOMP,XSTATE-UORIG(UP)        ; RBRAK\r
1972 ** NOW WHAT? Should work.\r
1973 *       DC.L    PSCODE\r
1974 \r
1975 * Here is the IP pusher for allowing\r
1976 * nested words in the virtual machine:\r
1977 * ( ;S is the equivalent un-nester )\r
1978 \r
1979 * ( *** oldIP ) \r
1980 * Characteristic of a colon (:) definition.  \r
1981 * Begins execution of a high-level definition,\r
1982 * i. e., nests the definition and begins processing icodes. \r
1983 * Mechanically, it pushes the IP \r
1984 * and loads the Parameter Field Address of the definition which\r
1985 * called it into the IP.\r
1986 DOCOL   MOVE.L  (RP),A0\r
1987         MOVE.L  IP,(RP)\r
1988         MOVE.L  W,IP\r
1989         JMP     (A0)    ; Return to NEXT.\r
1990 *\r
1991 * ======>>  48  <<\r
1992 * ( --- )                                                 P\r
1993 * { : name sundry-activities ; } typical input\r
1994 * ERROR check data stack against mark in CSP,\r
1995 * compile ;S,\r
1996 * unSMUDGE LATEST definition,\r
1997 * and set state to interpretation.\r
1998         EVEN\r
1999         DC.B    $C1     ; ;   imnediate code\r
2000         DC.B    ';'|$80\r
2001         DC.L    COLON-2-NATWID\r
2002 SEMI    DC.L    DOCOL,QCSP,COMPIL,SEMIS,SMUDGE,LBRAK\r
2003         DC.L    SEMIS\r
2004 *\r
2005 * ######>> screen 34 <<\r
2006 * ======>>  49  <<\r
2007 * ( n --- )\r
2008 * { value CONSTANT name } typical input\r
2009 * CREATE a header,\r
2010 * unSMUDGE it,\r
2011 * compile the constant value,\r
2012 * and compile the call to the trailing native CPU machine code DOCON.\r
2013         EVEN\r
2014         DC.B    0\r
2015         DC.B    $88\r
2016         DC.B    'CONSTAN'       ; 'CONSTANT'\r
2017         DC.B    'T'|$80\r
2018         DC.L    SEMI-2-NATWID\r
2019 CON     DC.L    DOCOL,CREATE,SMUDGE,COMMA,PSCODE\r
2020 * ( --- n ) \r
2021 * Characteristic of a CONSTANT. \r
2022 * A CONSTANT simply loads its value from its parameter field\r
2023 * and pushes it on the stack.\r
2024 DOCON   MOVE.L  (W),-(PSP)      ; Push the first natural width word of the parameter field.\r
2025         RTS\r
2026 *\r
2027 * Tempting to do a space-saving DOHCON:\r
2028 * DOHCON        CLR.L   D0      ; convert to 32-bit\r
2029 *       MOVE.W  (W),D0\r
2030 *       MOVE.L  D0,-(PSP)\r
2031 *       RTS\r
2032 * But, as you can see, it'll be a bit slower,\r
2033 * and it just may not be worth it for the number of times it would be used.\r
2034 * And there's a bettwer way lurking around the corner.\r
2035 *\r
2036 * ======>>  50  <<\r
2037 * ( init --- )\r
2038 * { init VARIABLE name } typical input\r
2039 * Use CONSTANT to CREATE a header and compile the initial value, init, \r
2040 * then overwrite the characteristic to point to DOVAR.\r
2041         EVEN\r
2042         DC.B    0\r
2043         DC.B    $88\r
2044         DC.B    'VARIABL'       ; 'VARIABLE'\r
2045         DC.B    'E'|$80\r
2046         DC.L    CON-9-NATWID\r
2047 VAR     DC.L    DOCOL,CON,PSCODE\r
2048 * ( --- vadr ) \r
2049 * Characteristic of a VARIABLE. \r
2050 * A VARIABLE pushes its PFA address on the stack. \r
2051 * The parameter field of a VARIABLE is the actual allocation of the variable,\r
2052 * so that pushing its address allows its contents to be @ed (fetched). \r
2053 * Ordinary arrays and strings that do not subscript themselves\r
2054 * may be allocated by defining a variable\r
2055 * and immediately ALLOTting the remaining needed space.\r
2056 * VARIABLES are global to all users,\r
2057 * and thus should be hidden in resource monitors, but aren't.\r
2058 DOVAR   MOVE.L  W,-(PSP)        ; Push address of first natural width word of the parameters.   \r
2059         RTS\r
2060 *\r
2061 * ======>>  51  <<\r
2062 * ( ub --- )\r
2063 * { uboffset USER name } typical input\r
2064 * CREATE a header and compile the unsigned byte offset in the per-USER table, \r
2065 * then overwrite the header with a call to DOUSER.\r
2066 * The USER is entirely responsible for maintaining allocation!\r
2067 * (We really need a word that controls allocation of these.)\r
2068         EVEN\r
2069         DC.B    0\r
2070         DC.B    $84\r
2071         DC.B    'USE'   ; 'USER'\r
2072         DC.B    'R'|$80\r
2073         DC.L    VAR-9-NATWID\r
2074 USER    DC.L    DOCOL,CON,PSCODE\r
2075 * ( --- vadr ) \r
2076 * Characteristic of a per-USER variable. \r
2077 * USER variables are similiar to VARIABLEs,\r
2078 * but are allocated (by hand!) in the per-user table. \r
2079 * A USER variable's parameter field contains its offset in the per-user table.\r
2080 * DOUSER        MOVE.L  UP,A0   ; Copy base of per-user/task space.\r
2081 *       ADD.L   (W),A0  ; Offset into the table.\r
2082 *       MOVE.L  A0,-(PSP)\r
2083 *       RTS\r
2084 DOUSER  MOVE.L  (W),D0  ; Offset into the table.\r
2085         LEA     (UP,D0.L),A0\r
2086         MOVE.L  A0,-(PSP)\r
2087         RTS\r
2088 \r
2089 * Hey, the per-user table can actually be larger than 256 bytes, esp. on the 68000!\r
2090 *\r
2091         PAGE\r
2092 *\r
2093 * ######>> screen 35 <<\r
2094 *\r
2095 * Some (theoretically) useful constants:\r
2096 * ======>>  52  <<\r
2097 * ( --- 0 )\r
2098         EVEN\r
2099         DC.B    $81     ; 0\r
2100         DC.B    '0'|$80\r
2101         DC.L    USER-5-NATWID\r
2102 ZERO    DC.L    DOCON\r
2103         DC.L    0000\r
2104 *\r
2105 * ======>>  53  <<\r
2106 * ( --- 1 )\r
2107         EVEN\r
2108         DC.B    $81     ; 1\r
2109         DC.B    '1'|$80\r
2110         DC.L    ZERO-2-NATWID\r
2111 ONE     DC.L    DOCON\r
2112 ONEV    DC.L    1\r
2113 *\r
2114 * ======>>  54  <<\r
2115 * ( --- 2 )\r
2116         EVEN\r
2117         DC.B    $81     ; 2\r
2118         DC.B    '2'|$80\r
2119         DC.L    ONE-2-NATWID\r
2120 TWO     DC.L    DOCON\r
2121 TWOV    DC.L    2\r
2122 *\r
2123 * ======>>  55  <<\r
2124 * ( --- 3 )\r
2125         EVEN\r
2126         DC.B    $81     ; 3\r
2127         DC.B    '3'|$80\r
2128         DC.L    TWO-2-NATWID\r
2129 THREE   DC.L    DOCON\r
2130         DC.L    3\r
2131 *\r
2132 * Useful constant, not in model, needed for abstraction:\r
2133 * The standard name is CELL, however.\r
2134 * ( --- NATWID )\r
2135 * The byte width of objects on stack.\r
2136         EVEN\r
2137         DC.B    0\r
2138         DC.B    $86\r
2139         DC.B    'NATWI' ; 'NATWID'\r
2140         DC.B    'D'|$80\r
2141         DC.L    THREE-2-NATWID\r
2142 NATWC   DC.L    DOCON\r
2143 NATWCV  DC.L    NATWID\r
2144 *\r
2145 * Not in model, wanted for abstraction:\r
2146 * Note that this is not defined as an instance of an INCREMENTER here!\r
2147 * Coded to increment by the exact constant returned by NATWID\r
2148 * ( n --- n+NATWID )\r
2149         EVEN\r
2150         DC.B    0\r
2151         DC.B    $84\r
2152         DC.B    'NAT'   ; 'NAT+'\r
2153         DC.B    '+'|$80\r
2154         DC.L    NATWC-7-NATWID\r
2155 NATP    DC.L    *+NATWID\r
2156         MOVE.L  (PSP),D0\r
2157         ADD.L   NATWCV(PC),D0\r
2158         MOVE.L  D0,(PSP)\r
2159         RTS\r
2160 *\r
2161 * Useful constant, not in model, needed for abstraction:\r
2162 * ( --- NATWID/2 )\r
2163 * Half the byte width of objects on stack.\r
2164         EVEN\r
2165         DC.B    0\r
2166         DC.B    $8A\r
2167         DC.B    'HALFNATWI'     ; 'HALFNATWID'\r
2168         DC.B    'D'|$80\r
2169         DC.L    NATP-5-NATWID\r
2170 HNATWC  DC.L    DOCON\r
2171 HNATWCV DC.L    NATWID/2\r
2172 *\r
2173         PAGE\r
2174 *\r
2175 * ======>>  56  <<\r
2176 * ( --- SP ) \r
2177 * ASCII SPACE character\r
2178         EVEN\r
2179         DC.B    0\r
2180         DC.B    $82\r
2181         DC.B    'B'     ; 'BL'\r
2182         DC.B    'L'|$80\r
2183         DC.L    HNATWC-11-NATWID\r
2184 BL      DC.L    DOCON   ; ascii blank\r
2185         DC.L    $20\r
2186 *\r
2187 * ======>>  57  <<\r
2188 * This really shouldn't be a CONSTANT.\r
2189 * ( --- adr )    \r
2190 * The base of the disk buffer space.\r
2191         EVEN\r
2192         DC.B    $85\r
2193         DC.B    'FIRS'  ; 'FIRST'\r
2194         DC.B    'T'|$80\r
2195         DC.L    BL-3-NATWID\r
2196 FIRST   DC.L    DOCON\r
2197         DC.L    BUFBAS\r
2198 *       FDB     MEMEND-528      ; (132 * NBLK)\r
2199 *\r
2200 * ======>>  58  <<\r
2201 * This really shouldn't be a CONSTANT.\r
2202 * ( --- adr ) \r
2203 * The limit of the disk buffer space.\r
2204         EVEN\r
2205         DC.B    $85\r
2206         DC.B    'LIMI'  ; 'LIMIT' :     ( the end of memory +1 )\r
2207         DC.B    'T'|$80\r
2208         DC.L    FIRST-6-NATWID\r
2209 LIMIT   DC.L    DOCON\r
2210         DC.L    BUFBAS+BUFSZ\r
2211 * In 6800 model, was\r
2212 *       FDB     MEMEND\r
2213 *\r
2214 * ======>>  59  <<\r
2215 * ( --- sectorsize )\r
2216 * The size, in bytes, of a buffer control region.\r
2217         EVEN\r
2218         DC.B    $85\r
2219         DC.B    'B/CT'  ; 'B/CTL' :     (bytes/control region)\r
2220         DC.B    'L'|$80\r
2221         DC.L    LIMIT-6-NATWID\r
2222 BCTL    DC.L    DOCON\r
2223         DC.L    SECTRL\r
2224 *\r
2225 * ( --- sectorsize )\r
2226 * The size, in bytes, of a buffer.\r
2227         EVEN\r
2228         DC.B    $85\r
2229         DC.B    'B/BU'  ; 'B/BUF' :     (bytes/buffer)\r
2230         DC.B    'F'|$80\r
2231         DC.L    BCTL-6-NATWID\r
2232 BBUF    DC.L    DOCON\r
2233         DC.L    RBLKSZ\r
2234 * Hardcoded in 6800 model:\r
2235 *       FDB     128\r
2236 *\r
2237 * ======>>  60  <<\r
2238 * ( --- blocksperscreen )      \r
2239 * The size, in blocks, of a screen.\r
2240         EVEN\r
2241         DC.B    $85\r
2242         DC.B    'B/SC'  ; 'B/SCR' :     (blocks/screen)\r
2243         DC.B    'R'|$80\r
2244         DC.L    BBUF-6-NATWID\r
2245 *BSCR   DC.L    DOCON\r
2246 *       DC.L    NBLK\r
2247 BSCR    DC.L    *+NATWID\r
2248         MOVE.L  #NBLK,-(PSP)\r
2249         RTS\r
2250 * Hardcoded in 6800 model as:\r
2251 *       FDB     8\r
2252 *       blocks/screen = 1024 / "B/BUF" = 8, if sectors are 128 bytes.\r
2253 *\r
2254 * ======>>  61  <<\r
2255 * ( n --- adr )\r
2256 * Calculate the address of entry (#n/2) in the boot-up parameter table. \r
2257 * (Adds the base of the boot-up table to n.)\r
2258         EVEN\r
2259         DC.B    $87\r
2260         DC.B    '+ORIGI'        ; '+ORIGIN'\r
2261         DC.B    'N'|$80\r
2262         DC.L    BSCR-6-NATWID\r
2263 PORIG   DC.L    DOCOL,LIT,ORIG,PLUS\r
2264         DC.L    SEMIS\r
2265 *\r
2266 * ######>> screen 36 <<\r
2267 * ======>>  62  <<\r
2268 * ( n --- adr )\r
2269 * This is the per-task variable recording the initial parameter stack pointer.\r
2270         EVEN\r
2271         DC.B    0\r
2272         DC.B    $82\r
2273         DC.B    'S'     ; 'S0'\r
2274         DC.B    '0'|$80\r
2275         DC.L    PORIG-8-NATWID\r
2276 *SZERO  DC.L    DOUSER\r
2277 *       DC.L    XSPZER-UORIG\r
2278 SZERO   DC.L    *+NATWID\r
2279         LEA     XSPZER-UORIG(UP),A0\r
2280         MOVE.L  A0,-(PSP)       ; Note that BRA.W takes 32 bits to encode, so saves no space.\r
2281         RTS\r
2282 *\r
2283 * ======>>  63  <<\r
2284 * ( n --- adr )\r
2285 * This is the per-task variable recording the initial return stack pointer.\r
2286         EVEN\r
2287         DC.B    0\r
2288         DC.B    $82\r
2289         DC.B    'R'     ; 'R0'\r
2290         DC.B    '0'|$80\r
2291         DC.L    SZERO-3-NATWID\r
2292 *RZERO  DC.L    DOUSER\r
2293 *       DC.L    XRZERO-UORIG\r
2294 RZERO   DC.L    *+NATWID\r
2295         LEA     XRZERO-UORIG(UP),A0\r
2296         MOVE.L  A0,-(PSP)       ; Note that BRA.W takes 32 bits to encode, so saves no space.\r
2297         RTS\r
2298 *\r
2299 * ======>>  64  <<\r
2300 * ( --- vadr )   \r
2301 * Terminal Input Buffer address. \r
2302 * Note that this is a variable, so users may allocate their own buffers, but it must be @ed.\r
2303         EVEN\r
2304         DC.B    $83\r
2305         DC.B    'TI'    ; 'TIB'\r
2306         DC.B    'B'|$80\r
2307         DC.L    RZERO-3-NATWID\r
2308 TIB     DC.L    DOUSER\r
2309         DC.L    XTIB-UORIG\r
2310 *\r
2311 * ======>>  65  <<\r
2312 * ( --- maxnamewidth )\r
2313 * This is the maximum width to which symbol names will be recorded.\r
2314         EVEN\r
2315         DC.B    $85\r
2316         DC.B    'WIDT'  ; 'WIDTH'\r
2317         DC.B    'H'|$80\r
2318         DC.L    TIB-4-NATWID\r
2319 WIDTH   DC.L    DOUSER\r
2320         DC.L    XWIDTH-UORIG\r
2321 *\r
2322 * ======>>  66  <<\r
2323 * ( --- vadr )   \r
2324 * Availability of error messages on disk.\r
2325 * Contains 1 if messages available, \r
2326 * 0 if not,\r
2327 * -1 if a disk error has occurred.\r
2328         EVEN\r
2329         DC.B    $87\r
2330         DC.B    'WARNIN'        ; 'WARNING'\r
2331         DC.B    'G'|$80\r
2332         DC.L    WIDTH-6-NATWID\r
2333 *WARN   DC.L    DOUSER          ; Must be callable from low-level.\r
2334 *       DC.L    XWARN-UORIG\r
2335 WARN    DC.L    *+NATWID\r
2336         LEA     XWARN-UORIG(UP),A0\r
2337         MOVE.L  A0,-(PSP)       ; Note that BRA.W takes 32 bits to encode, so saves no space.\r
2338         RTS\r
2339 *\r
2340 * ======>>  67  <<\r
2341 * ( --- vadr )   \r
2342 * Boundary for FORGET.\r
2343         EVEN\r
2344         DC.B    $85\r
2345         DC.B    'FENC'  ; 'FENCE'\r
2346         DC.B    'E'|$80\r
2347         DC.L    WARN-8-NATWID\r
2348 FENCE   DC.L    DOUSER\r
2349         DC.L    XFENCE-UORIG\r
2350 *\r
2351 * ======>>  68  <<\r
2352 * ( --- vadr )   \r
2353 * Dictionary pointer, fetched by HERE.\r
2354         EVEN\r
2355         DC.B    0\r
2356         DC.B    $82\r
2357         DC.B    'D'     ; 'DP' :        points to first free byte at end of dictionary\r
2358         DC.B    'P'|$80\r
2359         DC.L    FENCE-6-NATWID\r
2360 DICTPT  DC.L    DOUSER\r
2361         DC.L    XDICTP-UORIG\r
2362 *\r
2363 * ======>>  68.5  <<\r
2364 * ( --- vadr ) ******* Need to check what this is!\r
2365 * Used in maintaining vocabularies.\r
2366 * I think it points to the current "parent" vocabulary, but I'm not sure.\r
2367 * Or maybe this is the CONTEXT vocabulary. I'll have to come back here. *****\r
2368         EVEN\r
2369         DC.B    0\r
2370         DC.B    $88\r
2371         DC.B    'VOC-LIN'       ; 'VOC-LINK'\r
2372         DC.B    'N'|$80\r
2373         DC.L    DICTPT-3-NATWID\r
2374 VOCLIN  DC.L    DOUSER\r
2375         DC.L    XVOCL-UORIG\r
2376 *\r
2377 * ======>>  69  <<\r
2378 * ( --- vadr )   \r
2379 * Disk block being interpreted. \r
2380 * Zero refers to terminal.\r
2381 * ******** Should be made a 64 bit user variable! ********\r
2382 * But the base system needs to have full 64 bit support, div and mul, etc.\r
2383 * before we can do that.\r
2384         EVEN\r
2385         DC.B    $83\r
2386         DC.B    'BL'    ; 'BLK'\r
2387         DC.B    'K'|$80\r
2388         DC.L    VOCLIN-9-NATWID\r
2389 BLK     DC.L    DOUSER\r
2390         DC.L    XBLK-UORIG\r
2391 *\r
2392 * ======>>  70  <<\r
2393 * ( --- vadr )   \r
2394 * Input buffer offset/cursor.\r
2395         EVEN\r
2396         DC.B    0\r
2397         DC.B    $82\r
2398         DC.B    'I'     ; 'IN' :        scan pointer for input line buffer\r
2399         DC.B    'N'|$80\r
2400         DC.L    BLK-4-NATWID\r
2401 IN      DC.L    DOUSER\r
2402         DC.L    XIN-UORIG\r
2403 *\r
2404 * ======>>  71  <<\r
2405 * ( --- vadr )   \r
2406 * Output buffer offset/cursor.\r
2407         EVEN\r
2408         DC.B    $83\r
2409         DC.B    'OU'    ; 'OUT'\r
2410         DC.B    'T'|$80\r
2411         DC.L    IN-3-NATWID\r
2412 OUT     DC.L    DOUSER\r
2413         DC.L    XOUT-UORIG\r
2414 *\r
2415 * ======>>  72  <<\r
2416 * ( --- vadr )   \r
2417 * Screen currently being edited, once we have an editor running. \r
2418         EVEN\r
2419         DC.B    $83\r
2420         DC.B    'SC'    ; 'SCR'\r
2421         DC.B    'R'|$80\r
2422         DC.L    OUT-4-NATWID\r
2423 SCR     DC.L    DOUSER\r
2424         DC.L    XSCR-UORIG\r
2425 * ######>> screen 37 <<\r
2426 *\r
2427 * ======>>  73  <<\r
2428 * ( --- vadr )   \r
2429 * Sector offset for LOADing screens,\r
2430 * set by DRIVE to make a new drive the default.\r
2431 * This should also be 64 bit, if we had full 64-bit math.\r
2432         EVEN\r
2433         DC.B    0\r
2434         DC.B    $86\r
2435         DC.B    'OFFSE' ; 'OFFSET'\r
2436         DC.B    'T'|$80\r
2437         DC.L    SCR-4-NATWID\r
2438 *OFSET  DC.L    DOUSER\r
2439 *       DC.L    XOFSET-UORIG\r
2440 OFSET   DC.L    *+NATWID\r
2441         LEA     XOFSET-UORIG(UP),A0\r
2442         MOVE.L  A0,-(PSP)\r
2443         RTS\r
2444 *\r
2445 * ======>>  74  <<\r
2446 * ( --- vadr )   \r
2447 * Current context of interpretation (vocabulary root).\r
2448         EVEN\r
2449         DC.B    $87\r
2450         DC.B    'CONTEX'        ; 'CONTEXT' :   points to pointer to vocab to search first\r
2451         DC.B    'T'|$80\r
2452         DC.L    OFSET-7-NATWID\r
2453 CONTXT  DC.L    DOUSER\r
2454         DC.L    XCONT-UORIG\r
2455 *\r
2456 * ======>>  75  <<\r
2457 * ( --- vadr )   \r
2458 * Current context of definition (vocabulary root).\r
2459         EVEN\r
2460         DC.B    $87\r
2461         DC.B    'CURREN'        ; 'CURRENT' :   points to ptr. to vocab being extended\r
2462         DC.B    'T'|$80\r
2463         DC.L    CONTXT-8-NATWID\r
2464 CURENT  DC.L    DOUSER\r
2465         DC.L    XCURR-UORIG\r
2466 *\r
2467 * ======>>  76  <<\r
2468 * ( --- vadr )   \r
2469 * Compiler/interpreter state.\r
2470         EVEN\r
2471         DC.B    $85\r
2472         DC.B    'STAT'  ; 'STATE' :     1 if compiling, 0 if not\r
2473         DC.B    'E'|$80\r
2474         DC.L    CURENT-8-NATWID\r
2475 STATE   DC.L    DOUSER\r
2476         DC.L    XSTATE-UORIG\r
2477 *\r
2478 * ======>>  77  <<\r
2479 * ( --- vadr )   \r
2480 * Numeric conversion base.\r
2481         EVEN\r
2482         DC.B    0\r
2483         DC.B    $84\r
2484         DC.B    'BAS'   ; 'BASE' :      number base for all input & output\r
2485         DC.B    'E'|$80\r
2486         DC.L    STATE-6-NATWID\r
2487 BASE    DC.L    DOUSER\r
2488         DC.L    XBASE-UORIG\r
2489 *\r
2490 * ======>>  78  <<\r
2491 * ( --- vadr ) \r
2492 * Decimal point location for output.\r
2493         EVEN\r
2494         DC.B    $83\r
2495         DC.B    'DP'    ; 'DPL'\r
2496         DC.B    'L'|$80\r
2497         DC.L    BASE-5-NATWID\r
2498 DPL     DC.L    DOUSER\r
2499         DC.L    XDPL-UORIG\r
2500 *\r
2501 * ======>>  79  <<\r
2502 * ( --- vadr )   \r
2503 * Field width for I/O formatting.\r
2504         EVEN\r
2505         DC.B    $83\r
2506         DC.B    'FL'    ; 'FLD'\r
2507         DC.B    'D'|$80\r
2508         DC.L    DPL-4-NATWID\r
2509 FLD     DC.L    DOUSER\r
2510         DC.L    XFLD-UORIG\r
2511 *\r
2512 * ======>>  80  <<\r
2513 * ( --- vadr )   \r
2514 * Compiler stack mark for stack check.\r
2515         EVEN\r
2516         DC.B    $83\r
2517         DC.B    'CS'    ; 'CSP'\r
2518         DC.B    'P'|$80\r
2519         DC.L    FLD-4-NATWID\r
2520 CSP     DC.L    DOUSER\r
2521         DC.L    XCSP-UORIG\r
2522 *\r
2523 * ======>>  81  <<\r
2524 * ( --- vadr )   \r
2525 * Editing cursor location. \r
2526         EVEN\r
2527         DC.B    0\r
2528         DC.B    $82\r
2529         DC.B    'R'     ; 'R#'\r
2530         DC.B    '#'|$80\r
2531         DC.L    CSP-4-NATWID\r
2532 RNUM    DC.L    DOUSER\r
2533         DC.L    XRNUM-UORIG\r
2534 *\r
2535 * ======>>  82  <<\r
2536 * ( --- vadr )   \r
2537 * Pointer to last HELD character in PAD.\r
2538         EVEN\r
2539         DC.B    $83\r
2540         DC.B    'HL'    ; 'HLD'\r
2541         DC.B    'D'|$80\r
2542         DC.L    RNUM-3-NATWID\r
2543 HLD     DC.L    DOCON\r
2544         DC.L    XHLD\r
2545 *\r
2546 * ======>>  82.5  <<== SPECIAL\r
2547 * ( --- vadr )   \r
2548 * Line width of active terminal.\r
2549         EVEN\r
2550         DC.B    $87\r
2551         DC.B    'COLUMN'        ; 'COLUMNS' :   line width of terminal\r
2552         DC.B    'S'|$80\r
2553         DC.L    HLD-4-NATWID\r
2554 COLUMS  DC.L    DOUSER\r
2555         DC.L    XCOLUM-UORIG\r
2556 *\r
2557         PAGE\r
2558 *\r
2559 * ######>> screen 38 <<\r
2560 **\r
2561 ** An INCREMENTER probably should not be defined without a defined CONSTANT increment?\r
2562 ** Ergo, defined in pairs --\r
2563 **\r
2564 ** Make an INCREMENTER compiling word (not in model):\r
2565 ** ( n --- )\r
2566 ** { n INCREMENTER name } typical input\r
2567 ** CREATE a header and compile the increment constant, \r
2568 ** then overwrite the header with a call to DOINC.\r
2569 *       DC.B    $8B\r
2570 *       DC.B    'INCREMENTE'    ; 'INCREMENTER'\r
2571 *       DC.B    'R'|$80\r
2572 *       DC.L    COLUMS-8-NATWID\r
2573 * INCR  DC.L    DOCOL,CON,PSCODE\r
2574 ** ( n --- ninc ) \r
2575 ** Characteristic of an INCREMENTER.\r
2576 ** This is probably too naive:\r
2577 * DOINC MOVE.L  (W),D0  ; Get the increment,\r
2578 *       ADD.L   D0,(PSP)        ; and add it.\r
2579 *       RTS\r
2580 * Compiling word should check that it is compiling a CONSTANT.\r
2581 * On the other hand, there are reasons not to:\r
2582 *\r
2583 * ======>>  83  <<\r
2584 * ( n --- n+1 )\r
2585         EVEN\r
2586         DC.B    0\r
2587         DC.B    $82\r
2588         DC.B    '1'     ; '1+'\r
2589         DC.B    '+'|$80\r
2590         DC.L    COLUMS-8-NATWID\r
2591 * Using the model keeps things semantically connected for other processors:\r
2592 ONEP    DC.L    DOCOL,ONE,PLUS\r
2593         DC.L    SEMIS\r
2594 ** Greedy alternative:\r
2595 * ONEPG DC.L    *+NATWID\r
2596 *       MOVE.L  (PSP),D0\r
2597 *       ADD.L   ONEV(PC),D0\r
2598 *       MOVE.L  D0,(PSP)\r
2599 *       RTS\r
2600 * Naive alternative:\r
2601 * ONEPI DC.L    DOINC\r
2602 *       DC.L    1\r
2603 * Naive alternative:\r
2604 * ONEP1 DC.L    *+NATWID\r
2605 *       ADDQ.L  #1,(PSP) ; It's hard to imagine 1+ being other than 1.\r
2606 *       RTS\r
2607 *\r
2608 * ======>>  84  <<\r
2609 * ( n --- n+2 )\r
2610         EVEN\r
2611         DC.B    0\r
2612         DC.B    $82\r
2613         DC.B    '2'     ; '2+'\r
2614         DC.B    '+'|$80\r
2615         DC.L    ONEP-3-NATWID\r
2616 * Using the model keeps things semantically connected for other processors:\r
2617 TWOP    DC.L    DOCOL,TWO,PLUS\r
2618         DC.L    SEMIS\r
2619 ** Greedy alternative:\r
2620 * TWOP  DC.L    *+NATWID\r
2621 *       MOVE.L  (PSP),D0\r
2622 *       ADD.L   TWOV(PC),D0\r
2623 *       MOVE.L  D0,(PSP)\r
2624 *       RTS\r
2625 * Naive alternative:\r
2626 * TWOP  DC.L    DOINC\r
2627 *       DC.L    2\r
2628 * Naive alternative:\r
2629 * TWOP  DC.L    *+NATWID\r
2630 *       ADDQ.L  #2,(PSP) ; It's hard to imagine 1+ being other than 2.\r
2631 *       RTS\r
2632 *\r
2633 * ======>>  85  <<\r
2634 * ( --- adr )\r
2635 * Get the DICTPT allocation, like a USER constant.  \r
2636 * Should check the stack and heap for collision.\r
2637         EVEN\r
2638         DC.B    0\r
2639         DC.B    $84\r
2640         DC.B    'HER'   ; 'HERE'\r
2641         DC.B    'E'|$80\r
2642         DC.L    TWOP-3-NATWID\r
2643 HERE    DC.L    DOCOL,DICTPT,AT\r
2644         DC.L    SEMIS\r
2645 *\r
2646 * ======>>  86  <<\r
2647 * ( n --- )\r
2648 * Increase/decrease heap (add n to DP),\r
2649 * Should ERROR check stack/heap.\r
2650         EVEN\r
2651         DC.B    $85\r
2652         DC.B    'ALLO'  ; 'ALLOT'\r
2653         DC.B    'T'|$80\r
2654         DC.L    HERE-5-NATWID\r
2655 ALLOT   DC.L    DOCOL,DICTPT,PSTORE\r
2656         DC.L    SEMIS\r
2657 *\r
2658 * ======>>  87  <<\r
2659 * ( n --- )\r
2660 * Store word n at DP++,\r
2661 * Should ERROR check stack/heap.\r
2662         EVEN\r
2663         DC.B    $81     ; , (COMMA)\r
2664         DC.B    ','|$80\r
2665         DC.L    ALLOT-6-NATWID\r
2666 COMMA   DC.L    DOCOL,HERE,STORE,NATWC,ALLOT    ; race condition\r
2667         DC.L    SEMIS\r
2668 * COMMA DC.L    DOCOL,HERE,STORE,TWO,ALLOT      ;  The model hard-coded TWO\r
2669 *\r
2670 * ======>>  88  <<\r
2671 * ( b --- )\r
2672 * Store byte b at DP+,\r
2673 * Should ERROR check stack/heap.\r
2674 * Unfortunate naming.\r
2675         EVEN\r
2676         DC.B    0\r
2677         DC.B    $82\r
2678         DC.B    'C'     ; 'C,'\r
2679         DC.B    ','|$80\r
2680         DC.L    COMMA-2-NATWID\r
2681 CCOMM   DC.L    DOCOL,HERE,CSTORE,ONE,ALLOT     ; race condition\r
2682         DC.L    SEMIS\r
2683 *\r
2684 * ( n --- )\r
2685 * Bump the DICTPT if necessary to odd or even alignment, according to n,\r
2686 * by compiling in an extra NUL byte.\r
2687 * Odd n for odd alignment, even n for even.\r
2688         EVEN\r
2689         DC.B    $8B\r
2690         DC.B    'ALIGN-COMM'    ; 'ALIGN-COMMA'\r
2691         DC.B    'A'|$80\r
2692         DC.L    CCOMM-3-NATWID\r
2693 ALCOM   DC.L    DOCOL,HERE,ZERO,ALGNB,ZBRAN\r
2694         DC.L    ALCOMX-*-NATWID\r
2695         DC.L    ZERO,CCOMM\r
2696 ALCOMX  DC.L    DROP\r
2697         DC.L    SEMIS\r
2698 *\r
2699 * Not in model, but needed for 32-bit.\r
2700 * ( h --- )\r
2701 * Store half cell h at DP+.\r
2702 * Should ERROR check stack/heap.\r
2703         EVEN\r
2704         DC.B    0\r
2705         DC.B    $82\r
2706         DC.B    'H'     ; 'H,'\r
2707         DC.B    ','|$80\r
2708         DC.L    ALCOM-12-NATWID\r
2709 HCOMM   DC.L    DOCOL,HERE,HSTORE,HNATWC,ALLOT  ; race condition\r
2710         DC.L    SEMIS\r
2711 *\r
2712 * ======>>  89  <<\r
2713 * ( n1 n2 --- n1-n2 )\r
2714 * Subtract top two words.\r
2715         EVEN\r
2716         DC.B    $81     ; -\r
2717         DC.B    '-'|$80\r
2718         DC.L    HCOMM-3-NATWID\r
2719 SUB     DC.L    *+NATWID\r
2720         MOVE.L  (PSP)+,D0       ; Subtraction is not commutative.\r
2721         SUB.L   D0,(PSP)        ; left side operand is the deeper one on the stack.\r
2722         RTS\r
2723 * SUB   DC.L    DOCOL,MINUS,PLUS\r
2724 *       DC.L    SEMIS   ; Costs extra bytes and lots of cycles compared to native code.\r
2725 *\r
2726 * ( d1 d2 --- d1-d2 )\r
2727 * Subtract top two integers.\r
2728 * Yes, we do want this in the model.\r
2729         EVEN\r
2730         DC.B    0\r
2731         DC.B    $82\r
2732         DC.B    'D'     ; D-\r
2733         DC.B    '-'|$80\r
2734         DC.L    SUB-2-NATWID\r
2735 DSUB    DC.L    *+NATWID\r
2736         MOVEM.L (PSP)+,D0/D1/D2/D3      ; ADDX memory operand requires too much setup for just two long words.\r
2737         SUB.L   D1,D3                   ; Right order for subtraction.\r
2738         SUBX.L  D0,D2\r
2739         MOVEM.L D2/D3,-(PSP)\r
2740         RTS\r
2741 *\r
2742 * ======>>  90  <<\r
2743 * ( n1 n2 --- n1==n2 )\r
2744 * Return flag true if n1 and n2 are equal, otherwise false.\r
2745         EVEN\r
2746         DC.B    $81     ; =\r
2747         DC.B    '='|$80\r
2748         DC.L    DSUB-3-NATWID\r
2749 EQUAL   DC.L    DOCOL,SUB,ZEQU\r
2750         DC.L    SEMIS\r
2751 *\r
2752 * ======>>  91  <<\r
2753 * ( n1 n2 --- n1<n2 )\r
2754 * Return flag true if n1 is less than n2, otherwise false.\r
2755 * Signed compare.\r
2756         EVEN\r
2757         DC.B    $81     ; <\r
2758         DC.B    '<'|$80 \r
2759         DC.L    EQUAL-2-NATWID\r
2760 LESS    DC.L    *+NATWID\r
2761         CLR.L   D2      ; Guess false.\r
2762         MOVE.L  (PSP)+,D0\r
2763         MOVE.L  (PSP),D1\r
2764         SUB.L   D0,D1\r
2765         BGE.S   LESSST\r
2766 TRUE    MOVEQ   #1,D2   ; MOVEQ is a little faster than ADDQ.L\r
2767 LESSST  MOVE.L  D2,(PSP)\r
2768         RTS\r
2769\r
2770 *\r
2771 * ======>>  92  <<\r
2772 * ( n1 n2 --- n1>n2 )\r
2773 * Return flag true if n1 is greater than n2, false otherwise.\r
2774         EVEN\r
2775         DC.B    $81     ; >\r
2776         DC.B    '>'|$80\r
2777         DC.L    LESS-2-NATWID\r
2778 GREAT   DC.L    DOCOL,SWAP,LESS\r
2779         DC.L    SEMIS\r
2780 *\r
2781 * ======>>  93  <<\r
2782 * ( n1 n2 n3 --- n2 n3 n1 )\r
2783 * Rotate the top three words on stack,\r
2784 * bringing the third word to the top.\r
2785         EVEN\r
2786         DC.B    $83\r
2787         DC.B    'RO'    ; 'ROT'\r
2788         DC.B    'T'|$80\r
2789         DC.L    GREAT-2-NATWID\r
2790 ROT     DC.L    *+NATWID\r
2791         MOVEM.L (PSP),D0/D1/D2\r
2792         MOVEM.L D0/D1,NATWID(PSP)\r
2793         MOVE.L  D2,(PSP)\r
2794         RTS\r
2795 *\r
2796 * ======>>  94  <<\r
2797 * ( --- )\r
2798 * EMIT a SPACE.\r
2799         EVEN\r
2800         DC.B    $85\r
2801         DC.B    'SPAC'  ; 'SPACE'\r
2802         DC.B    'E'|$80\r
2803         DC.L    ROT-4-NATWID\r
2804 SPACE   DC.L    DOCOL,BL,EMIT\r
2805         DC.L    SEMIS\r
2806 *\r
2807 * ======>>  95  <<\r
2808 *  ( n0 n1 --- min(n0,n1) )\r
2809 * Leave the minimum of the top two integers.\r
2810 * Being too greedy here, but, whatever.\r
2811         EVEN\r
2812         DC.B    $83\r
2813         DC.B    'MI'    ; 'MIN'\r
2814         DC.B    'N'|$80\r
2815         DC.L    SPACE-6-NATWID\r
2816 MIN     DC.L    *+NATWID\r
2817         MOVE.L  (PSP)+,D0\r
2818         CMP.L   (PSP),D0\r
2819         BGE.S   MINX\r
2820         MOVE.L  D0,(PSP)        \r
2821 MINX    RTS     \r
2822 * MIN   DC.L    DOCOL,OVER,OVER,GREAT,ZBRAN\r
2823 *       DC.L    MIN2-*-NATWID\r
2824 *       DC.L    SWAP\r
2825 * MIN2  DC.L    DROP\r
2826 *       DC.L    SEMIS\r
2827 *\r
2828 * ======>>  96  <<\r
2829 * ( n0 n1 --- max(n0,n1) )\r
2830 * Leave the maximum of the top two integers.\r
2831 * Really should leave this as in the model, to reduce testing.\r
2832         EVEN\r
2833         DC.B    $83\r
2834         DC.B    'MA'    ; 'MAX'\r
2835         DC.B    'X'|$80\r
2836         DC.L    MIN-4-NATWID\r
2837 MAX     DC.L    *+NATWID\r
2838         MOVE.L  (PSP)+,D0\r
2839         CMP.L   (PSP),D0\r
2840         BLE.S   MAXX\r
2841         MOVE.L  D0,(PSP)        \r
2842 MAXX    RTS     \r
2843 * MAX   DC.L    DOCOL,OVER,OVER,LESS,ZBRAN\r
2844 *       DC.L    MAX2-*-NATWID\r
2845 *       DC.L    SWAP\r
2846 * MAX2  DC.L    DROP\r
2847 *       DC.L    SEMIS\r
2848 *\r
2849 * ======>>  97  <<\r
2850 * ( 0 --- 0 )\r
2851 * ( n --- n n )\r
2852 * DUP if non-zero.\r
2853         EVEN\r
2854         DC.B    0\r
2855         DC.B    $84\r
2856         DC.B    '-DU'   ; '-DUP'\r
2857         DC.B    'P'|$80\r
2858         DC.L    MAX-4-NATWID\r
2859 DDUP    DC.L    *+NATWID        ; Just being greedy for speed.\r
2860         MOVE.L  (PSP),D0\r
2861         BEQ.S   DDUPX\r
2862         MOVE.L  D0,-(PSP)\r
2863 DDUPX   RTS\r
2864 * DDUP  DC.L    DOCOL,DUP,ZBRAN\r
2865 *       DC.L    DDUP2-*-NATWID\r
2866 *       DC.L    DUP\r
2867 * DDUP2 DC.L    SEMIS\r
2868 *\r
2869 * ######>> screen 39 <<\r
2870 * ======>> 98.1 <<\r
2871 * Supplemental, intended to be used in refactoring TRAVERSE,\r
2872 * But really would not work there without more code:\r
2873 * ( n<0 --- -1 )\r
2874 * ( n>=~ --- 1 )\r
2875 * Change top integer to its sign.\r
2876         EVEN\r
2877         DC.B    0\r
2878         DC.B    $86\r
2879         DC.B    'SIGNU' ; 'SIGNUM'\r
2880         DC.B    'M'|$80\r
2881         DC.L    DDUP-5-NATWID\r
2882 SIGNUM  DC.L    *+NATWID\r
2883 SIGNUE  CLR.L   D0\r
2884         TST.L   (PSP)\r
2885         SMI     D0\r
2886         EXT.W   D0\r
2887         EXT.L   D0\r
2888         MOVE.L  D0,(PSP)\r
2889         RTS\r
2890 *\r
2891 * ======>>  98  <<\r
2892 * ( adr1 direction --- adr2 )\r
2893 * TRAVERSE the symbol name.\r
2894 * If direction is 1, find the end.\r
2895 * If direction is -1, find the beginning.\r
2896         EVEN\r
2897         DC.B    0\r
2898         DC.B    $88\r
2899         DC.B    'TRAVERS'       ; 'TRAVERSE'\r
2900         DC.B    'E'|$80\r
2901         DC.L    SIGNUM-7-NATWID\r
2902 *TRAV   DC.L    *+NATWID\r
2903 *       MOVEQ   #1,D1   ; Convert negative to -1, zero or positive to 1.\r
2904 *       TST.L   (PSP)+\r
2905 *       BPL.S   TRAVG\r
2906 *       NEG.L   D1\r
2907 *TRAVG  MOVE.L  (PSP),A0\r
2908 **      MOVEQ   #$7F,D0\r
2909 ** TRAVLP       LEA     (A0,D1.L),A0    ; Don't look at the one we start at.\r
2910 **      CMP.B   (A0),D0 ; This follows the FORTH code, but, we could just look at sign bit.\r
2911 **      BCC.S   TRAVLP\r
2912 *       CLR.L   D0      ; Scan by indexing so we can limit it.\r
2913 *TRAVLP ADD.L   D1,D0   ; Don't look at (A0).\r
2914 *       TST.B   (A0,D0.L)\r
2915 *       BMI.S   TRAVDN\r
2916 *       TST.L   D1      ; Limit the scan in the selected direction.\r
2917 *       BMI.S   TRAVLN\r
2918 *       CMP.W   #32,D0\r
2919 *       BCS.S   TRAVLP\r
2920 *TRAVLN CMP.W   #-31,D0\r
2921 *       BPL.S   TRAVLP\r
2922 *TRAVDN LEA     (A0,D0.L),A0\r
2923 *       MOVE.L  A0,(PSP)\r
2924 *       RTS\r
2925 * Doing this in 68000 or 6809 just because it can be done was getting too greedy.\r
2926 * Or not? I needed it to test that TRAVERSE was not screwing up.\r
2927 TRAV    DC.L    DOCOL\r
2928 *       DC.L    TRON    ; DBUG *****\r
2929         DC.L    SWAP\r
2930 TRAV2   DC.L    OVER,PLUS,LIT16\r
2931         DC.W    $7F\r
2932         DC.L    OVER,CAT,LESS,ZBRAN\r
2933         DC.L    TRAV2-*-NATWID\r
2934         DC.L    SWAP,DROP\r
2935 *       DC.L    TROFF   ; DBG *****\r
2936         DC.L    SEMIS\r
2937 *\r
2938 * ======>>  99  <<\r
2939 * ( --- symptr )\r
2940 * Fetch CURRENT as a per-USER constant.\r
2941         EVEN\r
2942         DC.B    0\r
2943         DC.B    $86\r
2944         DC.B    'LATES' ; 'LATEST'\r
2945         DC.B    'T'|$80\r
2946         DC.L    TRAV-9-NATWID\r
2947 LATEST  DC.L    DOCOL,CURENT,AT,AT\r
2948         DC.L    SEMIS\r
2949 * LATEST        DC.L    *+NATWID\r
2950 * Getting too greedy:\r
2951 *       MOVE.L  XCURR-UORIG(UP),D0\r
2952 *       MOVE.L  (UP,D0.L),A0\r
2953 *       MOVE.L  (A0),A0\r
2954 *       MOVE.L  A0,-(PSP)\r
2955 *       RTS\r
2956 * Too greedy, still too many smantic holes in the model to fall through.\r
2957 * Also, if the address at the CFA is made relative, \r
2958 * this is part of the code that would be affected --\r
2959 * especially if it is in native CPU code.\r
2960 *\r
2961 * ======>>  100  <<\r
2962 * Wanted to do these as INCREMENTERs,\r
2963 * but I need to stick with the model as much as possible,\r
2964 * (mostly, LOL) adding code only to make the model more clear.\r
2965 * ( pfa --- lfa )     \r
2966 * Convert PFA to LFA, unchecked. (Bump back from contents to allocation link.)\r
2967         EVEN\r
2968         DC.B    $83\r
2969         DC.B    'LF'    ; 'LFA'\r
2970         DC.B    'A'|$80\r
2971         DC.L    LATEST-7-NATWID\r
2972 LFA     DC.L    DOCOL,LIT16\r
2973 *       DC.W    4       ; on 6800\r
2974         DC.W    2*NATWID\r
2975         DC.L    SUB\r
2976         DC.L    SEMIS\r
2977 *\r
2978 * ======>>  101  <<\r
2979 * ( pfa --- cfa )    \r
2980 * Convert PFA to CFA, unchecked. (Bump back from contents to characterist code link.)\r
2981         EVEN\r
2982         DC.B    $83\r
2983         DC.B    'CF'    ; 'CFA'\r
2984         DC.B    'A'|$80\r
2985         DC.L    LFA-4-NATWID\r
2986 * CFA   DC.L    DOCOL,TWO,SUB   ; on 6800\r
2987 CFA     DC.L    DOCOL,NATWC,SUB\r
2988         DC.L    SEMIS\r
2989 *\r
2990 * ======>>  102  <<\r
2991 * ( pfa --- nfa )     \r
2992 * Convert PFA to NFA. (Bump back from contents to beginning of symbol name.)\r
2993         EVEN\r
2994         DC.B    $83\r
2995         DC.B    'NF'    ; 'NFA'\r
2996         DC.B    'A'|$80\r
2997         DC.L    CFA-4-NATWID\r
2998 NFA     DC.L    DOCOL,LIT16\r
2999 *       DC.W    5       ; on 6800\r
3000         DC.W    NATWID*2+1\r
3001         DC.L    SUB,ONE,MINUS,TRAV\r
3002         DC.L    SEMIS\r
3003 *\r
3004 * ======>>  103  <<\r
3005 * ( nfa --- pfa )     \r
3006 * Convert NFA to PFA. (Bump up from beginning of symbol name to contents.)\r
3007         EVEN\r
3008         DC.B    $83\r
3009         DC.B    'PF'    ; 'PFA'\r
3010         DC.B    'A'|$80\r
3011         DC.L    NFA-4-NATWID\r
3012 PFA     DC.L    DOCOL,ONE,TRAV,LIT16\r
3013 *       DC.W    5       ; on 6800\r
3014         DC.W    NATWID*2+1\r
3015         DC.L    PLUS\r
3016         DC.L    SEMIS\r
3017 *\r
3018 * ######>> screen 40 <<\r
3019 * ======>>  104  <<\r
3020 * ( --- )\r
3021 * Save the parameter stack pointer in CSP for compiler checks.\r
3022         EVEN\r
3023         DC.B    0\r
3024         DC.B    $84\r
3025         DC.B    '!CS'   ; '!CSP'\r
3026         DC.B    'P'|$80\r
3027         DC.L    PFA-4-NATWID\r
3028 *SCSP   DC.L    DOCOL,SPAT,CSP,STORE\r
3029 *       DC.L    SEMIS\r
3030 SCSP    DC.L    *+NATWID\r
3031         MOVE.L  PSP,XCSP-UORIG(UP)      \r
3032         RTS\r
3033 * How would the optimizer have been able to work through the following\r
3034 * to get the above?\r
3035 *SCSP   DC.L    *+NATWID\r
3036 *       MOVE.L  PSP,-(PSP)\r
3037 **      MOVE.L  (W),D0  ; Offset into the table.\r
3038 **      LEA     (UP,D0.L),A0\r
3039 *       LEA     XCSP-UORIG(UP),A0\r
3040 *       MOVE.L  A0,-(PSP)\r
3041 *       MOVEM.L (PSP)+,D0/A0\r
3042 *       EXG     D0,A0\r
3043 *       MOVE.L  D0,(A0)\r
3044 *       RTS\r
3045 *\r
3046         PAGE\r
3047 *\r
3048 * ======>>  105  <<\r
3049 * ( 0 n --- )             ( *** )\r
3050 * ( true n --- IN BLK )   ( anything *** nothing )\r
3051 * If flag is false, do nothing. \r
3052 * If flag is true, issue error MESSAGE and QUIT or ABORT, via ERROR. \r
3053 * Leaves cursor position (IN)\r
3054 * and currently loading block number (BLK) on stack, for analysis.\r
3055 *\r
3056 * This one is too important to be high-level Forth codes.\r
3057 * When we have an error, we want to disturb as little as possible.\r
3058 * But fixing that cascades through ERROR and MESSAGE \r
3059 * into the disk block system.\r
3060 * And we aren't ready for that yet.\r
3061         EVEN\r
3062         DC.B    0\r
3063         DC.B    $86\r
3064         DC.B    '?ERRO' ; '?ERROR'\r
3065         DC.B    'R'|$80\r
3066         DC.L    SCSP-5-NATWID\r
3067 * QERR  DC.L    *+NATWID\r
3068 *       TST.L   NATWID(PSP)\r
3069 *       BNE.S   QERROR\r
3070 *       LEA     NATWID(PSP),PSP\r
3071 *       RTS\r
3072 ** this doesn't work anyway: \r
3073 * QERROR        BRA.W   ERROR\r
3074 QERR    DC.L    DOCOL,SWAP,ZBRAN\r
3075         DC.L    QERR2-*-NATWID\r
3076         DC.L    ERROR,BRAN\r
3077         DC.L    QERR3-*-NATWID\r
3078 QERR2   DC.L    DROP\r
3079 QERR3   DC.L    SEMIS\r
3080 *       \r
3081 * ======>>  106  <<\r
3082 * STATE is compiling:\r
3083 * ( --- )                 ( *** )\r
3084 * STATE is not compiling:\r
3085 * ( --- IN BLK )          ( anything *** nothing )\r
3086 * ERROR if not compiling.\r
3087         EVEN\r
3088         DC.B    $85\r
3089         DC.B    '?COM'  ; '?COMP'\r
3090         DC.B    'P'|$80\r
3091         DC.L    QERR-7-NATWID\r
3092 QCOMP   DC.L    DOCOL,STATE,AT,ZEQU,LIT16\r
3093         DC.W    $11\r
3094         DC.L    QERR\r
3095         DC.L    SEMIS\r
3096 *\r
3097 * ======>>  107  <<\r
3098 * STATE is executing:\r
3099 * ( --- )                 ( *** )\r
3100 * STATE is not executing:\r
3101 * ( --- IN BLK )          ( anything *** nothing )\r
3102 * ERROR if not executing.\r
3103         EVEN\r
3104         DC.B    $85\r
3105         DC.B    '?EXE'  ; '?EXEC'\r
3106         DC.B    'C'|$80\r
3107         DC.L    QCOMP-6-NATWID\r
3108 QEXEC   DC.L    DOCOL,STATE,AT,LIT16\r
3109         DC.W    $12\r
3110         DC.L    QERR\r
3111         DC.L    SEMIS\r
3112 *\r
3113 * ======>>  108  <<\r
3114 * ( n1 n1 --- )           ( *** )\r
3115 * ( n1 n2 --- IN BLK )    ( anything *** nothing )\r
3116 * ERROR if top two are unequal. \r
3117 * MESSAGE says compiled conditionals do not match.\r
3118         EVEN\r
3119         DC.B    0\r
3120         DC.B    $86\r
3121         DC.B    '?PAIR' ; '?PAIRS'\r
3122         DC.B    'S'|$80\r
3123         DC.L    QEXEC-6-NATWID\r
3124 QPAIRS  DC.L    DOCOL,SUB,LIT16\r
3125         DC.W    $13\r
3126         DC.L    QERR\r
3127         DC.L    SEMIS\r
3128 *\r
3129 * ======>>  109  <<\r
3130 * CSP and parameter stack are balanced (equal):\r
3131 * ( --- )                 ( *** )\r
3132 * CSP and parameter stack are not balanced (unequal):\r
3133 * ( --- IN BLK )          ( anything *** nothing )\r
3134 * ERROR if return/control stack is not at same level as last !CSP.\r
3135 * Usually indicates that a definition has been left incomplete.\r
3136         EVEN\r
3137         DC.B    0\r
3138         DC.B    $84\r
3139         DC.B    '?CS'   ; '?CSP'\r
3140         DC.B    'P'|$80\r
3141         DC.L    QPAIRS-7-NATWID\r
3142 QCSP    DC.L    DOCOL,SPAT,CSP,AT,SUB,LIT16\r
3143         DC.W    $14\r
3144         DC.L    QERR\r
3145         DC.L    SEMIS\r
3146 *\r
3147 * ======>>  110  <<\r
3148 * Active BLK input:\r
3149 * ( --- )         ( *** )\r
3150 * No active BLK input:\r
3151 * ( --- IN BLK )          ( anything *** nothing )\r
3152 * ERROR if not loading, i. e., if BLK is zero.\r
3153         EVEN\r
3154         DC.B    0\r
3155         DC.B    $88\r
3156         DC.B    '?LOADIN'       ; '?LOADING'\r
3157         DC.B    'G'|$80\r
3158         DC.L    QCSP-5-NATWID\r
3159 QLOAD   DC.L    DOCOL,BLK,AT,ZEQU,LIT16\r
3160         DC.W    $16\r
3161         DC.L    QERR\r
3162         DC.L    SEMIS\r
3163 *\r
3164 * ######>> screen 41 <<\r
3165 * ======>>  111  <<\r
3166 * ( --- )\r
3167 * Compile an in-line literal value from the instruction stream.\r
3168         EVEN\r
3169         DC.B    $87\r
3170         DC.B    'COMPIL'        ; 'COMPILE'\r
3171         DC.B    'E'|$80\r
3172         DC.L    QLOAD-9-NATWID\r
3173 * COMPIL        DC.L    DOCOL,QCOMP,FROMR,TWOP,DUP,TOR,AT,COMMA\r
3174 * COMPIL        DC.L    DOCOL,QCOMP,FROMR,NATP,DUP,TOR,AT,COMMA\r
3175 COMPIL  DC.L    DOCOL,QCOMP,FROMR,DUP,NATP,TOR,AT,COMMA\r
3176         DC.L    SEMIS\r
3177 *\r
3178 * ======>>  112  <<\r
3179 * ( --- )                                                 P\r
3180 * Clear the compile state bit(s) (shift to interpret).\r
3181         EVEN\r
3182         DC.B    $C1     ; [     immediate\r
3183         DC.B    '['|$80\r
3184         DC.L    COMPIL-8-NATWID\r
3185 LBRAK   DC.L    DOCOL,ZERO,STATE,STORE\r
3186         DC.L    SEMIS\r
3187 *\r
3188 * ======>>  113  <<\r
3189\r
3190 STCOMP  EQU     $C0\r
3191 * ( --- )\r
3192 * Set the compile state bit(s) (shift to compile).\r
3193         EVEN\r
3194         DC.B    $81     ; ]\r
3195         DC.B    ']'|$80\r
3196         DC.L    LBRAK-2-NATWID\r
3197 *RBRAK  DC.L    DOCOL,LIT16\r
3198 *       DC.W    STCOMP\r
3199 *       DC.L    STATE,STORE\r
3200 *       DC.L    SEMIS\r
3201 RBRAK   DC.L    *+NATWID\r
3202         MOVE.L  #STCOMP,XSTATE-UORIG(UP)\r
3203         RTS\r
3204 *\r
3205 * ======>>  114  <<\r
3206 * ( --- )\r
3207 * Toggle SMUDGE bit of LATEST definition header,\r
3208 * to hide it until defined or reveal it after definition.\r
3209         EVEN\r
3210         DC.B    0\r
3211         DC.B    $86\r
3212         DC.B    'SMUDG' ; 'SMUDGE'\r
3213         DC.B    'E'|$80\r
3214         DC.L    RBRAK-2-NATWID\r
3215 SMUDGE  DC.L    DOCOL,LATEST,LIT16\r
3216         DC.W    FSMUDG\r
3217         DC.L    TOGGLE\r
3218         DC.L    SEMIS\r
3219 *\r
3220 * ======>>  115  <<\r
3221 * ( --- )\r
3222 * Set the conversion base to sixteen (b00010000).\r
3223         EVEN\r
3224         DC.B    $83\r
3225         DC.B    'HE'    ; 'HEX'\r
3226         DC.B    'X'|$80\r
3227         DC.L    SMUDGE-7-NATWID\r
3228 HEX     DC.L    DOCOL\r
3229         DC.L    LIT16\r
3230         DC.W    16      ; decimal sixteen\r
3231         DC.L    BASE,STORE\r
3232         DC.L    SEMIS\r
3233 *\r
3234 * ======>>  116  <<\r
3235 * ( --- )\r
3236 * Set the conversion base to ten (b00001010).\r
3237         EVEN\r
3238         DC.B    $87\r
3239         DC.B    'DECIMA'        ; 'DECIMAL'\r
3240         DC.B    'L'|$80\r
3241         DC.L    HEX-4-NATWID\r
3242 DEC     DC.L    DOCOL\r
3243         DC.L    LIT16\r
3244         DC.W    10      ; decimal ten\r
3245         DC.L    BASE,STORE\r
3246         DC.L    SEMIS\r
3247 *\r
3248 * ######>> screen 42 <<\r
3249 * ======>>  117  <<\r
3250 * ( --- )         ( IP *** ) \r
3251 * Pop the saved IP and use it to \r
3252 * compile the latest symbol as a reference to a ;CODE definition;\r
3253 * overwrite the code field of the symbol found by LATEST\r
3254 * with the address of the low-level characteristic code\r
3255 * provided in the defining definition.\r
3256 * Look closely at where things return, consider the operation of R> and >R .\r
3257 *\r
3258 * The machine-level code which follows (;CODE) in the instruction stream\r
3259 * is not executed by the defining symbol,\r
3260 * but becomes the characteristic of the defined symbol. \r
3261 * This is the usual way to generate the characteristics of VARIABLEs,\r
3262 * CONSTANTs, COLON definitions, etc., when FORTH compiles itself. \r
3263 *\r
3264 * Finally, note that, if code shifts from low level back to high \r
3265 * (native CPU machine code calling into a list of FORTH codes),\r
3266 * the low level code can't just call a high-level definition. \r
3267 * Leaf definitions can directly call other leaf definitions, \r
3268 * but not non-leafs.\r
3269 * It will need an anonymous list, probably embedded in the low-level code,\r
3270 * and Y and X will have to be set appropriately before entering the list.\r
3271         EVEN\r
3272         DC.B    $87\r
3273         DC.B    '(;CODE'        ; '(;CODE)'\r
3274         DC.B    ')'|$80\r
3275         DC.L    DEC-8-NATWID\r
3276 * PSCODE        DC.L    DOCOL,FROMR,TWOP,LATEST,PFA,CFA,STORE\r
3277 PSCODE  DC.L    DOCOL,FROMR     ; A5/IP is post-inc, needs no adjustment.\r
3278         DC.L    LATEST,PFA,CFA,STORE\r
3279         DC.L    SEMIS\r
3280 *\r
3281 * ======>>  118  <<\r
3282 * ( --- )                                                 P\r
3283 * ?CSP to see if there are loose ends in the defining definition\r
3284 * before shifting to the assembler,\r
3285 * compile (;CODE) in the defining definition's instruction stream,\r
3286 * shift to interpreting,\r
3287 * make the ASSEMBLER vocabulary current,\r
3288 * and !CSP to mark the stack\r
3289 * in preparation for assembling low-level code.\r
3290 * Note that ;CODE, unlike DOES>, is IMMEDIATE,\r
3291 * and compiles (;CODE),\r
3292 * which will do the actual work of changing\r
3293 * the LATEST definition's characteristic when the defining word runs.\r
3294 * Assembly is done by the interpreter, rather than the compiler.\r
3295 * I could have avoided the anomalous three-byte code fields by\r
3296 *\r
3297 * Note that the ASSEMBLER is not part of the model (at this time).\r
3298 * That means that, until the assembler is ready, \r
3299 * if you want to define low-level words,\r
3300 * you have to poke (comma) in hand-assembled stuff.\r
3301 *\r
3302         EVEN\r
3303         DC.B    $C5     immediate\r
3304         DC.B    ';COD'  ; ';CODE'\r
3305         DC.B    'E'|$80\r
3306         DC.L    PSCODE-8-NATWID\r
3307 SEMIC   DC.L    DOCOL,QCSP,COMPIL,PSCODE,SMUDGE,LBRAK,QSTACK\r
3308         DC.L    NOOP    ; note: will be replaced by "ASSEMBLER" later\r
3309         DC.L    SEMIS\r
3310 * note: I think I'd rather keep ?STACK here, so I'm adding a NOOP to be patched later. \r
3311 *\r
3312 * ######>> screen 43 <<\r
3313 * ======>>  119  <<\r
3314 * ( --- )                                                 C\r
3315 * Make the word currently being defined\r
3316 * build a header for DOES> definitions. \r
3317 * Actually just compiles a CONSTANT zero\r
3318 * which can be overwritten later by DOES>.\r
3319 * Since the fig models were established, this technique has been deprecated.\r
3320 *\r
3321 * Note that <BUILDS is not IMMEDIATE,\r
3322 * and therefore executes during a definition's run-time,\r
3323 * rather than its compile-time. \r
3324 * It is not intended to be used directly,\r
3325 * but rather so that one definition word can build another. \r
3326 * Also, note that nothing particularly special happens\r
3327 * in the defining definition until DOES> executes. \r
3328 * The name <BUILDS is intended to be a reminder of what is about to occur.\r
3329 *\r
3330 * <BUILDS probably should have compiled an ERROR instead of a ZERO CONSTANT.\r
3331         EVEN\r
3332         DC.B    $87\r
3333         DC.B    '<BUILD'        ; '<BUILDS'\r
3334         DC.B    'S'|$80\r
3335         DC.L    SEMIC-6-NATWID\r
3336 BUILDS  DC.L    DOCOL,ZERO,CON\r
3337         DC.L    SEMIS\r
3338 *\r
3339 * ======>>  120  <<\r
3340 * ( --- )         ( IP *** )                              C\r
3341 * Define run-time behavior of definitions compiled/defined\r
3342 * by a high-level defining definition --\r
3343 * the FORTH equivalent of a compiler-compiler. \r
3344 * DOES> assumes that the LATEST symbol table entry\r
3345 * has at least one word of parameter field,\r
3346 * which <BUILDS provides. \r
3347 * Note that DOES> is also not IMMEDIATE. \r
3348 *\r
3349 * When the defining word containing DOES> executes the DOES> icode,\r
3350 * it overwrites the LATEST symbol's CFA with jsr <XDOES,\r
3351 * overwrites the first word of that symbol's parameter field with its own IP,\r
3352 * and pops the previous IP from the return stack.\r
3353 * The icodes which follow DOES> in the stream\r
3354 * do not execute at the defining word's run-time.\r
3355 *\r
3356 * Examining XDOES in the virtual machine shows\r
3357 * that the defined word will execute those icodes\r
3358 * which follow DOES> at its own run-time. \r
3359 *\r
3360 * The advantage of this kind of behaviour,\r
3361 * which you will also note in ;CODE,\r
3362 * is that the defined word can contain\r
3363 * both operations and data to be operated on. \r
3364 * This is how FORTH data objects define their own behavior. \r
3365 *\r
3366 * Finally, note that the effective parameter field for DOES> definitions\r
3367 * starts two NATWID words after the CFA, instead of just one\r
3368 * (eight bytes instead of four in a thirty-two-bit addressing Forth).\r
3369 *\r
3370 * VOCABULARYs will use this. See definition of word FORTH.\r
3371         EVEN\r
3372         DC.B    $85\r
3373         DC.B    'DOES'  ; 'DOES>'\r
3374         DC.B    '>'|$80\r
3375         DC.L    BUILDS-8-NATWID\r
3376 * DOES  DC.L    DOCOL,FROMR,TWOP,LATEST,PFA,STORE\r
3377 DOES    DC.L    DOCOL,FROMR     ; A5/IP is post-inc, needs no adjustment.\r
3378         DC.L    LATEST,PFA,STORE\r
3379         DC.L    PSCODE\r
3380 *\r
3381 * ( --- PFA+NATWID )     ( *** IP )\r
3382 * Characteristic of a DOES> defined word. \r
3383 * The characteristics of DOES> definitions are written in high-level\r
3384 * Forth codes rather than native CPU machine level code.\r
3385 * The first parameter word points to the high-level characteristic. \r
3386 * This routine's job is to push the IP,\r
3387 * load the high level characteristic pointer in IP,\r
3388 * and leave the address following the characteristic pointer on the stack\r
3389 * so the parameter field can be accessed.\r
3390 DODOES  MOVE.L  (RP),A0\r
3391         MOVE.L  IP,(RP) ; Save/nest the current IP on the return stack.\r
3392         MOVE.L  (W),IP  ; First parameter is new IP.\r
3393         LEA     NATWID(W),A1    ; Address of second parameter.\r
3394         MOVE.L  A1,-(PSP)       ; Note that PEA would push on Forth RP\r
3395         JMP     (A0)    ; return to NEXT.\r
3396 *\r
3397 * ######>> screen 44 <<\r
3398 * ======>>  121  <<\r
3399 * ( strptr --- strptr+1 count )\r
3400 * Convert counted string to string and count. \r
3401 * (Fetch the byte at strptr, post-increment.)\r
3402         EVEN\r
3403         DC.B    $85\r
3404         DC.B    'COUN'  ; 'COUNT'\r
3405         DC.B    'T'|$80\r
3406         DC.L    DOES-6-NATWID\r
3407 *COUNT  DC.L    DOCOL,DUP,ONEP,SWAP,CAT\r
3408 *       DC.L    SEMIS\r
3409 COUNT   DC.L    *+NATWID\r
3410         MOVE.L  (PSP),A0\r
3411         CLR.L   D0\r
3412         MOVE.B  (A0)+,D0\r
3413         MOVE.L  A0,(PSP)\r
3414         MOVE.L  D0,-(PSP)\r
3415         RTS\r
3416 *\r
3417 * ======>>  122  <<\r
3418 * ( strptr count --- )\r
3419 * EMIT count characters at strptr.\r
3420         EVEN\r
3421         DC.B    0\r
3422         DC.B    $84\r
3423         DC.B    'TYP'   ; 'TYPE'\r
3424         DC.B    'E'|$80\r
3425         DC.L    COUNT-6-NATWID\r
3426 *TYPE   DC.L    DOCOL,DDUP,ZBRAN\r
3427 *       DC.L    TYPE3-*-NATWID\r
3428 *       DC.L    OVER,PLUS,SWAP,XDO\r
3429 *TYPE2  DC.L    I,CAT,EMIT,XLOOP\r
3430 *       DC.L    TYPE2-*-NATWID\r
3431 *       DC.L    BRAN\r
3432 *       DC.L    TYPE4-*-NATWID\r
3433 *TYPE3  DC.L    DROP\r
3434 *TYPE4  DC.L    SEMIS\r
3435 *\r
3436 TYPE    DC.L    *+NATWID\r
3437         MOVEM.L (PSP)+,D0/A0\r
3438         LEA     (A0,D0.L),A1\r
3439         BRA.S   TYPET\r
3440 TYPEL   CLR.L   D0\r
3441         MOVE.B  (A0)+,D0\r
3442         MOVE.L  D0,-(PSP)\r
3443         BSR.W   EMIT+NATWID\r
3444 TYPET   CMP.L   A0,A1\r
3445         BHI.S   TYPEL\r
3446 TYPEX   RTS\r
3447 *\r
3448 * ======>>  123  <<\r
3449 * ( strptr count1 --- strptr count2 )\r
3450 * Supress trailing blanks (subtract count of trailing blanks from strptr).\r
3451         EVEN\r
3452         DC.B    $89\r
3453         DC.B    '-TRAILIN'      ; '-TRAILING'\r
3454         DC.B    'G'|$80\r
3455         DC.L    TYPE-5-NATWID\r
3456 DTRAIL  DC.L    DOCOL,DUP,ZERO,XDO\r
3457 DTRAL2  DC.L    OVER,OVER,PLUS,ONE,SUB,CAT,BL\r
3458         DC.L    SUB,ZBRAN\r
3459         DC.L    DTRAL3-*-NATWID\r
3460         DC.L    LEAVE,BRAN\r
3461         DC.L    DTRAL4-*-NATWID\r
3462 DTRAL3  DC.L    ONE,SUB\r
3463 DTRAL4  DC.L    XLOOP\r
3464         DC.L    DTRAL2-*-NATWID\r
3465         DC.L    SEMIS\r
3466 *\r
3467 * ======>>  124  <<\r
3468 * ( --- ) \r
3469 * TYPE counted string out of instruction stream (updating IP).\r
3470         EVEN\r
3471         DC.B    0\r
3472         DC.B    $84\r
3473         DC.B    '(."'   ; '(.")'\r
3474         DC.B    ')'|$80\r
3475         DC.L    DTRAIL-10-NATWID\r
3476 * PDOTQ DC.L    DOCOL,R,TWOP,COUNT,DUP,ONEP\r
3477 * PDOTQ DC.L    DOCOL,R,NATP,COUNT,DUP,ONEP\r
3478 *PDOTQ  DC.L    DOCOL,R         ; A5/IP is post-inc.\r
3479 *       DC.L    COUNT,DUP,ONEP  ; There's a count byte, too.\r
3480 *       DC.L    ZERO,ALGNB,PLUS ; Align the count.\r
3481 *       DC.L    FROMR,PLUS,TOR  ; IP ready to continue after the string.\r
3482 *       DC.L    TYPE\r
3483 *       DC.L    BREAK   ; DBG *****\r
3484 *       DC.L    SEMIS\r
3485 *\r
3486 PDOTQ   DC.L    *+NATWID        ; DOCOL\r
3487         MOVE.L  IP,-(PSP)       ; R -- Without DOCOL, IP (post-inc) is where the pointer is.\r
3488         BSR.W   COUNT+NATWID    ; Don't want to break the binding to COUNT.\r
3489         MOVEM.L (PSP),D0/A0     ; count and pointer to string, leave ready for TYPE\r
3490         ADD.L   A0,D0           ; pointer to end of string in D0\r
3491         BTST    #0,D0           ; Odd?\r
3492         BEQ.S   PDOTQZ\r
3493         ADDQ    #1,D0           ; Bump it even.\r
3494 PDOTQZ  MOVE.L  D0,IP           ; Bump IP over the string.\r
3495         BRA.W   TYPE            ; Tail-call.\r
3496 *\r
3497 * ======>>  125  <<\r
3498 * ( --- )                                                 P\r
3499 * { ." something-to-be-printed " } typical input\r
3500 * Use WORD to parse to trailing quote;\r
3501 * if compiling, compile XDOTQ and string parsed,\r
3502 * otherwise, TYPE string.\r
3503         EVEN\r
3504         DC.B    0\r
3505         DC.B    $C2     immediate\r
3506         DC.B    '.'     ; '."'\r
3507         DC.B    '"'|$80\r
3508         DC.L    PDOTQ-5-NATWID\r
3509 DOTQ    DC.L    DOCOL\r
3510         DC.L    LIT16\r
3511         DC.W    $22     ascii quote\r
3512         DC.L    STATE,AT,ZBRAN\r
3513         DC.L    DOTQ1-*-NATWID\r
3514         DC.L    COMPIL,PDOTQ,WORD\r
3515         DC.L    HERE,CAT,ONEP,DUP,ALLOT\r
3516         DC.L    ALGNB,ZBRAN     ; Rely on PDOTQ to adjust the IP for the odd length.\r
3517         DC.L    DOTQ0-*-NATWID\r
3518         DC.L    ZERO,CCOMM      ; Align and fill with NUL\r
3519 DOTQ0   DC.L    BRAN\r
3520         DC.L    DOTQ2-*-NATWID\r
3521 DOTQ1   DC.L    WORD,HERE,COUNT,TYPE\r
3522 DOTQ2   DC.L    SEMIS\r
3523 *\r
3524 * ######>> screen 45 <<\r
3525 * ======>>  126  <<== MACHINE DEPENDENT\r
3526 * ( --- )                 ( *** )\r
3527 * ( --- IN BLK )          ( anything *** nothing )\r
3528 * ERROR if parameter stack out of bounds.\r
3529\r
3530 * But checking whether the stack is in bounds or not\r
3531 * really should not use the stack.\r
3532 * And there really should be a ?RSTACK, as well.\r
3533         EVEN\r
3534         DC.B    0\r
3535         DC.B    $86\r
3536         DC.B    '?STAC' ; '?STACK'\r
3537         DC.B    'K'|$80\r
3538         DC.L    DOTQ-3-NATWID\r
3539 QSTACK  DC.L    DOCOL,LIT16\r
3540 *       DC.W    $12\r
3541         DC.W    SINIT-ORIG\r
3542 * But why use that instead of XSPZER (S0)?\r
3543 * Multi-user or multi-tasking would not want that.\r
3544 *       CMP.L   XSPZER-UORIG(UP),PSP    ; something like this   \r
3545 *       DC.L    PORIG,AT,TWO,SUB,SPAT,LESS,ONE\r
3546         DC.L    PORIG,AT,SPAT,LESS,ONE  ; Not post-decrement push.\r
3547         DC.L    QERR\r
3548 * prints 'empty stack'\r
3549 *\r
3550 QSTAC2  DC.L    SPAT\r
3551 * Here, we compare with a value at least 128\r
3552 * higher than dict. ptr. (DICTPT)\r
3553 *       DC.L    HERE,LIT16\r
3554 *       DC.W    $80     ; This is a rough check anyway, leave it as is. \r
3555 * But shouldn't it be the terminal width?\r
3556         DC.L    HERE,COLUMS,AT\r
3557         DC.L    PLUS,LESS,ZBRAN\r
3558         DC.L    QSTAC3-*-NATWID\r
3559         DC.L    TWO     ; NOT the NATWID constant!\r
3560         DC.L    QERR\r
3561 * prints 'full stack'\r
3562 *\r
3563 QSTAC3  DC.L    SEMIS\r
3564 *\r
3565 * ======>>  127  <<     this word's function\r
3566 *           is done by ?STACK in this version\r
3567 *       EVEN\r
3568 *       DC.B    $85\r
3569 *       DC.B    4,?FREE\r
3570 *       DC.B    'E'|$80\r
3571 *       DC.L    QSTACK-7-NATWID\r
3572 *QFREE  DC.L    DOCOL,SPAT,HERE,LIT16\r
3573 *       DC.W    $80\r
3574 *       DC.L    PLUS,LESS,TWO,QERR,SEMIS        ; This TWO is not NATWID!\r
3575 *\r
3576         PAGE\r
3577 *\r
3578 * ######>> screen 46 <<\r
3579 * ======>>  128  <<\r
3580 * ( buffer n --- )\r
3581 * ***** Check that this is how it works here:\r
3582 * Get up to n-1 characters from the keyboard,\r
3583 * storing at buffer and echoing, with backspace editing,\r
3584 * quitting when a CR is read.\r
3585 * Terminate it with a NUL.\r
3586         EVEN\r
3587         DC.B    0\r
3588         DC.B    $86\r
3589         DC.B    'EXPEC' ; 'EXPECT'\r
3590         DC.B    'T'|$80\r
3591         DC.L    QSTACK-7-NATWID\r
3592 EXPECT  DC.L    DOCOL,OVER,PLUS,OVER,XDO        ; brace the buffer area\r
3593 * EXPEC2        DC.L    KEY,DUP,LIT16\r
3594 EXPEC2  DC.L    KEY\r
3595         DC.L    DUP,LIT16\r
3596         DC.W    BACKSP-ORIG     ; again, this should be in the per-task table\r
3597         DC.L    PORIG,AT,EQUAL,ZBRAN    ; check for backspacing \r
3598         DC.L    EXPEC3-*-NATWID\r
3599         DC.L    DROP,LIT16\r
3600         DC.W    8       ; ( backspace character to emit )\r
3601         DC.L    OVER,I,EQUAL,DUP,FROMR,TWO,SUB,PLUS     ; back I up TWO characters \r
3602         DC.L    TOR,SUB,BRAN\r
3603         DC.L    EXPEC6-*-NATWID\r
3604 EXPEC3  DC.L    DUP,LIT16\r
3605         DC.W    $D      ; ( carriage return )\r
3606         DC.L    EQUAL,ZBRAN\r
3607         DC.L    EXPEC4-*-NATWID\r
3608 * DC.L BREAK    ; dbg\r
3609         DC.L    LEAVE,DROP,BL,ZERO,BRAN ; I think this is the NUL terminator.\r
3610         DC.L    EXPEC5-*-NATWID\r
3611 EXPEC4  DC.L    DUP\r
3612 * DC.L BREAK    ; dbg\r
3613 EXPEC5  DC.L    I,CSTORE,ZERO,I,ONEP,CSTORE,ZERO,I,TWOP,CSTORE  ; save two NULs to make sure address is even\r
3614 EXPEC6  DC.L    EMIT,XLOOP\r
3615         DC.L    EXPEC2-*-NATWID\r
3616         DC.L    DROP\r
3617         DC.L    SEMIS\r
3618 *\r
3619 * ======>>  129  <<\r
3620 * ( --- )\r
3621 * EXPECT terminal width characters to TIB.\r
3622         EVEN\r
3623         DC.B    $85\r
3624         DC.B    'QUER'  ; 'QUERY'\r
3625         DC.B    'Y'|$80\r
3626         DC.L    EXPECT-7-NATWID\r
3627 QUERY   DC.L    DOCOL,TIB,AT,COLUMS,AT\r
3628 *       DC.L    TRON    ; dbg *****\r
3629         DC.L    EXPECT,ZERO,IN,STORE\r
3630 *       DC.L    TROFF   ; dbg *****\r
3631         DC.L    SEMIS\r
3632 *\r
3633 * ======>>  130  <<\r
3634 * ( --- )                                                 P\r
3635 * End interpretation of a line or screen, and/or prepare for a new block. \r
3636 * Note that the name of this definition is an empty string,\r
3637 * so it matches on the terminating NUL in the terminal or block buffer.\r
3638         EVEN\r
3639         DC.B    $C1     ; immediate     < carriage return >\r
3640         DC.B    $00|$80 ; NUL character (end of buffered text)\r
3641         DC.L    QUERY-6-NATWID\r
3642 NULL    DC.L    DOCOL,BLK,AT,ZBRAN\r
3643         DC.L    NULL2-*-NATWID\r
3644         DC.L    ONE,BLK,PSTORE\r
3645         DC.L    ZERO,IN,STORE,BLK,AT,BSCR,MOD\r
3646         DC.L    ZEQU\r
3647 *     check for end of screen\r
3648         DC.L    ZBRAN\r
3649         DC.L    NULL1-*-NATWID\r
3650         DC.L    QEXEC,FROMR,DROP\r
3651 NULL1   DC.L    BRAN\r
3652         DC.L    NULL3-*-NATWID\r
3653 NULL2   DC.L    FROMR,DROP\r
3654 NULL3   DC.L    SEMIS\r
3655 *\r
3656         PAGE\r
3657 *\r
3658 * ######>> screen 47 <<\r
3659 * ======>>  133  <<\r
3660 * ( adr n b --- )\r
3661 * Fill n bytes at adr with b.\r
3662 * This relies on CMOVE having a certain lack of parameter checking,\r
3663 * where overlapping regions are not properly inverted in copy.\r
3664 * And this really should be done in low-level.\r
3665 * None of the advantages of doing things in high-level apply to fill.\r
3666         EVEN\r
3667         DC.B    0\r
3668         DC.B    $84\r
3669         DC.B    'FIL'   ; 'FILL'\r
3670         DC.B    'L'|$80\r
3671         DC.L    NULL-2-NATWID\r
3672 FILL    DC.L    DOCOL\r
3673 *       DC.L    BREAK   ; DBG\r
3674         DC.L    SWAP,TOR,OVER,CSTORE,DUP,ONEP\r
3675         DC.L    FROMR,ONE,SUB,CMOVE\r
3676         DC.L    SEMIS\r
3677 *\r
3678 * ======>>  134  <<\r
3679 * ( adr n --- )\r
3680 * Fill n bytes with 0.\r
3681         EVEN\r
3682         DC.B    $85\r
3683         DC.B    'ERAS'  ; 'ERASE'\r
3684         DC.B    'E'|$80\r
3685         DC.L    FILL-5-NATWID\r
3686 ERASE   DC.L    DOCOL,ZERO,FILL\r
3687         DC.L    SEMIS\r
3688 *\r
3689 * ======>>  135  <<\r
3690 * ( adr n --- )\r
3691 * Fill n bytes with ASCII SPACE.\r
3692         EVEN\r
3693         DC.B    0\r
3694         DC.B    $86\r
3695         DC.B    'BLANK' ; 'BLANKS'\r
3696         DC.B    'S'|$80\r
3697         DC.L    ERASE-6-NATWID\r
3698 BLANKS  DC.L    DOCOL,BL,FILL\r
3699         DC.L    SEMIS\r
3700 *\r
3701 * ======>>  136  <<\r
3702 * ( c --- )\r
3703 * Format a character at the left of the HLD output buffer.\r
3704         EVEN\r
3705         DC.B    0\r
3706         DC.B    $84\r
3707         DC.B    'HOL'   ; 'HOLD'\r
3708         DC.B    'D'|$80\r
3709         DC.L    BLANKS-7-NATWID\r
3710 HOLD    DC.L    DOCOL,LIT\r
3711         DC.L    -1      ; $FFFF in 16-bit model, but -1 is -1. DPL flag.\r
3712         DC.L    HLD,PSTORE,HLD,AT,CSTORE\r
3713         DC.L    SEMIS\r
3714 *\r
3715 * ======>>  137  <<\r
3716 * ( --- adr )\r
3717 * Give the address of the output PAD buffer. \r
3718 * PAD points to the end of a 68 byte buffer for numeric conversion.\r
3719 * 68 bytes is enough to convert a 64-bit integer to binary.\r
3720         EVEN\r
3721         DC.B    $83\r
3722         DC.B    'PA'    ; 'PAD'\r
3723         DC.B    'D'|$80\r
3724         DC.L    HOLD-5-NATWID\r
3725 PAD     DC.L    DOCOL,HERE,LIT16\r
3726         DC.W    $44\r
3727         DC.L    PLUS\r
3728         DC.L    SEMIS\r
3729 *\r
3730 * ######>> screen 48 <<\r
3731 * ======>>  138  <<\r
3732 * ( c --- )\r
3733 * Scan a string terminated by the character c or ASCII NUL out of input;\r
3734 * store symbol at WORDPAD with leading count byte and trailing ASCII NUL. \r
3735 * Leading c are passed over, per ENCLOSE.\r
3736 * Scans from BLK, or from TIB if BLK is zero. \r
3737 * May overwrite the numeric conversion pad,\r
3738 * if really long (length > 31) symbols are scanned.\r
3739 * Does not ALLOCate the symbol.\r
3740         EVEN\r
3741         DC.B    0\r
3742         DC.B    $84\r
3743         DC.B    'WOR'   ; 'WORD'\r
3744         DC.B    'D'|$80\r
3745         DC.L    PAD-4-NATWID\r
3746 WORD    DC.L    DOCOL,BLK,AT,ZBRAN\r
3747         DC.L    WORD2-*-NATWID\r
3748         DC.L    BLK,AT,BLOCK,BRAN\r
3749         DC.L    WORD3-*-NATWID\r
3750 WORD2   DC.L    TIB,AT\r
3751 WORD3   DC.L    IN,AT,PLUS,SWAP,ENCLOS,HERE,LIT16\r
3752         DC.W    MAXNML+2\r
3753         DC.L    BLANKS,IN,PSTORE,OVER,SUB,TOR,R,HERE\r
3754         DC.L    CSTORE,PLUS,HERE,ONEP,FROMR,CMOVE\r
3755         DC.L    SEMIS\r
3756 *\r
3757 * ######>> screen 49 <<\r
3758 * ======>>  139  <<\r
3759 * ( d1 string --- d2 adr )\r
3760 * Convert the text at string into a number, accumulating the result into d1,\r
3761 * leaving adr pointing to the first character not converted. \r
3762 * If DPL is non-negative at entry,\r
3763 * accumulates the number of characters converted into DPL.\r
3764         EVEN\r
3765         DC.B    0\r
3766         DC.B    $88\r
3767         DC.B    '(NUMBER'       ; '(NUMBER)'\r
3768         DC.B    ')'|$80\r
3769         DC.L    WORD-5-NATWID\r
3770 PNUMB   DC.L    DOCOL\r
3771 *       DC.L    BREAK   ; DBG *****\r
3772 PNUMB2  DC.L    ONEP,DUP,TOR,CAT,BASE,AT,DIGIT,ZBRAN\r
3773         DC.L    PNUMB4-*-NATWID\r
3774         DC.L    SWAP,BASE,AT,USTAR,DROP,ROT,BASE\r
3775         DC.L    AT,USTAR,DPLUS,DPL,AT,ONEP,ZBRAN\r
3776         DC.L    PNUMB3-*-NATWID\r
3777         DC.L    ONE,DPL,PSTORE\r
3778 PNUMB3  DC.L    FROMR,BRAN\r
3779         DC.L    PNUMB2-*-NATWID\r
3780 PNUMB4  DC.L    FROMR\r
3781 *       DC.L    BREAK   ; DBG *****\r
3782         DC.L    SEMIS\r
3783 *\r
3784 * ======>>  140  <<\r
3785 * ( ctstr --- d )\r
3786 * Convert text at ctstr to a double integer,\r
3787 * taking the 0 ERROR if the conversion is not valid. \r
3788 * If a decimal point is present,\r
3789 * accumulate the count of digits to the decimal point's right into DPL\r
3790 * (negative DPL at exit indicates single precision). \r
3791 * ctstr is a counted string\r
3792 * -- the first byte at ctstr is the length of the string,\r
3793 * but NUMBER ignores the count and expects a NUL terminator instead.\r
3794         EVEN\r
3795         DC.B    0\r
3796         DC.B    $86\r
3797         DC.B    'NUMBE' ; 'NUMBER'\r
3798         DC.B    'R'|$80\r
3799         DC.L    PNUMB-9-NATWID\r
3800 NUMB    DC.L    DOCOL,ZERO,ZERO,ROT,DUP,ONEP,CAT,LIT16\r
3801         DC.W    "-"     minus sign\r
3802         DC.L    EQUAL,DUP,TOR,PLUS,LIT\r
3803         DC.L    -1      ; $FFFF in 16-bit model, but -1 is -1. DPL flag.\r
3804 NUMB1   DC.L    DPL,STORE,PNUMB,DUP,CAT,BL,SUB\r
3805         DC.L    ZBRAN\r
3806         DC.L    NUMB2-*-NATWID\r
3807         DC.L    DUP,CAT,LIT16\r
3808         DC.W    "."\r
3809         DC.L    SUB,ZERO,QERR,ZERO,BRAN\r
3810         DC.L    NUMB1-*-NATWID\r
3811 NUMB2   DC.L    DROP,FROMR,ZBRAN\r
3812         DC.L    NUMB3-*-NATWID\r
3813         DC.L    DMINUS\r
3814 NUMB3   DC.L    SEMIS\r
3815 *\r
3816 * ======>>  141  <<\r
3817 * ( --- locptr length true )      { -FIND name } typical input\r
3818 * ( --- false )\r
3819 * Parse a word, then FIND,\r
3820 * first in the definition vocabulary,\r
3821 * then in the CONTEXT (interpretation) vocabulary, if necessary.\r
3822 * Returns what (FIND) returns, flag and optional location and length.\r
3823         EVEN\r
3824         DC.B    $85\r
3825         DC.B    '-FIN'  ; '-FIND'\r
3826         DC.B    'D'|$80\r
3827         DC.L    NUMB-7-NATWID\r
3828 DFIND   DC.L    DOCOL,BL,WORD,HERE,CONTXT,AT,AT\r
3829         DC.L    PFIND,DUP,ZEQU,ZBRAN\r
3830         DC.L    DFIND2-*-NATWID\r
3831         DC.L    DROP,HERE,LATEST,PFIND\r
3832 DFIND2  DC.L    SEMIS\r
3833 *\r
3834         PAGE\r
3835 * ######>> screen 50 <<\r
3836 * ======>>  142  <<\r
3837 * ( anything --- nothing )        ( anything *** nothing )\r
3838 * An indirection for ABORT, for ERROR,\r
3839 * which may be modified carefully.\r
3840 * We are now using PABORT for what it probably was originally intended --\r
3841 * a way to break the dependency cycle in ERROR.\r
3842         EVEN\r
3843         DC.B    $87\r
3844         DC.B    '(ABORT'        ; '(ABORT)'\r
3845         DC.B    ')'|$80\r
3846         DC.L    DFIND-6-NATWID\r
3847 *PABORT DC.L    DOCOL,ABORT\r
3848 *       DC.L    SEMIS\r
3849 PABORT  DC.L    *+NATWID\r
3850         MOVE.L  #ABORT+NATWID,IP\r
3851         BRA.W   NEXT    ; Don't even return.\r
3852 *\r
3853 * ======>>  143  <<\r
3854 * ERROR ( anything line --- IN BLK )    ( anything *** nothing )\r
3855 * ( anything --- nothing )\r
3856 * ( anything *** nothing ) WARNING < 0\r
3857 * Prints out the last symbol scanned and MESSAGE number line.  If\r
3858 * WARNING is less than zero, ABORTs through (ABORT), otherwise,\r
3859 * clears the parameter stack, pushes the INput cursor and\r
3860 * interpretaion BLK, and QUITs.\r
3861         EVEN\r
3862         DC.B    $85\r
3863         DC.B    'ERRO'  ; 'ERROR'\r
3864         DC.B    'R'|$80\r
3865         DC.L    PABORT-8-NATWID\r
3866 * It's time to make this low-level.\r
3867 ERROR   DC.L    DOCOL,WARN,AT,ZLESS\r
3868         DC.L    ZBRAN\r
3869         DC.L    ERROR2-*-NATWID\r
3870 * note: WARNING is\r
3871 * -1 to abort,\r
3872 * 0 to print error #\r
3873 * and 1 to print error message from disc\r
3874         DC.L    PABORT\r
3875 ERROR2  DC.L    HERE,COUNT,TYPE,PDOTQ\r
3876         DC.B    4,7     ; ( bell )\r
3877         DC.B    " ? "\r
3878         DC.B    0       ; hand-align\r
3879         DC.L    MESS,SPSTOR,IN,AT,BLK,AT,QUIT\r
3880         DC.L    SEMIS\r
3881 *\r
3882 * ======>>  144  <<\r
3883 * ( n adr --- )\r
3884 * Mask byte at adr with n.\r
3885 * Not in FIG, don't need it for 8 bit characters after all.\r
3886 *       EVEN\r
3887 *       DC.B    $85\r
3888 *       DC.B    'CMAS'  ; 'CMASK'\r
3889 *       DC.B    'K'|$80\r
3890 *       DC.L    ERROR-6-NATWID\r
3891 * CMASK DC.L    *+NATWID\r
3892 *       MOVE.L  (PSP)+,A0       ; adr\r
3893 *       MOVE.L  (PSP)+,D0       ; prepare for mask\r
3894 *       AND.B   D0,(A0)\r
3895 *       RTS\r
3896 *\r
3897 * ( adr --- adr )\r
3898 * Mask high bit of tail of name in PAD buffer.\r
3899 * Not in FIG, need it for characters with high bit set.\r
3900         EVEN\r
3901         DC.B    0\r
3902         DC.B    $86\r
3903         DC.B    'IDFLA' ; 'IDFLAT'\r
3904         DC.B    'T'|$80\r
3905         DC.L    ERROR-6-NATWID\r
3906 IDFLAT  DC.L    *+NATWID\r
3907         MOVE.L  (PSP),A0\r
3908         MOVE.B  (A0),D1 ; get the count\r
3909         AND.W   #CTMASK,D1\r
3910         AND.B   #$7F,(A0,D1.W)  ; point to the tail and clear the EndOfName flag bit.\r
3911         RTS\r
3912 *\r
3913 * ( symptr --- )\r
3914 * Print definition's name from its NFA.\r
3915         EVEN\r
3916         DC.B    $83\r
3917         DC.B    'ID'    ; 'ID.'\r
3918         DC.B    '.'|$80\r
3919         DC.L    IDFLAT-7-NATWID\r
3920 IDDOT   DC.L    DOCOL,PAD\r
3921 *       DC.L    BREAK   ; DBG *****\r
3922         DC.L    LIT16\r
3923         DC.W    MAXNML  ; Why did I hard code this?\r
3924 *       DC.L    WIDTH,ONEP      ; Because WIDTH is a (USER) variable.\r
3925         DC.L    LIT16\r
3926         DC.W    '_'     ( underline )\r
3927         DC.L    FILL,DUP,PFA,LFA,OVER,SUB,PAD\r
3928 *       DC.L    SWAP,CMOVE,PAD,COUNT,LIT16\r
3929 *       DC.W    NMLMSK\r
3930         DC.L    SWAP,CMOVE,PAD\r
3931         DC.L    IDFLAT\r
3932         DC.L    COUNT,LIT16\r
3933         DC.W    NMLMSK\r
3934         DC.L    AND,TYPE,SPACE\r
3935         DC.L    SEMIS\r
3936 *\r
3937 * ######>> screen 51 <<\r
3938 * ======>>  145  <<\r
3939 * ( --- )         { CREATE name } input\r
3940 * Parse a name (length < MAXNML characters) and create a header,\r
3941 * reporting first duplicate found in either the defining vocabulary\r
3942 * or the context (interpreting) vocabulary. \r
3943 * Install the header in the defining vocabulary\r
3944 * with CFA dangerously pointing to the parameter field.\r
3945 * Leave the name SMUDGEd.\r
3946         EVEN\r
3947         DC.B    0\r
3948         DC.B    $86\r
3949         DC.B    'CREAT' ; 'CREATE'\r
3950         DC.B    'E'|$80\r
3951         DC.L    IDDOT-4-NATWID\r
3952 CREATE  DC.L    DOCOL,DFIND,ZBRAN\r
3953         DC.L    CREAT2-*-NATWID\r
3954         DC.L    DROP,PDOTQ\r
3955         DC.B    8\r
3956         DC.B    7       ; ( bel )\r
3957         DC.B    "redef: "\r
3958         DC.B    0       ; hand align\r
3959         DC.L    NFA,IDDOT,LIT16\r
3960         DC.W    4\r
3961         DC.L    MESS,SPACE\r
3962 *CREAT2 DC.L    HERE,DUP,CAT,WIDTH,AT,MIN       ; clip to WIDTH\r
3963 CREAT2  DC.L    BREAK,HERE,CAT,WIDTH,AT,MIN     ; clip to WIDTH, hold off copying HERE ; DBG *****\r
3964 * Make sure it ends up aligned by moving the name.\r
3965 * Note that we don't need to copy beyond WIDTH.\r
3966         DC.L    DUP,HERE,PLUS,ONEP      ; tentative LFA\r
3967         DC.L    ONE,AND,ZBRAN           ; Will LFA, as is, be even?\r
3968         DC.L    CREATN-*-NATWID         ; will be even\r
3969 \r
3970         DC.L    HERE,OVER,HERE,ONEP,SWAP,ONEP   ; source, destination, length including count\r
3971         DC.L    CMOVD                   ; Use descending copy so it doesn't just fill.\r
3972 \r
3973         DC.L    ZERO,CCOMM              ; insert a NUL byte, update HERE.\r
3974 \r
3975 * Now build header.\r
3976 CREATN  DC.L    HERE,SWAP,ONEP,ALLOT,DUP,LIT16\r
3977         DC.W    ($80|FSMUDG)            ; Bracket the name.\r
3978         DC.L    TOGGLE\r
3979         DC.L    HERE,ONE,SUB,LIT16\r
3980         DC.W    $80\r
3981         DC.L    TOGGLE\r
3982         DC.L    LATEST,COMMA,CURENT,AT,STORE\r
3983 *       DC.L    HERE,TWOP,COMMA\r
3984         DC.L    HERE,NATP,COMMA\r
3985         DC.L    SEMIS\r
3986 *\r
3987 * ######>> screen 52 <<\r
3988 * ======>>  146  <<\r
3989 * ( --- )                                         P\r
3990 *                       { [COMPILE] name } typical use\r
3991 * -DFIND next WORD and COMPILE it, literally;\r
3992 * used to compile immediate definitions into words.\r
3993         EVEN\r
3994         DC.B    $C9     immediate\r
3995         DC.B    '[COMPILE'      ; '[COMPILE]'\r
3996         DC.B    ']'|$80\r
3997         DC.L    CREATE-7-NATWID\r
3998 BCOMP   DC.L    DOCOL,DFIND,ZEQU,ZERO,QERR,DROP,CFA,COMMA\r
3999         DC.L    SEMIS\r
4000 *\r
4001 * ======>>  147  <<\r
4002 * ( n --- ) if compiling.                          P\r
4003 * ( n --- n ) if interpreting.\r
4004 * Compile n as a literal, if compiling.\r
4005         EVEN\r
4006         DC.B    $C7     immediate\r
4007         DC.B    'LITERA'        ; 'LITERAL'\r
4008         DC.B    'L'|$80\r
4009         DC.L    BCOMP-10-NATWID\r
4010 LITER   DC.L    DOCOL,STATE,AT,ZBRAN\r
4011         DC.L    LITER2-*-NATWID\r
4012         DC.L    COMPIL,LIT,COMMA\r
4013 LITER2  DC.L    SEMIS\r
4014 *\r
4015 * ======>>  148  <<\r
4016 * ( d --- )  if compiling.                        P\r
4017 * ( d --- d ) if interpreting.\r
4018 * Compile d as a double literal, if compiling.\r
4019         EVEN\r
4020         DC.B    0\r
4021         DC.B    $C8     immediate\r
4022         DC.B    'DLITERA'       ; 'DLITERAL'\r
4023         DC.B    'L'|$80\r
4024         DC.L    LITER-8-NATWID\r
4025 DLITER  DC.L    DOCOL,STATE,AT,ZBRAN\r
4026         DC.L    DLITE2-*-NATWID\r
4027         DC.L    SWAP,LITER,LITER        ; Just two literals in the right order.\r
4028 DLITE2  DC.L    SEMIS\r
4029 *\r
4030 * ######>> screen 53 <<\r
4031 * ======>>  149  <<\r
4032 * ( --- )\r
4033 * Interpret or compile, according to STATE. \r
4034 * Searches words parsed in dictionary first, via -FIND,\r
4035 * then checks for valid NUMBER.\r
4036 * Pushes or COMPILEs double literal if NUMBER leaves DPL non-negative. \r
4037 * ERROR checks the stack via ?STACK before returning to its caller. \r
4038         EVEN\r
4039         DC.B    $89\r
4040         DC.B    'INTERPRE'      ; 'INTERPRET'\r
4041         DC.B    'T'|$80\r
4042 *       DC.L    LITER-8-NATWID\r
4043         DC.L    DLITER-9-NATWID\r
4044 INTERP  DC.L    DOCOL\r
4045 INTER2  DC.L    DFIND,ZBRAN\r
4046         DC.L    INTER5-*-NATWID\r
4047         DC.L    STATE,AT,LESS\r
4048         DC.L    ZBRAN\r
4049         DC.L    INTER3-*-NATWID\r
4050         DC.L    CFA,COMMA,BRAN\r
4051         DC.L    INTER4-*-NATWID\r
4052 INTER3  DC.L    CFA,EXEC\r
4053 INTER4  DC.L    BRAN\r
4054         DC.L    INTER7-*-NATWID\r
4055 INTER5  DC.L    HERE,NUMB,DPL,AT,ONEP,ZBRAN\r
4056         DC.L    INTER6-*-NATWID\r
4057         DC.L    DLITER,BRAN\r
4058         DC.L    INTER7-*-NATWID\r
4059 INTER6  DC.L    DROP,LITER\r
4060 INTER7  DC.L    QSTACK,BRAN\r
4061 *INTER7 DC.L    BREAK,QSTACK,BRAN       ; DBG\r
4062         DC.L    INTER2-*-NATWID\r
4063 *       DC.L    SEMIS   never executed\r
4064 \r
4065 *\r
4066 * ######>> screen 54 <<\r
4067 * ======>>  150  <<\r
4068 * ( --- )\r
4069 * Toggle precedence bit of LATEST definition header. \r
4070 * During compiling, most symbols scanned are compiled. \r
4071 * IMMEDIATE definitions execute whenever the outer INTERPRETer scans them,\r
4072 * but may be compiled via ' (TICK).\r
4073         EVEN\r
4074         DC.B    $89\r
4075         DC.B    'IMMEDIAT'      ; 'IMMEDIATE'\r
4076         DC.B    'E'|$80\r
4077         DC.L    INTERP-10-NATWID\r
4078 IMMED   DC.L    DOCOL,LATEST,LIT16\r
4079         DC.W    FIMMED\r
4080         DC.L    TOGGLE\r
4081         DC.L    SEMIS\r
4082 *\r
4083 * ======>>  151  <<\r
4084 * ( --- )         { VOCABULARY name } input\r
4085 * Create a vocabulary entry with a flag for terminating vocabulary searches.\r
4086 * Store the current search context in it for linking.\r
4087 * At run-time, VOCABULARY makes itself the CONTEXT vocabulary.\r
4088         EVEN\r
4089         DC.B    0\r
4090         DC.B    $8A\r
4091         DC.B    'VOCABULAR'     ; 'VOCABULARY'\r
4092         DC.B    'Y'|$80\r
4093         DC.L    IMMED-10-NATWID\r
4094 VOCAB   DC.L    DOCOL,BUILDS,LIT,VOCFLG,COMMA,CURENT,AT,CFA\r
4095         DC.L    COMMA,HERE,VOCLIN,AT,COMMA,VOCLIN,STORE,DOES\r
4096 * DOVOC DC.L    TWOP,CONTXT,STORE\r
4097 DOVOC   DC.L    NATP,CONTXT,STORE\r
4098         DC.L    SEMIS\r
4099 *\r
4100 * ======>>  152  <<\r
4101 *\r
4102 * Note: FORTH does not go here in the rom-able dictionary,\r
4103 *    since FORTH is a type of variable.\r
4104 *\r
4105 * (Should make a proper architecture for this at some point.)\r
4106 *\r
4107 *\r
4108 * ======>>  153  <<\r
4109 * ( --- )\r
4110 * Makes the current interpretation CONTEXT vocabulary\r
4111 * also the CURRENT defining vocabulary.\r
4112         EVEN\r
4113         DC.B    $8B\r
4114         DC.B    'DEFINITION'    ; 'DEFINITIONS'\r
4115         DC.B    'S'|$80\r
4116         DC.L    VOCAB-11-NATWID\r
4117 DEFIN   DC.L    DOCOL,CONTXT,AT,CURENT,STORE\r
4118         DC.L    SEMIS\r
4119 *\r
4120 * ======>>  154  <<\r
4121 * ( --- )\r
4122 * Parse out a comment and toss it away. \r
4123 * Leaves the leading characters in WORDPAD, which may or may not be useful.\r
4124         EVEN\r
4125         DC.B    $C1     immediate       (\r
4126         DC.B    '('|$80\r
4127         DC.L    DEFIN-12-NATWID\r
4128 PAREN   DC.L    DOCOL,LIT16\r
4129         DC.W    ")"\r
4130         DC.L    WORD\r
4131         DC.L    SEMIS\r
4132 *\r
4133 * ######>> screen 55 <<\r
4134 * ======>>  155  <<\r
4135 * ( anything *** nothing )\r
4136 * Clear return stack. \r
4137 * Then INTERPRET and, if not compiling, prompt with OK,\r
4138 * in infinite loop.\r
4139         EVEN\r
4140         DC.B    0\r
4141         DC.B    $84\r
4142         DC.B    'QUI'   ; 'QUIT'\r
4143         DC.B    'T'|$80\r
4144         DC.L    PAREN-2-NATWID\r
4145 QUIT    DC.L    DOCOL,ZERO,BLK,STORE\r
4146         DC.L    BREAK   ; DBG ****\r
4147         DC.L    LBRAK\r
4148 *\r
4149 *  Here is the outer interpretter\r
4150 *  which gets a line of input, does it, prints " OK"\r
4151 *  then repeats :\r
4152 QUIT2   DC.L    RPSTOR,CR,QUERY\r
4153         DC.L    BREAK   ; DBG *****\r
4154         DC.L    INTERP,STATE,AT,ZEQU\r
4155         DC.L    ZBRAN\r
4156         DC.L    QUIT3-*-NATWID\r
4157         DC.L    PDOTQ\r
4158         DC.B    3\r
4159         DC.B    ' OK'   ; ' OK'\r
4160 QUIT3   DC.L    BRAN\r
4161         DC.L    QUIT2-*-NATWID\r
4162 *       DC.L    SEMIS   ( never executed )\r
4163 *\r
4164 * ======>>  156  <<\r
4165 * ( anything --- nothing )        ( anything *** nothing )\r
4166 * Clear parameter stack,\r
4167 * set STATE to interpret and BASE to DECIMAL,\r
4168 * return to input from terminal,\r
4169 * restore DRIVE OFFSET to 0,\r
4170 * print out "Forth-68",\r
4171 * set interpret and define vocabularies to FORTH,\r
4172 * and finally, QUIT. \r
4173 * Used to force the system to a known state\r
4174 * and return control to the initial INTERPRETer.\r
4175         EVEN\r
4176         DC.B    $85\r
4177         DC.B    'ABOR'  ; 'ABORT'\r
4178         DC.B    'T'|$80\r
4179         DC.L    QUIT-5-NATWID\r
4180 *ABORT  DC.L    DOCOL,SPSTOR,DEC,QSTACK,DRZERO,CR,PDOTQ\r
4181 ABORT   DC.L    DOCOL,SPSTOR,DEC,QSTACK,DRZERO,CR,BREAK,PDOTQ\r
4182         DC.B    15\r
4183         DC.B    "fig-Forth-68000"\r
4184 *       DC.B    0       ; hand align\r
4185         DC.L    FORTH,DEFIN\r
4186 *       DC.L    CR,TROFF,VLIST  ; (whole line is) DBG ****\r
4187         DC.L    QUIT\r
4188 *       DC.L    SEMIS   never executed\r
4189         PAGE\r
4190 *\r
4191 * ######>> screen 56 <<\r
4192 * bootstrap code... moves rom contents to ram :\r
4193 * ======>>  157  <<\r
4194         EVEN\r
4195         DC.B    0\r
4196         DC.B    $84\r
4197         DC.B    'COL'   ; 'COLD'\r
4198         DC.B    'D'|$80\r
4199         DC.L    ABORT-6-NATWID\r
4200 COLD    DC.L    *+NATWID\r
4201 * Ultimately, we want position indepence,\r
4202 * so I'm using PCR where it seems reasonable.\r
4203 * Time for some testing.\r
4204 CENT    MOVE.L  RINIT(PC),RP    ; Get a useable initial return stack,\r
4205         MOVE.L  SINIT(PC),PSP   ; a useable initial parameter stack,\r
4206 *       MOVE.L  #IUP,UP         ; and a useable initial task base (not in init table).\r
4207         MOVE.L  #UORIG,UP               ; and a useable initial task base (not in init table).\r
4208 *\r
4209         LEA     ERAM(PC),A2     ; end of stuff to move, A2 as loop terminator\r
4210         MOVE.L  #RBEG,A1        ; bottom of (open-ended) destination\r
4211         LEA     RAM(PC),A0      ; bottom of stuff to move\r
4212 COLD2   MOVE.B  (A0)+,(A1)+     ; move TASK & FORTH to ram\r
4213         CMP.L   A2,A0\r
4214         BNE.S   COLD2\r
4215 * The above leaves USE and PREV uninitialized.\r
4216         MOVE.L  BUFINT(PC),A2\r
4217         MOVE.L  A2,XUSE-UORIG(UP)\r
4218         MOVE.L  A2,XPREV-UORIG(UP)\r
4219 * ... or we could go top to bottom.\r
4220 * Definitely no need to use the return stack pointer like in the 6800 model,\r
4221 * nor to fiddle with it, since it is already pointing to a place that should be safe.\r
4222         MOVE.L  COLINT(PC),XCOLUM-UORIG(UP)\r
4223         MOVE.L  DELINT(PC),XDELAY-UORIG(UP)\r
4224         MOVE.L  VOCINT(PC),XVOCL-UORIG(UP)\r
4225         MOVE.L  DPINIT(PC),XDICTP-UORIG(UP)\r
4226         MOVE.L  FENCIN(PC),XFENCE-UORIG(UP)\r
4227 *\r
4228 WENT    MOVE.L  RINIT(PC),RP    ; Get a useable initial return stack,\r
4229         MOVE.L  SINIT(PC),PSP   ; a useable initial parameter stack,\r
4230 *       MOVE.L  #IUP,UP         ; and a useable initial task base (not in init table).\r
4231         MOVE.L  #UORIG,UP               ; and a useable initial task base (not in init table).\r
4232 *\r
4233         LEA     SINIT(PC),A2            ; for loop termination\r
4234         LEA     XFENCE-UORIG(UP),A1     ; top of destination\r
4235         LEA     FENCIN(PC),A0           ; top of stuff to move\r
4236 WARM2   MOVE.L  -(A0),-(A1)             ; All entries are 32 bit.\r
4237         CMP.L   A2,A0\r
4238         BNE.S   WARM2\r
4239 *\r
4240         LEA     ABORT+NATWID(PC),IP     ; IP never points to DOCOL!\r
4241 *\r
4242         NOP             ; Here is a place to jump to special user\r
4243         NOP             ; initializations such as I/0 interrups\r
4244         NOP\r
4245 *\r
4246 \r
4247 \r
4248 * For systems with TRACE:\r
4249         CLR.L   (RP)            ; The hole above the return stack\r
4250         CLR.L   (PSP)           ; The hole above the parameter stack\r
4251         LEA     N(PC),A0\r
4252         CLR.W   TRLIM-N(A0)     ; clear trace limit (all bytes)\r
4253         CLR.W   TRACEM-N(A0)    ; and mode (all bytes)\r
4254 * DBG:\r
4255 *       ADDQ.W  #1,TRACEM-N(A0) ; DBG *******************\r
4256         CLR.L   BRKPT-N(A0)     ; clear breakpoint address\r
4257         BRA.W   RPSTOR+NATWID   ; start the virtual machine running !\r
4258 *       RPSTOR's NEXT will pick up the IP set above, and start ABORT.\r
4259 *       RP! sets up the return stack pointer, then IP references abort.\r
4260 \r
4261 * Comment out the branch above and use something like this to jump direct to test code:\r
4262 *       LEA     TESTMIN(PC),IP\r
4263 *       RTS\r
4264 \r
4265 *\r
4266 * Here is the stuff that gets copied to ram :\r
4267 * (not * at address $140:)\r
4268 * at an appropriate address:\r
4269 *\r
4270 * RAM   DC.L    $3000,$3000,0,0\r
4271 * RAM   DC.L    BUFBAS,BUFBAS,0,0       ; ... except the direct page has moved.\r
4272 * These initialization values for USE and PREV were here to help pack the code.\r
4273 * They don't belong here unless we move the USER table\r
4274 * back below the writable dictionary, \r
4275 * *and* move these USER variables to the end of the direct page --\r
4276 * *or* let these definitions exist in the USER table.\r
4277 RAM     EQU     *       ; Does RAM need to have the BUFfer BASe address before RFORTH?\r
4278 \r
4279 * ======>>  (152)  <<\r
4280 * ( --- )                                                 P\r
4281 * Makes FORTH the current interpretation vocabulary.\r
4282 * In order to make this ROMmable,\r
4283 * this entry is set up as the tail-end of its VOCABULARY,\r
4284 * and copied to RAM in the start-up code.\r
4285 * We want a more elegant solution to this, too. Greedy, maybe.\r
4286         EVEN\r
4287         DC.B    $C5     immediate\r
4288         DC.B    'FORT'  ; 'FORTH'\r
4289         DC.B    'H'|$80\r
4290         DC.L    NOOP-5-NATWID   ; Note that this does not link to COLD!\r
4291 RFORTH  DC.L    DODOES,DOVOC,VOCFLG,TASK-5-NATWID\r
4292         DC.L    0\r
4293         DC.B    "Copyright 1979 Forth Interest Group, David Lion,"\r
4294         DC.B    $0D\r
4295         DC.B    "Parts Copyright 2019 Joel Matthew Rees"\r
4296         DC.B    $0D\r
4297 *\r
4298         EVEN\r
4299         DC.B    0\r
4300         DC.B    $84\r
4301         DC.B    'TAS'   ; 'TASK'\r
4302         DC.B    'K'|$80\r
4303         DC.L    FORTH-6-NATWID\r
4304 RTASK   DC.L    DOCOL,SEMIS\r
4305 ERAM    EQU     *\r
4306 ERAMSZ  EQU     *-RAM   ; So we can get a look at it.\r
4307 *\r
4308         PAGE\r
4309 * ######>> screen 57 <<\r
4310 * ======>>  158  <<\r
4311 * ( n0 --- d0 )\r
4312 * Sign extend n0 to a double integer.\r
4313         EVEN\r
4314         DC.B    0\r
4315         DC.B    $84\r
4316         DC.B    'S->'   ; 'S->D'\r
4317         DC.B    'D'|$80\r
4318         DC.L    COLD-5-NATWID   ; Note that this does not link to FORTH (RFORTH)!\r
4319 *STOD   DC.L    DOCOL,DUP,ZLESS,MINUS\r
4320 *       DC.L    SEMIS\r
4321 STOD    DC.L    *+NATWID        ; Make it directly callable.\r
4322         TST.L   (PSP)\r
4323         SMI     D0\r
4324         AND.L   #1,D0\r
4325         NEG.L   D0\r
4326         MOVE.L  D0,-(PSP)\r
4327         RTS\r
4328 *       CLR.L   D0\r
4329 *       TST.L   (PSP)\r
4330 *       BMI.S   STODS\r
4331 *       COM.L   D0\r
4332 *STODS  MOVE.L  D0,-(PSP)\r
4333 *       RTS\r
4334 \r
4335 *       TST.L   (PSP)\r
4336 *       SMI     D0\r
4337 *       AND.L   #1,D0\r
4338 *       NEG.L   D0\r
4339 *       MOVE.L  D0,-(PSP)\r
4340 *       RTS\r
4341 *\r
4342 * ======>>  159  <<\r
4343 * ( multiplier multiplicand --- product )\r
4344 * Signed word multiply.\r
4345         EVEN\r
4346         DC.B    $81     ; *\r
4347         DC.B    '*'|$80\r
4348         DC.L    STOD-5-NATWID\r
4349 STAR    DC.L    DOCOL\r
4350         DC.L    USTAR,DROP,SEMIS        ; Drop high word.\r
4351 * STAR  DC.L    *+NATWID\r
4352 *       BSR.W   USTAR+NATWID\r
4353 *       LEA     NATWID(PSP),PSP ; Drop high word. Seems like magic, doesn't it?\r
4354 *       RTS\r
4355 *\r
4356 * ======>>  160  <<\r
4357 * ( dividend divisor --- remainder quotient )\r
4358 * M/ in word-only form, i. e., signed division of 2nd word by top word,\r
4359 * yielding signed word quotient and remainder.\r
4360 * Except *BUG* it isn't signed.\r
4361         EVEN\r
4362         DC.B    0\r
4363         DC.B    $84\r
4364         DC.B    '/MO'   ; '/MOD'\r
4365         DC.B    'D'|$80\r
4366         DC.L    STAR-2-NATWID\r
4367 SLMOD   DC.L    DOCOL,TOR,STOD,FROMR,USLASH\r
4368         DC.L    SEMIS\r
4369 *\r
4370 * ======>>  161  <<\r
4371 * ( dividend divisor --- quotient )\r
4372 * Signed word divide without remainder.\r
4373 * Except *BUG* it isn't signed.\r
4374         EVEN\r
4375         DC.B    $81     ; /\r
4376         DC.B    '/'|$80\r
4377         DC.L    SLMOD-5-NATWID\r
4378 SLASH   DC.L    DOCOL,SLMOD,SWAP,DROP\r
4379         DC.L    SEMIS\r
4380 *\r
4381 * ======>>  162  <<\r
4382 * ( dividend divisor --- remainder )\r
4383 * Remainder function, result takes sign of dividend.\r
4384         EVEN\r
4385         DC.B    $83\r
4386         DC.B    'MO'    ; 'MOD'\r
4387         DC.B    'D'|$80\r
4388         DC.L    SLASH-2-NATWID\r
4389 MOD     DC.L    DOCOL,SLMOD,DROP\r
4390         DC.L    SEMIS\r
4391 *\r
4392 * ======>>  163  <<\r
4393 * ( multiplier multiplicand divisor --- remainder quotient )\r
4394 * Signed precise division of product:\r
4395 * multiply 2nd and 3rd words on stack\r
4396 * and divide the 31-bit product by the top word,\r
4397 * leaving both quotient and remainder.\r
4398 * Remainder takes sign of product. \r
4399 * Guaranteed not to lose significant bits in 16 bit integer math.\r
4400         EVEN\r
4401         DC.B    $85\r
4402         DC.B    '*/MO'  ; '*/MOD'\r
4403         DC.B    'D'|$80\r
4404         DC.L    MOD-4-NATWID\r
4405 SSMOD   DC.L    DOCOL,TOR,USTAR,FROMR,USLASH\r
4406         DC.L    SEMIS\r
4407 *\r
4408 * ======>>  164  <<\r
4409 * ( multiplier multiplicand divisor --- quotient )\r
4410 *   */MOD without remainder.\r
4411         EVEN\r
4412         DC.B    0\r
4413         DC.B    $82\r
4414         DC.B    '*'     ; '*/'\r
4415         DC.B    '/'|$80\r
4416         DC.L    SSMOD-6-NATWID\r
4417 SSLASH  DC.L    DOCOL,SSMOD,SWAP,DROP\r
4418         DC.L    SEMIS\r
4419 *\r
4420 * ======>>  165  <<\r
4421 * ( ud1 u1 --- u2 ud2 )\r
4422 * U/ with an (unsigned) double quotient. \r
4423 * Guaranteed not to lose significant bits in 32 bit / 16 bit bit integer math,\r
4424 * if you are prepared to deal with the extra 16 bits of result.\r
4425         EVEN\r
4426         DC.B    $85\r
4427         DC.B    'M/MO'  ; 'M/MOD'\r
4428         DC.B    'D'|$80\r
4429         DC.L    SSLASH-3-NATWID\r
4430 MSMOD   DC.L    DOCOL,TOR,ZERO,R,USLASH\r
4431         DC.L    FROMR,SWAP,TOR,USLASH,FROMR\r
4432         DC.L    SEMIS\r
4433 *\r
4434 * ======>>  166  <<\r
4435 * ( n>=0 --- n )\r
4436 * ( n<0 --- -n )\r
4437 * Convert the top of stack to its absolute value.\r
4438         EVEN\r
4439         DC.B    $83\r
4440         DC.B    'AB'    ; 'ABS'\r
4441         DC.B    'S'|$80\r
4442         DC.L    MSMOD-6-NATWID\r
4443 ABS     DC.L    DOCOL,DUP,ZLESS,ZBRAN\r
4444         DC.L    ABS2-*-NATWID\r
4445         DC.L    MINUS\r
4446 ABS2    DC.L    SEMIS\r
4447 *\r
4448 * ======>>  167  <<\r
4449 * ( d>=0 --- d )\r
4450 * ( d<0 --- -d )\r
4451 * Convert the top double to its absolute value.\r
4452         EVEN\r
4453         DC.B    0\r
4454         DC.B    $84\r
4455         DC.B    'DAB'   ; 'DABS'\r
4456         DC.B    'S'|$80\r
4457         DC.L    ABS-4-NATWID\r
4458 DABS    DC.L    DOCOL,DUP,ZLESS,ZBRAN\r
4459         DC.L    DABS2-*-NATWID\r
4460         DC.L    DMINUS\r
4461 DABS2   DC.L    SEMIS\r
4462 *\r
4463         PAGE\r
4464 * ######>> screen 58 <<\r
4465 * Disc primitives :\r
4466 * ======>>  168  <<\r
4467 * ( --- vadr )   \r
4468 * Least Recently Used buffer.\r
4469 * Really should be with FIRST and LIMIT in the per-task table.\r
4470         EVEN\r
4471         DC.B    $83\r
4472         DC.B    'US'    ; 'USE'\r
4473         DC.B    'E'|$80\r
4474         DC.L    DABS-5-NATWID\r
4475 USE     DC.L    DOCON\r
4476         DC.L    XUSE    ; The address of XUSE is the constant.\r
4477 * ======>>  169  <<\r
4478 * ( --- vadr )   \r
4479 * Most Recently Used buffer.\r
4480 * Really should be with FIRST and LIMIT in the per-task table.\r
4481         EVEN\r
4482         DC.B    0\r
4483         DC.B    $84\r
4484         DC.B    'PRE'   ; 'PREV'\r
4485         DC.B    'V'|$80\r
4486         DC.L    USE-4-NATWID\r
4487 PREV    DC.L    DOCON\r
4488         DC.L    XPREV   ; The address of XPREV is the constant.\r
4489 * ======>>  170  <<\r
4490 * ( buffer1 --- buffer2 f )\r
4491 * Bump to next buffer,\r
4492 * flag false if result is PREVious buffer,\r
4493 * otherwise flag true. \r
4494 * Used in the LRU allocation routines.\r
4495         EVEN\r
4496         DC.B    0\r
4497         DC.B    $84\r
4498         DC.B    '+BU'   ; '+BUF'\r
4499         DC.B    'F'|$80\r
4500         DC.L    PREV-5-NATWID\r
4501 * PBUF  DC.L    DOCOL,LIT16\r
4502 *       DC.W    $84     ; This was a hard-wiring bug.\r
4503 PBUF    DC.L    DOCOL,BBUF,BCTL,PLUS    ; Size of the buffer record.\r
4504 *       DC.L    PLUS,DUP,LIMIT,EQUAL,ZBRAN\r
4505         DC.L    PLUS,DUP,LIMIT,LESS,ZEQU,OVER,FIRST,LESS,OR,ZBRAN\r
4506         DC.L    PBUF2-*-NATWID  ; Use defensive programming.\r
4507         DC.L    DROP,FIRST\r
4508 PBUF2   DC.L    DUP,PREV,AT,SUB\r
4509         DC.L    SEMIS\r
4510 *\r
4511 * ======>>  171  <<\r
4512 *\r
4513 UPDATB  EQU     $80000000       ; $8000 in the 6800 model -- puts limits on sector count.\r
4514 *\r
4515 * ( --- f )\r
4516 * Flag to mark a buffer dirty, in need of being written out.\r
4517 * This flag limits the max number of sectors in a disk to ((256^NATWID)/2)-1.\r
4518 * It also hard-codes an implicit test which is used elsewhere.\r
4519         EVEN\r
4520         DC.B    0\r
4521         DC.B    $8A\r
4522         DC.B    'UPDATE-BI'     ; 'UPDATE-BIT'\r
4523         DC.B    'T'|$80\r
4524         DC.L    PBUF-5-NATWID\r
4525 UPDBIT  DC.L    DOCON\r
4526         DC.L    UPDATB\r
4527 *\r
4528 * ( --- )\r
4529 * Mark PREVious buffer dirty, in need of being written out.\r
4530         EVEN\r
4531         DC.B    0\r
4532         DC.B    $86\r
4533         DC.B    'UPDAT' ; 'UPDATE'\r
4534         DC.B    'E'|$80\r
4535         DC.L    UPDBIT-11-NATWID\r
4536 * UPDATE        DC.L    DOCOL,PREV,AT,AT,LIT,UPDATB,OR,PREV,AT,STORE\r
4537 UPDATE  DC.L    DOCOL,PREV,AT,AT,UPDBIT,OR,PREV,AT,STORE\r
4538         DC.L    SEMIS\r
4539 *\r
4540 * ======>>  172  <<\r
4541 *\r
4542 * Going to leave the 0 sector bug in place, I guess. Maybe.\r
4543 * ( adr --- )\r
4544 ** Mark the buffer addressed as empty.\r
4545 ** Have to add code to avoid block 0 appearing to be in a buffer from COLD.\r
4546 ** Usually, there is no sector 0 (?), but the RAM buffers are too simple.\r
4547 ** Note that without this block number being made illegal, \r
4548 ** about 8 binaryMegabytes (256 bytes/block) of disk can be addressed total.\r
4549 ** With this block number made illegal, the max is 1 block less,\r
4550 ** still about 8 biMeg.\r
4551 *       EVEN\r
4552 *       DC.B    $8B\r
4553 *       DC.B    'KILL-BUFFE'    ; 'KILL-BUFFER'\r
4554 *       DC.B    'R'|$80\r
4555 *       DC.L    UPDATE-7-NATWID\r
4556 *KILBUF DC.L    *+NATWID        ; DOCOL,UPDBIT,ONE,SUB,SWAP,STORE\r
4557 *       MOVE.L  (PSP)+,A0       \r
4558 *       MOVE.L  UPDBIT+NATWID(PC),D0\r
4559 *       SUBQ.L  #1,D0\r
4560 *       MOVE.L  D0,(A0)\r
4561 *       RTS\r
4562 *\r
4563 * ( --- )\r
4564 * Mark all buffers empty. \r
4565 *       EVEN\r
4566 *       DC.B    0\r
4567 *       DC.B    $8C\r
4568 *       DC.B    'KILL-BUFFER'   ; 'KILL-BUFFERS'\r
4569 *       DC.B    'S'|$80\r
4570 *       DC.L    KILBUF-12-NATWID\r
4571 *KLBFS  DC.L    DOCOL,FIRST,LIT16\r
4572 *       DC.W    4       ; Want to make sure it's only four.\r
4573 *       DC.L    ZERO,XDO        ; It would be "cleaner" to let +BUF control the loop.\r
4574 *       DC.L    DUP,KILBUF,PBUF,DROP,XLOOP\r
4575 *       DC.L    DROP,SEMIS\r
4576 ** KLBFS        DC.L    *+NATWID\r
4577 **      LDD     #4\r
4578 **      PSHU    D\r
4579 **      LDD     FIRST+NATWID,PCR\r
4580 **      INC     <TRACEM\r
4581 **      LBSR    DBGREG\r
4582 **      PSHU    D       ; DUP\r
4583 ** KLBFSL       PSHU    D\r
4584 **      BSR     KILBUF+NATWID\r
4585 **      LDD     ,U      \r
4586 **      LBSR    DBGREG\r
4587 **      ADDD    BBUF+NATWID,PCR\r
4588 **      ADDD    BCTL+NATWID,PCR\r
4589 **      STD     ,U\r
4590 **      LBSR    DBGREG\r
4591 **      DEC     NATWID+1,U\r
4592 **      BNE     KLBFSL\r
4593 **      LBSR    DBGREG\r
4594 **      LEAU    NATWID*2,U\r
4595 **      DEC     <TRACEM\r
4596 **      LBRA    NEXT\r
4597 *\r
4598 * ( --- )\r
4599 * Erase and mark all buffers empty. \r
4600 * Standard method of discarding changes.\r
4601         EVEN\r
4602         DC.B    $8D\r
4603         DC.B    'EMPTY-BUFFER'  ; 'EMPTY-BUFFERS'\r
4604         DC.B    'S'|$80\r
4605 *       DC.L    KLBFS-13-NATWID\r
4606         DC.L    UPDATE-7-NATWID\r
4607 MTBUF   DC.L    DOCOL,FIRST,LIMIT,OVER,SUB,ERASE\r
4608 *       DC.L    FIRST,DUP,KILBUF,PBUF,DROP,DUP,KILBUF\r
4609 *       DC.L    PBUF,DROP,DUP,KILBUF,PBUF,DROP,KILBUF\r
4610 *       DC.L    KLBFS\r
4611         DC.L    SEMIS\r
4612 *\r
4613 * ======>>  173  <<\r
4614 * ( --- )\r
4615 * Clear the current offset to the block numbers in the drive interface.\r
4616 * The drives need to be re-architected.\r
4617 * Would be cool to have RAM and ROM drives supported\r
4618 * in addition to regular physical persistent store.\r
4619         EVEN\r
4620         DC.B    $83\r
4621         DC.B    'DR'    ; 'DR0'\r
4622         DC.B    '0'|$80\r
4623         DC.L    MTBUF-14-NATWID\r
4624 DRZERO  DC.L    DOCOL,ZERO,OFSET,STORE\r
4625         DC.L    SEMIS\r
4626 *\r
4627 * ======>>  174  <<== system dependant word\r
4628 * ( --- )\r
4629 * Set the current offset in the drive interface to reference the second drive.\r
4630 * The hard-coded number in there needs to be in a table.\r
4631         EVEN\r
4632         DC.B    $83\r
4633         DC.B    'DR'    ; 'DR1'\r
4634         DC.B    '1'|$80\r
4635         DC.L    DRZERO-4-NATWID\r
4636 *DRONE  DC.L    DOCOL,LIT,$07D0,OFSET,STORE     \r
4637 ; **** hard-codes the size of the disc !!!!\r
4638 DRONE   DC.L    DOCOL,LIT,RAMDSZ,OFSET,STORE\r
4639         DC.L    SEMIS\r
4640 *\r
4641 * ######>> screen 59 <<\r
4642 * ======>>  175  <<\r
4643 * ( n --- buffer )\r
4644 * Get a free buffer,\r
4645 * assign it to block n,\r
4646 * return buffer address.\r
4647 * Will free a buffer by writing it, if necessary. \r
4648 * Does not actually read the block. \r
4649 * A bug in the fig LRU algorithm, which I have not fixed,\r
4650 * gives the PREVious buffer if USE gets set to PREVious.\r
4651 * (The bug is that USE sometimes gets set to PREVious.) \r
4652 * This bug sometimes causes sector moves to become sector fills.\r
4653         EVEN\r
4654         DC.B    0\r
4655         DC.B    $86\r
4656         DC.B    'BUFFE' ; 'BUFFER'\r
4657         DC.B    'R'|$80\r
4658         DC.L    DRONE-4-NATWID\r
4659 BUFFER  DC.L    DOCOL,USE,AT,DUP,TOR\r
4660 BUFFR2  DC.L    PBUF,ZBRAN\r
4661         DC.L    BUFFR2-*-NATWID\r
4662         DC.L    USE,STORE,R,AT,ZLESS\r
4663         DC.L    ZBRAN\r
4664         DC.L    BUFFR3-*-NATWID\r
4665 *       DC.L    R,TWOP,R,AT,LIT,$7FFF,AND,ZERO,RW\r
4666         DC.L    R,NATP,R,AT,UPDBIT,LNOT,AND,ZERO,RW\r
4667 * BUFFR3        DC.L    R,STORE,R,PREV,STORE,FROMR,TWOP\r
4668 BUFFR3  DC.L    R,STORE,R,PREV,STORE,FROMR,NATP\r
4669         DC.L    SEMIS\r
4670 *\r
4671 * ######>> screen 60 <<\r
4672 * ======>>  176  <<\r
4673 * ( n --- buffer )\r
4674 * Get BUFFER containing block n, relative to OFFSET. \r
4675 * If block n is not in a buffer, bring it in. \r
4676 * Returns buffer address.\r
4677         EVEN\r
4678         DC.B    $85\r
4679         DC.B    'BLOC'  ; 'BLOCK'\r
4680         DC.B    'K'|$80\r
4681         DC.L    BUFFER-7-NATWID\r
4682 BLOCK   DC.L    DOCOL,OFSET,AT,PLUS,TOR\r
4683         DC.L    PREV,AT,DUP,AT,R,SUB,DUP,PLUS,ZBRAN\r
4684         DC.L    BLOCK5-*-NATWID\r
4685 BLOCK3  DC.L    PBUF,ZEQU,ZBRAN\r
4686         DC.L    BLOCK4-*-NATWID\r
4687 *       DC.L    DROP,R,BUFFER,DUP,R,ONE,RW,TWO,SUB\r
4688         DC.L    DROP,R,BUFFER,DUP,R,ONE,RW,NATWC,SUB\r
4689 BLOCK4  DC.L    DUP,AT,R,SUB,DUP,PLUS,ZEQU,ZBRAN\r
4690         DC.L    BLOCK3-*-NATWID\r
4691         DC.L    DUP,PREV,STORE\r
4692 * BLOCK5        DC.L    FROMR,DROP,TWOP\r
4693 BLOCK5  DC.L    FROMR,DROP,NATP\r
4694         DC.L    SEMIS\r
4695 *\r
4696 * ######>> screen 61 <<\r
4697 * ======>>  177  <<\r
4698 * ( line screen --- buffer C/L)\r
4699 * Bring in the sector containing the specified line of the specified screen. \r
4700 * Returns the buffer address and the width of the screen. \r
4701 * Screen number is relative to OFFSET. \r
4702 * The line number may be beyond screen 4,\r
4703 * (LINE) will get the appropriate screen.\r
4704         EVEN\r
4705         DC.B    0\r
4706         DC.B    $86\r
4707         DC.B    '(LINE' ; '(LINE)'\r
4708         DC.B    ')'|$80\r
4709         DC.L    BLOCK-6-NATWID\r
4710 PLINE   DC.L    DOCOL,TOR,LIT16\r
4711         DC.W    $40\r
4712         DC.L    BBUF,SSMOD,FROMR,BSCR,STAR,PLUS,BLOCK,PLUS,LIT16\r
4713         DC.W    $40\r
4714         DC.L    SEMIS\r
4715 *\r
4716 * ======>>  178  <<\r
4717 * ( line screen --- )\r
4718 * Print the line of the screen as found by (LINE), suppress trailing BLANKS.\r
4719         EVEN\r
4720         DC.B    $85\r
4721         DC.B    '.LIN'  ; '.LINE'\r
4722         DC.B    'E'|$80\r
4723         DC.L    PLINE-7-NATWID\r
4724 DLINE   DC.L    DOCOL,PLINE,DTRAIL,TYPE\r
4725         DC.L    SEMIS\r
4726 *\r
4727 * ======>>  179  <<\r
4728 * ( n --- )\r
4729 * If WARNING is 0, print "MESSAGE #n";\r
4730 * otherwise, print line n relative to screen 4,\r
4731 * the line number may be negative. \r
4732 * Uses .LINE, but counter-adjusts to be relative to the real drive 0.\r
4733 * BUG: -DUP will cause this to reach farther into the stack than the error number \r
4734 * when WARNING is set and err# is zero (can't find entry in dictionary).\r
4735         EVEN\r
4736         DC.B    $87\r
4737         DC.B    'MESSAG'        ; 'MESSAGE'\r
4738         DC.B    'E'|$80\r
4739         DC.L    DLINE-6-NATWID\r
4740 MESS    DC.L    DOCOL,WARN,AT,ZBRAN\r
4741         DC.L    MESS3-*-NATWID\r
4742         DC.L    DDUP,ZBRAN      ; -DUP here is a bug from the original 6800 model, at least.\r
4743         DC.L    MESS3-*-NATWID\r
4744         DC.L    LIT16\r
4745         DC.W    4\r
4746         DC.L    OFSET,AT,BSCR,SLASH,SUB,DLINE,BRAN\r
4747         DC.L    MESS4-*-NATWID\r
4748 MESS3   DC.L    PDOTQ\r
4749         DC.B    6\r
4750         DC.B    'err # '        ; 'err # '\r
4751         DC.B    0       ; hand align\r
4752         DC.L    DOT\r
4753 MESS4   DC.L    SEMIS\r
4754 *\r
4755 * ======>>  180  <<\r
4756 * ( n --- )\r
4757 * Begin interpretation of screen (block) n. \r
4758 * See also ARROW, SEMIS, and NULL.\r
4759         EVEN\r
4760         DC.B    0\r
4761         DC.B    $84\r
4762         DC.B    'LOA'   ; 'LOAD' :      input:scr #\r
4763         DC.B    'D'|$80\r
4764         DC.L    MESS-8-NATWID\r
4765 LOAD    DC.L    DOCOL,BLK,AT,TOR,IN,AT,TOR,ZERO,IN,STORE\r
4766         DC.L    BSCR,STAR,BLK,STORE\r
4767         DC.L    INTERP,FROMR,IN,STORE,FROMR,BLK,STORE\r
4768         DC.L    SEMIS\r
4769 *\r
4770 * ======>>  181  <<\r
4771 * ( --- )                                                 P\r
4772 * Continue interpreting source code on the next screen.\r
4773         EVEN\r
4774         DC.B    $C3\r
4775         DC.B    '--'    ; '-->'\r
4776         DC.B    '>'|$80\r
4777         DC.L    LOAD-5-NATWID\r
4778 ARROW   DC.L    DOCOL,QLOAD,ZERO,IN,STORE,BSCR\r
4779         DC.L    BLK,AT,OVER,MOD,SUB,BLK,PSTORE\r
4780         DC.L    SEMIS\r
4781 *\r
4782         PAGE\r
4783 *\r
4784 * ######>> screen 63 <<\r
4785 *    The next clot of subroutines are machine dependent.\r
4786 *    PEMIT, PKEY, PQTER, and PCR (_P_arenthetic versions) are called by\r
4787 *    EMIT, KEY, QTERM, and CR, words 13 through 16 in the dictionary.\r
4788 *    This is all native CPU code.\r
4789 *\r
4790 * ATARI BIOS call parameters on _A7_ == SP. (Not PSP!)\r
4791 * Defining for Atari ST BIOS:\r
4792 * Atari BIOS messes with D0-D2/A0-A2.\r
4793 * We do not know D0/D1/A0/A1 are safe to overwrite in our runtime.\r
4794 *\r
4795 * ======>>  185  << code for CR\r
4796 * ( --- ) No stack effect.\r
4797 * Output a CR/LF combo to the CONSOLE device \r
4798 * using the Atari ST BIOS.\r
4799 * Move this here to keep it in reach of short branch.\r
4800 PCR     MOVEM.L D1,-(SP)        Don't destroy D1.\r
4801         MOVE.W  #$0D,D1\r
4802         BSR.S   PEMIT\r
4803         MOVE.W  #$0A,D1\r
4804         BSR.S   PEMIT   ; Don't rob PEMIT's return.\r
4805         MOVEM.L (SP)+,D1        ; Restore D1\r
4806         RTS\r
4807 *\r
4808 * ( --- ) No parameter stack effect.\r
4809 * Assume volatile registers saved,\r
4810 * Use Atari terminal emulation to turn the text cursor on.\r
4811 PCURON  MOVEM.L D1,-(SP)        Don't destroy D1.\r
4812         MOVE.W  #$1B,D1\r
4813         BSR.S   PEMIT\r
4814         MOVE.W  #'e',D1\r
4815         BSR.S   PEMIT   ; Don't rob PEMIT's return.\r
4816         MOVEM.L (SP)+,D1        ; Restore D1\r
4817         RTS     \r
4818 *\r
4819 * ( --- ) No parameter stack effect.\r
4820 * Assume volatile registers saved,\r
4821 * Use Atari terminal emulation to turn the text cursor off.\r
4822 PCROFF  MOVEM.L D1,-(SP)        Don't destroy D1.\r
4823         MOVE.W  #$1B,D1\r
4824         BSR.S   PEMIT\r
4825         MOVE.W  #'f',D1\r
4826         BSR.S   PEMIT   ; Don't rob PEMIT's return.\r
4827         MOVEM.L (SP)+,D1        ; Restore D1\r
4828         RTS     \r
4829 *\r
4830 * ======>>  182  << code for EMIT\r
4831 * ( --- ) No parameter stack effect.\r
4832 * Put one byte from D1 out on the CONSOLE device\r
4833 * using Atari ST BIOS.\r
4834 PEMIT   MOVEM.L D0/D1/D2/A0/A1/A2,-(PSP)        ; Save volatile registers, D0 lowest.\r
4835         LEA     -6(SP),SP       ; allocate BIOS parameter space\r
4836 PEMITW  MOVE.W  #2,2(SP)        ; console device\r
4837         MOVE.W  #8,(SP)         ; bcostat\r
4838         TRAP    #13             ; BIOS call\r
4839         TST.L   D0              ; not really necessary?\r
4840         BEQ.S   PEMITW          ; wait for CONSOLE out ready\r
4841         MOVE.W  NATWID+NATWID/2(PSP),4(SP)      ; low word of PSP top is character to output\r
4842         MOVE.W  #2,2(SP)        ; console device\r
4843         MOVE.W  #3,(SP)         ; bconout\r
4844         TRAP    #13             ; BIOS call\r
4845         LEA     6(SP),SP        ; deallocate BIOS workspace\r
4846         MOVEM.L (PSP)+,D0/D1/D2/A0/A1/A2        ; Restore volatile registers and parameter stack.\r
4847         RTS\r
4848 *\r
4849 * ======>>  183  << code for KEY\r
4850 * ( --- ) No parameter stack effect.\r
4851 * Wait for one keypress from the CONSOLE device\r
4852 * and return the character code for the key pressed in D1\r
4853 * using Atari ST BIOS.\r
4854 PKEY    MOVEM.L D0/D2/A0/A1/A2,-(PSP)   ; Save volatile registers.\r
4855         BSR.S   PCURON          ; Show the cursor\r
4856 PKEYG   MOVE.W  #2,-(SP)        ; console device\r
4857         MOVE.W  #2,-(SP)        ; bconin\r
4858         TRAP    #13             ; BIOS call\r
4859         LEA     4(SP),SP        ; clean up stack\r
4860 PKEYT   BSR.S   PCROFF\r
4861         CMP.B   #3,D0           ; CTL-C? (Atari BIOS emulates a nice terminal.)\r
4862         BNE.S   PKEYX\r
4863         OR.L    #$FFFFFF00,D0   ; set the N flag\r
4864 PKEYX   MOVE.L  D0,D1           ; KEY and QTERM expect it in D1.\r
4865         MOVEM.L (PSP)+,D0/D2/A0/A1/A2   ; Restore registers without touching flags.\r
4866         RTS\r
4867 *\r
4868 * ######>> screen 64 <<\r
4869 * ======>>  184  << code for ?TERMINAL\r
4870 * ( --- ) No stack effect.\r
4871 * Check for break key on the CONSOLE device without waiting\r
4872 * using Atari ST BIOS.\r
4873 PQTER   MOVEM.L D0/D2/A0/A1/A2,-(PSP)   ; Save D2.\r
4874         MOVE.W  #2,-(SP)        ; console device\r
4875         MOVE.W  #1,-(SP)        ; bconstat\r
4876         TRAP    #13             ; BIOS call\r
4877         LEA     4(SP),SP        ; clean up stack, don't wait\r
4878         TST.L   D0              ; Got a key?\r
4879         BMI.S   PKEYG           ; Get the key, but D2 already saved.\r
4880         BRA.S   PKEYX           ; Rob PKEY's tail and restore.\r
4881 *\r
4882 * ######>> screen 66 <<\r
4883 * ======>>  187  <<\r
4884 * ( ??? )\r
4885 * Query the disk, I suppose.\r
4886 * Not sure what the model had in mind for this stub.\r
4887         EVEN\r
4888         DC.B    $85\r
4889         DC.B    '?DIS'  ; '?DISC'\r
4890         DC.B    'C'|$80\r
4891         DC.L    ARROW-4-NATWID\r
4892 QDISC   DC.L    *+NATWID\r
4893         JMP     NEXT\r
4894 *\r
4895 * ######>> screen 67 <<\r
4896 * ======>>  189  <<\r
4897 * ( ??? )\r
4898 * Write one block of data to disk.\r
4899 * Parameters unspecified in model. Stub in model.\r
4900         EVEN\r
4901         DC.B    $8B\r
4902         DC.B    'BLOCK-WRIT'    ; 'BLOCK-WRITE'\r
4903         DC.B    'E'|$80\r
4904         DC.L    QDISC-6-NATWID\r
4905 BWRITE  DC.L    *+NATWID\r
4906         JMP     NEXT\r
4907 *\r
4908 * ######>> screen 68 <<\r
4909 * ======>>  190  <<\r
4910 * ( ??? )\r
4911 * Read one block of data from disk.\r
4912 * Parameters unspecified in model. Stub in model.\r
4913         EVEN\r
4914         DC.B    0\r
4915         DC.B    $8A\r
4916         DC.B    'BLOCK-REA'     ; 'BLOCK-READ'\r
4917         DC.B    'D'|$80\r
4918         DC.L    BWRITE-12-NATWID\r
4919 BREAD   DC.L    *+NATWID\r
4920         JMP     NEXT\r
4921 *\r
4922 *The next 3 words are written to create a substitute for disc\r
4923 * mass memory,located between MASSLO & MASSHI in ram --\r
4924 * ($3210 and $3fff in the 6800 model).\r
4925 * ======>>  190.1  <<\r
4926         EVEN\r
4927         DC.B    0\r
4928         DC.B    $82\r
4929         DC.B    'L'     ; 'LO'\r
4930         DC.B    'O'|$80\r
4931         DC.L    BREAD-11-NATWID\r
4932 LO      DC.L    DOCON\r
4933         DC.L    MEMEND  a system dependent equate at front\r
4934 *\r
4935 * ======>>  190.2  <<\r
4936         EVEN\r
4937         DC.B    0\r
4938         DC.B    $82\r
4939         DC.B    'H'     ; 'HI'\r
4940         DC.B    'I'|$80\r
4941         DC.L    LO-3-NATWID\r
4942 HI      DC.L    DOCON\r
4943         DC.L    MEMTOP  ( $3FFF or $7FFF in this version )\r
4944 *\r
4945 * ######>> screen 69 <<\r
4946 * ======>>  191  <<\r
4947 * ( buffer sector f --- )\r
4948 * Read or Write the specified (absolute -- ignores OFFSET) sector\r
4949 * from or to the specified buffer. \r
4950 * A zero flag specifies write,\r
4951 * non-zero specifies read. \r
4952 * Sector is an unsigned integer,\r
4953 * buffer is the buffer's address. \r
4954 * Will need to use the CoCo ROM disk routines. \r
4955 * For now, provides a virtual disk in RAM.\r
4956         EVEN\r
4957         DC.B    $83\r
4958         DC.B    'R/'    ; 'R/W'\r
4959         DC.B    'W'|$80\r
4960         DC.L    HI-3-NATWID\r
4961 RW      DC.L    DOCOL,TOR,BBUF,STAR,LO,PLUS,DUP,HI,GREAT,ZBRAN\r
4962         DC.L    RW2-*-NATWID\r
4963         DC.L    PDOTQ\r
4964         DC.B    8\r
4965         DC.B    ' Range ?'      ; ' Range ?'\r
4966         DC.B    0       ; hand align\r
4967         DC.L    QUIT\r
4968 RW2     DC.L    FROMR,ZBRAN\r
4969         DC.L    RW3-*-NATWID\r
4970         DC.L    SWAP\r
4971 RW3     DC.L    BBUF,CMOVE\r
4972         DC.L    SEMIS\r
4973 *\r
4974 * From BIF-6809:\r
4975 * RW    PSHS Y,U,DP\r
4976 *       LDY $C006 control table\r
4977 *       LDX #DROFFS+7   ; This is BIF's table of drive sizes.\r
4978 *       LDD 2,U\r
4979 * RWD   SUBD ,X++ sectors\r
4980 *       BHS RWD\r
4981 *       BVC RWR table end?\r
4982 *       LDD #6\r
4983 *       PSHU D\r
4984 *       JMP ERROR\r
4985 * RWR   ADDD ,--X back one\r
4986 *       PSHS X\r
4987 *       PSHU D\r
4988 *       LDD #18 sectors/track\r
4989 *       PSHU D\r
4990 *       DOCOL\r
4991 *       FDB SLAMOD\r
4992 *       FDB XMACH\r
4993 *       PULU D\r
4994 *       STB 2,Y track\r
4995 *       PULU D\r
4996 *       INCB\r
4997 *       STB 3,Y sector\r
4998 *       PULS D table entry\r
4999 *       SUBD #DROFFS+7\r
5000 *       ASRB drive #\r
5001 *       STB 1,Y\r
5002 *       LDD 4,U buffer\r
5003 *       STD 4,Y\r
5004 *       LDB #2 coco READ\r
5005 *       LDX ,U 0?\r
5006 *       BNE *+3\r
5007 *       INCB coco WRITE\r
5008 *       STB ,Y op code\r
5009 *       CLRA\r
5010 *       TFR A,DP\r
5011 *       JSR [$C004]     ROM handles timeout\r
5012 *       PULS Y,U,DP     if IRQ enabled\r
5013 *       LEAU 6,U\r
5014 *       LDX $C006\r
5015 *       LDB 6,X coco status\r
5016 *       BEQ RWE\r
5017 *       LDX <UP\r
5018 *       LDD #0 no disc\r
5019 *       STD UWARN,X\r
5020 *       LDD #8\r
5021 *       PSHU D\r
5022 *       JMP ERROR\r
5023 * RWE   NEXT\r
5024 *\r
5025         PAGE\r
5026 *\r
5027 * ######>> screen 72 <<\r
5028 * ======>>  192  <<\r
5029 * ( --- ) compiling                                       P\r
5030 * ( --- adr ) interpreting\r
5031 * { ' name } input\r
5032 * Parse a symbol name from input and search the dictionary for it, per -FIND;\r
5033 * compile the address as a literal if compiling,\r
5034 * otherwise just push it. \r
5035         EVEN\r
5036         DC.B    $C1     ; immediate\r
5037         DC.B    "'"|$80 ; '     ( tick )\r
5038         DC.L    RW-4-NATWID\r
5039 TICK    DC.L    DOCOL,DFIND,ZEQU,ZERO,QERR,DROP,LITER\r
5040         DC.L    SEMIS\r
5041 *\r
5042 * ======>>  193  <<\r
5043 * ( --- ) { FORGET name } input\r
5044 * Parse out name of definition to FORGET to, -DFIND it,\r
5045 * then lop it and everything that follows out of the dictionary. \r
5046 * In fig Forth, CURRENT and CONTEXT have to be the same to FORGET.\r
5047         EVEN\r
5048         DC.B    0\r
5049         DC.B    $86\r
5050         DC.B    'FORGE' ; 'FORGET'\r
5051         DC.B    'T'|$80\r
5052         DC.L    TICK-2-NATWID\r
5053 FORGET  DC.L    DOCOL,CURENT,AT,CONTXT,AT,SUB,LIT16\r
5054         DC.W    $18\r
5055         DC.L    QERR,TICK,DUP,FENCE,AT,LESS,LIT16\r
5056         DC.W    $15\r
5057         DC.L    QERR,DUP,ZERO,PORIG,GREAT,LIT16\r
5058         DC.W    $15\r
5059         DC.L    QERR,DUP,NFA,DICTPT,STORE,LFA,AT,CONTXT,AT,STORE\r
5060         DC.L    SEMIS\r
5061 *\r
5062 * ######>> screen 73 <<\r
5063 * ======>>  194  <<\r
5064 *  ( adr --- )                                             C\r
5065 * Calculate a back reference from HERE and compile it. \r
5066         EVEN\r
5067         DC.B    0\r
5068         DC.B    $84\r
5069         DC.B    'BAC'   ; 'BACK'\r
5070         DC.B    'K'|$80\r
5071         DC.L    FORGET-7-NATWID\r
5072 * BACK  DC.L    DOCOL,HERE,SUB,COMMA\r
5073 BACK    DC.L    DOCOL,HERE,NATP,SUB,COMMA\r
5074         DC.L    SEMIS\r
5075 *\r
5076 * ======>>  195  <<\r
5077 * ( --- )   runtime\r
5078 * typical use: BEGIN code-loop test UNTIL  \r
5079 * typical use: BEGIN code-loop AGAIN  \r
5080 * typical use: BEGIN code-loop test WHILE code-true REPEAT  \r
5081 * ( --- adr n )  compile time                       P,C\r
5082 * Push HERE for BACK reference for general (non-counting) loops,\r
5083 * with BEGIN construct flag.\r
5084 * A better flag: $4245 (ASCII for 'BE').\r
5085         EVEN\r
5086         DC.B    $C5\r
5087         DC.B    'BEGI'  ; 'BEGIN'\r
5088         DC.B    'N'|$80\r
5089         DC.L    BACK-5-NATWID\r
5090 BEGIN   DC.L    DOCOL,QCOMP,HERE,ONE    ; ONE is a flag for BEGIN loops.\r
5091         DC.L    SEMIS\r
5092 *\r
5093 * ======>>  196  <<\r
5094 * ( --- )   runtime\r
5095 * typical use: test IF code-true ELSE code-false ENDIF \r
5096 * ENDIF is just a sort of intersection piece, \r
5097 * marking where execution resumes after both branches.\r
5098 * ( adr n --- ) compile time\r
5099 * Check the mark and resolve the IF.\r
5100 * A better flag: $4846 (ASCII for 'IF').\r
5101         EVEN\r
5102         DC.B    $C5\r
5103         DC.B    'ENDI'  ; 'ENDIF'\r
5104         DC.B    'F'|$80\r
5105         DC.L    BEGIN-6-NATWID\r
5106 ENDIF   DC.L    DOCOL,QCOMP,TWO,QPAIRS,HERE     ; This TWO is a flag for IF.\r
5107 *       DC.L    OVER,SUB,SWAP,STORE\r
5108         DC.L    OVER,NATP,SUB,SWAP,STORE\r
5109         DC.L    SEMIS\r
5110 *\r
5111 * ======>>  197  <<\r
5112 * ( --- )   runtime\r
5113 * typical use: test IF code-true ELSE code-false ENDIF \r
5114 * ( adr n --- ) \r
5115 * Alias for ENDIF .\r
5116         EVEN\r
5117         DC.B    0\r
5118         DC.B    $C4\r
5119         DC.B    'THE'   ; 'THEN'\r
5120         DC.B    'N'|$80\r
5121         DC.L    ENDIF-6-NATWID\r
5122 THEN    DC.L    DOCOL,ENDIF\r
5123         DC.L    SEMIS\r
5124 *\r
5125 * ======>>  198  <<\r
5126 * ( limit index --- )   runtime\r
5127 * typical use: DO code-loop LOOP  \r
5128 * typical use: DO code-loop increment +LOOP\r
5129 * Counted loop, index is initial value of index.\r
5130 * Will loop until index equals (positive going)\r
5131 * or passes (negative going) limit.\r
5132 *  ( --- adr n )  compile time                        P,C\r
5133 * Compile (DO), push HERE for BACK reference,\r
5134 * and push DO control construct flag.\r
5135 * A better flag: $444F (ASCII for 'DO').\r
5136         EVEN\r
5137         DC.B    0\r
5138         DC.B    $C2\r
5139         DC.B    'D'     ; 'DO'\r
5140         DC.B    'O'|$80\r
5141         DC.L    THEN-5-NATWID\r
5142 DO      DC.L    DOCOL,COMPIL,XDO,HERE,THREE     ; THREE is a flag for DO loops.\r
5143         DC.L    SEMIS\r
5144 *\r
5145 * ======>>  199  <<\r
5146 * ( --- )   runtime\r
5147 * typical use: DO code-loop LOOP  \r
5148 * Increments the index by one and branches back to beginning of loop.\r
5149 * Will loop until index equals limit.\r
5150 * ( adr n --- )  compile time                        P,C\r
5151 * Check the mark and compile (LOOP), fill in BACK reference.\r
5152 * A better flag: $444F (ASCII for 'DO').\r
5153         EVEN\r
5154         DC.B    0\r
5155         DC.B    $C4\r
5156         DC.B    'LOO'   ; 'LOOP'\r
5157         DC.B    'P'|$80\r
5158         DC.L    DO-3-NATWID\r
5159 LOOP    DC.L    DOCOL,THREE,QPAIRS,COMPIL,XLOOP,BACK    ; THREE for DO loops.\r
5160         DC.L    SEMIS\r
5161 *\r
5162 * ======>>  200  <<\r
5163 * ( n --- )   runtime\r
5164 * typical use: DO code-loop increment +LOOP\r
5165 * Increments the index by n and branches back to beginning of loop.\r
5166 * Will loop until index equals (positive going)\r
5167 * or passes (negative going) limit.\r
5168 * ( adr n --- )  compile time                       P,C\r
5169 * Check the mark and compile (+LOOP), fill in BACK reference.\r
5170 * A better flag: $444F (ASCII for 'DO').\r
5171         EVEN\r
5172         DC.B    $C5\r
5173         DC.B    '+LOO'  ; '+LOOP'\r
5174         DC.B    'P'|$80\r
5175         DC.L    LOOP-5-NATWID\r
5176 PLOOP   DC.L    DOCOL,THREE,QPAIRS,COMPIL,XPLOOP,BACK   ; THREE for DO loops.\r
5177         DC.L    SEMIS\r
5178 *\r
5179 * ======>>  201  <<\r
5180 * ( n --- )   runtime\r
5181 * typical use: BEGIN code-loop test UNTIL  \r
5182 * Will loop until UNTIL tests true.\r
5183 * ( adr n --- )  compile time                      P,C\r
5184 * Check the mark and compile (0BRANCH), fill in BACK reference.\r
5185 * A better flag: $4245 (ASCII for 'BE').\r
5186         EVEN\r
5187         DC.B    $C5\r
5188         DC.B    'UNTI'  ; 'UNTIL' :     ( same as END )\r
5189         DC.B    'L'|$80\r
5190         DC.L    PLOOP-6-NATWID\r
5191 UNTIL   DC.L    DOCOL,ONE,QPAIRS,COMPIL,ZBRAN,BACK      ; ONE for BEGIN loops.\r
5192         DC.L    SEMIS\r
5193 *\r
5194 * ######>> screen 74 <<\r
5195 * ======>>  202  <<\r
5196 * ( n --- )   runtime\r
5197 * typical use: BEGIN code-loop test END  \r
5198 * ( adr n --- ) \r
5199 * Alias for UNTIL .\r
5200         EVEN\r
5201         DC.B    $C3\r
5202         DC.B    'EN'    ; 'END'\r
5203         DC.B    'D'|$80\r
5204         DC.L    UNTIL-6-NATWID\r
5205 END     DC.L    DOCOL,UNTIL\r
5206         DC.L    SEMIS\r
5207 *\r
5208 * ======>>  203  <<\r
5209 * ( --- )   runtime\r
5210 * typical use: BEGIN code-loop AGAIN  \r
5211 * Will loop forever \r
5212 * (or until something uses R> DROP to force the current definition to die,\r
5213 *  or perhaps ABORT or ERROR or some such other drastic means stops things).\r
5214 * ( adr n --- )  compile time                      P,C\r
5215 * Check the mark and compile (0BRANCH), fill in BACK reference.\r
5216 * A better flag: $4245 (ASCII for 'BE').\r
5217         EVEN\r
5218         DC.B    $C5\r
5219         DC.B    'AGAI'  ; 'AGAIN'\r
5220         DC.B    'N'|$80\r
5221         DC.L    END-4-NATWID\r
5222 AGAIN   DC.L    DOCOL,ONE,QPAIRS,COMPIL,BRAN,BACK       ; ONE for BEGIN loops.\r
5223         DC.L    SEMIS\r
5224 *\r
5225 * ======>>  204  <<\r
5226 * ( --- )   runtime\r
5227 * typical use: BEGIN code-loop test WHILE code-true REPEAT  \r
5228 * Will loop until WHILE tests false, skipping code-true on end.\r
5229 * REPEAT marks where execution resumes after the WHILE find a false flag.\r
5230 * ( aadr1 n1 adr2 n2 --- )   compile time         P,C\r
5231 * Check the marks for WHILE and BEGIN,\r
5232 * compile BRANCH and BACK fill adr1 reference,\r
5233 * FILL-IN 0BRANCH reference at adr2.\r
5234 * Better flags: $4245 (ASCII for 'BE') and $5747 (ASCII for 'WH').\r
5235         EVEN\r
5236         DC.B    0\r
5237         DC.B    $C6\r
5238         DC.B    'REPEA' ; 'REPEAT'\r
5239         DC.B    'T'|$80\r
5240         DC.L    AGAIN-6-NATWID\r
5241 REPEAT  DC.L    DOCOL,TOR,TOR,AGAIN,FROMR,FROMR ; ONE for BEGIN loops.\r
5242         DC.L    TWO,SUB,ENDIF   ; TWO is for IF, 4 is for WHILE.\r
5243         DC.L    SEMIS\r
5244 *\r
5245 * ======>>  205  <<\r
5246 * ( n --- )   runtime\r
5247 * typical use: test IF code-true ELSE code-false ENDIF \r
5248 * Will pass execution to the true part on a true flag \r
5249 * and to the false part on a false flag.\r
5250 * ( --- adr n )  compile time                       P,C\r
5251 * Compile a 0BRANCH and dummy offset\r
5252 * and push IF reference to fill in and\r
5253 * IF control construct flag.\r
5254 * A better flag: $4946 (ASCII for 'IF').\r
5255         EVEN\r
5256         DC.B    0\r
5257         DC.B    $C2\r
5258         DC.B    'I'     ; 'IF'\r
5259         DC.B    'F'|$80\r
5260         DC.L    REPEAT-7-NATWID\r
5261 IF      DC.L    DOCOL,COMPIL,ZBRAN,HERE,ZERO,COMMA,TWO  ; TWO is a flag for IF.\r
5262         DC.L    SEMIS\r
5263 *\r
5264 * ======>>  206  <<\r
5265 * ( --- )   runtime\r
5266 * typical use: test IF code-true ELSE code-false ENDIF \r
5267 * ELSE is just a sort of intersection piece, \r
5268 * marking where execution resumes on a false branch.\r
5269 * ( adr1 n --- adr2 n )  compile time         P,C\r
5270 * Check the marks,\r
5271 * compile BRANCH with dummy offset,\r
5272 * resolve IF reference,\r
5273 * and leave reference to BRANCH for ELSE.\r
5274 * A better flag: $4946 (ASCII for 'IF').\r
5275         EVEN\r
5276         DC.B    0\r
5277         DC.B    $C4\r
5278         DC.B    'ELS'   ; 'ELSE'\r
5279         DC.B    'E'|$80\r
5280         DC.L    IF-3-NATWID\r
5281 ELSE    DC.L    DOCOL,TWO,QPAIRS,COMPIL,BRAN,HERE\r
5282         DC.L    ZERO,COMMA,SWAP,TWO,ENDIF,TWO   ; TWO is a flag for IF.\r
5283         DC.L    SEMIS\r
5284 *\r
5285 * ======>>  207  <<\r
5286 * ( n --- )   runtime\r
5287 * typical use: BEGIN code-loop test WHILE code-true REPEAT  \r
5288 * Will loop until WHILE tests false, skipping code-true on end.\r
5289 * ( --- adr n ) compile time                        P,C\r
5290 * Compile 0BRANCH with dummy offset (using IF),\r
5291 * push WHILE reference.\r
5292 * BEGIN flag will sit underneath this.\r
5293 * Better flags: $4245 (ASCII for 'BE') and $5747 (ASCII for 'WH').\r
5294         EVEN\r
5295         DC.B    $C5\r
5296         DC.B    'WHIL'  ; 'WHILE'\r
5297         DC.B    'E'|$80\r
5298         DC.L    ELSE-5-NATWID\r
5299 WHILE   DC.L    DOCOL,IF,TWOP   ; TWO is a flag for IF, 4 is for WHILE.\r
5300         DC.L    SEMIS\r
5301 *\r
5302         PAGE\r
5303 *\r
5304 * ######>> screen 75 <<\r
5305 * ======>>  208  <<\r
5306 * ( count --- )\r
5307 * EMIT count spaces, for non-zero, non-negative counts.\r
5308         EVEN\r
5309         DC.B    0\r
5310         DC.B    $86\r
5311         DC.B    'SPACE' ; 'SPACES'\r
5312         DC.B    'S'|$80\r
5313         DC.L    WHILE-6-NATWID\r
5314 SPACES  DC.L    DOCOL,ZERO,MAX,DDUP,ZBRAN\r
5315         DC.L    SPACE3-*-NATWID\r
5316         DC.L    ZERO,XDO\r
5317 SPACE2  DC.L    SPACE,XLOOP\r
5318         DC.L    SPACE2-*-NATWID\r
5319 SPACE3  DC.L    SEMIS\r
5320 *\r
5321 * ======>>  209  <<\r
5322 * ( --- )\r
5323 * Initialize HLD for converting a double integer. \r
5324 * Stores the PAD address in HLD.\r
5325         EVEN\r
5326         DC.B    0\r
5327         DC.B    $82\r
5328         DC.B    '<'     ; '<#'\r
5329         DC.B    '#'|$80\r
5330         DC.L    SPACES-7-NATWID\r
5331 BDIGS   DC.L    DOCOL,PAD,HLD,STORE\r
5332         DC.L    SEMIS\r
5333 *\r
5334 * ======>>  210  <<\r
5335 * ( d --- string length )\r
5336 * Terminate numeric conversion,\r
5337 * drop the number being converted,\r
5338 * leave the address of the conversion string and the length, ready for TYPE.\r
5339         EVEN\r
5340         DC.B    0\r
5341         DC.B    $82\r
5342         DC.B    '#'     ; '#>'\r
5343         DC.B    '>'|$80\r
5344         DC.L    BDIGS-3-NATWID\r
5345 EDIGS   DC.L    DOCOL,DROP,DROP,HLD,AT,PAD,OVER,SUB\r
5346         DC.L    SEMIS\r
5347 *\r
5348 * ======>>  211  <<\r
5349 * ( n d --- d )\r
5350 * Put sign of n (as a flag) at the head of the conversion string.\r
5351 * Drop the sign flag.\r
5352         EVEN\r
5353         DC.B    0\r
5354         DC.B    $84\r
5355         DC.B    'SIG'   ; 'SIGN'\r
5356         DC.B    'N'|$80\r
5357         DC.L    EDIGS-3-NATWID\r
5358 SIGN    DC.L    DOCOL,ROT,ZLESS,ZBRAN\r
5359         DC.L    SIGN2-*-NATWID\r
5360         DC.L    LIT16\r
5361         DC.W    "-"     \r
5362         DC.L    HOLD\r
5363 SIGN2   DC.L    SEMIS\r
5364 *\r
5365 * ======>>  212  <<\r
5366 * ( d --- d/base )\r
5367 * Generate next most significant digit in the conversion BASE,\r
5368 * putting the digit at the head of the conversion string.\r
5369         EVEN\r
5370         DC.B    $81     ; #\r
5371         DC.B    '#'|$80\r
5372         DC.L    SIGN-5-NATWID\r
5373 DIG     DC.L    DOCOL,BASE,AT,MSMOD,ROT,LIT16\r
5374         DC.W    9\r
5375         DC.L    OVER,LESS,ZBRAN\r
5376         DC.L    DIG2-*-NATWID\r
5377         DC.L    LIT16\r
5378         DC.W    7\r
5379         DC.L    PLUS\r
5380 DIG2    DC.L    LIT16\r
5381         DC.W    "0"     ; ascii zero\r
5382         DC.L    PLUS,HOLD\r
5383         DC.L    SEMIS\r
5384 *\r
5385 * ======>>  213  <<\r
5386 * ( d --- dzero )\r
5387 * Convert d to a numeric string using # until the result is zero.\r
5388 * Leave the double result on the stack for #> to drop.\r
5389         EVEN\r
5390         DC.B    0\r
5391         DC.B    $82\r
5392         DC.B    '#'     ; '#S'\r
5393         DC.B    'S'|$80\r
5394         DC.L    DIG-2-NATWID\r
5395 DIGS    DC.L    DOCOL\r
5396 DIGS2   DC.L    DIG,OVER,OVER,OR,ZEQU,ZBRAN\r
5397         DC.L    DIGS2-*-NATWID\r
5398         DC.L    SEMIS\r
5399 *\r
5400 * ######>> screen 76 <<\r
5401 * ======>>  214  <<\r
5402 * ( n width --- )\r
5403 * Print n on the output device in the current conversion base,\r
5404 * with sign,\r
5405 * right aligned in a field at least width wide.\r
5406         EVEN\r
5407         DC.B    0\r
5408         DC.B    $82\r
5409         DC.B    '.'     ; '.R'\r
5410         DC.B    'R'|$80\r
5411         DC.L    DIGS-3-NATWID\r
5412 DOTR    DC.L    DOCOL,TOR,STOD,FROMR,DDOTR\r
5413         DC.L    SEMIS\r
5414 *\r
5415 * ======>>  215  <<\r
5416 * ( d width --- )\r
5417 * Print d on the output device in the current conversion base,\r
5418 * with sign,\r
5419 * right aligned in a field at least width wide.\r
5420         EVEN\r
5421         DC.B    $83\r
5422         DC.B    'D.'    ; 'D.R'\r
5423         DC.B    'R'|$80\r
5424         DC.L    DOTR-3-NATWID\r
5425 DDOTR   DC.L    DOCOL,TOR,SWAP,OVER,DABS,BDIGS,DIGS,SIGN\r
5426         DC.L    EDIGS,FROMR,OVER,SUB,SPACES,TYPE\r
5427         DC.L    SEMIS\r
5428 *\r
5429 * ======>>  216  <<\r
5430 * D.      ( d --- )\r
5431 * Print d on the output device in the current conversion base,\r
5432 * with sign,\r
5433 * in free format with trailing space.\r
5434         EVEN\r
5435         DC.B    0\r
5436         DC.B    $82\r
5437         DC.B    'D'     ; 'D.'\r
5438         DC.B    '.'|$80\r
5439         DC.L    DDOTR-4-NATWID\r
5440 DDOT    DC.L    DOCOL,ZERO,DDOTR,SPACE\r
5441         DC.L    SEMIS\r
5442 *\r
5443 * ======>>  217  <<\r
5444 * ( n --- )\r
5445 * Print n on the output device in the current conversion base,\r
5446 * with sign,\r
5447 * in free format with trailing space.\r
5448         EVEN\r
5449         DC.B    $81     ; .\r
5450         DC.B    '.'|$80\r
5451         DC.L    DDOT-3-NATWID\r
5452 *DOT    DC.L    DOCOL,STOD,DDOT\r
5453 DOT     DC.L    DOCOL,BREAK,STOD,DDOT   ; DBG *****\r
5454         DC.L    SEMIS\r
5455 *\r
5456 * ======>>  218  <<\r
5457 * ( adr --- )\r
5458 * Print signed word at adr, per DOT.\r
5459         EVEN\r
5460         DC.B    $81     ; ?\r
5461         DC.B    '?'|$80\r
5462         DC.L    DOT-2-NATWID\r
5463 QUEST   DC.L    DOCOL,AT,DOT\r
5464         DC.L    SEMIS\r
5465 *\r
5466         PAGE\r
5467 *\r
5468 * ######>> screen 77 <<\r
5469 * ======>>  219  <<\r
5470 * ( n --- )\r
5471 * Print out screen n as a field of ASCII,\r
5472 * with line numbers in decimal.\r
5473 * Needs a console more than 70 characters wide.\r
5474         EVEN\r
5475         DC.B    0\r
5476         DC.B    $84\r
5477         DC.B    'LIS'   ; 'LIST'\r
5478         DC.B    'T'|$80\r
5479         DC.L    QUEST-2-NATWID\r
5480 LIST    DC.L    DOCOL,DEC,CR,DUP,SCR,STORE,PDOTQ\r
5481         DC.B    6\r
5482         DC.B    "SCR # "\r
5483         DC.B    0       ; hand align\r
5484         DC.L    DOT,LIT16\r
5485         DC.W    $10\r
5486         DC.L    ZERO,XDO\r
5487 LIST2   DC.L    CR,I,THREE\r
5488         DC.L    DOTR,SPACE,I,SCR,AT,DLINE,XLOOP\r
5489         DC.L    LIST2-*-NATWID\r
5490         DC.L    CR\r
5491         DC.L    SEMIS\r
5492 *\r
5493 * ======>>  220  <<\r
5494 * ( start end --- )\r
5495 * Print comment lines (line 0, and line 1 if C/L < 41) of screens\r
5496 * from start to end.\r
5497 * Needs a console more than 70 characters wide.\r
5498         EVEN\r
5499         DC.B    $85\r
5500         DC.B    'INDE'  ; 'INDEX'\r
5501         DC.B    'X'|$80\r
5502         DC.L    LIST-5-NATWID\r
5503 INDEX   DC.L    DOCOL,CR,ONEP,SWAP,XDO\r
5504 INDEX2  DC.L    CR,I,THREE\r
5505         DC.L    DOTR,SPACE,ZERO,I,DLINE\r
5506         DC.L    QTERM,ZBRAN\r
5507         DC.L    INDEX3-*-NATWID\r
5508         DC.L    LEAVE\r
5509 INDEX3  DC.L    XLOOP\r
5510         DC.L    INDEX2-*-NATWID\r
5511         DC.L    SEMIS\r
5512 *\r
5513 * ======>>  221  <<\r
5514 * ( n --- )\r
5515 * List a printer page full of screens.\r
5516 * Line and screen number are in current base.\r
5517 * Needs a console more than 70 characters wide.\r
5518         EVEN\r
5519         DC.B    $85\r
5520         DC.B    'TRIA'  ; 'TRIAD'\r
5521         DC.B    'D'|$80\r
5522         DC.L    INDEX-6-NATWID\r
5523 TRIAD   DC.L    DOCOL,THREE,SLASH,THREE,STAR\r
5524         DC.L    THREE,OVER,PLUS,SWAP,XDO\r
5525 TRIAD2  DC.L    CR,I\r
5526         DC.L    LIST,QTERM,ZBRAN\r
5527         DC.L    TRIAD3-*-NATWID\r
5528         DC.L    LEAVE\r
5529 TRIAD3  DC.L    XLOOP\r
5530         DC.L    TRIAD2-*-NATWID\r
5531         DC.L    CR,LIT16\r
5532         DC.W    $0F\r
5533         DC.L    MESS,CR\r
5534         DC.L    SEMIS\r
5535 *\r
5536 * ######>> screen 78 <<\r
5537 * ======>>  222  <<\r
5538 * ( --- )\r
5539 * List the definitions in the current vocabulary.\r
5540 * Expects to output to full-width screen of printer, not a 32- or 40- column screen\r
5541         EVEN\r
5542         DC.B    $85\r
5543         DC.B    'VLIS'  ; 'VLIST'\r
5544         DC.B    'T'|$80\r
5545         DC.L    TRIAD-6-NATWID\r
5546 VLIST   DC.L    DOCOL\r
5547 *       DC.L    TRON    ; DBG ******\r
5548 *       DC.L    LIT16   ; should not be hard coded.\r
5549 *       DC.W    $80\r
5550         DC.L    COLUMS,AT\r
5551         DC.L    OUT,STORE,CONTXT,AT,AT\r
5552 VLIST1  DC.L    OUT,AT,COLUMS,AT\r
5553 *       DC.L    LIT16   ; Should not be hard coded.\r
5554 *       DC.W    32\r
5555         DC.L    WIDTH,AT\r
5556         DC.L    SUB,GREAT,ZBRAN\r
5557         DC.L    VLIST2-*-NATWID\r
5558         DC.L    CR,ZERO,OUT,STORE\r
5559 VLIST2  DC.L    DUP,IDDOT\r
5560 *       DC.L    BREAK   ; dbg *****\r
5561         DC.L    SPACE,SPACE,PFA,LFA,AT\r
5562         DC.L    DUP,ZEQU,QTERM,OR,ZBRAN\r
5563         DC.L    VLIST1-*-NATWID\r
5564         DC.L    DROP\r
5565 *       DC.L    TROFF,BREAK     ; DBG ********\r
5566         DC.L    SEMIS\r
5567 *\r
5568 * Need some utility stuff that isn't in the fig FORTH:\r
5569 * ( c --- )\r
5570 * Emit dot if c is less than blank, else emit c\r
5571         EVEN\r
5572         DC.B    $85\r
5573         DC.B    'BEMI'  ; 'BEMIT'\r
5574         DC.B    'T'|$80\r
5575         DC.L    VLIST-6-NATWID\r
5576 BEMIT   DC.L    DOCOL\r
5577         DC.L    DUP,BL,LESS,ZBRAN\r
5578         DC.L    BEMITO-*-NATWID\r
5579         DC.L    DROP,LIT16\r
5580         DC.W    $2e     ; '.'\r
5581 BEMITO  DC.L    EMIT\r
5582         DC.L    SEMIS\r
5583 *\r
5584 * ( n width --- )\r
5585 * Output n in hexadecimal with field width.\r
5586         EVEN\r
5587         DC.B    $83\r
5588         DC.B    'X.'    ; 'X.R'\r
5589         DC.B    'R'|$80\r
5590         DC.L    BEMIT-6-NATWID\r
5591 XDOTR   DC.L    DOCOL\r
5592         DC.L    BASE,AT,TOR,HEX,DOTR,FROMR,BASE,STORE\r
5593         DC.L    SEMIS\r
5594 *\r
5595 BYTPLN  EQU     16      ; bytes to dump per line\r
5596 * ( adr --- )\r
5597 * Dump a line of 16 bytes in memory, in hex and as characters.\r
5598         EVEN\r
5599         DC.B    $85\r
5600         DC.B    'BLIN'  ; 'BLINE'\r
5601         DC.B    'E'|$80\r
5602         DC.L    XDOTR-4-NATWID\r
5603 BLINE   DC.L    DOCOL\r
5604         DC.L    DUP,LIT16\r
5605         DC.W    BYTPLN\r
5606         DC.L    PLUS,OVER,XDO\r
5607 BLINEX  DC.L    I,CAT,THREE,XDOTR,XLOOP\r
5608         DC.L    BLINEX-*-NATWID\r
5609         DC.L    SPACE,SPACE\r
5610         DC.L    DUP,LIT16\r
5611         DC.W    BYTPLN\r
5612         DC.L    PLUS,SWAP,XDO\r
5613 BLINEC  DC.L    I,CAT,BEMIT,XLOOP\r
5614         DC.L    BLINEC-*-NATWID\r
5615         DC.L    SEMIS\r
5616 *\r
5617 * ( adr ct --- )\r
5618 * Dump memory via BLINE from adr to ct (ceiling BYTPLN) bytes.\r
5619         EVEN\r
5620         DC.B    $85\r
5621         DC.B    'BDUM'  ; 'BDUMP'\r
5622         DC.B    'P'|$80\r
5623         DC.L    BLINE-6-NATWID\r
5624 BDUMP   DC.L    DOCOL\r
5625         DC.L    CR,OVER,PLUS,SWAP,XDO\r
5626 BDUMPL  DC.L    I,LIT16\r
5627         DC.W    4\r
5628         DC.L    XDOTR,LIT16\r
5629         DC.W    $3A\r
5630         DC.L    EMIT,SPACE\r
5631         DC.L    I,BLINE,CR,LIT16\r
5632         DC.W    BYTPLN\r
5633         DC.L    XPLOOP\r
5634         DC.L    BDUMPL-*-NATWID\r
5635         DC.L    SEMIS\r
5636 *\r
5637 * ======>>  XX  <<\r
5638 * ( --- )\r
5639 * Place holder for triggering low-level debuggers (not in fig Forth).\r
5640         EVEN\r
5641         DC.B    $85\r
5642         DC.B    'BREA'  ; 'BREAK'\r
5643         DC.B    'K'|$80\r
5644         DC.L    BDUMP-6-NATWID\r
5645 BREAK   DC.L    *+NATWID\r
5646 BREAKF  NOP                     ; set a low-level break in here\r
5647         NOP\r
5648         NOP\r
5649         RTS\r
5650 *\r
5651 *\r
5652         EVEN\r
5653         DC.B    $85\r
5654         DC.B    'TROF'  ; 'TROFF'\r
5655         DC.B    'F'|$80\r
5656         DC.L    BREAK-6-NATWID\r
5657 TROFF   DC.L    *+NATWID\r
5658         CLR.W   TRACEM-UORIG(UP)\r
5659         RTS\r
5660 *\r
5661         EVEN\r
5662         DC.B    0\r
5663         DC.B    $84\r
5664         DC.B    'TRO'   ; 'TRON'\r
5665         DC.B    'N'|$80\r
5666         DC.L    TROFF-6-NATWID\r
5667 TRON    DC.L    *+NATWID\r
5668         MOVE.W  #1,TRACEM-UORIG(UP)\r
5669         RTS\r
5670 *\r
5671 *\r
5672 * NOOP  NEXT    a useful no-op\r
5673 *\r
5674 * ======>>  XX  <<\r
5675 * ( --- )\r
5676 * Mostly for place holding (fig Forth).\r
5677         EVEN\r
5678         DC.B    0\r
5679         DC.B    $84\r
5680         DC.B    'NOO'   ; 'NOOP'\r
5681         DC.B    'P'|$80\r
5682         DC.L    TRON-5-NATWID\r
5683 NOOP    DC.L    *+NATWID\r
5684         NOP\r
5685         NOP\r
5686         NOP\r
5687         RTS\r
5688 * NOOP  NEXT    a useful no-op\r
5689 ZZZZ    DC.L    0,0,0,0,0,0,0,0 end of rom program\r
5690 \r
5691 * About 10.3K in the dictionary image proper.\r
5692 * This is not surprising, given that the 6809 image is about 6.9K. \r
5693 * (The 6800 image is about 6.3K, if I remember right.)\r
5694 * Since the image is mostly pointers, and pointers in the 68000 are 32 bits, not 16\r
5695 * (since we don't want to limit ourselves to a 32K or so dictionary),\r
5696 * the 68000 image should be something less than double the size of the 6809 or 6800 image.\r
5697 \r
5698         PAGE\r
5699 *\r
5700 \r
5701 \r
5702 *\r
5703 * Build test lists here:\r
5704 *TESTNEXT:\r
5705 *       DC.L    LIT,$FEEDBEEF\r
5706 *       DC.L    LIT16\r
5707 *       DC.W    $FF0F\r
5708 *       DC.L    LIT,AND\r
5709 *       DC.L    EXEC\r
5710 *       DC.L    BRAN\r
5711 *       DC.L    TESTNEXT-*-NATWID\r
5712 *\r
5713 *TESTMIN:\r
5714 *       DC.L    LIT,5\r
5715 *       DC.L    SIGNUM\r
5716 *       DC.L    LIT,-10\r
5717 *       DC.L    SIGNUM\r
5718 *       DC.L    MIN\r
5719 *       DC.L    LIT,100\r
5720 *       DC.L    MIN\r
5721 *       DC.L    DROP\r
5722 *TESTSUB:\r
5723 *       DC.L    LIT,$DEEFEED\r
5724 *       DC.L    LIT,$FEDDEBB\r
5725 *       DC.L    SUB     ; DEEFEED - FEDDEBB\r
5726 *       DC.L    BRAN\r
5727 *       DC.L    TESTNEXT-*-NATWID\r
5728 *\r
5729 \r
5730 * Here you can see some of the advantages and disadvantages of the inner interpreter loop,\r
5731 * and of indirect threading.\r
5732 * PTRACE saves and restores D0/D1/D2/A2 so it can use them.\r
5733 * PEMIT will also save and restore D1/D2/A2 to protect them from the BIOS calls.\r
5734 D1MKHX:\r
5735         AND.L   #$0F,D1\r
5736         ADD.B   #'0',D1\r
5737         CMP.B   #'9',D1\r
5738         BLE.S   D1MKHR\r
5739         ADD.B   #'A'-'9'-1,D1\r
5740 D1MKHR  RTS\r
5741 *\r
5742 PD1H1:\r
5743         MOVEM.L D1,-(SP)\r
5744         BSR.S   D1MKHX\r
5745         BSR.W   PEMIT\r
5746         MOVEM.L (SP)+,D1\r
5747         RTS\r
5748 *\r
5749 PD1H8:\r
5750         MOVEM.L D2,-(SP)\r
5751         MOVE.W  #7,D2\r
5752 PD1H8L:\r
5753         ROL.L   #4,D1   ; Grab the top four bits.\r
5754         BSR.S   PD1H1\r
5755         DBF     D2,PD1H8L\r
5756         MOVEM.L (SP)+,D2\r
5757         RTS\r
5758 *\r
5759 PTRACE:\r
5760         MOVEM.L D0/D1/D2/A2,-(SP)\r
5761         MOVE.B  #'|',D1\r
5762         BSR.W   PEMIT\r
5763         MOVE.L  (PSP),D1\r
5764         BSR.S   PD1H8\r
5765         MOVE.B  #'|',D1\r
5766         BSR.W   PEMIT\r
5767         MOVE.L  NATWID(PSP),D1\r
5768         BSR.S   PD1H8\r
5769         MOVE.B  #':',D1\r
5770         BSR.W   PEMIT\r
5771         MOVE.L  W,D1\r
5772         BSR.S   PD1H8\r
5773         MOVE.B  #'>',D1\r
5774         BSR.W   PEMIT\r
5775         BSR.S   PNAME\r
5776         BSR.W   PCR\r
5777         MOVEM.L (SP)+,D0/D1/D2/A2\r
5778         RTS\r
5779 *\r
5780 PSTR:\r
5781         SUBQ    #1,D2   ; for DBF count\r
5782 PSTRL   MOVE.B  (A2)+,D1\r
5783         AND.L   #$7F,D1\r
5784         BSR.W   PEMIT\r
5785         DBF     D2,PSTRL\r
5786         RTS\r
5787 *\r
5788 IXNAME:\r
5789         LEA     -2*NATWID(W),A2 ; back up to one past the mode byte.\r
5790         TST.B   -(A2)   ; is it a mode byte?\r
5791         BPL.S   IXNAMX  ; If this is not an end/mode byte, stop.\r
5792 IXNAML  TST.B   -(A2)   ; back up to the length byte\r
5793         BPL.s   IXNAML\r
5794 IXNAMX  RTS\r
5795 *\r
5796 PNAMN0  DC.B    $0E             ; Not a dictionary entry, unadorned length,\r
5797         DC.B    '** NOT NAME **'        ; and no tail char flag.\r
5798         EVEN    \r
5799 PNAME:\r
5800         BSR.S   IXNAME\r
5801         MOVE.B  (A2)+,D2        ; Length byte, point to 1st character\r
5802         BPL.S   PNAMEF\r
5803         AND.W   #$1F,D2         ; extract length, word for DBF\r
5804         BEQ.S   PNAMEF          ; all names have length, even NUL\r
5805 PNAMEP  BSR.S   PSTR\r
5806         RTS\r
5807 PNAMEF  LEA     PNAMN0(PC),A2\r
5808         MOVE.B  (A2)+,D2        ; Error message has length (unadorned), too.\r
5809         BRA.S   PNAMEP\r
5810 *\r
5811 ZZZZ2   DC.L    0,0,0,0,0,0,0,0         ; "real" end of "rom" program\r
5812 *       ALIGN   256     ; want to do this, but the ATARI CNOP directive doesn't look standard to me.\r
5813 *\r
5814 *       substitute for disc mass memory\r
5815 *NBLK   EQU     4 ; # of disc buffer blocks for virtual memory, must be defined before using\r
5816 * Should NBLK be SCRSZ/RBLKSZ? maybe not.\r
5817 *  each block is RBLKSZ+SECTRL bytes in size,\r
5818 *  holding RBLKSZ characters\r
5819 *RBLKSZ EQU     256     ; must be defined before using.\r
5820 *SECTRL EQU     2*NATWID        ; Currently held sector number, etc., define with rest\r
5821 *BUFSZ  EQU     (RBLKSZ+SECTRL)*NBLK    ; define with rest\r
5822 *\r
5823 BUFBAS  DS.L    BUFSZ\r
5824 * This is a really awkward place to define the disk buffer records.\r
5825 *\r
5826 * *BUG* SECTRL was magic-number hard-wired into several definitions.\r
5827 * It will take a bit of work to ferret them out.\r
5828 * It is too small, and it should not be hard-wired.\r
5829 * RBLKSZ was also magic-number hard-wired into several definitions,\r
5830 * will I find them all?\r
5831         DC.L    0,0,0,0,0,0,0,0         ; put a little space between\r
5832 *       ALIGN   256     ; Again, I want to, but ...\r
5833 MEMEND  EQU     *\r
5834 *\r
5835 *SCRSZ  EQU     1024    ; must be defined before using\r
5836 *\r
5837 *                                               FIRST\r
5838 *\r
5839 VDISK   EQU     MEMEND\r
5840 *\r
5841 *       Screens for drive 0, including error messages.\r
5842 *\r
5843 * SCREEN 0\r
5844         DC.B    "000~000: ( Index to disk SCREENS SCREEN 0 )                     " 0\r
5845         DC.B    "001~002: ( More Index lines )                                   " 1\r
5846         DC.B    "003~003: ( FIG Title page, FIG Copyright Notice )               " 2\r
5847         DC.B    "004~005: ( FIG ERROR MESSAGES )                                 " 3\r
5848         DC.B    "006~007: ( Custom Error Messages )                              " 4\r
5849         DC.B    "008~???: ( Modifications, copyright notices )                   " 5\r
5850         DC.B    "XXX~XXX:                                                        " 6\r
5851         DC.B    "XXX~XXX:                                                        " 7\r
5852         DC.B    "XXX~XXX:                                                        " 8\r
5853         DC.B    "XXX~XXX:                                                        " 9\r
5854         DC.B    "XXX~XXX:                                                        " 10\r
5855         DC.B    "XXX~XXX:                                                        " 11\r
5856         DC.B    "XXX~XXX:                                                        " 12\r
5857         DC.B    "XXX~XXX:                                                        " 13\r
5858         DC.B    "XXX~XXX:                                                        " 14\r
5859         DC.B    "XXX~XXX:                                                        " 15\r
5860 * SCREEN 1\r
5861         DC.B    "XXX~XXX: ( More index SCREEN 1 )                                " 0\r
5862         DC.B    "XXX~XXX:                                                        " 1\r
5863         DC.B    "XXX~XXX:                                                        " 2\r
5864         DC.B    "XXX~XXX:                                                        " 3\r
5865         DC.B    "XXX~XXX:                                                        " 4\r
5866         DC.B    "XXX~XXX:                                                        " 5\r
5867         DC.B    "XXX~XXX:                                                        " 6\r
5868         DC.B    "XXX~XXX:                                                        " 7\r
5869         DC.B    "XXX~XXX:                                                        " 8\r
5870         DC.B    "XXX~XXX:                                                        " 9\r
5871         DC.B    "XXX~XXX:                                                        " 10\r
5872         DC.B    "XXX~XXX:                                                        " 11\r
5873         DC.B    "XXX~XXX:                                                        " 12\r
5874         DC.B    "XXX~XXX:                                                        " 13\r
5875         DC.B    "XXX~XXX:                                                        " 14\r
5876         DC.B    "XXX~XXX:                                                        " 15\r
5877 * SCREEN 2\r
5878         DC.B    "XXX~XXX: ( More index SCREEN 2 )                                " 0\r
5879         DC.B    "XXX~XXX:                                                        " 1\r
5880         DC.B    "XXX~XXX:                                                        " 2\r
5881         DC.B    "XXX~XXX:                                                        " 3\r
5882         DC.B    "XXX~XXX:                                                        " 4\r
5883         DC.B    "XXX~XXX:                                                        " 5\r
5884         DC.B    "XXX~XXX:                                                        " 6\r
5885         DC.B    "XXX~XXX:                                                        " 7\r
5886         DC.B    "XXX~XXX:                                                        " 8\r
5887         DC.B    "XXX~XXX:                                                        " 9\r
5888         DC.B    "XXX~XXX:                                                        " 10\r
5889         DC.B    "XXX~XXX:                                                        " 11\r
5890         DC.B    "XXX~XXX:                                                        " 12\r
5891         DC.B    "XXX~XXX:                                                        " 13\r
5892         DC.B    "XXX~XXX:                                                        " 14\r
5893         DC.B    "XXX~XXX:                                                        " 15\r
5894 * SCREEN 3\r
5895         DC.B    "*************** Code from the fig-FORTH MODEL ***************   " 0\r
5896         DC.B    "                                                                " 1\r
5897         DC.B    "                   Through the courtesy of                      " 2\r
5898         DC.B    "                                                                " 3\r
5899         DC.B    "                    FORTH INTEREST GROUP                        " 4\r
5900         DC.B    "                       P. O. BOX 1105                           " 5\r
5901         DC.B    "                   SAN CARLOS, CA. 94070                        " 6\r
5902         DC.B    "                                                                " 7\r
5903         DC.B    "                                                                " 8\r
5904         DC.B    "                         RELEASE 1                              " 9\r
5905         DC.B    "                   WITH COMPILER SECURITY                       " 10\r
5906         DC.B    "                           AND                                  " 11\r
5907         DC.B    "                   VARIABLE LENGTH NAMES                        " 12\r
5908         DC.B    "                                                                " 13\r
5909         DC.B    "                                                                " 14\r
5910         DC.B    "       Further distribution must include the above notice.      " 15\r
5911 * SCREEN 4\r
5912         DC.B    "(  ERROR MESSAGES  )                                              " 0\r
5913         DC.B    "DATA STACK UNDERFLOW                                            " 1\r
5914         DC.B    "DICTIONARY FULL                                                 " 2\r
5915         DC.B    "HAS INCORRECT ADDRESS MODE                                      " 3\r
5916         DC.B    "ISN'T UNIQUE                                                    " 4\r
5917         DC.B    "                                                                " 5\r
5918         DC.B    "DISC RANGE?                                                     " 6\r
5919         DC.B    "DATA STACK OVERFLOW                                             " 7\r
5920         DC.B    "DISC ERROR!                                                     " 8\r
5921         DC.B    "                                                                " 9\r
5922         DC.B    "                                                                " 10\r
5923         DC.B    "                                                                " 11\r
5924         DC.B    "                                                                " 12\r
5925         DC.B    "                                                                " 13\r
5926         DC.B    "                                                                " 14\r
5927         DC.B    "FORTH INTEREST GROUP                                            " 15\r
5928 * SCREEN 5\r
5929         DC.B    "(  ERROR MESSAGES  )                                            " 0\r
5930         DC.B    "COMPILATION ONLY, USE IN DEFINITION                             " 1\r
5931         DC.B    "EXECUTION ONLY                                                  " 2\r
5932         DC.B    "CONDITIONALS NOT PAIRED                                         " 3\r
5933         DC.B    "DEFINITION NOT FINISHED                                         " 4\r
5934         DC.B    "IN PROTECTED DICTIONARY                                         " 5\r
5935         DC.B    "USE ONLY WHEN LOADING                                           " 6\r
5936         DC.B    "OFF CURRENT EDITING SCREEN                                      " 7 \r
5937         DC.B    "DECLARE VOCABULARY                                              " 8\r
5938         DC.B    "                                                                " 9\r
5939         DC.B    "                                                                " 10\r
5940         DC.B    "                                                                " 11\r
5941         DC.B    "                                                                " 12\r
5942         DC.B    "                                                                " 13\r
5943         DC.B    "                                                                " 14\r
5944         DC.B    "FORTH INTEREST GROUP                                            " 15\r
5945 * SCREEN 6\r
5946         DC.B    "( MORE ERROR MESSAGES SCREEN 6 )                                " 0\r
5947         DC.B    "                                                                " 1\r
5948         DC.B    "                                                                " 2\r
5949         DC.B    "                                                                " 3\r
5950         DC.B    "                                                                " 4\r
5951         DC.B    "                                                                " 5\r
5952         DC.B    "                                                                " 6\r
5953         DC.B    "                                                                " 7\r
5954         DC.B    "                                                                " 8\r
5955         DC.B    "                                                                " 9\r
5956         DC.B    "                                                                " 10\r
5957         DC.B    "                                                                " 11\r
5958         DC.B    "                                                                " 12\r
5959         DC.B    "                                                                " 13\r
5960         DC.B    "                                                                " 14\r
5961         DC.B    "                                                                " 15\r
5962\r
5963 * SCREEN 7\r
5964         DC.B    " ( MORE ERROR MESSAGES SCREEN 7 )                               " 0\r
5965         DC.B    "                                                                " 1\r
5966         DC.B    "                                                                " 2\r
5967         DC.B    "                                                                " 3\r
5968         DC.B    "                                                                " 4\r
5969         DC.B    "                                                                " 5\r
5970         DC.B    "                                                                " 6\r
5971         DC.B    "                                                                " 7\r
5972         DC.B    "                                                                " 8\r
5973         DC.B    "                                                                " 9\r
5974         DC.B    "                                                                " 10\r
5975         DC.B    "                                                                " 11\r
5976         DC.B    "                                                                " 12\r
5977         DC.B    "                                                                " 13\r
5978         DC.B    "                                                                " 14\r
5979         DC.B    "                                                                " 15\r
5980 *\r
5981 * SCREEN 8\r
5982         DC.B    " ( TEXT, LINE                                     WFR-79MAY01 ) " 0\r
5983         DC.B    " FORTH DEFINITIONS  HEX                                         " 1\r
5984         DC.B    "                                                                " 2\r
5985         DC.B    " 64 CONSTANT C/L                                                " 3\r
5986         DC.B    "                                                                " 4\r
5987         DC.B    " : TEXT                       ( ACCEPT FOLLOWING TEXT TO PAD *) " 5\r
5988         DC.B    "      HERE  C/L  1+  BLANKS  WORD  HERE  PAD  C/L  1+  CMOVE  ; " 6\r
5989         DC.B    "                                                                " 7\r
5990         DC.B    " : LINE             ( RELATIVE TO SCR, LEAVE ADDRESS OF LINE *) " 8\r
5991         DC.B    "       DUP  FFF0  AND   17   ?ERROR     ( KEEP ON THIS SCREEN ) " 9\r
5992         DC.B    "       SCR  @  (LINE)   DROP   ;                                " 10\r
5993         DC.B    "                                                                " 11\r
5994         DC.B    "                                                                " 12\r
5995         DC.B    "                                                                " 13\r
5996         DC.B    "                                                                " 14\r
5997         DC.B    "                                                                " 15\r
5998 *\r
5999 * SCREEN 9\r
6000         DC.B    " ( More crude editing facilities. -- one byte characters )      " 0\r
6001         DC.B    "                                                                " 1\r
6002         DC.B    " 0 VARIABLE LNEDBUF 62 ALLOT        ( buffer for line editing ) " 2\r
6003         DC.B    "                                                                " 3\r
6004         DC.B    " ( ns nl -- )              ( overwrite one line of the screen ) " 4\r
6005         DC.B    " : PUTLINE LNEDBUF 64 BLANKS   ( just enough to write to disc ) " 5\r
6006         DC.B    "           CR LNEDBUF 64 EXPECT CR     ( just enough to write ) " 6\r
6007         DC.B    "           SL2BB LNEDBUF SWAP 64 CMOVE UPDATE ;                 " 7\r
6008         DC.B    "       ( Full screen editing requires keyboard control codes. ) " 8\r
6009         DC.B    "                                                                " 9\r
6010         DC.B    "                                                                " 10\r
6011         DC.B    "                                                                " 11\r
6012         DC.B    "                                                                " 12\r
6013         DC.B    "                                                                " 13\r
6014         DC.B    "                                                                " 14\r
6015         DC.B    "                                                                " 15\r
6016 *\r
6017 * SCREEN 10\r
6018         DC.B    "                                                                " 0\r
6019         DC.B    "                                                                " 1\r
6020         DC.B    "                                                                " 2\r
6021         DC.B    "                                                                " 3\r
6022         DC.B    "                                                                " 4\r
6023         DC.B    "                                                                " 5\r
6024         DC.B    "                                                                " 6\r
6025         DC.B    "                                                                " 7\r
6026         DC.B    "                                                                " 8\r
6027         DC.B    "                                                                " 9\r
6028         DC.B    "                                                                " 10\r
6029         DC.B    "                                                                " 11\r
6030         DC.B    "                                                                " 12\r
6031         DC.B    "                                                                " 13\r
6032         DC.B    "                                                                " 14\r
6033         DC.B    "                                                                " 15\r
6034 *\r
6035 * SCREEN 11\r
6036         DC.B    "                                                                " 0\r
6037         DC.B    "                                                                " 1\r
6038         DC.B    "                                                                " 2\r
6039         DC.B    "                                                                " 3\r
6040         DC.B    "                                                                " 4\r
6041         DC.B    "                                                                " 5\r
6042         DC.B    "                                                                " 6\r
6043         DC.B    "                                                                " 7\r
6044         DC.B    "                                                                " 8\r
6045         DC.B    "                                                                " 9\r
6046         DC.B    "                                                                " 10\r
6047         DC.B    "                                                                " 11\r
6048         DC.B    "                                                                " 12\r
6049         DC.B    "                                                                " 13\r
6050         DC.B    "                                                                " 14\r
6051         DC.B    "                                                                " 15\r
6052 *\r
6053 * SCREEN 12\r
6054         DC.B    "                                                                " 0\r
6055         DC.B    "                                                                " 1\r
6056         DC.B    "                                                                " 2\r
6057         DC.B    "                                                                " 3\r
6058         DC.B    "                                                                " 4\r
6059         DC.B    "                                                                " 5\r
6060         DC.B    "                                                                " 6\r
6061         DC.B    "                                                                " 7\r
6062         DC.B    "                                                                " 8\r
6063         DC.B    "                                                                " 9\r
6064         DC.B    "                                                                " 10\r
6065         DC.B    "                                                                " 11\r
6066         DC.B    "                                                                " 12\r
6067         DC.B    "                                                                " 13\r
6068         DC.B    "                                                                " 14\r
6069         DC.B    "                                                                " 15\r
6070 *\r
6071 * SCREEN 13\r
6072         DC.B    "                                                                " 0\r
6073         DC.B    "                                                                " 1\r
6074         DC.B    "                                                                " 2\r
6075         DC.B    "                                                                " 3\r
6076         DC.B    "                                                                " 4\r
6077         DC.B    "                                                                " 5\r
6078         DC.B    "                                                                " 6\r
6079         DC.B    "                                                                " 7\r
6080         DC.B    "                                                                " 8\r
6081         DC.B    "                                                                " 9\r
6082         DC.B    "                                                                " 10\r
6083         DC.B    "                                                                " 11\r
6084         DC.B    "                                                                " 12\r
6085         DC.B    "                                                                " 13\r
6086         DC.B    "                                                                " 14\r
6087         DC.B    "                                                                " 15\r
6088 *\r
6089 * SCREEN 14\r
6090         DC.B    "                                                                " 0\r
6091         DC.B    "                                                                " 1\r
6092         DC.B    "                                                                " 2\r
6093         DC.B    "                                                                " 3\r
6094         DC.B    "                                                                " 4\r
6095         DC.B    "                                                                " 5\r
6096         DC.B    "                                                                " 6\r
6097         DC.B    "                                                                " 7\r
6098         DC.B    "                                                                " 8\r
6099         DC.B    "                                                                " 9\r
6100         DC.B    "                                                                " 10\r
6101         DC.B    "                                                                " 11\r
6102         DC.B    "                                                                " 12\r
6103         DC.B    "                                                                " 13\r
6104         DC.B    "                                                                " 14\r
6105         DC.B    "                                                                " 15\r
6106 *\r
6107 * SCREEN 15\r
6108         DC.B    "                                                                " 0\r
6109         DC.B    "                                                                " 1\r
6110         DC.B    "                                                                " 2\r
6111         DC.B    "                                                                " 3\r
6112         DC.B    "                                                                " 4\r
6113         DC.B    "                                                                " 5\r
6114         DC.B    "                                                                " 6\r
6115         DC.B    "                                                                " 7\r
6116         DC.B    "                                                                " 8\r
6117         DC.B    "                                                                " 9\r
6118         DC.B    "                                                                " 10\r
6119         DC.B    "                                                                " 11\r
6120         DC.B    "                                                                " 12\r
6121         DC.B    "                                                                " 13\r
6122         DC.B    "                                                                " 14\r
6123         DC.B    "                                                                " 15\r
6124 *\r
6125 VDR1    EQU     *\r
6126 RAMDSZ  EQU     VDR1-VDISK\r
6127 *\r
6128         DS      RAMDSZ\r
6129 *\r
6130 MEMTOP  EQU     *\r
6131 *\r
6132 *                                               LO\r
6133 *\r
6134 MASSLO  EQU     VDISK\r
6135 MASSHI  EQU     MEMTOP\r
6136 *\r
6137 *                                               HI\r
6138 *\r
6139 * "end" of "usable ram" (If disc mass memory emulation is removed, actual end.)\r
6140 *\r
6141         end     ORIG    \r
6142 \r
6143 \r
6144 \r
6145 \r
6146 \r