4 * ASSEMBLY SOURCE LISTING
8 * WITH COMPILER SECURITY
9 * AND VARIABLE LENGTH NAMES
11 * Adapted by Joel Matthew Rees
12 * from fig-FORTH for 6800 by Dave Lion, et. al.
14 * This free/libre/open source publication is provided
15 * through the courtesy of:
20 * and other interested parties.
23 * P.O. Box 8231 - San Jose, CA 95155 - (408) 277-0668
24 * URL: http://www.forth.org
25 * Further distribution must include this notice.
27 NAM Copyright: FORTH Interest Group, original authors, and Joel Matthew Rees
29 * filename fig-forth-auto6809opt.asm
30 * === FORTH-6809 {date} {time}
33 * Permission is hereby granted, free of charge, to any person obtaining a copy
34 * of this software and associated documentation files (the "Software"), to deal
35 * in the Software without restriction, including without limitation the rights
36 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
37 * copies of the Software, and to permit persons to whom the Software is
38 * furnished to do so, subject to the following conditions:
40 * The above copyright notice and this permission notice shall be included in
41 * all copies or substantial portions of the Software.
43 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
44 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
45 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
46 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
47 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
48 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
51 * "Associated documentation" for this declaration of license
52 * shall be interpreted to include only the comments in this file,
53 * or, if the code is split into multiple files,
54 * all files containing the complete source.
56 * This is the MIT model license, as published by the Open Source Consortium,
57 * with associated documentation defined.
58 * It was chosen to reflect the spirit of the original
59 * terms of use, which used archaic legal terminology.
62 * Authors of the 6800 model:
63 * === Primary: Dave Lion,
67 * === The Forth Interest Group
69 * === San Carlos, CA 94070
71 * === Unbounded Computing
72 * === 1134-K Aster Ave.
73 * === Sunnyvale, CA 94086
75 NATWID EQU 2 ; bytes per natural integer/pointer
76 * The original version was developed on an AMI EVK 300 PROTO
77 * system using an ACIA for the I/O.
78 * This version is developed targeting the Tandy Color Computer.
81 * is done in three subroutines:
82 * PEMIT ( word # 182 )
86 * The FORTH words for disc related I/O follow the model
87 * of the FORTH Interest Group, but have not yet been
88 * tested using a real disc.
90 * Addresses in the 6800 implementation reflect the fact that,
91 * on the development system, it was convenient to
92 * write-protect memory at hex 1000, and leave the first
93 * 4K bytes write-enabled. As a consequence, code from
94 * location $1000 to lable ZZZZ could be put in ROM.
95 * Minor deviations from the model were made in the
96 * initialization and words ?STACK and FORGET
97 * in order to do this.
98 * Those deviations will be altered in this
99 * implementation for the 6809 -- Color Computer.
103 MEMT32 EQU $7FFF absolute end of all ram
105 MEMTOP EQU MEMT16 ; tentative guess
106 ACIAC EQU $FBCE the ACIA control address and
107 ACIAD EQU ACIAC+1 data address for PROTO
109 * MEMORY MAP for this 16K|32K system:
110 * ( delineated so that systems with 4k byte write-
111 * protected segments can write protect FORTH )
113 * addr. contents pointer init by
114 * **** ******************************* ******* ******
115 * 2nd through 4th per-user tables
117 USERSZ EQU 256 ; (Addressable by DP)
118 USER16 EQU 1 ; We can change these for ROMPACK or 64K.
121 IUP16 EQU MEMT16+1-USER16*USERSZ
122 IUP32 EQU MEMT32+1-USER32*USERSZ
125 * user tables of variables
126 * registers & pointers for the virtual machine
127 * scratch area used by various words
128 * 3F00|7C00 <== UP (DICTPT)
130 * substitute for disc mass memory
133 * 3300|7000 LO,MEMEND
134 RAMD16 EQU IUP16-RAMSCR*SCRSZ
135 RAMD32 EQU IUP32-RAMSCR*SCRSZ
141 * 4 buffer sectors of VIRTUAL MEMORY
142 NBLK EQU 4 ; # of disc buffer blocks for virtual memory
143 * Should NBLK be SCRSZ/SECTSZ?
144 * each block is SECTSZ+SECTRL bytes in size,
145 * holding SECTSZ characters
148 BUFSZ EQU (SECTSZ+SECTRL)*NBLK
150 BUFB16 EQU MEME16-BUFSZ
151 BUFB32 EQU MEME32-BUFSZ
153 * "end" of "usable ram" -- in 16K
154 * 2EE0|6BE0 <== RP RINIT
159 * (64|112 levels nesting)
163 SFTB16 EQU IRP16-RSTK16
164 SFTB32 EQU IRP32-RSTK32
167 * holds up to 256 characters
168 * and is scanned upward by IN
172 ITIB16 EQU SFTB16-TIBSZ
173 ITIB32 EQU SFTB32-TIBSZ
175 * 2D60|6A00 <== IN TIB
179 * 2D60|6A00 <== SP SP0,SINIT
181 * | grows downward from 2A60|6A00
185 * I DICTIONARY grows upward
187 * ???? end of ram-dictionary. <== DICTPT DPINIT
190 * ???? "FORTH" ( a word ) <=, <== CONTEXT
192 * start of ram-dictionary.
194 * >>>>>> memory from here up must be in RAM area <<<<<<
197 * 6k of romable "FORTH" <== IP ABORT
199 * the VIRTUAL FORTH MACHINE
201 * 1208 initialization tables
202 * 1204 <<< WARM START ENTRY >>>
203 * 1200 <<< COLD START ENTRY >>>
204 * 1200 lowest address used by FORTH
208 * >>>>>> memory from here down left alone <<<<<<
209 * >>>>>> so we can safely call ROM routines <<<<<<
215 * CONVENTIONS USED IN THIS PROGRAM ARE AS FOLLOWS :
217 * IP (hardware Y) points to the current instruction ( pre-increment mode )
218 * RP (hardware S) points to last return address pushedin return stack
219 * SP (hardware U) points to last byte pushed in data stack
221 * Y must be IP when NEXT is entered (if using the inner loop).
223 * When A and B hold one 16 bit FORTH data word,
224 * A contains the high byte, B, the low byte.
226 * UP (hardware DP) is the base of per-task ("user") variables.
227 * (Be careful of the stray semantics of "user".)
229 * W (hardware X) is the pointer to the "code field" address of native CPU
230 * machine code to be executed for the definition of the dictionary word
231 * to be executed/currently executing.
232 * The following natural integer (word) begins any "parameter section"
233 * (body) -- similar to a "this" pointer, but not the same.
234 * It may be native CPU machine code, or it may be a global variable,
235 * or it may be a list of Forth definition words (addresses).
238 * This implementation uses the native subroutine architecture
239 * rather than a postponed-push call that the 6800 model VM uses
240 * to save code and time in leaf routines.
242 * This should allow directly calling many of the Forth words
243 * from assembly language code.
244 * (Be aware of the need for a valid W in some cases.)
245 * It won't allow mixing assembly language directly into Forth word lists.
249 * 0 is false, anything else is true.
250 * Most places in this model that set a boolean flag set true as 1.
251 * This is in contrast to many models that set a boolean flag as -1.
256 * This system is shown with one user (task),
257 * but additional users (tasks) may be added
258 * by allocating additional user tables:
262 UBASEX RMB USERSZ data table for extra users
264 * Some of this stuff gets initialized during
265 * COLD start and WARM start:
266 * [ names correspond to FORTH words of similar (no X) name ]
270 * A few useful VM variables
271 * Will be removed when they are no longer needed.
272 * All are replaced by 6809 registers.
274 N RMB 10 used as scratch by (FIND),ENCLOSE,CMOVE,EMIT,KEY,
275 * SP@,SWAP,DOES>,COLD
278 * These locations are used by the TRACE routine :
280 TRLIM RMB 1 the count for tracing without user intervention
281 TRACEM RMB 1 non-zero = trace mode
282 BRKPT RMB 2 the breakpoint address at which
283 * the program will go into trace mode
284 VECT RMB 2 vector to machine code
285 * (only needed if the TRACE routine is resident)
288 * Registers used by the FORTH virtual machine:
292 W RMB 2 the instruction register points to 6800 code
293 * This is not exactly accurate. Points to the definiton body,
294 * which is native CPU machine code when it is native CPU machine code.
295 IP RMB 2 the instruction pointer points to pointer to 6800 code
296 RP RMB 2 the return stack pointer
297 UP RMB 2 the pointer to base of current user's 'USER' table
298 * ( altered during multi-tasking )
300 *UORIG RMB 6 3 reserved variables
301 XSPZER RMB 2 initial top of data stack for this user
302 XRZERO RMB 2 initial top of return stack
303 XTIB RMB 2 start of terminal input buffer
304 XWIDTH RMB 2 name field width
305 XWARN RMB 2 warning message mode (0 = no disc)
306 XFENCE RMB 2 fence for FORGET
307 XDICTP RMB 2 dictionary pointer
308 XVOCL RMB 2 vocabulary linking
309 XBLK RMB 2 disc block being accessed
310 XIN RMB 2 scan pointer into the block
311 XOUT RMB 2 cursor position
312 XSCR RMB 2 disc screen being accessed ( O=terminal )
313 XOFSET RMB 2 disc sector offset for multi-disc
314 XCONT RMB 2 last word in primary search vocabulary
315 XCURR RMB 2 last word in extensible vocabulary
316 XSTATE RMB 2 flag for 'interpret' or 'compile' modes
317 XBASE RMB 2 number base for I/O numeric conversion
318 XDPL RMB 2 decimal point place
320 XCSP RMB 2 current stack position, for compile checks
323 XDELAY RMB 2 carriage return delay count
324 XCOLUM RMB 2 carriage width
325 IOSTAT RMB 2 last acia status from write/read
336 * end of user table, start of common system variables
345 * The FORTH program ( address $1200 to about $27FF ) will be written
346 * so that it can be in a ROM, or write-protected if desired,
347 * but right now we're just getting it running.
350 * ######>> screen 3 <<
352 ***************************
353 ** C O L D E N T R Y **
354 ***************************
357 ***************************
358 ** W A R M E N T R Y **
359 ***************************
361 JMP WENT warm-start code, keeps current dictionary intact
366 ******* startup parmeters **************************
368 FDB $6809,0000 cpu & revision
369 FDB 0 topmost word in FORTH vocabulary
370 * BACKSP FDB $7F backspace character for editing
371 BACKSP FDB $08 backspace character for editing
372 UPINIT FDB UORIG initial user area
373 * UPINIT FDB UORIG initial user area
374 SINIT FDB ISP ; initial top of data stack
375 * SINIT FDB ORIG-$D0 initial top of data stack
376 RINIT FDB IRP ; initial top of return stack
377 * RINIT FDB ORIG-2 initial top of return stack
378 FDB ITIB ; terminal input buffer
379 * FDB ORIG-$D0 terminal input buffer
380 FDB 31 initial name field width
381 FDB 0 initial warning mode (0 = no disc)
382 FENCIN FDB REND initial fence
383 DPINIT FDB REND cold start value for DICTPT
385 COLINT FDB 132 initial terminal carriage width
386 DELINT FDB 4 initial carriage return delay
387 ****************************************************
391 * ######>> screen 13 <<
392 * These were of questionable use anyway,
393 * kept here now to satisfy the assembler and show hints.
394 * They're too much trouble to use with native subroutine call anyway.
395 * PULABX PULS A ; 24 cycles until 'NEXT'
397 PULABX PULU A,B ; ?? cycles until 'NEXT'
398 * STABX STA 0,X 16 cycles until 'NEXT'
400 STABX STD 0,X ; ?? cycles until 'NEXT'
402 * GETX LDA 0,X 18 cycles until 'NEXT'
404 GETX LDD 0,X ?? cycles until 'NEXT'
405 * PUSHBA PSHS B ; 8 cycles until 'NEXT'
407 PUSHBA PSHU A,B ; ?? cycles until 'NEXT'
411 * "NEXT" takes ?? cycles if TRACE is removed,
413 * and ?? cycles if trace is present and NOT tracing.
415 * = = = = = = = t h e v i r t u a l m a c h i n e = = = = =
417 * NEXT itself might just completely go away.
418 * About the only reason to keep it is to allowing executing a list
419 * which allows a cheap TRACE routine.
421 * NEXT is a loop which implements the Forth VM.
422 * It basically cycles through calling the code out of code lists,
424 * Using a native CPU return for this uses a few extra cycles per call,
425 * compared to simply jumping to each definition and jumping back
426 * to the known beginning of the loop,
427 * but the loop itself is really only there for convenience.
429 * This implementation uses the native subroutine call,
430 * to break the wall between Forth code and non-Forth code.
433 * LEAX 1,X ; pre-increment mode
436 NEXT ; IP is Y, push before using, pull before you come back here.
438 * NEXT2 LDX 0,X get W which points to CFA of word to be done
439 NEXT2 LDX ,Y++ get W which points to CFA of word to be done
440 * But NEXT2 is too much trouble to use with subroutine threading anyway.
442 NEXT3 ; W is X until you use X for something else. (TOS points back here.)
443 * But NEXT3 is too much trouble to use with subroutine threading anyway.
444 * LDX 0,X get VECT which points to executable code
446 * The next instruction could be patched to JMP TRACE =
447 * if a TRACE routine is available: =
450 JSR [,X] ; Saving the postinc cycles,
451 * ; but X must be bumped NATWID to the parameters.
453 * JMP TRACE ( an alternate for the above )
454 * In other words, with the call and the NOP,
455 * there is room to patch the call with a JMP to your TRACE
456 * routine, which you have to provide.
459 * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
466 * Pushes the following natural width integer from the instruction stream
467 * as a literal, or immediate value.
472 * FDB LITERAL-TO-BE-PUSHED
475 * In native processor code, there should be a better way, use that instead.
476 * More specifically, DO NOT CALL THIS from assembly language code.
477 * (Note that there is no compile-only flag in the fig model.)
479 * See (FIND), or PFIND , for layout of the header format.
482 FCC 'LI' ; 'LIT' : NOTE: this is different from LITERAL
483 FCB $D4 ; 'T'|'\x80' ; character code for T, with high bit set.
484 FDB 0 ; link of zero to terminate dictionary scan
485 LIT FDB *+NATWID ; Note also that it is meaningless in native code.
497 * ######>> screen 14 <<
500 * Pushes the following byte from the instruction stream
501 * as a literal, or immediate value.
506 * FCB LITERAL-TO-BE-PUSHED
509 * If this is kept, it should have a header for TRACE to read.
510 * If the data bus is wider than a byte, you don't want to do this.
511 * Byte shaving like this is often counter-productive anyway.
512 * Changing the name to LIT8, hoping that will be more understandable.
513 * Also, see comments for LIT.
514 * (Note that there is no compile-only flag in the fig model.)
516 FCC 'LIT' ; 'LIT8' : NOTE: this is different from LITERAL
519 LIT8 FDB *+NATWID (this was an invisible word, with no header)
520 LDB ,Y+ ; This also is meaningless in native code.
533 * Jump to address on stack. Used by the "outer" interpreter to
534 * interactively invoke routines.
535 * Might be useful to have EXECUTE test the pointer, as done in BIF-6809.
537 FCC 'EXECUT' ; 'EXECUTE'
541 PULU X ; Gotta have W anyway, just in case.
542 JMP [,X] ; Tail return.
544 * LDX 0,X get code field address (CFA)
545 * LEAS 1,S ; pop stack
549 * ######>> screen 15 <<
552 * Add the following word from the instruction stream to the
553 * instruction pointer (Y++). Causes a program branch in Forth code stream.
555 * In native processor code, there should be a better way, use that instead.
556 * More specifically, DO NOT CALL THIS from assembly language code.
557 * This is only for Forth code stream.
558 * Also, see comments for LIT.
560 FCC 'BRANC' ; 'BRANCH'
563 BRAN FDB ZBYES ; Go steal code in ZBRANCH
565 * Moving code around to optimize the branch taking case in 0BRANCH.
566 ZBNO LEAY NATWID,Y ; No branch.
570 * BRANCH if flag is zero.
572 * In native processor code, there should be a better way, use that instead.
573 * More specifically, DO NOT CALL THIS from assembly language code.
574 * This is only for Forth code stream.
575 * Also, see comments for LIT.
577 FCC '0BRANC' ; '0BRANCH'
584 LEAY D,Y ; IP is postinc
588 * PSHS B ; ** emulating ABA:
592 * ZBYES LDX IP Note: code is shared with BRANCH, (+LOOP), (LOOP)
600 * ZBNO LDX IP no branch. This code is shared with (+LOOP), (LOOP).
601 * LEAX 1,X ; jump over branch delta
606 * ######>> screen 16 <<
608 * ( --- ) ( limit index *** limit index+1) C
609 * ( limit index *** )
610 * Counting loop primitive. The counter and limit are the top two
611 * words on the return stack. If the updated index/counter does
612 * not exceed the limit, a branch occurs. If it does, the branch
613 * does not occur, and the index and limit are dropped from the
616 * In native processor code, there should be a better way, use that instead.
617 * More specifically, DO NOT CALL THIS from assembly language code.
618 * This is only for Forth code stream.
619 * Also, see comments for LIT.
621 FCC '(LOOP' ; '(LOOP)'
625 LDD #1 ; Borrowing from BIF-6809.
626 XLOOPA ADDD NATWID,S ; Dodge the return address.
631 LDX ,S ; synthetic return
632 LEAS 3*NATWID,S ; Clean up the index and limit.
635 * LDB #1 get set to increment counter by 1 (Clears N.)
636 * BRA XPLOP2 go steal other guy's code!
639 * ( n --- ) ( limit index *** limit index+n ) C
640 * ( limit index *** )
641 * Loop with a variable increment. Terminates when the index
642 * crosses the boundary from one below the limit to the limit. A
643 * positive n will cause termination if the result index equals the
644 * limit. A negative n must cause the index to become less than
645 * the limit to cause loop termination.
647 * Note that the end conditions are not symmetric around zero.
649 * In native processor code, there should be a better way, use that instead.
650 * More specifically, DO NOT CALL THIS from assembly language code.
651 * This is only for Forth code stream.
652 * Also, see comments for LIT.
654 FCC '(+LOOP' ; '(+LOOP)'
657 XPLOOP FDB *+NATWID ; Borrowing from BIF-6809.
659 BPL XLOOPA ; Steal plain loop code for forward count.
660 ADDD NATWID,S ; Dodge the return address
664 BRA XLOOPN ; This path is less time-sensitive.
666 * This should work, but I want to use tested code.
667 * PULU A,B ; Get the increment.
668 * XPLOP2 PULS X ; Pre-clear the return stack.
669 * PSHU A ; Save the direction in high bit.
672 * SUBD NATWID,S ; Check limit.
674 ** I think this should work:
675 * EORA ,U+ ; dir < 0 and (count - limit) >= 0
676 * BPL XPLONO ; or dir >= 0 and (count - limit) < 0
678 * LEAY D,Y ; IP is postinc
680 * XPLONO LEAS 2*NATWID,S
681 * JMP ,X ; synthetic return
683 * This definitely should work:
684 * TST ,U+ ; Get the sign
689 * LEAY D,Y ; IP is postinc
691 * XPLOF CMPD NATWID,S
693 * XPLONO LEAS 2*NATWID,S
694 * JMP ,X ; synthetic return
696 * 6800 Probably could have used the exclusive-or method, too.:
697 * PULS A ; get increment
700 * BPL XPLOF forward looping
706 * BRA XPLONO fall through
710 * ADDB 3,X add it to counter
712 * STB 3,X store new counter value
721 * XPLONO LEAX 1,X ; done, don't branch back
726 * BRA ZBNO use ZBRAN to skip over unused delta
728 * ######>> screen 17 <<
730 * ( limit index --- ) ( *** limit index )
731 * Move the loop parameters to the return stack. Synonym for D>R.
736 XDO FDB *+NATWID This is the RUNTIME DO, not the COMPILING DO
737 LDX ,S ; Save the return address.
740 PULU A,B ; Maintain order.
742 JMP ,X ; synthetic return
761 * ( --- index ) ( limit index *** limit index )
762 * Copy the loop index from the return stack. Synonym for R.
767 LDD NATWID,S ; Dodge return address.
775 * ######>> screen 18 <<
777 * ( c base --- false )
778 * ( c base --- n true )
779 * Translate C in base, yielding a translation valid flag. If the
780 * translation is not valid in the specified base, only the false
786 DIGIT FDB *+NATWID NOTE: legal input range is 0-9, A-Z
787 LDD NATWID,U ; Check the whole thing.
788 SUBD #$30 ; ascii zero
789 BMI DIGIT2 IF LESS THAN '0', ILLEGAL
791 BMI DIGIT0 IF '9' OR LESS
793 BMI DIGIT2 if less than 'A'
795 BPL DIGIT2 if greater than 'Z'
796 SUBD #7 translate 'A' thru 'F'
797 DIGIT0 CMPD ,U ; Check the base.
798 BPL DIGIT2 if not less than the base
799 STD NATWID,U ; Store converted digit. (High byte known zero.)
800 LDD #1 ; set valid flag
801 DIGIT1 STD ,U ; store the flag
803 DIGIT2 LDD #0 ; set not valid flag
804 LEAU NATWID,U ; pop base
808 * SUBA #$30 ascii zero
809 * BMI DIGIT2 IF LESS THAN '0', ILLEGAL
811 * BMI DIGIT0 IF '9' OR LESS
813 * BMI DIGIT2 if less than 'A'
815 * BPL DIGIT2 if greater than 'Z'
816 * SUBA #7 translate 'A' thru 'F'
818 * BPL DIGIT2 if not less than the base
820 * STA 3,X store digit
821 * DIGIT1 STB 1,X store the flag
825 * LEAS 1,S ; pop bottom number
827 * STB 0,X make sure both bytes are 00
830 * ######>> screen 19 <<
832 * The word definition format in the dictionary:
834 * (Symbol names are bracketed by bytes with the high bit set, rather than linked.)
836 * NFA (name field address):
837 * char-count + $80 Length of symbol name, flagged with high bit set.
838 * char 1 Characters of symbol name.
841 * char n + $80 symbol termination flag (char set < 128 code points)
842 * LFA (link field address):
843 * link high byte \___pointer to previous word in list
844 * link low byte / -- Combined allocation/dictionary list. --
845 * CFA (code field address):
846 * CFA high byte \___pointer to native CPU machine code
847 * CFA low byte / -- Consider this the characteristic code. --
848 * PFA (parameter field address):
849 * parameter fields -- Machine code for low-level native machine CPU code,
850 * " instruction list for high-level Forth code,
851 * " constant data for constants, pointers to per task variables,
852 * " space for variables, for global variables, etc.
854 * In the case of native CPU machine code, the address at CFA will be PFA.
856 * Definition attributes:
857 FIMMED EQU $40 ; Immediate word flag.
858 FSMUDG EQU $20 ; Smudged => definition not ready.
859 CTMASK EQU ($FF&(^($80|FIMMED))) ; For unmasking the length byte.
860 * Note that the SMUDGE bit is not masked out.
862 * But we really want more (Thinking for a new model, need one more byte):
863 * FCOMPI EQU $10 ; Compile-time-only.
864 * FASSEM EQU $08 ; Assembly-language code only.
865 * F4THLV EQU $04 ; Must not be called from assembly language code.
866 * These would require some significant adjustments to the model.
867 * We also want to put the low-level VM stuff in its own vocabulary.
870 * (FIND) ( name vocptr --- locptr length true )
871 * ( name vocptr --- false )
872 * Search vocabulary for a symbol called name.
873 * name is a pointer to a high-bit bracket string with length head.
874 * vocptr is a pointer to the NFA of the tail-end (LATEST) definition
875 * in the vocabulary to be searched.
876 * Hidden (SMUDGEd) definitions are lexically not equal to their name strings.
878 FCC '(FIND' ; '(FIND)'
882 PSHS Y ; Have to track two pointers.
883 * Use the stack and registers instead of temp area N.
884 PA0 EQU NATWID ; pointer to the length byte of name being searched against
885 PD EQU 0 ; pointer to NFA of dict word being checked
887 LDX PD,U ; Start in on the vocabulary (NFA).
888 PFNDLP LDY PA0,U ; Point to the name to check against.
889 LDB ,X+ ; get dict name length byte
890 TFR B,A ; Save it in case it matches.
892 CMPB ,Y+ ; Compare lengths
895 TSTB ; ; Is high bit of character in dictionary entry set?
897 ANDB #$7F ; Clear high bit from dictionary.
898 CMPB ,Y+ ; Compare "last" characters.
899 BEQ FOUND ; Matches even if dictionary actual length is shorter.
900 PFNDLN LDX ,X++ ; Get previous link in vocabulary.
901 BNE PFNDLP ; Continue if link not=0
904 LEAU NATWID,U ; Return only false flag.
909 PFNDCH CMPB ,Y+ ; Compare characters.
912 PFNDSC LDB ,X+ ; scan forward to end of this name in dictionary
918 FOUND LEAX 2*NATWID,X
928 * NOP ; Probably leftovers from a debugging session.
930 * PD EQU N ptr to dict word being checked
936 * PFIND0 PULS A ; loop to get arguments
943 * PFNDLP LDB 0,X get count dict count
949 * LDA 0,X get count from arg
951 * STX PA intialize PA
952 * PSHS B ; ** emulating CBA:
953 * CMPA ,S+ ; compare lengths
963 * TSTB ; is dict entry neg. ?
965 * ANDB #$7F clear sign
966 * PSHS B ; ** emulating CBA:
969 * PFNDLN LDX 0,X get new link
970 * BNE PFNDLP continue if link not=0
977 * PFNDCH PSHS B ; ** emulating CBA:
981 * PFNDSC LDB 0,X scan forward to end of this name
988 * FOUND LDA PD compute CFA
1001 * PSHS A ; Left over from a stray copy-paste, I guess.
1007 * ######>> screen 20 <<
1009 * ( buffer ch --- buffer symboloffset delimiteroffset scancount )
1010 * ( buffer ch --- buffer symboloffset nuloffset scancount ) ( Scan count == nuloffset )
1011 * ( buffer ch --- buffer nuloffset onepast scancount )
1012 * Scan buffer for a symbol delimited by ch or ASCII NUL,
1013 * return the length of the buffer region scanned,
1014 * the offset to the trailing delimiter,
1015 * and the offset of the first character of the symbol.
1016 * Leave the buffer on the stack.
1017 * Scancount is also offset to first character not yet looked at.
1018 * If no symbol in buffer, scancount and symboloffset point to NUL
1019 * and delimiteroffset points one beyond for some reason.
1020 * On trailing NUL, delimiteroffset == scancount.
1021 * (Buffer is the address of the buffer array to scan.)
1022 * (This is a bit too tricky, really.)
1024 FCC 'ENCLOS' ; 'ENCLOSE'
1028 LDA 1,U ; Delimiter character to match against in A.
1029 LDX NATWID,U ; Buffer to scan in.
1030 CLRB ; Initialize offset. (Buffer < 256 wide!)
1031 * Scan to a non-delimiter or a NUL
1032 ENCDEL TST B,X ; NUL ?
1034 CMPA B,X ; Delimiter?
1036 INCB ; count character
1038 * Found first character. Save the offset.
1039 ENC1ST STB 1,U ; Found first non-delimiter character --
1040 CLR ,U ; store the count, zero high byte.
1041 * Scan to a delimiter or a NUL
1042 ENCSYM TST B,X ; NUL ?
1044 CMPA B,X ; delimiter?
1048 * Found end of symbol. Push offset to delimiter found.
1049 ENCEND CLRA ; high byte -- buffer < 255 wide!
1050 PSHU A,B ; Offset to seen delimiter.
1051 * Advance and push address of next character to check.
1052 ADDD #1 ; In case offset was 255.
1055 * Found NUL before non-delimiter, therefore there is no word
1056 ENCNUL CLRA ; high byte -- buffer < 255 wide!
1057 STD ,U ; offset to NUL.
1058 ADDD #1 ; For some reason, point after NUL.
1060 SUBD #1 ; Next is not passed NUL.
1061 PSHU A,B ; Stealing code will save only one byte.
1063 * Found NUL following the word instead of delimiter.
1064 ENC0TR PSHU A,B ; Save offset to first after symbol (NUL)
1065 PSHU A,B ; and count scanned.
1068 * FC means offset (bytes) to First Character of next word
1069 * EW " " to End of Word
1070 * NC " " to Next Character to start next enclose at
1071 * ENCLOS FDB *+NATWID
1073 * PULS B ; now, get the low byte, for an 8-bit delimiter
1077 * * wait for a non-delimiter or a NUL
1080 * PSHS B ; ** emulating CBA:
1081 * CMPA ,S+ ; CHECK FOR DELIM
1086 * * found first character. Push FC
1087 * ENC1ST LDA N found first char.
1091 * wait for a delimiter or a NUL
1094 * PSHS B ; ** emulating CBA:
1095 * CMPA ,S+ ; ckech for delim.
1100 * * found EW. Push it
1105 * * advance and push NC
1108 * found NUL before non-delimiter, therefore there is no word
1109 * ENCNUL LDB N found NUL
1113 * BRA ENC0TR+2 ; ********** POTENTIAL BUG HERE *******
1114 * ******** Should use labels in case opcodes change! ********
1115 * found NUL following the word instead of SPACE
1119 * ENCL8 LDB N save NC
1124 * ######>> screen 21 <<
1125 * The next 4 words call system dependant I/O routines
1126 * which are listed after word "-->" ( lable: "arrow" )
1127 * in the dictionary.
1131 * Write c to the output device (screen or printer).
1132 * ROM Uses the ECB device number at address $6F,
1133 * -2 is printer, 0 is screen.
1139 LBSR PEMIT ; PEMIT handles the stack.
1148 * INC XOUT+1-UORIG,X
1150 * ****WARNING**** HARD OFFSET: *+4 ****
1157 * Wait for a key from the keyboard.
1158 * If the key is BREAK, set the high byte (result $FF03).
1164 LBSR PKEY ; PKEY handles the stack.
1174 * Scan keyboard, but do not wait.
1175 * Return 0 if no key,
1176 * BREAK ($ff03) if BREAK is pressed,
1177 * or key currently pressed.
1179 FCC '?TERMINA' ; '?TERMINAL'
1183 LBSR PQTER ; PQTER handles the stack.
1187 * JMP PUSHBA stack the flag
1191 * EMIT a Carriage Return (ASCII CR).
1197 LBSR PCR ; PCR handles the stack.
1202 * ######>> screen 22 <<
1204 * ( source target count --- )
1205 * Copy/move count bytes from source to target.
1206 * Moves ascending addresses,
1207 * so that overlapping only works if the source is above the destination.
1209 FCC 'CMOV' ; 'CMOVE' : source, destination, count
1213 * One way: ; takes ( 37+17*count+9*(count/256) cycles )
1214 PSHS Y ; #2~7 ; Gotta have our pointers.
1216 PSHS A ; #2~6 ; Gotta have our pointers.
1227 * Another way ; takes ( 42+17*count+9*(count/256) cycles )
1229 * SUBD ,U++ ; #2~9 ; invert the count
1241 * PULS A,Y,PC ; #2~10
1242 * Yet another way ; takes ( 37+29*count cycles )
1244 * LDX NATWID,U ; #2~6
1245 * LDY NATWID,U ; #3~7
1255 * LEAU 3*NATWID,U ; #2~5
1257 * Yet another way ; takes ( 44+24*odd+33*count/2 cycles )
1259 * LDX NATWID,U ; #2~6
1260 * LDY 2*NATWID,U ; #3~7
1278 * LEAU 3*NATWID,U ; #2~5
1280 * From the 6800 model:
1281 * CMOVE FDB *+2 takes ( 43+47*count cycles ) on 6800
1285 * STA 0,X move parameters to scratch area
1307 * ######>> screen 23 <<
1310 * Multiplies the top two unsigned integers,
1311 * yielding a double integer product.
1318 LDA 2*NATWID+1,U ; least
1322 LDA 2*NATWID,U ; most
1326 LDD 2*NATWID+1,U ; first inner (u2 lo, u1 hi)
1332 LDA 2*NATWID,U ; second inner (u2 hi)
1333 LDB 3*NATWID,U ; (u1 lo)
1350 * The following is a subroutine which
1351 * multiplies top 2 words on stack,
1352 * leaving 32-bit result: high order word in A,B
1353 * low order word in 2nd word of stack.
1355 * USTARS LDA #16 bits/word counter
1360 * USTAR2 ROR 5,X shift multiplier
1368 * RORB ; shift result
1370 * USTAR4 LEAS 1,S ; dump counter
1373 * ######>> screen 24 <<
1375 * ( ud u --- uremainder uquotient )
1376 * Divides the top unsigned integer
1377 * into the second and third words on the stack
1378 * as a single unsigned double integer,
1379 * leaving the remainder and quotient (quotient on top)
1380 * as unsigned integers.
1382 * The smaller the divisor, the more likely dropping the high word
1383 * of the quotient loses significant bits. See M/MOD .
1392 LDD NATWID,U ; dividend
1393 USLDIV CMPD ,U ; divisor
1395 ANDCC #~1 ; carry clear
1398 ORCC #1 ; quotient, (carry set)
1399 USLBIT ROL 2*NATWID+1,U ; save it
1411 PULS A,PC ; Avoiding a LEAS 1,S by discarding A.
1424 * USL2 ANDCC #~$01 ; CLC :
1442 * JMP SWAP+4 reverse quotient & remainder
1444 * ######>> screen 25 <<
1447 * Bitwise and the top two integers.
1467 * Bitwise or the top two integers.
1487 * Bitwise exclusive or the top two integers.
1505 * ######>> screen 26 <<
1508 * Fetch the parameter stack pointer (before it is pushed).
1509 * This points at whatever was on the top of stack before.
1519 * STX N scratch area
1524 * ( whatever --- nothing )
1525 * Initialize the parameter stack pointer from the USER variable S0.
1526 * Effectively clears the stack.
1535 * LDX XSPZER-UORIG,X
1536 * TFR X,S ; TXS : watch it ! X and S are not equal on 6800.
1539 * ( whatever *** nothing )
1540 * Initialize the return stack pointer from the initialization table
1541 * instead of the user variable R0, for some reason.
1542 * Quite possibly, this should be from R0.
1543 * Effectively aborts all in process definitions, except the active one.
1544 * An emergency measure, to be sure.
1545 * The routine that calls this must never execute a return.
1546 * So this should never be executed from the terminal, I guess.
1547 * This is another that should be compile-time only, and in a separate vocabulary.
1553 PULS X ; But this guy has to return to his caller.
1556 * LDX RINIT initialize from rom constant
1562 * Pop IP from return stack (return from high-level definition).
1563 * Can be used in a screen to force interpretion to terminate.
1564 * Must not be executed when temporaries are saved on top of the return stack.
1570 PULS D,Y ; return address in D, and saved IP in Y.
1571 TFR D,PC ; Synthetic return.
1578 * LDX 0,X get address we have just finished.
1579 * JMP NEXT+2 increment the return address & do next word
1581 * ######>> screen 27 <<
1583 * ( limit index *** index index )
1584 * Force the terminating condition for the innermost loop by
1585 * copying its index to its limit.
1586 * Termination is postponed until the next
1587 * LOOP or +LOOP instruction is executed.
1588 * The index remains available for use until
1589 * the LOOP or +LOOP instruction is encountered.
1590 * Note that the assumption is that the current count is the correct count
1591 * to end at, rather than pushing the count to the final count.
1593 FCC 'LEAV' ; 'LEAVE'
1597 LDD NATWID,S ; Dodge the return address.
1610 * Move top of parameter stack to top of return stack.
1618 STD ,S ; Put it where the return address was.
1633 * Move top of return stack to top of parameter stack.
1653 * Copy the top of return stack to top of parameter stack.
1665 * ######>> screen 28 <<
1668 * Logically invert top of stack;
1669 * or flag true if top is zero, otherwise false.
1687 *ZEQU2 TFR S,X ; TSX :
1692 * Flag true if top is negative (MSbit set), otherwise false.
1705 * LDA #$80 check the sign bit
1714 * ######>> screen 29 <<
1716 * ( n1 n2 --- n1+n2 )
1717 * Add top two words.
1734 * ( d1 d2 --- d1+d2 )
1735 * Add top two double integers.
1751 * ANDCC #~$01 ; CLC :
1767 * Negate (two's complement) top of stack.
1769 FCC 'MINU' ; 'MINUS'
1778 * from 6800 model code:
1789 * Negate (two's complement) top two words on stack as a double integer.
1791 FCC 'DMINU' ; 'DMINUS'
1796 SUBD NATWID,U ; #2~7
1816 * ######>> screen 30 <<
1818 * ( n1 n2 --- n1 n2 n1 )
1819 * Push a copy of the second word on stack.
1835 * Discard the top word on stack.
1848 * ( n1 n2 --- n2 n1 )
1849 * Swap the top two words on stack.
1873 * Push a copy of the top word on stack.
1888 * ######>> screen 31 <<
1891 * Add the second word on stack to the word at the adr on top of stack.
1906 * PULS A ; get stack data
1908 * ADDB 1,X add & store low byte
1910 * ADCA 0,X add & store hi byte
1916 * Exclusive or byte at adr with low byte of top word.
1918 FCC 'TOGGL' ; 'TOGGLE'
1926 * Using the model code would be less likely to introduce bugs,
1927 * but that would sort-of defeat my purposes here.
1928 * Anyway, I can borrow from theoretically known good bif-6809 code
1929 * and it's fewer bytes and much faster code this way.
1931 * FDB DOCOL,OVER,CAT,XOR,SWAP,CSTORE
1934 * ######>> screen 32 <<
1937 * Replace address on stack with the word at the address.
1946 * LDX 0,X get address
1953 * Replace address on top of stack with the byte at the address.
1954 * High byte of result is clear.
1976 * Store second word on stack at address on top of stack.
1986 * LDX 0,X get address
1993 * Store low byte of second word on stack at address on top of stack.
1994 * High byte is ignored.
2005 * LDX 0,X get address
2014 * ######>> screen 33 <<
2017 * { : name sundry-activities ; } typical input
2018 * If executing (not compiling),
2019 * record the data stack mark in CSP,
2020 * Set the CONTEXT vocabulary to CURRENT,
2022 * set state to compile,
2023 * and compile the call to the trailing native CPU machine code DOCOL.
2025 * This would not be hard to flatten to native code.
2026 * But that's not the purpose of a model.
2030 COLON FDB DOCOL,QEXEC,SCSP,CURENT,AT,CONTXT,STORE
2034 * Here is the IP pusher for allowing
2035 * nested words in the virtual machine:
2036 * ( ;S is the equivalent un-nester )
2039 * Characteristic of a colon (:) definition.
2040 * Begins execution of a high-level definition,
2041 * i. e., nests the definition and begins processing icodes.
2042 * Mechanically, it pushes the IP (Y register)
2043 * and loads the Parameter Field Address of the definition which
2044 * called it into the IP.
2045 DOCOL LDD ,S ; Save the return address.
2046 STY ,S ; Nest the old IP.
2047 LEAY NATWID,X ; W still in X, bump to parameters, load as new IP.
2048 TFR D,PC ; synthetic return to interpret.
2050 * DOCOL LDX RP make room in the stack
2056 * STA 2,X Store address of the high level word
2057 * STB 3,X that we are starting to execute
2058 * LDX W Get first sub-word of that definition
2059 * JMP NEXT+2 and execute it
2063 * { : name sundry-activities ; } typical input
2064 * ERROR check data stack against mark in CSP,
2066 * unSMUDGE LATEST definition,
2067 * and set state to interpretation.
2068 FCB $C1 ; imnediate code
2071 SEMI FDB DOCOL,QCSP,COMPIL,SEMIS,SMUDGE,LBRAK
2074 * ######>> screen 34 <<
2077 * { value CONSTANT name } typical input
2080 * compile the constant value,
2081 * and compile the call to the trailing native CPU machine code DOCON.
2083 FCC 'CONSTAN' ; 'CONSTANT'
2086 CON FDB DOCOL,CREATE,SMUDGE,COMMA,PSCODE
2088 * Characteristic of a CONSTANT.
2089 * A CONSTANT simply loads its value from its parameter field
2090 * and pushes it on the stack.
2091 DOCON LDD NATWID,X ; Get the first natural width word of the parameter field.
2096 * LDB 3,X A & B now contain the constant
2099 * Not in model, needed for abstraction:
2101 * The byte width of objects on stack.
2103 FCC 'NATWI' ; 'NATWID'
2109 * Not in model, needed for abstraction:
2110 * Note that this is not defined as an INCREMENTER!
2111 * Coded to increment by the exact constant returned by NATWID
2112 * ( n --- n+NATWID )
2119 ADDD NATWCV,PCR ; Looking ahead, does not have to be PCRelative.
2122 * How this might have been done for 6800 model:
2123 * CLRA ; We know the natural width is less than 255, LOL.
2132 * { init VARIABLE name } typical input
2133 * Use CONSTANT to CREATE a header and compile the initial value, init,
2134 * then overwrite the characteristic to point to DOVAR.
2136 FCC 'VARIABL' ; 'VARIABLE'
2139 VAR FDB DOCOL,CON,PSCODE
2141 * Characteristic of a VARIABLE.
2142 * A VARIABLE pushes its PFA address on the stack.
2143 * The parameter field of a VARIABLE is the actual allocation of the variable,
2144 * so that pushing its address allows its contents to be @ed (fetched).
2145 * Ordinary arrays and strings that do not subscript themselves
2146 * may be allocated by defining a variable
2147 * and immediately ALLOTting the remaining needed space.
2148 * VARIABLES are global to all users,
2149 * and thus should be hidden in resource monitors, but aren't.
2150 DOVAR LEAX NATWID,X ; Point to the first natural width word of the parameters.
2156 * ADCA #0 A,B now contain the address of the variable
2161 * { uboffset USER name } typical input
2162 * CREATE a header and compile the unsigned byte offset in the per-USER table,
2163 * then overwrite the header with a call to DOUSER.
2164 * The USER is entirely responsible for maintaining allocation!
2169 USER FDB DOCOL,CON,PSCODE
2171 * Characteristic of a per-USER variable.
2172 * USER variables are similiar to VARIABLEs,
2173 * but are allocated (by hand!) in the per-user table.
2174 * A USER variable's parameter field contains its offset in the per-user table.
2175 DOUSER TFR DP,A ; Make a pointer to the direct page.
2177 * See Alternative -- alternatives start from this point.
2178 ADDD NATWID,X ; Add it to the offset to the per-user variable.
2180 TFR D,X ; Cache the pointer in X for the caller.
2182 * Hey, the per-user table could actually be larger than 256 bytes!
2183 * But we knew that. It's just not as esthetic to calculate it this way.
2185 * LDX NATWID,X ; Keep the offset
2186 * EXG D,X ; Prepare for EA
2191 * PSHS Y ; Get Y free for calculations.
2192 * TFR D,Y ; Y points to the UP base
2193 * LDD NATWID,X ; Get the offset
2194 * LEAX D,Y ; Leave the pointer cached in X.
2198 * From the 6800 model:
2199 * DOUSER LDX W get offset into user's table
2202 * ADDB UP+1 add to users base address
2204 * JMP PUSHBA push address of user's variable
2206 * ######>> screen 35 <<
2241 * ASCII SPACE character
2246 BL FDB DOCON ascii blank
2250 * This really shouldn't be a CONSTANT.
2252 * The base of the disk buffer space.
2254 FCC 'FIRS' ; 'FIRST'
2259 * FDB MEMEND-528 (132 * NBLK)
2262 * This really shouldn't be a CONSTANT.
2264 * The limit of the disk buffer space.
2266 FCC 'LIMI' ; 'LIMIT' : ( the end of memory +1 )
2271 * In 6800 model, was
2275 * ( --- sectorsize )
2276 * The size, in bytes, of a buffer.
2278 FCC 'B/BU' ; 'B/BUF' : (bytes/buffer)
2283 * Hardcoded in 6800 model:
2287 * ( --- blocksperscreen )
2288 * The size, in blocks, of a screen.
2289 * Should this be the same as NBLK, the number of block buffers maintained?
2291 FCC 'B/SC' ; 'B/SCR' : (blocks/screen)
2296 * Hardcoded in 6800 model as:
2298 * blocks/screen = 1024 / "B/BUF" = 8, if sectors are 128 bytes.
2302 * Calculate the address of entry (#n/2) in the boot-up parameter table.
2303 * (Adds the base of the boot-up table to n.)
2305 FCC '+ORIGI' ; '+ORIGIN'
2308 PORIG FDB DOCOL,LIT,ORIG,PLUS
2311 * ######>> screen 36 <<
2314 * This is the per-task variable recording the initial parameter stack pointer.
2324 * This is the per-task variable recording the initial return stack pointer.
2334 * Terminal Input Buffer address.
2335 * Note that this is a variable, so users may allocate their own buffers, but it must be @ed.
2344 * ( --- maxnamewidth )
2345 * This is the maximum width to which symbol names will be recorded.
2347 FCC 'WIDT' ; 'WIDTH'
2355 * Availability of error messages on disk.
2356 * Contains 1 if messages available,
2358 * -1 if a disk error has occurred.
2360 FCC 'WARNIN' ; 'WARNING'
2368 * Boundary for FORGET.
2370 FCC 'FENC' ; 'FENCE'
2378 * Dictionary pointer, fetched by HERE.
2380 FCC 'D' ; 'DP' : points to first free byte at end of dictionary
2387 * ( --- vadr ) ******* Need to check what this is!
2388 * Used in maintaining vocabularies.
2389 * I think it points to the "parent" vocabulary, but I'm not sure.
2390 * Or maybe this is the CONTEXT vocabulary. I'll have to come back here. *****
2392 FCC 'VOC-LIN' ; 'VOC-LINK'
2400 * Disk block being interpreted.
2401 * Zero refers to terminal.
2402 * ******** Should be made a 32 bit user variable! ********
2403 * But the base system needs to have full 32 bit support, div and mul, etc.
2404 * before we can do that.
2414 * Input buffer offset/cursor.
2416 FCC 'I' ; 'IN' : scan pointer for input line buffer
2424 * Output buffer offset/cursor.
2434 * Screen currently being edited, once we have an editor running.
2441 * ######>> screen 37 <<
2445 * Sector offset for LOADing screens,
2446 * set by DRIVE to make a new drive the default.
2447 * This should also be 32 bit or bigger.
2449 FCC 'OFFSE' ; 'OFFSET'
2457 * Current context of interpretation (vocabulary root).
2459 FCC 'CONTEX' ; 'CONTEXT' : points to pointer to vocab to search first
2467 * Current context of definition (vocabulary root).
2469 FCC 'CURREN' ; 'CURRENT' : points to ptr. to vocab being extended
2477 * Compiler/interpreter state.
2479 FCC 'STAT' ; 'STATE' : 1 if compiling, 0 if not
2487 * Numeric conversion base.
2489 FCC 'BAS' ; 'BASE' : number base for all input & output
2497 * Decimal point location for output.
2507 * Field width for I/O formatting.
2517 * Compiler stack mark for stack check.
2527 * Editing cursor location.
2537 * Pointer to last HELD character in PAD.
2545 * ======>> 82.5 <<== SPECIAL
2547 * Line width of active terminal.
2549 FCC 'COLUMN' ; 'COLUMNS' : line width of terminal
2555 * ######>> screen 38 <<
2557 ** An INCREMENTER probably should not be defined without a defined CONSTANT?
2559 ** Make an INCREMENTER compiling word (not in model):
2561 ** { n INCREMENTER name } typical input
2562 ** CREATE a header and compile the increment constant,
2563 ** then overwrite the header with a call to DOINC.
2565 * FCC 'INCREMENTE' ; 'INCREMENTER'
2568 * INCR FDB DOCOL,CON,PSCODE
2570 ** Characteristic of an INCREMENTER.
2571 ** This is too naive:
2573 * ADDD NATWID,X ; Add the increment.
2576 * Compiling word should check that it is compiling a CONSTANT.
2584 * Using the model keeps things semantically connected for other processors:
2585 ONEP FDB DOCOL,ONE,PLUS
2587 ** Greedy alternative:
2593 * Naive alternative:
2596 * Naive alternative:
2599 * ADDD #1 ; It's hard to imagine 1+ being other than 1.
2609 * Using the model keeps things semantically connected for other processors:
2610 TWOP FDB DOCOL,TWO,PLUS
2612 ** Greedy alternative:
2615 * ADDD TWOV,PCR ; See NAT+ (NATP)
2618 * Naive alternative:
2621 * Naive alternative:
2624 * ADDD #2 ; See NAT+ (NATP)
2630 * Get the DICTPT allocation, like a USER constant.
2631 * Should check the stack and heap for collision.
2636 HERE FDB DOCOL,DICTPT,AT
2641 * Increase/decrease heap (add n to DP),
2642 * Should ERROR check stack/heap.
2644 FCC 'ALLO' ; 'ALLOT'
2647 ALLOT FDB DOCOL,DICTPT,PSTORE
2652 * Store word n at DP++,
2653 * Should ERROR check stack/heap.
2657 COMMA FDB DOCOL,HERE,STORE,NATWC,ALLOT
2659 * COMMA FDB DOCOL,HERE,STORE,TWO,ALLOT
2664 * Store byte b at DP+,
2665 * Should ERROR check stack/heap.
2670 CCOMM FDB DOCOL,HERE,CSTORE,ONE,ALLOT
2674 * ( n1 n2 --- n1-n2 )
2675 * Subtract top two words.
2684 * SUB FDB DOCOL,MINUS,PLUS
2685 * FDB SEMIS ; Costs 6 bytes and lots of cycles.
2688 * ( n1 n2 --- n1==n2 )
2689 * Return flag true if n1 and n2 are equal, otherwise false.
2693 EQUAL FDB DOCOL,SUB,ZEQU
2697 * ( n1 n2 --- n1<n2 )
2698 * Return flag true if n1 is less than n2, otherwise false.
2719 * CMPB 1,X ; Why not sub, sbc, bge?
2729 * ( n1 n2 --- n1>n2 )
2730 * Return flag true if n1 is greater than n2, false otherwise.
2734 GREAT FDB DOCOL,SWAP,LESS
2738 * ( n1 n2 n3 --- n2 n3 n1 )
2739 * Rotate the top three words on stack,
2740 * bringing the third word to the top.
2751 * ROT FDB DOCOL,TOR,SWAP,FROMR,SWAP
2758 FCC 'SPAC' ; 'SPACE'
2761 SPACE FDB DOCOL,BL,EMIT
2765 * ( n0 n1 --- min(n0,n1) )
2766 * Leave the minimum of the top two integers.
2767 * Being too greedy here, but, whatever.
2778 * MIN FDB DOCOL,OVER,OVER,GREAT,ZBRAN
2785 * ( n0 n1 --- max(n0,n1) )
2786 * Leave the maximum of the top two integers.
2787 * Really should leave this as in the model.
2798 * MAX FDB DOCOL,OVER,OVER,LESS,ZBRAN
2817 * DDUP FDB DOCOL,DUP,ZBRAN
2822 * ######>> screen 39 <<
2827 * Change top integer to its sign.
2829 FCC 'SIGNU' ; 'SIGNUM'
2837 SIGNUP SEX ; Couldn't they have called SignEXtend EXT instead?
2838 STD ,U ; Am I too much of a prude?
2840 * 6800 model version should be something like this:
2851 * ( adr1 direction --- adr2 )
2852 * TRAVERSE the symbol name.
2853 * If direction is 1, find the end.
2854 * If direction is -1, find the beginning.
2856 FCC 'TRAVERS' ; 'TRAVERSE'
2860 BSR SIGNUE ; Convert negative to -, zero or positive to 1.
2861 LDD ,U++ ; Still in D, but we have to pop it anyway.
2862 LDX ,U ; If D is 1 or -1, so is B.
2864 TRAVLP LEAX B,X ; Don't look at the one we start at.
2865 CMPA ,X ; Not sure why we aren't just doing LDA ,X ; BPL.
2869 * Doing this in 6809 just because it can be done may be getting too greedy.
2870 * TRAV FDB DOCOL,SWAP
2871 * TRAV2 FDB OVER,PLUS,LIT8
2873 * FDB OVER,CAT,LESS,ZBRAN
2880 * Fetch CURRENT as a per-USER constant.
2882 FCC 'LATES' ; 'LATEST'
2885 LATEST FDB DOCOL,CURENT,AT,AT
2887 * LATEST FDB *+NATWID
2888 * Getting too greedy:
2893 * LDD CURENT+NATWID,PCR
2895 * PSHU X ; Leave the address in X.
2904 * Too greedy, too many smantic holes to fall through.
2905 * If the address at the CFA is made relative,
2906 * this is part of the code that would be affected
2907 * if it is in native CPU code.
2910 * Wanted to do these as INCREMENTERs,
2911 * but I need to stick with the model as much as possible,
2912 * (mostly, LOL) adding code only to make the model more clear.
2914 * Convert PFA to LFA, unchecked. (Bump back from contents to allocation link.)
2927 * Convert PFA to CFA, unchecked. (Bump back from contents to characterist code link.)
2932 * CFA FDB DOCOL,TWO,SUB
2933 CFA FDB DOCOL,NATWC,SUB
2938 * Convert PFA to NFA. (Bump back from contents to beginning of symbol name.)
2946 FDB SUB,ONE,MINUS,TRAV
2951 * Convert NFA to PFA. (Bump up from beginning of symbol name to contents.)
2956 PFA FDB DOCOL,ONE,TRAV,LIT8
2962 * ######>> screen 40 <<
2965 * Save the parameter stack pointer in CSP for compiler checks.
2970 SCSP FDB DOCOL,SPAT,CSP,STORE
2974 * ( 0 n --- ) ( *** )
2975 * ( true n --- IN BLK ) ( anything *** nothing )
2976 * If flag is false, do nothing.
2977 * If flag is true, issue error MESSAGE and QUIT or ABORT, via ERROR.
2978 * Leaves cursor position (IN)
2979 * and currently loading block number (BLK) on stack, for analysis.
2981 * This one is too important to be high-level Forth codes.
2982 * When we have an error, we want to disturb as little as possible.
2983 * But fixing that cascades through ERROR and MESSAGE
2984 * into the disk block system.
2985 * And we aren't ready for that yet.
2987 FCC '?ERRO' ; '?ERROR'
2995 ** this doesn't work anyway: QERROR LBR ERROR
2996 QERR FDB DOCOL,SWAP,ZBRAN
3004 * STATE is compiling:
3006 * STATE is compiling:
3007 * ( --- IN BLK ) ( anything *** nothing )
3008 * ERROR if not compiling.
3010 FCC '?COM' ; '?COMP'
3013 QCOMP FDB DOCOL,STATE,AT,ZEQU,LIT8
3019 * STATE is executing:
3021 * STATE is executing:
3022 * ( --- IN BLK ) ( anything *** nothing )
3023 * ERROR if not executing.
3025 FCC '?EXE' ; '?EXEC'
3028 QEXEC FDB DOCOL,STATE,AT,LIT8
3034 * ( n1 n1 --- ) ( *** )
3035 * ( n1 n2 --- IN BLK ) ( anything *** nothing )
3036 * ERROR if top two are unequal.
3037 * MESSAGE says compiled conditionals do not match.
3039 FCC '?PAIR' ; '?PAIRS'
3042 QPAIRS FDB DOCOL,SUB,LIT8
3048 * CSP and parameter stack are balanced (equal):
3050 * CSP and parameter stack are not balanced (unequal):
3051 * ( --- IN BLK ) ( anything *** nothing )
3052 * ERROR if return/control stack is not at same level as last !CSP.
3053 * Usually indicates that a definition has been left incomplete.
3058 QCSP FDB DOCOL,SPAT,CSP,AT,SUB,LIT8
3066 * No active BLK input:
3067 * ( --- IN BLK ) ( anything *** nothing )
3068 * ERROR if not loading, i. e., if BLK is zero.
3070 FCC '?LOADIN' ; '?LOADING'
3073 QLOAD FDB DOCOL,BLK,AT,ZEQU,LIT8
3078 * ######>> screen 41 <<
3081 * Compile an in-line literal value from the instruction stream.
3083 FCC 'COMPIL' ; 'COMPILE'
3086 * COMPIL FDB DOCOL,QCOMP,FROMR,TWOP,DUP,TOR,AT,COMMA
3087 COMPIL FDB DOCOL,QCOMP,FROMR,NATP,DUP,TOR,AT,COMMA
3092 * Clear the compile state bit(s) (shift to interpret).
3096 LBRAK FDB DOCOL,ZERO,STATE,STORE
3103 * Set the compile state bit(s) (shift to compile).
3107 RBRAK FDB DOCOL,LIT8
3114 * Toggle SMUDGE bit of LATEST definition header,
3115 * to hide it until defined or reveal it after definition.
3117 FCC 'SMUDG' ; 'SMUDGE'
3120 SMUDGE FDB DOCOL,LATEST,LIT8
3127 * Set the conversion base to sixteen (b00010000).
3134 FCB 16 ; decimal sixteen
3140 * Set the conversion base to ten (b00001010).
3142 FCC 'DECIMA' ; 'DECIMAL'
3147 FCB 10 ; decimal ten
3151 * ######>> screen 42 <<
3153 * ( --- ) ( IP *** )
3154 * Pop the saved IP and use it to
3155 * compile the latest symbol as a reference to a ;CODE definition;
3156 * overwrite the code field of the symbol found by LATEST
3157 * with the address of the low-level characteristic code
3158 * provided in the defining definition.
3159 * Look closely at where things return, consider the operation of R> and >R .
3161 * The machine-level code which follows (;CODE) in the instruction stream
3162 * is not executed by the defining symbol,
3163 * but becomes the characteristic of the defined symbol.
3164 * This is the usual way to generate the characteristics of VARIABLEs,
3165 * CONSTANTs, COLON definitions, etc., when FORTH compiles itself.
3167 * Finally, note that, if code shifts from low level back to high
3168 * (native CPU machine code calling into a list of FORTH codes),
3169 * the low level code can't just call a high-level definition.
3170 * Leaf definitions can directly call other leaf definitions,
3171 * but not non-leafs.
3172 * It will need an anonymous list, probably embedded in the low-level code,
3173 * and Y and X will have to be set appropriately before entering the list.
3175 FCC '(;CODE' ; '(;CODE)'
3178 * PSCODE FDB DOCOL,FROMR,TWOP,LATEST,PFA,CFA,STORE
3179 PSCODE FDB DOCOL,FROMR ; Y/IP is post-inc, needs no adjustment.
3180 FDB LATEST,PFA,CFA,STORE
3185 * ?CSP to see if there are loose ends in the defining definition
3186 * before shifting to the assembler,
3187 * compile (;CODE) in the defining definition's instruction stream,
3188 * shift to interpreting,
3189 * make the ASSEMBLER vocabulary current,
3190 * and !CSP to mark the stack
3191 * in preparation for assembling low-level code.
3192 * Note that ;CODE, unlike DOES>, is IMMEDIATE,
3193 * and compiles (;CODE),
3194 * which will do the actual work of changing
3195 * the LATEST definition's characteristic when the defining word runs.
3196 * Assembly is done by the interpreter, rather than the compiler.
3197 * I could have avoided the anomalous three-byte code fields by
3199 * Note that the ASSEMBLER is not part of the model (at this time).
3200 * That means that, until the assembler is ready,
3201 * if you want to define low-level words,
3202 * you have to poke (comma) in hand-assembled stuff.
3205 FCC ';COD' ; ';CODE'
3208 SEMIC FDB DOCOL,QCSP,COMPIL,PSCODE,SMUDGE,LBRAK,QSTACK
3210 * note: "QSTACK" will be replaced by "ASSEMBLER" later
3212 * ######>> screen 43 <<
3215 * Make the word currently being defined
3216 * build a header for DOES> definitions.
3217 * Actually just compiles a CONSTANT zero
3218 * which can be overwritten later by DOES>.
3219 * Since the fig models were established, this technique has been deprecated.
3221 * Note that <BUILDS is not IMMEDIATE,
3222 * and therefore executes during a definition's run-time,
3223 * rather than its compile-time.
3224 * It is not intended to be used directly,
3225 * but rather so that one definition word can build another.
3226 * Also, note that nothing particularly special happens
3227 * in the defining definition until DOES> executes.
3228 * The name <BUILDS is intended to be a reminder of what is about to occur.
3230 * <BUILDS probably should have compiled an ERROR instead of a ZERO CONSTANT.
3232 FCC '<BUILD' ; '<BUILDS'
3235 BUILDS FDB DOCOL,ZERO,CON
3239 * ( --- ) ( IP *** ) C
3240 * Define run-time behavior of definitions compiled/defined
3241 * by a high-level defining definition --
3242 * the FORTH equivalent of a compiler-compiler.
3243 * DOES> assumes that the LATEST symbol table entry
3244 * has at least one word of parameter field,
3245 * which <BUILDS provides.
3246 * Note that DOES> is also not IMMEDIATE.
3248 * When the defining word containing DOES> executes the DOES> icode,
3249 * it overwrites the LATEST symbol's CFA with jsr <XDOES,
3250 * overwrites the first word of that symbol's parameter field with its own IP,
3251 * and pops the previous IP from the return stack.
3252 * The icodes which follow DOES> in the stream
3253 * do not execute at the defining word's run-time.
3255 * Examining XDOES in the virtual machine shows
3256 * that the defined word will execute those icodes
3257 * which follow DOES> at its own run-time.
3259 * The advantage of this kind of behaviour,
3260 * which you will also note in ;CODE,
3261 * is that the defined word can contain
3262 * both operations and data to be operated on.
3263 * This is how FORTH data objects define their own behavior.
3265 * Finally, note that the effective parameter field for DOES> definitions
3266 * starts two NATWID words after the CFA, instead of just one
3267 * (four bytes instead of two in a sixteen-bit addressing Forth).
3269 * VOCABULARYs will use this. See definition of word FORTH.
3271 FCC 'DOES' ; 'DOES>'
3274 * DOES FDB DOCOL,FROMR,TWOP,LATEST,PFA,STORE
3275 DOES FDB DOCOL,FROMR ; Y/IP is post-inc, needs no adjustment.
3276 FDB LATEST,PFA,STORE
3279 * ( --- PFA+NATWID ) ( *** IP )
3280 * Characteristic of a DOES> defined word.
3281 * The characteristics of DOES> definitions are written in high-level
3282 * Forth codes rather than native CPU machine level code.
3283 * The first parameter word points to the high-level characteristic.
3284 * This routine's job is to push the IP,
3285 * load the high level characteristic pointer in IP,
3286 * and leave the address following the characteristic pointer on the stack
3287 * so the parameter field can be accessed.
3288 DODOES LDD ,S ; Keep the return address.
3289 STY ,S ; Save/nest the current IP on the return stack.
3290 LDY NATWID,X ; First parameter is new IP.
3291 LEAX 2*NATWID,X ; Address of second parameter.
3293 TFR D,PC ; Synthetic return.
3295 * From the 6800 model:
3298 * LDX RP make room on return stack
3302 * STA 2,X push return address
3304 * LDX W get addr of pointer to run-time code
3307 * STX N stash it in scratch area
3308 * LDX 0,X get new IP
3310 * CLRA ; get address of parameter
3314 * PSHS B ; and push it on data stack
3318 * ######>> screen 44 <<
3320 * ( strptr --- strptr+1 count )
3321 * Convert counted string to string and count.
3322 * (Fetch the byte at strptr, post-increment.)
3324 FCC 'COUN' ; 'COUNT'
3327 COUNT FDB DOCOL,DUP,ONEP,SWAP,CAT
3331 * ( strptr count --- )
3332 * EMIT count characters at strptr.
3337 TYPE FDB DOCOL,DDUP,ZBRAN
3339 FDB OVER,PLUS,SWAP,XDO
3340 TYPE2 FDB I,CAT,EMIT,XLOOP
3348 * ( strptr count1 --- strptr count2 )
3349 * Supress trailing blanks (subtract count of trailing blanks from strptr).
3351 FCC '-TRAILIN' ; '-TRAILING'
3354 DTRAIL FDB DOCOL,DUP,ZERO,XDO
3355 DTRAL2 FDB OVER,OVER,PLUS,ONE,SUB,CAT,BL
3367 * TYPE counted string out of instruction stream (updating IP).
3372 * PDOTQ FDB DOCOL,R,TWOP,COUNT,DUP,ONEP
3373 PDOTQ FDB DOCOL,R,NATP,COUNT,DUP,ONEP
3374 FDB FROMR,PLUS,TOR,TYPE
3379 * { ." something-to-be-printed " } typical input
3380 * Use WORD to parse to trailing quote;
3381 * if compiling, compile XDOTQ and string parsed,
3382 * otherwise, TYPE string.
3392 FDB COMPIL,PDOTQ,WORD
3393 FDB HERE,CAT,ONEP,ALLOT,BRAN
3395 DOTQ1 FDB WORD,HERE,COUNT,TYPE
3398 * ######>> screen 45 <<
3399 * ======>> 126 <<== MACHINE DEPENDENT
3401 * ( --- IN BLK ) ( anything *** nothing )
3402 * ERROR if parameter stack out of bounds.
3404 * But checking whether the stack is in bounds or not
3405 * really should not use the stack.
3406 * And there really should be a ?RSTACK, as well.
3408 FCC '?STAC' ; '?STACK'
3411 QSTACK FDB DOCOL,LIT8
3414 * But why use that instead of XSPZER (S0)?
3415 * Multi-user or multi-tasking would not want that.
3417 * FDB PORIG,AT,TWO,SUB,SPAT,LESS,ONE
3418 FDB PORIG,AT,SPAT,LESS,ONE ; Not post-decrement push.
3420 * prints 'empty stack'
3423 * Here, we compare with a value at least 128
3424 * higher than dict. ptr. (DICTPT)
3426 FCB $80 ; This is a rough check anyway, leave it as is.
3429 FDB TWO ; NOT the NATWID constant!
3431 * prints 'full stack'
3435 * ======>> 127 << this word's function
3436 * is done by ?STACK in this version
3441 *QFREE FDB DOCOL,SPAT,HERE,LIT8
3443 * FDB PLUS,LESS,TWO,QERR,SEMIS ; This TWO is not NATWID!
3445 * ######>> screen 46 <<
3448 * ***** Check that this is how it works here:
3449 * Get up to n-1 characters from the keyboard,
3450 * storing at buffer and echoing, with backspace editing,
3451 * quitting when a CR is read.
3452 * Terminate it with a NUL.
3454 FCC 'EXPEC' ; 'EXPECT'
3457 EXPECT FDB DOCOL,OVER,PLUS,OVER,XDO ; brace the buffer area
3458 EXPEC2 FDB KEY,DUP,LIT8
3460 FDB PORIG,AT,EQUAL,ZBRAN ; check for backspacing
3463 FCB 8 ( backspace character to emit )
3464 FDB OVER,I,EQUAL,DUP,FROMR,TWO,SUB,PLUS ; back up TWO characters
3468 FCB $D ( carriage return )
3471 FDB LEAVE,DROP,BL,ZERO,BRAN ; I think this is the NUL terminator.
3474 EXPEC5 FDB I,CSTORE,ZERO,I,ONEP,STORE
3475 EXPEC6 FDB EMIT,XLOOP
3482 * EXPECT 128 (TWID) characters to TIB.
3484 FCC 'QUER' ; 'QUERY'
3487 QUERY FDB DOCOL,TIB,AT,COLUMS
3488 FDB AT,EXPECT,ZERO,IN,STORE
3493 * End interpretation of a line or screen, and/or prepare for a new block.
3494 * Note that the name of this definition is an empty string,
3495 * so it matches on the terminating NUL in the terminal or block buffer.
3496 FCB $C1 immediate < carriage return >
3499 NULL FDB DOCOL,BLK,AT,ZBRAN
3502 FDB ZERO,IN,STORE,BLK,AT,BSCR,MOD
3504 * check for end of screen
3507 FDB QEXEC,FROMR,DROP
3510 NULL2 FDB FROMR,DROP
3513 * ######>> screen 47 <<
3516 * Fill n bytes at adr with b.
3521 FILL FDB DOCOL,SWAP,TOR,OVER,CSTORE,DUP,ONEP
3522 FDB FROMR,ONE,SUB,CMOVE
3527 * Fill n bytes with 0.
3529 FCC 'ERAS' ; 'ERASE'
3532 ERASE FDB DOCOL,ZERO,FILL
3537 * Fill n bytes with ASCII SPACE.
3539 FCC 'BLANK' ; 'BLANKS'
3542 BLANKS FDB DOCOL,BL,FILL
3547 * Format a character at the left of the HLD output buffer.
3552 HOLD FDB DOCOL,LIT,$FFFF,HLD,PSTORE,HLD,AT,CSTORE
3557 * Give the address of the output PAD buffer.
3558 * PAD points to the end of a 68 byte buffer for numeric conversion.
3563 PAD FDB DOCOL,HERE,LIT8
3568 * ######>> screen 48 <<
3571 * Scan a string terminated by the character c or ASCII NUL out of input;
3572 * store symbol at WORDPAD with leading count byte and trailing ASCII NUL.
3573 * Leading c are passed over, per ENCLOSE.
3574 * Scans from BLK, or from TIB if BLK is zero.
3575 * May overwrite the numeric conversion pad,
3576 * if really long (length > 31) symbols are scanned.
3581 WORD FDB DOCOL,BLK,AT,ZBRAN
3583 FDB BLK,AT,BLOCK,BRAN
3586 WORD3 FDB IN,AT,PLUS,SWAP,ENCLOS,HERE,LIT8
3588 FDB BLANKS,IN,PSTORE,OVER,SUB,TOR,R,HERE
3589 FDB CSTORE,PLUS,HERE,ONEP,FROMR,CMOVE
3592 * ######>> screen 49 <<
3594 * ( d1 string --- d2 adr )
3595 * Convert the text at string into a number, accumulating the result into d1,
3596 * leaving adr pointing to the first character not converted.
3597 * If DPL is non-negative at entry,
3598 * accumulates the number of characters converted into DPL.
3600 FCC '(NUMBER' ; '(NUMBER)'
3604 PNUMB2 FDB ONEP,DUP,TOR,CAT,BASE,AT,DIGIT,ZBRAN
3606 FDB SWAP,BASE,AT,USTAR,DROP,ROT,BASE
3607 FDB AT,USTAR,DPLUS,DPL,AT,ONEP,ZBRAN
3610 PNUMB3 FDB FROMR,BRAN
3617 * Convert text at ctstr to a double integer,
3618 * taking the 0 ERROR if the conversion is not valid.
3619 * If a decimal point is present,
3620 * accumulate the count of digits to the decimal point's right into DPL
3621 * (negative DPL at exit indicates single precision).
3622 * ctstr is a counted string
3623 * -- the first byte at ctstr is the length of the string,
3624 * but NUMBER ignores the count and expects a NUL terminator instead.
3626 FCC 'NUMBE' ; 'NUMBER'
3629 NUMB FDB DOCOL,ZERO,ZERO,ROT,DUP,ONEP,CAT,LIT8
3631 FDB EQUAL,DUP,TOR,PLUS,LIT,$FFFF
3632 NUMB1 FDB DPL,STORE,PNUMB,DUP,CAT,BL,SUB
3637 FDB SUB,ZERO,QERR,ZERO,BRAN
3639 NUMB2 FDB DROP,FROMR,ZBRAN
3645 * ( --- locptr length true ) { -FIND name } typical input
3647 * Parse a word, then FIND,
3648 * first in the definition vocabulary,
3649 * then in the CONTEXT (interpretation) vocabulary, if necessary.
3650 * Returns what (FIND) returns, flag and optional location and length.
3652 FCC '-FIN' ; '-FIND'
3655 DFIND FDB DOCOL,BL,WORD,HERE,CONTXT,AT,AT
3656 FDB PFIND,DUP,ZEQU,ZBRAN
3658 FDB DROP,HERE,LATEST,PFIND
3661 * ######>> screen 50 <<
3663 * ( anything --- nothing ) ( anything *** nothing )
3664 * An indirection for ABORT, for ERROR,
3665 * which may be modified carefully.
3667 FCC '(ABORT' ; '(ABORT)'
3670 PABORT FDB DOCOL,ABORT
3675 FCC 'ERRO' ; 'ERROR'
3678 * This really should not be high level, according to best practices.
3679 * But fixing that cascades through MESSAGE,
3680 * requiring re-architecting the disk block system.
3681 * First, we need to get this transliteration running.
3682 ERROR FDB DOCOL,WARN,AT,ZLESS
3686 * 0 to print error #
3687 * and 1 to print error message from disc
3690 ERROR2 FDB HERE,COUNT,TYPE,PDOTQ
3693 FDB MESS,SPSTOR,IN,AT,BLK,AT,QUIT
3698 * Print definition's name from its NFA.
3703 IDDOT FDB DOCOL,PAD,LIT8
3706 FCB $5F ( underline )
3707 FDB FILL,DUP,PFA,LFA,OVER,SUB,PAD
3708 FDB SWAP,CMOVE,PAD,COUNT,LIT8
3713 * ######>> screen 51 <<
3715 * ( --- ) { CREATE name } input
3716 * Parse a name (length < 32 characters) and create a header,
3717 * reporting first duplicate found in either the defining vocabulary
3718 * or the context (interpreting) vocabulary.
3719 * Install the header in the defining vocabulary
3720 * with CFA dangerously pointing to the parameter field.
3721 * Leave the name SMUDGEd.
3723 FCC 'CREAT' ; 'CREATE'
3726 CREATE FDB DOCOL,DFIND,ZBRAN
3735 CREAT2 FDB HERE,DUP,CAT,WIDTH,AT,MIN
3736 FDB ONEP,ALLOT,DUP,LIT8
3737 FCB ($80|FSMUDG) ; Bracket the name.
3738 FDB TOGGLE,HERE,ONE,SUB,LIT8
3740 FDB TOGGLE,LATEST,COMMA,CURENT,AT,STORE
3741 * FDB HERE,TWOP,COMMA
3745 * ######>> screen 52 <<
3748 * { [COMPILE] name } typical use
3749 * -DFIND next WORD and COMPILE it, literally;
3750 * used to compile immediate definitions into words.
3752 FCC '[COMPILE' ; '[COMPILE]'
3755 BCOMP FDB DOCOL,DFIND,ZEQU,ZERO,QERR,DROP,CFA,COMMA
3759 * ( n --- ) if compiling. P
3760 * ( n --- n ) if interpreting.
3761 * Compile n as a literal, if compiling.
3763 FCC 'LITERA' ; 'LITERAL'
3766 LITER FDB DOCOL,STATE,AT,ZBRAN
3768 FDB COMPIL,LIT,COMMA
3772 * ( d --- ) if compiling. P
3773 * ( d --- d ) if interpreting.
3774 * Compile d as a double literal, if compiling.
3776 FCC 'DLITERA' ; 'DLITERAL'
3779 DLITER FDB DOCOL,STATE,AT,ZBRAN
3781 FDB SWAP,LITER,LITER ; Just two literals in the right order.
3784 * ######>> screen 53 <<
3787 * Interpret or compile, according to STATE.
3788 * Searches words parsed in dictionary first, via -FIND,
3789 * then checks for valid NUMBER.
3790 * Pushes or COMPILEs double literal if NUMBER leaves DPL non-negative.
3791 * ERROR checks the stack via ?STACK before returning to its caller.
3793 FCC 'INTERPRE' ; 'INTERPRET'
3797 INTER2 FDB DFIND,ZBRAN
3807 INTER5 FDB HERE,NUMB,DPL,AT,ONEP,ZBRAN
3811 INTER6 FDB DROP,LITER
3812 INTER7 FDB QSTACK,BRAN
3814 * FDB SEMIS never executed
3817 * ######>> screen 54 <<
3820 * Toggle precedence bit of LATEST definition header.
3821 * During compiling, most symbols scanned are compiled.
3822 * IMMEDIATE definitions execute whenever the outer INTERPRETer scans them,
3823 * but may be compiled via ' (TICK).
3825 FCC 'IMMEDIAT' ; 'IMMEDIATE'
3828 IMMED FDB DOCOL,LATEST,LIT8
3834 * ( --- ) { VOCABULARY name } input
3835 * Create a vocabulary entry with a flag for terminating vocabulary searches.
3836 * Store the current search context in it for linking.
3837 * At run-time, VOCABULARY makes itself the CONTEXT vocabulary.
3839 FCC 'VOCABULAR' ; 'VOCABULARY'
3842 VOCAB FDB DOCOL,BUILDS,LIT,$81A0,COMMA,CURENT,AT,CFA
3843 FDB COMMA,HERE,VOCLIN,AT,COMMA,VOCLIN,STORE,DOES
3844 * DOVOC FDB TWOP,CONTXT,STORE
3845 DOVOC FDB NATP,CONTXT,STORE
3850 * Note: FORTH does not go here in the rom-able dictionary,
3851 * since FORTH is a type of variable.
3853 * (Should make a proper architecture for this at some point.)
3858 * Makes the current interpretation CONTEXT vocabulary
3859 * also the CURRENT defining vocabulary.
3861 FCC 'DEFINITION' ; 'DEFINITIONS'
3864 DEFIN FDB DOCOL,CONTXT,AT,CURENT,STORE
3869 * Parse out a comment and toss it away.
3870 * Leaves the first 32 characters in WORDPAD, which may or may not be useful.
3874 PAREN FDB DOCOL,LIT8
3879 * ######>> screen 55 <<
3881 * ( anything *** nothing )
3882 * Clear return stack.
3883 * Then INTERPRET and, if not compiling, prompt with OK,
3889 QUIT FDB DOCOL,ZERO,BLK,STORE
3892 * Here is the outer interpretter
3893 * which gets a line of input, does it, prints " OK"
3895 QUIT2 FDB RPSTOR,CR,QUERY,INTERP,STATE,AT,ZEQU
3903 * FDB SEMIS ( never executed )
3906 * ( anything --- nothing ) ( anything *** nothing )
3907 * Clear parameter stack,
3908 * set STATE to interpret and BASE to DECIMAL,
3909 * return to input from terminal,
3910 * restore DRIVE OFFSET to 0,
3911 * print out "Forth-68",
3912 * set interpret and define vocabularies to FORTH,
3913 * and finally, QUIT.
3914 * Used to force the system to a known state
3915 * and return control to the initial INTERPRETer.
3917 FCC 'ABOR' ; 'ABORT'
3920 ABORT FDB DOCOL,SPSTOR,DEC,QSTACK,DRZERO,CR,PDOTQ
3925 * FDB SEMIS never executed
3928 * ######>> screen 56 <<
3929 * bootstrap code... moves rom contents to ram :
3936 * Ultimately, we want position indepence,
3937 * so I'm using PCR where it seems reasonable.
3938 CENT LDS SINIT,PCR ; Get a useable return stack, at least.
3939 LDA #IUPDP ; This is not relative to PC.
3940 TFR A,DP ; And a useable direct page, too.
3941 SETDP IUPDP ; (For good measure.)
3943 * We'll keep this here for the time being.
3944 * There are better ways to do this, of course.
3945 * Re-architect, re-architect.
3947 STX <XFENCE ; Borrow this variable for a loop terminator.
3948 LEAY REND,PCR ; top of destination
3949 LEAX ERAM,PCR ; top of stuff to move
3951 STA ,-Y ; move TASK & FORTH to ram
3955 * CENT LDS #REND-1 top of destination
3956 * LDX #ERAM top of stuff to move
3959 * PSHS A ; move TASK & FORTH to ram
3963 * LDS #XFENCE-1 put stack at a safe place for now
3964 * But that is taken care of.
3986 WENT LDS SINIT,PCR ; Get a useable return stack, at least.
3987 LDA #IUPDP ; This is not relative to PC.
3988 TFR A,DP ; And a useable direct page, too.
3989 SETDP IUPDP ; (For good measure.)
3992 PSHS X ; for loop termination
3993 CLRB ; Yes, I'm being a little ridiculous. Only a little.
3995 LEAY XFENCE,Y ; top of destination
3996 LEAX FENCIN,PCR ; top of stuff to move
3997 WARM2 LDD ,--X ; All entries are 16 bit.
4001 LEAS 2,S ; But we'll reset the return stack shortly, anyway.
4002 * WENT LDS #XFENCE-1 top of destination
4003 * LDX #FENCIN top of stuff to move
4011 * S is already there.
4013 * STX UP init user ram pointer
4014 * UP is already there (DP).
4017 LEAY ABORT,PCR ; Prepare IP.
4019 NOP Here is a place to jump to special user
4020 NOP initializations such as I/0 interrups
4023 * For systems with TRACE:
4025 * STX TRLIM clear trace mode
4026 STX <TRLIM clear trace mode
4028 * STX BRKPT clear breakpoint address
4029 STX <BRKPT clear breakpoint address
4030 * JMP RPSTOR+2 start the virtual machine running !
4031 LBSR RPSTOR+NATWID start the virtual machine running !
4032 LBRA NEXT ; But we must also give RP! someplace to return.
4033 * RP! sets up the return stack pointer, then Y references abort.
4035 * Here is the stuff that gets copied to ram :
4036 * (not * at address $140:)
4037 * at an appropriate address:
4039 RAM FDB $3000,$3000,0,0
4043 * Makes FORTH the current interpretation vocabulary.
4044 * In order to make this ROMmable, this entry is set up as the tail-end,
4045 * and copied to RAM in the start-up code.
4046 * We want a more elegant solution to this, too. Greedy, maybe.
4048 FCC 'FORT' ; 'FORTH'
4050 FDB NOOP-7 ; Note that this does not link to COLD!
4051 RFORTH FDB DODOES,DOVOC,$81A0,TASK-7
4053 FCC "(C) Forth Interest Group, 1979"
4058 RTASK FDB DOCOL,SEMIS
4059 ERAM FCC "David Lion"
4062 * ######>> screen 57 <<
4065 * Sign extend n0 to a double integer.
4069 FDB COLD-7 ; Note that this does not link to FORTH (RFORTH)!
4070 STOD FDB DOCOL,DUP,ZLESS,MINUS
4076 * ( multiplier multiplicand --- product )
4077 * Signed word multiply.
4082 LBSR USTAR+NATWID ; or [USTAR,PCR]?
4083 LEAU NATWID,U ; Drop high word.
4091 * ( dividend divisor --- remainder quotient )
4092 * M/ in word-only form, i. e., signed division of 2nd word by top word,
4093 * yielding signed word quotient and remainder.
4098 SLMOD FDB DOCOL,TOR,STOD,FROMR,USLASH
4102 * ( dividend divisor --- quotient )
4103 * Signed word divide without remainder.
4107 SLASH FDB DOCOL,SLMOD,SWAP,DROP
4111 * ( dividend divisor --- remainder )
4112 * Remainder function, result takes sign of dividend.
4117 MOD FDB DOCOL,SLMOD,DROP
4121 * ( multiplier multiplicand divisor --- remainder quotient )
4122 * Signed precise division of product:
4123 * multiply 2nd and 3rd words on stack
4124 * and divide the 31-bit product by the top word,
4125 * leaving both quotient and remainder.
4126 * Remainder takes sign of product.
4127 * Guaranteed not to lose significant bits in 16 bit integer math.
4129 FCC '*/MO' ; '*/MOD'
4132 SSMOD FDB DOCOL,TOR,USTAR,FROMR,USLASH
4136 * ( multiplier multiplicand divisor --- quotient )
4137 * */MOD without remainder.
4142 SSLASH FDB DOCOL,SSMOD,SWAP,DROP
4146 * ( ud1 u1 --- u2 ud2 )
4147 * U/ with an (unsigned) double quotient.
4148 * Guaranteed not to lose significant bits in 32 bit / 16 bit bit integer math,
4149 * if you are prepared to deal with the extra 16 bits of result.
4151 FCC 'M/MO' ; 'M/MOD'
4154 MSMOD FDB DOCOL,TOR,ZERO,R,USLASH
4155 FDB FROMR,SWAP,TOR,USLASH,FROMR
4161 * Convert the top of stack to its absolute value.
4166 ABS FDB DOCOL,DUP,ZLESS,ZBRAN
4174 * Convert the top double to its absolute value.
4179 DABS FDB DOCOL,DUP,ZLESS,ZBRAN
4184 * ######>> screen 58 <<
4188 * Least Recently Used buffer.
4189 * Really should be with FIRST and LIMIT in the per-task table.
4198 * Most Recently Used buffer.
4199 * Really should be with FIRST and LIMIT in the per-task table.
4207 * ( buffer1 --- buffer2 f )
4208 * Bump to next buffer,
4209 * flag false if result is PREVious buffer,
4210 * otherwise flag true.
4211 * Used in the LRU allocation routines.
4218 FDB PLUS,DUP,LIMIT,EQUAL,ZBRAN
4221 PBUF2 FDB DUP,PREV,AT,SUB
4226 * Mark PREVious buffer dirty, in need of being written out.
4228 FCC 'UPDAT' ; 'UPDATE'
4231 UPDATE FDB DOCOL,PREV,AT,AT,LIT,$8000,OR,PREV,AT,STORE
4236 * Mark all buffers empty.
4237 * Standard method of discarding changes.
4239 FCC 'EMPTY-BUFFER' ; 'EMPTY-BUFFERS'
4242 MTBUF FDB DOCOL,FIRST,LIMIT,OVER,SUB,ERASE
4247 * Clear the current offset to the block numbers in the drive interface.
4248 * The drives need to be re-architected.
4249 * Would be cool to have RAM and ROM drives supported
4250 * in addition to regular physical persistent store.
4255 DRZERO FDB DOCOL,ZERO,OFSET,STORE
4258 * ======>> 174 <<== system dependant word
4260 * Set the current offset in the drive interface to reference the second drive.
4261 * The hard-coded number in there needs to be in a table.
4266 DRONE FDB DOCOL,LIT,$07D0,OFSET,STORE
4269 * ######>> screen 59 <<
4272 * Get a free buffer,
4273 * assign it to block n,
4274 * return buffer address.
4275 * Will free a buffer by writing it, if necessary.
4276 * Does not actually read the block.
4277 * A bug in the fig LRU algorithm, which I have not fixed,
4278 * gives the PREVious buffer if USE gets set to PREVious.
4279 * (The bug is that USE sometimes gets set to PREVious.)
4280 * This bug sometimes causes sector moves to become sector fills.
4282 FCC 'BUFFE' ; 'BUFFER'
4285 BUFFER FDB DOCOL,USE,AT,DUP,TOR
4286 BUFFR2 FDB PBUF,ZBRAN
4288 FDB USE,STORE,R,AT,ZLESS
4291 * FDB R,TWOP,R,AT,LIT,$7FFF,AND,ZERO,RW
4292 FDB R,NATP,R,AT,LIT,$7FFF,AND,ZERO,RW
4293 * BUFFR3 FDB R,STORE,R,PREV,STORE,FROMR,TWOP
4294 BUFFR3 FDB R,STORE,R,PREV,STORE,FROMR,NATP
4297 * ######>> screen 60 <<
4300 * Get BUFFER containing block n, relative to OFFSET.
4301 * If block n is not in a buffer, bring it in.
4302 * Returns buffer address.
4304 FCC 'BLOC' ; 'BLOCK'
4307 BLOCK FDB DOCOL,OFSET,AT,PLUS,TOR
4308 FDB PREV,AT,DUP,AT,R,SUB,DUP,PLUS,ZBRAN
4310 BLOCK3 FDB PBUF,ZEQU,ZBRAN
4312 * FDB DROP,R,BUFFER,DUP,R,ONE,RW,TWO,SUB
4313 FDB DROP,R,BUFFER,DUP,R,ONE,RW,NATWC,SUB
4314 BLOCK4 FDB DUP,AT,R,SUB,DUP,PLUS,ZEQU,ZBRAN
4317 * BLOCK5 FDB FROMR,DROP,TWOP
4318 BLOCK5 FDB FROMR,DROP,NATP
4321 * ######>> screen 61 <<
4323 * ( line screen --- buffer C/L)
4324 * Bring in the sector containing the specified line of the specified screen.
4325 * Returns the buffer address and the width of the screen.
4326 * Screen number is relative to OFFSET.
4327 * The line number may be beyond screen 4,
4328 * (LINE) will get the appropriate screen.
4330 FCC '(LINE' ; '(LINE)'
4333 PLINE FDB DOCOL,TOR,LIT8
4335 FDB BBUF,SSMOD,FROMR,BSCR,STAR,PLUS,BLOCK,PLUS,LIT8
4340 * ( line screen --- )
4341 * Print the line of the screen as found by (LINE), suppress trailing BLANKS.
4343 FCC '.LIN' ; '.LINE'
4346 DLINE FDB DOCOL,PLINE,DTRAIL,TYPE
4351 * If WARNING is 0, print "MESSAGE #n";
4352 * otherwise, print line n relative to screen 4,
4353 * the line number may be negative.
4354 * Uses .LINE, but counter-adjusts to be relative to the real drive 0.
4356 FCC 'MESSAG' ; 'MESSAGE'
4359 MESS FDB DOCOL,WARN,AT,ZBRAN
4365 FDB OFSET,AT,BSCR,SLASH,SUB,DLINE,BRAN
4369 FCC 'err # ' ; 'err # '
4375 * Begin interpretation of screen (block) n.
4376 * See also ARROW, SEMIS, and NULL.
4378 FCC 'LOA' ; 'LOAD' : input:scr #
4381 LOAD FDB DOCOL,BLK,AT,TOR,IN,AT,TOR,ZERO,IN,STORE
4382 FDB BSCR,STAR,BLK,STORE
4383 FDB INTERP,FROMR,IN,STORE,FROMR,BLK,STORE
4388 * Continue interpreting source code on the next screen.
4393 ARROW FDB DOCOL,QLOAD,ZERO,IN,STORE,BSCR
4394 FDB BLK,AT,OVER,MOD,SUB,BLK,PSTORE
4399 * ######>> screen 63 <<
4400 * The next 4 subroutines are machine dependent, and are
4401 * called by words 13 through 16 in the dictionary.
4403 * ======>> 182 << code for EMIT
4405 * output using rom CHROUT: redirectable to a printer on Coco.
4406 * Outputs the character on stack (low byte of 1 bit word/cell).
4408 PEMITW TFR B,A ; Coco ROM wants it in A.
4409 PSHS Y,U,DP ; Save everything important!
4411 TFR B,DP ; Give the ROM it's direct page.
4412 JSR [$A002] ; Output the character in A.
4414 * PEMIT STB N save B
4417 * BITB #2 check ready bit
4418 * BEQ PEMIT+4 if not ready for more data
4421 * STB IOSTAT-UORIG,X
4422 * LDB N recover B & X
4424 * RTS only A register may change
4425 * PEMIT JMP $E1D1 for MIKBUG
4426 * PEMIT FCB $3F,$11,$39 for PROTO
4427 * PEMIT JMP $D286 for Smoke Signal DOS
4429 * ======>> 183 << code for KEY
4431 * wait for key from POLCAT on Coco.
4432 * Returns the character code for the key pressed.
4434 LDA #$CF ; a cursor of sorts
4444 PKEYR CLRB ; for the break flag
4447 COMB ; for the break flag
4456 * BCC PKEY+4 no incoming data yet
4458 * ANDA #$7F strip parity bit
4460 * STB IOSTAT+1-UORIG,X
4464 * PKEY JMP $E1AC for MIKBUG
4465 * PKEY FCB $3F,$14,$39 for PROTO
4466 * PKEY JMP $D289 for Smoke Signal DOS
4468 * ######>> screen 64 <<
4469 * ======>> 184 << code for ?TERMINAL
4471 * check break key using POLCAT
4472 * Returns a flag to tell whether the break key was pressed or not.
4476 JSR [$A000] ; Look but don't wait.
4478 * PQTER LDA ACIAC Test for 'break' condition
4479 * ANDA #$11 mask framing error bit and
4482 * LDA ACIAD clear input buffer
4489 * ======>> 185 << code for CR
4491 * For Coco just output a CR.
4492 * Also subject to redirection in Coco BASIC ROM.
4495 * PCR LDA #$D carriage return
4501 * LDB XDELAY+1-UORIG,X
4503 * BMI PQTER2 return if minus
4504 * PSHS B ; save counter
4505 * BSR PEMIT print RUBOUTs to delay.....
4512 * ######>> screen 66 <<
4515 * Query the disk, I suppose.
4516 * Not sure what the model had in mind for this stub.
4518 FCC '?DIS' ; '?DISC'
4524 * ######>> screen 67 <<
4527 * Write one block of data to disk.
4528 * Parameters unspecified in model. Stub in model.
4530 FCC 'BLOCK-WRIT' ; 'BLOCK-WRITE'
4536 * ######>> screen 68 <<
4539 * Read one block of data from disk.
4540 * Parameters unspecified in model. Stub in model.
4542 FCC 'BLOCK-REA' ; 'BLOCK-READ'
4548 *The next 3 words are written to create a substitute for disc
4549 * mass memory,located between $3210 & $3FFF in ram.
4556 FDB MEMEND a system dependent equate at front
4564 FDB MEMTOP ( $3FFF or $7FFF in this version )
4566 * ######>> screen 69 <<
4568 * ( buffer sector f --- )
4569 * Read or Write the specified (absolute -- ignores OFFSET) sector
4570 * from or to the specified buffer.
4571 * A zero flag specifies write,
4572 * non-zero specifies read.
4573 * Sector is an unsigned integer,
4574 * buffer is the buffer's address.
4575 * Will need to use the CoCo ROM disk routines.
4576 * For now, provides a virtual disk in RAM.
4581 RW FDB DOCOL,TOR,BBUF,STAR,LO,PLUS,DUP,HI,GREAT,ZBRAN
4585 FCC ' Range ?' ; ' Range ?'
4595 * LDY $C006 control table
4596 * LDX #DROFFS+7 ; This is BIF's table of drive sizes.
4598 * RWD SUBD ,X++ sectors
4600 * BVC RWR table end?
4604 * RWR ADDD ,--X back one
4607 * LDD #18 sectors/track
4617 * PULS D table entry
4630 * JSR [$C004] ROM handles timeout
4631 * PULS Y,U,DP if IRQ enabled
4634 * LDB 6,X coco status
4644 * ######>> screen 72 <<
4646 * ( --- ) compiling P
4647 * ( --- adr ) interpreting
4649 * Parse a symbol name from input and search the dictionary for it, per -FIND;
4650 * compile the address as a literal if compiling,
4651 * otherwise just push it.
4655 TICK FDB DOCOL,DFIND,ZEQU,ZERO,QERR,DROP,LITER
4659 * ( --- ) { FORGET name } input
4660 * Parse out name of definition to FORGET to, -DFIND it,
4661 * then lop it and everything that follows out of the dictionary.
4662 * In fig Forth, CURRENT and CONTEXT have to be the same to FORGET.
4664 FCC 'FORGE' ; 'FORGET'
4667 FORGET FDB DOCOL,CURENT,AT,CONTXT,AT,SUB,LIT8
4669 FDB QERR,TICK,DUP,FENCE,AT,LESS,LIT8
4671 FDB QERR,DUP,ZERO,PORIG,GREAT,LIT8
4673 FDB QERR,DUP,NFA,DICTPT,STORE,LFA,AT,CONTXT,AT,STORE
4676 * ######>> screen 73 <<
4679 * Calculate a back reference from HERE and compile it.
4684 BACK FDB DOCOL,HERE,SUB,COMMA
4689 * typical use: BEGIN code-loop test UNTIL
4690 * typical use: BEGIN code-loop AGAIN
4691 * typical use: BEGIN code-loop test WHILE code-true REPEAT
4692 * ( --- adr n ) compile time P,C
4693 * Push HERE for BACK reference for general (non-counting) loops,
4694 * with BEGIN construct flag.
4695 * A better flag: $4245 (ASCII for 'BE').
4697 FCC 'BEGI' ; 'BEGIN'
4700 BEGIN FDB DOCOL,QCOMP,HERE,ONE ; ONE is a flag for BEGIN loops.
4705 * typical use: test IF code-true ELSE code-false ENDIF
4706 * ENDIF is just a sort of intersection piece,
4707 * marking where execution resumes after both branches.
4708 * ( adr n --- ) compile time
4709 * Check the mark and resolve the IF.
4710 * A better flag: $4846 (ASCII for 'IF').
4712 FCC 'ENDI' ; 'ENDIF'
4715 ENDIF FDB DOCOL,QCOMP,TWO,QPAIRS,HERE ; This TWO is a flag for IF.
4716 FDB OVER,SUB,SWAP,STORE
4721 * typical use: test IF code-true ELSE code-false ENDIF
4728 THEN FDB DOCOL,ENDIF
4732 * ( limit index --- ) runtime
4733 * typical use: DO code-loop LOOP
4734 * typical use: DO code-loop increment +LOOP
4735 * Counted loop, index is initial value of index.
4736 * Will loop until index equals (positive going)
4737 * or passes (negative going) limit.
4738 * ( --- adr n ) compile time P,C
4739 * Compile (DO), push HERE for BACK reference,
4740 * and push DO control construct flag.
4741 * A better flag: $444F (ASCII for 'DO').
4746 DO FDB DOCOL,COMPIL,XDO,HERE,THREE ; THREE is a flag for DO loops.
4751 * typical use: DO code-loop LOOP
4752 * Increments the index by one and branches back to beginning of loop.
4753 * Will loop until index equals limit.
4754 * ( adr n --- ) compile time P,C
4755 * Check the mark and compile (LOOP), fill in BACK reference.
4756 * A better flag: $444F (ASCII for 'DO').
4761 LOOP FDB DOCOL,THREE,QPAIRS,COMPIL,XLOOP,BACK ; THREE for DO loops.
4766 * typical use: DO code-loop increment +LOOP
4767 * Increments the index by n and branches back to beginning of loop.
4768 * Will loop until index equals (positive going)
4769 * or passes (negative going) limit.
4770 * ( adr n --- ) compile time P,C
4771 * Check the mark and compile (+LOOP), fill in BACK reference.
4772 * A better flag: $444F (ASCII for 'DO').
4774 FCC '+LOO' ; '+LOOP'
4777 PLOOP FDB DOCOL,THREE,QPAIRS,COMPIL,XPLOOP,BACK ; THREE for DO loops.
4782 * typical use: BEGIN code-loop test UNTIL
4783 * Will loop until UNTIL tests true.
4784 * ( adr n --- ) compile time P,C
4785 * Check the mark and compile (0BRANCH), fill in BACK reference.
4786 * A better flag: $4245 (ASCII for 'BE').
4788 FCC 'UNTI' ; 'UNTIL' : ( same as END )
4791 UNTIL FDB DOCOL,ONE,QPAIRS,COMPIL,ZBRAN,BACK ; ONE for BEGIN loops.
4794 * ######>> screen 74 <<
4797 * typical use: BEGIN code-loop test END
4809 * typical use: BEGIN code-loop AGAIN
4811 * (or until something uses R> DROP to force the current definition to die,
4812 * or perhaps ABORT or ERROR or some such other drastic means stops things).
4813 * ( adr n --- ) compile time P,C
4814 * Check the mark and compile (0BRANCH), fill in BACK reference.
4815 * A better flag: $4245 (ASCII for 'BE').
4817 FCC 'AGAI' ; 'AGAIN'
4820 AGAIN FDB DOCOL,ONE,QPAIRS,COMPIL,BRAN,BACK ; ONE for BEGIN loops.
4825 * typical use: BEGIN code-loop test WHILE code-true REPEAT
4826 * Will loop until WHILE tests false, skipping code-true on end.
4827 * REPEAT marks where execution resumes after the WHILE find a false flag.
4828 * ( aadr1 n1 adr2 n2 --- ) compile time P,C
4829 * Check the marks for WHILE and BEGIN,
4830 * compile BRANCH and BACK fill adr1 reference,
4831 * FILL-IN 0BRANCH reference at adr2.
4832 * Better flags: $4245 (ASCII for 'BE') and $5747 (ASCII for 'WH').
4834 FCC 'REPEA' ; 'REPEAT'
4837 REPEAT FDB DOCOL,TOR,TOR,AGAIN,FROMR,FROMR ; ONE for BEGIN loops.
4838 FDB TWO,SUB,ENDIF ; TWO is for IF, 4 is for WHILE.
4843 * typical use: test IF code-true ELSE code-false ENDIF
4844 * Will pass execution to the true part on a true flag
4845 * and to the false part on a false flag.
4846 * ( --- adr n ) compile time P,C
4847 * Compile a 0BRANCH and dummy offset
4848 * and push IF reference to fill in and
4849 * IF control construct flag.
4850 * A better flag: $4946 (ASCII for 'IF').
4855 IF FDB DOCOL,COMPIL,ZBRAN,HERE,ZERO,COMMA,TWO ; TWO is a flag for IF.
4860 * typical use: test IF code-true ELSE code-false ENDIF
4861 * ELSE is just a sort of intersection piece,
4862 * marking where execution resumes on a false branch.
4863 * ( adr1 n --- adr2 n ) compile time P,C
4865 * compile BRANCH with dummy offset,
4866 * resolve IF reference,
4867 * and leave reference to BRANCH for ELSE.
4868 * A better flag: $4946 (ASCII for 'IF').
4873 ELSE FDB DOCOL,TWO,QPAIRS,COMPIL,BRAN,HERE
4874 FDB ZERO,COMMA,SWAP,TWO,ENDIF,TWO ; TWO is a flag for IF.
4879 * typical use: BEGIN code-loop test WHILE code-true REPEAT
4880 * Will loop until WHILE tests false, skipping code-true on end.
4881 * ( --- adr n ) compile time P,C
4882 * Compile 0BRANCH with dummy offset (using IF),
4883 * push WHILE reference.
4884 * BEGIN flag will sit underneath this.
4885 * Better flags: $4245 (ASCII for 'BE') and $5747 (ASCII for 'WH').
4887 FCC 'WHIL' ; 'WHILE'
4890 WHILE FDB DOCOL,IF,TWOP ; TWO is a flag for IF, 4 is for WHILE.
4893 * ######>> screen 75 <<
4896 * EMIT count spaces, for non-zero, non-negative counts.
4898 FCC 'SPACE' ; 'SPACES'
4901 SPACES FDB DOCOL,ZERO,MAX,DDUP,ZBRAN
4904 SPACE2 FDB SPACE,XLOOP
4910 * Initialize HLD for converting a double integer.
4911 * Stores the PAD address in HLD.
4916 BDIGS FDB DOCOL,PAD,HLD,STORE
4920 * ( d --- string length )
4921 * Terminate numeric conversion,
4922 * drop the number being converted,
4923 * leave the address of the conversion string and the length, ready for TYPE.
4928 EDIGS FDB DOCOL,DROP,DROP,HLD,AT,PAD,OVER,SUB
4933 * Put sign of n (as a flag) at the head of the conversion string.
4934 * Drop the sign flag.
4939 SIGN FDB DOCOL,ROT,ZLESS,ZBRAN
4948 * Generate next most significant digit in the conversion BASE,
4949 * putting the digit at the head of the conversion string.
4953 DIG FDB DOCOL,BASE,AT,MSMOD,ROT,LIT8
4967 * Convert d to a numeric string using # until the result is zero.
4968 * Leave the double result on the stack for #> to drop.
4974 DIGS2 FDB DIG,OVER,OVER,OR,ZEQU,ZBRAN
4978 * ######>> screen 76 <<
4981 * Print n on the output device in the current conversion base,
4983 * right aligned in a field at least width wide.
4988 DOTR FDB DOCOL,TOR,STOD,FROMR,DDOTR
4993 * Print d on the output device in the current conversion base,
4995 * right aligned in a field at least width wide.
5000 DDOTR FDB DOCOL,TOR,SWAP,OVER,DABS,BDIGS,DIGS,SIGN
5001 FDB EDIGS,FROMR,OVER,SUB,SPACES,TYPE
5006 * Print d on the output device in the current conversion base,
5008 * in free format with trailing space.
5013 DDOT FDB DOCOL,ZERO,DDOTR,SPACE
5018 * Print n on the output device in the current conversion base,
5020 * in free format with trailing space.
5024 DOT FDB DOCOL,STOD,DDOT
5029 * Print signed word at adr, per DOT.
5033 QUEST FDB DOCOL,AT,DOT
5036 * ######>> screen 77 <<
5039 * Print out screen n as a field of ASCII,
5040 * with line numbers in decimal.
5045 LIST FDB DOCOL,DEC,CR,DUP,SCR,STORE,PDOTQ
5051 LIST2 FDB CR,I,THREE
5052 FDB DOTR,SPACE,I,SCR,AT,DLINE,XLOOP
5059 * Print comment lines (line 0, and line 1 if C/L < 41) of screens
5060 * from start to end.
5062 FCC 'INDE' ; 'INDEX'
5065 INDEX FDB DOCOL,CR,ONEP,SWAP,XDO
5066 INDEX2 FDB CR,I,THREE
5067 FDB DOTR,SPACE,ZERO,I,DLINE
5077 * List a printer page full of screens.
5078 * Line and screen number are in current base.
5080 FCC 'TRIA' ; 'TRIAD'
5083 TRIAD FDB DOCOL,THREE,SLASH,THREE,STAR
5084 FDB THREE,OVER,PLUS,SWAP,XDO
5086 FDB LIST,QTERM,ZBRAN
5096 * ######>> screen 78 <<
5099 * Alphabetically list the definitions in the current vocabulary.
5101 FCC 'VLIS' ; 'VLIST'
5104 VLIST FDB DOCOL,LIT8
5106 FDB OUT,STORE,CONTXT,AT,AT
5107 VLIST1 FDB OUT,AT,COLUMS,AT,LIT8
5111 FDB CR,ZERO,OUT,STORE
5112 VLIST2 FDB DUP,IDDOT,SPACE,SPACE,PFA,LFA,AT
5113 FDB DUP,ZEQU,QTERM,OR,ZBRAN
5120 * Mostly for place holding.
5125 NOOP FDB NEXT a useful no-op
5126 ZZZZ FDB 0,0,0,0,0,0,0,0 end of rom program
5129 * These things, up through the lable 'REND', are overwritten
5130 * at time of cold load and should have the same contents
5133 * This can be moved whereever the bottom of the
5134 * user's dictionary is going to be put.
5137 FCC 'FORT' ; 'FORTH'
5140 FORTH FDB DODOES,DOVOC,$81A0,TASK-7
5143 FCC "(C) Forth Interest Group, 1979"
5149 TASK FDB DOCOL,SEMIS
5151 REND EQU * ( first empty location in dictionary )