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 UPINIT FDB UORIG initial user area
372 * UPINIT FDB UORIG initial user area
373 SINIT FDB ISP ; initial top of data stack
374 * SINIT FDB ORIG-$D0 initial top of data stack
375 RINIT FDB IRP ; initial top of return stack
376 * RINIT FDB ORIG-2 initial top of return stack
377 FDB ITIB ; terminal input buffer
378 * FDB ORIG-$D0 terminal input buffer
379 FDB 31 initial name field width
380 FDB 0 initial warning mode (0 = no disc)
381 FENCIN FDB REND initial fence
382 DPINIT FDB REND cold start value for DICTPT
384 COLINT FDB 132 initial terminal carriage width
385 DELINT FDB 4 initial carriage return delay
386 ****************************************************
390 * ######>> screen 13 <<
391 * These were of questionable use anyway,
392 * kept here now to satisfy the assembler and show hints.
393 * They're too much trouble to use with native subroutine call anyway.
394 * PULABX PULS A ; 24 cycles until 'NEXT'
396 PULABX PULU A,B ; ?? cycles until 'NEXT'
397 * STABX STA 0,X 16 cycles until 'NEXT'
399 STABX STD 0,X ; ?? cycles until 'NEXT'
401 * GETX LDA 0,X 18 cycles until 'NEXT'
403 GETX LDD 0,X ?? cycles until 'NEXT'
404 * PUSHBA PSHS B ; 8 cycles until 'NEXT'
406 PUSHBA PSHU A,B ; ?? cycles until 'NEXT'
410 * "NEXT" takes ?? cycles if TRACE is removed,
412 * and ?? cycles if trace is present and NOT tracing.
414 * = = = = = = = t h e v i r t u a l m a c h i n e = = = = =
416 * NEXT itself might just completely go away.
417 * About the only reason to keep it is to allowing executing a list
418 * which allows a cheap TRACE routine.
420 * NEXT is a loop which implements the Forth VM.
421 * It basically cycles through calling the code out of code lists,
423 * Using a native CPU return for this uses a few extra cycles per call,
424 * compared to simply jumping to each definition and jumping back
425 * to the known beginning of the loop,
426 * but the loop itself is really only there for convenience.
428 * This implementation uses the native subroutine call,
429 * to break the wall between Forth code and non-Forth code.
432 * LEAX 1,X ; pre-increment mode
435 NEXT ; IP is Y, push before using, pull before you come back here.
437 * NEXT2 LDX 0,X get W which points to CFA of word to be done
438 NEXT2 LDX ,Y++ get W which points to CFA of word to be done
439 * But NEXT2 is too much trouble to use with subroutine threading anyway.
441 NEXT3 ; W is X until you use X for something else. (TOS points back here.)
442 * But NEXT3 is too much trouble to use with subroutine threading anyway.
443 * LDX 0,X get VECT which points to executable code
445 * The next instruction could be patched to JMP TRACE =
446 * if a TRACE routine is available: =
449 JSR [,X] ; Saving the postinc cycles,
450 * ; but X must be bumped NATWID to the parameters.
452 * JMP TRACE ( an alternate for the above )
453 * In other words, with the call and the NOP,
454 * there is room to patch the call with a JMP to your TRACE
455 * routine, which you have to provide.
458 * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
465 * Pushes the following natural width integer from the instruction stream
466 * as a literal, or immediate value.
471 * FDB LITERAL-TO-BE-PUSHED
474 * In native processor code, there should be a better way, use that instead.
475 * More specifically, DO NOT CALL THIS from assembly language code.
476 * (Note that there is no compile-only flag in the fig model.)
478 * See (FIND), or PFIND , for layout of the header format.
481 FCC 'LI' ; 'LIT' : NOTE: this is different from LITERAL
483 FDB 0 ; link of zero to terminate dictionary scan
484 LIT FDB *+NATWID ; Note also that it is meaningless in native code.
496 * ######>> screen 14 <<
499 * Pushes the following byte from the instruction stream
500 * as a literal, or immediate value.
505 * FCB LITERAL-TO-BE-PUSHED
508 * If this is kept, it should have a header for TRACE to read.
509 * If the data bus is wider than a byte, you don't want to do this.
510 * Byte shaving like this is often counter-productive anyway.
511 * Changing the name to LIT8, hoping that will be more understandable.
512 * Also, see comments for LIT.
513 * (Note that there is no compile-only flag in the fig model.)
515 FCC 'LIT' ; 'LIT8' : NOTE: this is different from LITERAL
518 LIT8 FDB *+NATWID (this was an invisible word, with no header)
519 LDB ,Y+ ; This also is meaningless in native code.
532 * Jump to address on stack. Used by the "outer" interpreter to
533 * interactively invoke routines.
534 * Might be useful to have EXECUTE test the pointer, as done in BIF-6809.
536 FCC 'EXECUT' ; 'EXECUTE'
540 PULU X ; Gotta have W anyway, just in case.
541 JMP [,X] ; Tail return.
543 * LDX 0,X get code field address (CFA)
544 * LEAS 1,S ; pop stack
548 * ######>> screen 15 <<
551 * Add the following word from the instruction stream to the
552 * instruction pointer (Y++). Causes a program branch in Forth code stream.
554 * In native processor code, there should be a better way, use that instead.
555 * More specifically, DO NOT CALL THIS from assembly language code.
556 * This is only for Forth code stream.
557 * Also, see comments for LIT.
559 FCC 'BRANC' ; 'BRANCH'
562 BRAN FDB ZBYES ; Go steal code in ZBRANCH
564 * Moving code around to optimize the branch taking case in 0BRANCH.
565 ZBNO LEAY NATWID,Y ; No branch.
569 * BRANCH if flag is zero.
571 * In native processor code, there should be a better way, use that instead.
572 * More specifically, DO NOT CALL THIS from assembly language code.
573 * This is only for Forth code stream.
574 * Also, see comments for LIT.
576 FCC '0BRANC' ; '0BRANCH'
583 LEAY D,Y ; IP is postinc
587 * PSHS B ; ** emulating ABA:
591 * ZBYES LDX IP Note: code is shared with BRANCH, (+LOOP), (LOOP)
599 * ZBNO LDX IP no branch. This code is shared with (+LOOP), (LOOP).
600 * LEAX 1,X ; jump over branch delta
605 * ######>> screen 16 <<
607 * ( --- ) ( limit index *** limit index+1) C
608 * ( limit index *** )
609 * Counting loop primitive. The counter and limit are the top two
610 * words on the return stack. If the updated index/counter does
611 * not exceed the limit, a branch occurs. If it does, the branch
612 * does not occur, and the index and limit are dropped from the
615 * In native processor code, there should be a better way, use that instead.
616 * More specifically, DO NOT CALL THIS from assembly language code.
617 * This is only for Forth code stream.
618 * Also, see comments for LIT.
620 FCC '(LOOP' ; '(LOOP)'
624 LDD #1 ; Borrowing from BIF-6809.
625 XLOOPA ADDD 2,S ; Dodge the return address.
630 LDX ,S ; synthetic return
631 LEAS 6,S ; Clean up the index and limit.
634 * LDB #1 get set to increment counter by 1 (Clears N.)
635 * BRA XPLOP2 go steal other guy's code!
638 * ( n --- ) ( limit index *** limit index+n ) C
639 * ( limit index *** )
640 * Loop with a variable increment. Terminates when the index
641 * crosses the boundary from one below the limit to the limit. A
642 * positive n will cause termination if the result index equals the
643 * limit. A negative n must cause the index to become less than
644 * the limit to cause loop termination.
646 * Note that the end conditions are not symmetric around zero.
648 * In native processor code, there should be a better way, use that instead.
649 * More specifically, DO NOT CALL THIS from assembly language code.
650 * This is only for Forth code stream.
651 * Also, see comments for LIT.
653 FCC '(+LOOP' ; '(+LOOP)'
656 XPLOOP FDB *+NATWID ; Borrowing from BIF-6809.
658 BPL XLOOPA ; Steal plain loop code for forward count.
659 ADDD 2,S ; Dodge the return address
663 BRA XLOOPN ; This path is less time-sensitive.
665 * This should work, but I want to use tested code.
666 * PULU A,B ; Get the increment.
667 * XPLOP2 PULS X ; Pre-clear the return stack.
668 * PSHU A ; Save the direction in high bit.
671 * SUBD NATWID,S ; Check limit.
673 ** I think this should work:
674 * EORA ,U+ ; dir < 0 and (count - limit) >= 0
675 * BPL XPLONO ; or dir >= 0 and (count - limit) < 0
677 * LEAY D,Y ; IP is postinc
679 * XPLONO LEAS 2*NATWID,S
680 * JMP ,X ; synthetic return
682 * This definitely should work:
683 * TST ,U+ ; Get the sign
688 * LEAY D,Y ; IP is postinc
690 * XPLOF CMPD NATWID,S
692 * XPLONO LEAS 2*NATWID,S
693 * JMP ,X ; synthetic return
695 * 6800 Probably could have used the exclusive-or method, too.:
696 * PULS A ; get increment
699 * BPL XPLOF forward looping
705 * BRA XPLONO fall through
709 * ADDB 3,X add it to counter
711 * STB 3,X store new counter value
720 * XPLONO LEAX 1,X ; done, don't branch back
725 * BRA ZBNO use ZBRAN to skip over unused delta
727 * ######>> screen 17 <<
729 * ( limit index --- ) ( *** limit index )
730 * Move the loop parameters to the return stack. Synonym for D>R.
735 XDO FDB *+NATWID This is the RUNTIME DO, not the COMPILING DO
736 LDX ,S ; Save the return address.
739 PULU A,B ; Maintain order.
741 JMP ,X ; synthetic return
760 * ( --- index ) ( limit index *** limit index )
761 * Copy the loop index from the return stack. Synonym for R.
766 LDD NATWID,S ; Dodge return address.
774 * ######>> screen 18 <<
776 * ( c base --- false )
777 * ( c base --- n true )
778 * Translate C in base, yielding a translation valid flag. If the
779 * translation is not valid in the specified base, only the false
785 DIGIT FDB *+NATWID NOTE: legal input range is 0-9, A-Z
786 LDD 2,U ; Check the whole thing.
787 SUBD #$30 ; ascii zero
788 BMI DIGIT2 IF LESS THAN '0', ILLEGAL
790 BMI DIGIT0 IF '9' OR LESS
792 BMI DIGIT2 if less than 'A'
794 BPL DIGIT2 if greater than 'Z'
795 SUBD #7 translate 'A' thru 'F'
796 DIGIT0 CMPD ,U ; Check the base.
797 BPL DIGIT2 if not less than the base
798 STD 2,U ; Store converted digit. (High byte known zero.)
799 LDD #1 ; set valid flag
800 DIGIT1 STD ,U ; store the flag
802 DIGIT2 LDD #0 ; set not valid flag
807 * SUBA #$30 ascii zero
808 * BMI DIGIT2 IF LESS THAN '0', ILLEGAL
810 * BMI DIGIT0 IF '9' OR LESS
812 * BMI DIGIT2 if less than 'A'
814 * BPL DIGIT2 if greater than 'Z'
815 * SUBA #7 translate 'A' thru 'F'
817 * BPL DIGIT2 if not less than the base
819 * STA 3,X store digit
820 * DIGIT1 STB 1,X store the flag
824 * LEAS 1,S ; pop bottom number
826 * STB 0,X make sure both bytes are 00
829 * ######>> screen 19 <<
831 * The word definition format in the dictionary:
833 * (Symbol names are bracketed by bytes with the high bit set, rather than linked.)
835 * NFA (name field address):
836 * char-count + $80 Length of symbol name, flagged with high bit set.
837 * char 1 Characters of symbol name.
840 * char n + $80 symbol termination flag (char set < 128 code points)
841 * LFA (link field address):
842 * link high byte \___pointer to previous word in list
843 * link low byte / -- Combined allocation/dictionary list. --
844 * CFA (code field address):
845 * CFA high byte \___pointer to native CPU machine code
846 * CFA low byte / -- Consider this the characteristic code. --
847 * PFA (parameter field address):
848 * parameter fields -- Machine code for low-level native machine CPU code,
849 * " instruction list for high-level Forth code,
850 * " constant data for constants, pointers to per task variables,
851 * " space for variables, for global variables, etc.
853 * In the case of native CPU machine code, the address at CFA will be PFA.
855 * Definition attributes:
856 FIMMED EQU $40 ; Immediate word flag.
857 FSMUDG EQU $20 ; Smudged => definition not ready.
858 CTMASK EQU ($FF&(^($80|FIMMED))) ; For unmasking the length byte.
860 * But we really want more:
861 * FCOMPI EQU $10 ; Compile-time-only.
862 * FASSEM EQU $08 ; Assembly-language code only.
863 * F4THLV EQU $04 ; Must not be called from assembly language code.
864 * These would require some significant adjustments to the model.
865 * We also want to put the low-level VM stuff in its own vocabulary.
868 * (FIND) ( name vocptr --- locptr length true )
869 * ( name vocptr --- false )
870 * Search vocabulary for a symbol called name.
871 * name is a pointer to a high-bit bracket string with length head.
872 * vocptr is a pointer to the NFA of the tail-end (LATEST) definition
873 * in the vocabulary to be searched.
874 * HIDDEN (smudged) definitions are lexically less than their name strings.
876 FCC '(FIND' ; '(FIND)'
880 PSHS Y ; Have to track two pointers.
881 * Use the stack and registers instead of temp area N.
882 PA0 EQU 2 ; pointer to the length byte of name being searched against
883 PD EQU 0 ; pointer to NFA of dict word being checked
885 LDX PD,U ; Start in on the vocabulary (NFA).
886 PFNDLP LDY PA0,U ; Point to the name to check against.
887 LDB ,X+ ; get dict name length byte
888 TFR B,A ; Save it in case it matches.
890 CMPB ,Y+ ; Compare lengths
893 TSTB ; ; Is high bit of character in dictionary entry set?
895 ANDB #$7F ; Clear high bit from dictionary.
896 CMPB ,Y+ ; Compare "last" characters.
897 BEQ FOUND ; Matches even if dictionary actual length is shorter.
898 PFNDLN LDX ,X++ ; Get previous link in vocabulary.
899 BNE PFNDLP ; Continue if link not=0
902 LEAU 2,U ; Return only false flag.
907 PFNDCH CMPB ,Y+ ; Compare characters.
910 PFNDSC LDB ,X+ ; scan forward to end of this name in dictionary
925 * NOP ; Probably leftovers from a debugging session.
927 * PD EQU N ptr to dict word being checked
933 * PFIND0 PULS A ; loop to get arguments
940 * PFNDLP LDB 0,X get count dict count
946 * LDA 0,X get count from arg
948 * STX PA intialize PA
949 * PSHS B ; ** emulating CBA:
950 * CMPA ,S+ ; compare lengths
960 * TSTB ; is dict entry neg. ?
962 * ANDB #$7F clear sign
963 * PSHS B ; ** emulating CBA:
966 * PFNDLN LDX 0,X get new link
967 * BNE PFNDLP continue if link not=0
974 * PFNDCH PSHS B ; ** emulating CBA:
978 * PFNDSC LDB 0,X scan forward to end of this name
985 * FOUND LDA PD compute CFA
998 * PSHS A ; Left over from a stray copy-paste, I guess.
1004 * ######>> screen 20 <<
1006 * ( buffer ch --- buffer symboloffset delimiteroffset scancount )
1007 * ( buffer ch --- buffer symboloffset nuloffset scancount ) ( Scan count == nuloffset )
1008 * ( buffer ch --- buffer nuloffset onepast scancount )
1009 * Scan buffer for a symbol delimited by ch or ASCII NUL,
1010 * return the length of the buffer region scanned,
1011 * the offset to the trailing delimiter,
1012 * and the offset of the first character of the symbol.
1013 * Leave the buffer on the stack.
1014 * Scancount is also offset to first character not yet looked at.
1015 * If no symbol in buffer, scancount and symboloffset point to NUL
1016 * and delimiteroffset points one beyond for some reason.
1017 * On trailing NUL, delimiteroffset == scancount.
1018 * (Buffer is the address of the buffer array to scan.)
1019 * (This is a bit too tricky, really.)
1021 FCC 'ENCLOS' ; 'ENCLOSE'
1025 LDA 1,U ; Delimiter character to match against in A.
1026 LDX 2,U ; Buffer to scan in.
1027 CLRB ; Initialize offset. (Buffer < 256 wide!)
1028 * Scan to a non-delimiter or a NUL
1029 ENCDEL TST B,X ; NUL ?
1031 CMPA B,X ; Delimiter?
1033 INCB ; count character
1035 * Found first character. Save the offset.
1036 ENC1ST STB 1,U ; Found first non-delimiter character --
1037 CLR ,U ; store the count, zero high byte.
1038 * Scan to a delimiter or a NUL
1039 ENCSYM TST B,X ; NUL ?
1041 CMPA B,X ; delimiter?
1045 * Found end of symbol. Push offset to delimiter found.
1046 ENCEND CLRA ; high byte -- buffer < 255 wide!
1047 PSHU A,B ; Offset to seen delimiter.
1048 * Advance and push address of next character to check.
1049 ADDD #1 ; In case offset was 255.
1052 * Found NUL before non-delimiter, therefore there is no word
1053 ENCNUL CLRA ; high byte -- buffer < 255 wide!
1054 STD ,U ; offset to NUL.
1055 ADDD #1 ; For some reason, point after NUL.
1057 SUBD #1 ; Next is not passed NUL.
1058 PSHU A,B ; Stealing code will save only one byte.
1060 * Found NUL following the word instead of delimiter.
1061 ENC0TR PSHU A,B ; Save offset to first after symbol (NUL)
1062 PSHU A,B ; and count scanned.
1065 * FC means offset (bytes) to First Character of next word
1066 * EW " " to End of Word
1067 * NC " " to Next Character to start next enclose at
1068 * ENCLOS FDB *+NATWID
1070 * PULS B ; now, get the low byte, for an 8-bit delimiter
1074 * * wait for a non-delimiter or a NUL
1077 * PSHS B ; ** emulating CBA:
1078 * CMPA ,S+ ; CHECK FOR DELIM
1083 * * found first character. Push FC
1084 * ENC1ST LDA N found first char.
1088 * wait for a delimiter or a NUL
1091 * PSHS B ; ** emulating CBA:
1092 * CMPA ,S+ ; ckech for delim.
1097 * * found EW. Push it
1102 * * advance and push NC
1105 * found NUL before non-delimiter, therefore there is no word
1106 * ENCNUL LDB N found NUL
1110 * BRA ENC0TR+2 ; ********** POTENTIAL BUG HERE *******
1111 * ******** Should use labels in case opcodes change! ********
1112 * found NUL following the word instead of SPACE
1116 * ENCL8 LDB N save NC
1121 * ######>> screen 21 <<
1122 * The next 4 words call system dependant I/O routines
1123 * which are listed after word "-->" ( lable: "arrow" )
1124 * in the dictionary.
1128 * Write c to the output device (screen or printer).
1129 * ROM Uses the ECB device number at address $6F,
1130 * -2 is printer, 0 is screen.
1136 LBSR PEMIT ; PEMIT handles the stack.
1145 * INC XOUT+1-UORIG,X
1147 * ****WARNING**** HARD OFFSET: *+4 ****
1154 * Wait for a key from the keyboard.
1155 * If the key is BREAK, set the high byte (result $FF03).
1161 LBSR PKEY ; PKEY handles the stack.
1171 * Scan keyboard, but do not wait.
1172 * Return 0 if no key,
1173 * BREAK ($ff03) if BREAK is pressed,
1174 * or key currently pressed.
1176 FCC '?TERMINA' ; '?TERMINAL'
1180 LBSR PQTER ; PQTER handles the stack.
1184 * JMP PUSHBA stack the flag
1188 * EMIT a Carriage Return (ASCII CR).
1194 LBSR PCR ; PCR handles the stack.
1199 * ######>> screen 22 <<
1201 * ( source target count --- )
1202 * Copy/move count bytes from source to target.
1203 * Moves ascending addresses,
1204 * so that overlapping only works if the source is above the destination.
1206 FCC 'CMOV' ; 'CMOVE' : source, destination, count
1210 * One way: ; takes ( 37+17*count+9*(count/256) cycles )
1211 PSHS Y ; #2~7 ; Gotta have our pointers.
1213 PSHS A ; #2~6 ; Gotta have our pointers.
1224 * Another way ; takes ( 42+17*count+9*(count/256) cycles )
1226 * SUBD ,U++ ; #2~9 ; invert the count
1238 * PULS A,Y,PC ; #2~10
1239 * Yet another way ; takes ( 37+29*count cycles )
1254 * Yet another way ; takes ( 44+24*odd+33*count/2 cycles )
1277 * From the 6800 model:
1278 * CMOVE FDB *+2 takes ( 43+47*count cycles ) on 6800
1282 * STA 0,X move parameters to scratch area
1304 * ######>> screen 23 <<
1307 * Multiplies the top two unsigned integers,
1308 * yielding a double integer product.
1323 LDD 5,U ; first inner (u2 lo, u1 hi)
1329 LDA 4,U ; second inner (u2 hi)
1345 * The following is a subroutine which
1346 * multiplies top 2 words on stack,
1347 * leaving 32-bit result: high order word in A,B
1348 * low order word in 2nd word of stack.
1350 * USTARS LDA #16 bits/word counter
1355 * USTAR2 ROR 5,X shift multiplier
1363 * RORB ; shift result
1365 * USTAR4 LEAS 1,S ; dump counter
1368 * ######>> screen 24 <<
1370 * ( ud u --- uremainder uquotient )
1371 * Divides the top unsigned integer
1372 * into the second and third words on the stack
1373 * as a single unsigned double integer,
1374 * leaving the remainder and quotient (quotient on top)
1375 * as unsigned integers.
1377 * The smaller the divisor, the more likely dropping the high word
1378 * of the quotient loses significant bits.
1388 USLDIV CMPD ,U ; divisor
1390 ANDCC #~1 ; carry clear
1393 ORCC #1 ; quotient, (carry set)
1394 USLBIT ROL 5,U ; save it
1406 PULS A,PC ; Avoiding a LEAS 1,S by discarding A.
1417 * USL2 ANDCC #~$01 ; CLC :
1435 * JMP SWAP+4 reverse quotient & remainder
1437 * ######>> screen 25 <<
1440 * Bitwise and the top two integers.
1460 * Bitwise or the top two integers.
1480 * Bitwise exclusive or the top two integers.
1498 * ######>> screen 26 <<
1501 * Fetch the parameter stack pointer (before it is pushed).
1502 * This points at whatever was on the top of stack before.
1512 * STX N scratch area
1517 * ( whatever --- nothing )
1518 * Initialize the parameter stack pointer from the USER variable S0.
1519 * Effectively clears the stack.
1528 * LDX XSPZER-UORIG,X
1529 * TFR X,S ; TXS : watch it ! X and S are not equal on 6800.
1532 * ( whatever *** nothing )
1533 * Initialize the return stack pointer from the initialization table
1534 * instead of the user variable R0, for some reason.
1535 * Quite possibly, this should be from R0.
1536 * Effectively aborts all in process definitions, except the active one.
1537 * An emergency measure, to be sure.
1538 * The routine that calls this must never execute a return.
1539 * So this should never be executed from the terminal, I guess.
1540 * This is another that should be compile-time only, and in a separate vocabulary.
1546 PULS X ; But this guy has to return to his caller.
1549 * LDX RINIT initialize from rom constant
1555 * Pop IP from return stack (return from high-level definition).
1556 * Can be used in a screen to force interpretion to terminate.
1557 * Must not be executed when temporaries are saved on top of the return stack.
1564 TFR D,PC ; and discard X.
1569 * LDX 0,X get address we have just finished.
1570 * JMP NEXT+2 increment the return address & do next word
1572 * ######>> screen 27 <<
1574 * ( limit index *** index index )
1575 * Force the terminating condition for the innermost loop by
1576 * copying its index to its limit.
1577 * Termination is postponed until the next
1578 * LOOP or +LOOP instruction is executed.
1579 * The index remains available for use until
1580 * the LOOP or +LOOP instruction is encountered.
1581 * Note that the assumption is that the current count is the correct count
1582 * to end at, rather than pushing the count to the final count.
1584 FCC 'LEAV' ; 'LEAVE'
1588 LDD 2,S ; Dodge the return address.
1601 * Move top of parameter stack to top of return stack.
1609 STD ,S ; Put it where the return address was.
1624 * Move top of return stack to top of parameter stack.
1644 * Copy the top of return stack to top of parameter stack.
1656 * ######>> screen 28 <<
1659 * Logically invert top of stack;
1660 * or flag true if top is zero, otherwise false.
1678 *ZEQU2 TFR S,X ; TSX :
1683 * Flag true if top is negative (MSbit set), otherwise false.
1696 * LDA #$80 check the sign bit
1705 * ######>> screen 29 <<
1707 * ( n1 n2 --- n1+n2 )
1708 * Add top two words.
1725 * ( d1 d2 --- d1+d2 )
1726 * Add top two double integers.
1742 * ANDCC #~$01 ; CLC :
1758 * Negate (two's complement) top of stack.
1760 FCC 'MINU' ; 'MINUS'
1778 * Negate (two's complement) top two words on stack as a double integer.
1780 FCC 'DMINU' ; 'DMINUS'
1805 * ######>> screen 30 <<
1807 * ( n1 n2 --- n1 n2 n1 )
1808 * Push a copy of the second word on stack.
1824 * Discard the top word on stack.
1837 * ( n1 n2 --- n2 n1 )
1838 * Swap the top two words on stack.
1862 * Push a copy of the top word on stack.
1877 * ######>> screen 31 <<
1880 * Add the second word on stack to the word at the adr on top of stack.
1895 * PULS A ; get stack data
1897 * ADDB 1,X add & store low byte
1899 * ADCA 0,X add & store hi byte
1905 * Exclusive or byte at adr with low byte of top word.
1907 FCC 'TOGGL' ; 'TOGGLE'
1915 * Using the model code would be less likely to introduce bugs,
1916 * but that would sort-of defeat my purposes here.
1917 * Anyway, I can borrow from theoretically known good bif-6809 code
1918 * and it's fewer bytes and much faster code this way.
1920 * FDB DOCOL,OVER,CAT,XOR,SWAP,CSTORE
1923 * ######>> screen 32 <<
1926 * Replace address on stack with the word at the address.
1935 * LDX 0,X get address
1942 * Replace address on top of stack with the byte at the address.
1943 * High byte of result is clear.
1965 * Store second word on stack at address on top of stack.
1975 * LDX 0,X get address
1982 * Store low byte of second word on stack at address on top of stack.
1983 * High byte is ignored.
1994 * LDX 0,X get address
2003 * ######>> screen 33 <<
2006 * { : name sundry-activities ; } typical input
2007 * If executing (not compiling),
2008 * record the data stack mark in CSP,
2009 * Set the CONTEXT vocabulary to CURRENT,
2011 * set state to compile,
2012 * and compile the call to the trailing native CPU machine code DOCOL.
2013 * *** This would not be hard to flatten to native code. Maybe later.
2017 COLON FDB DOCOL,QEXEC,SCSP,CURENT,AT,CONTXT,STORE
2021 * Here is the IP pusher for allowing
2022 * nested words in the virtual machine:
2023 * ( ;S is the equivalent un-nester )
2026 * Characteristic of a colon (:) definition.
2027 * Begins execution of a high-level definition,
2028 * i. e., nests the definition and begins processing icodes.
2029 * Mechanically, it pushes the IP (Y register)
2030 * and loads the Parameter Field Address of the definition which
2031 * called it into the IP.
2032 DOCOL LDD ,S ; Save the return address.
2033 STY ,S ; Nest the old IP.
2034 LEAX 2,X ; W still in X, bump to parameter field.
2035 TFR X,Y ; Load the new IP.
2036 TFR D,PC ; synthetic return to interpret.
2038 * DOCOL LDX RP make room in the stack
2044 * STA 2,X Store address of the high level word
2045 * STB 3,X that we are starting to execute
2046 * LDX W Get first sub-word of that definition
2047 * JMP NEXT+2 and execute it
2051 * { : name sundry-activities ; } typical input
2052 * ERROR check data stack against mark in CSP,
2054 * unSMUDGE LATEST definition,
2055 * and set state to interpretation.
2056 FCB $C1 ; imnediate code
2059 SEMI FDB DOCOL,QCSP,COMPIL,SEMIS,SMUDGE,LBRAK
2062 * ######>> screen 34 <<
2065 * { value CONSTANT name } typical input
2068 * compile the constant value,
2069 * and compile the call to the trailing native CPU machine code DOCON.
2071 FCC 'CONSTAN' ; 'CONSTANT'
2074 CON FDB DOCOL,CREATE,SMUDGE,COMMA,PSCODE
2076 * Characteristic of a CONSTANT.
2077 * A CONSTANT simply loads its value from its parameter field
2078 * and pushes it on the stack.
2079 DOCON LDD 2,X ; Get the first natural width word of the parameter field.
2084 * LDB 3,X A & B now contain the constant
2089 * { init VARIABLE name } typical input
2090 * CREATE a header and compile the initial value, init, using CONSTANT,
2091 * overwrite the characteristic to point to DOVAR.
2093 FCC 'VARIABL' ; 'VARIABLE'
2096 VAR FDB DOCOL,CON,PSCODE
2098 * Characteristic of a VARIABLE.
2099 * A VARIABLE pushes its PFA address on the stack.
2100 * The parameter field of a VARIABLE is the actual allocation of the variable,
2101 * so that pushing its address allows its contents to be @ed (fetched).
2102 * Ordinary arrays and strings that do not subscript themselves
2103 * may be allocated by defining a variable
2104 * and immediately ALLOTting the remaining needed space.
2105 * VARIABLES are global to all users,
2106 * and thus should be hidden in resource monitors, but aren't.
2107 DOVAR LEAX 2,X ; Point to the first natural width word of the parameters.
2113 * ADCA #0 A,B now contain the address of the variable
2118 * { uboffset USER name } typical input
2119 * CREATE a header and compile the unsigned byte offset in the per-USER table,
2120 * then overwrite the header with a call to DOUSER.
2121 * The USER is entirely responsible for maintaining allocation!
2126 USER FDB DOCOL,CON,PSCODE
2128 * Characteristic of a per-USER variable.
2129 * USER variables are similiar to VARIABLEs,
2130 * but are allocated (by hand!) in the per-user table.
2131 * A USER variable's parameter field contains its offset in the per-user table.
2132 DOUSER TFR DP,A ; Make a pointer to the direct page.
2134 ADDD 2,X ; Add the offset to the per-user variable.
2137 * Hey, the per-user table could actually be larger than 256 bytes!
2138 * But we knew that. It's just not as esthetic to calculate it this way.
2140 * DOUSER LDX W get offset into user's table
2143 * ADDB UP+1 add to users base address
2145 * JMP PUSHBA push address of user's variable
2147 * ######>> screen 35 <<
2182 * ASCII SPACE character
2187 BL FDB DOCON ascii blank
2191 * This really shouldn't be a CONSTANT.
2193 * The base of the disk buffer space.
2195 FCC 'FIRS' ; 'FIRST'
2200 * FDB MEMEND-528 (132 * NBLK)
2203 * This really shouldn't be a CONSTANT.
2205 * The limit of the disk buffer space.
2207 FCC 'LIMI' ; 'LIMIT' : ( the end of memory +1 )
2215 * ( --- sectorsize )
2216 * The size, in bytes, of a buffer.
2218 FCC 'B/BU' ; 'B/BUF' : (bytes/buffer)
2226 * ( --- blocksperscreen )
2227 * The size, in blocks, of a screen.
2228 * Should this be the same as NBLK, the number of block buffers maintained?
2230 FCC 'B/SC' ; 'B/SCR' : (blocks/screen)
2236 * blocks/screen = 1024 / "B/BUF" = 8, if sectors are 128 bytes.
2240 * Calculate the address of entry (#n/2) in the boot-up parameter table.
2241 * (Adds the base of the boot-up table to n.)
2243 FCC '+ORIGI' ; '+ORIGIN'
2246 PORIG FDB DOCOL,LIT,ORIG,PLUS
2249 * ######>> screen 36 <<
2252 * This is the per-task variable recording the initial parameter stack pointer.
2262 * This is the per-task variable recording the initial return stack pointer.
2272 * Terminal Input Buffer address.
2273 * Note that this is a variable, so users may allocate their own buffers, but it must be @ed.
2282 * ( --- maxnamewidth )
2283 * This is the maximum width to which symbol names will be recorded.
2285 FCC 'WIDT' ; 'WIDTH'
2293 * Availability of error messages on disk.
2294 * Contains 1 if messages available,
2296 * -1 if a disk error has occurred.
2298 FCC 'WARNIN' ; 'WARNING'
2306 * Boundary for FORGET.
2308 FCC 'FENC' ; 'FENCE'
2316 * Dictionary pointer, fetched by HERE.
2318 FCC 'D' ; 'DP' : points to first free byte at end of dictionary
2325 * ( --- vadr ) ******* Need to check what this is!
2326 * Used in maintaining vocabularies.
2327 * I think it points to the "parent" vocabulary, but I'm not sure.
2329 FCC 'VOC-LIN' ; 'VOC-LINK'
2337 * Disk block being interpreted.
2338 * Zero refers to terminal.
2339 * ******** Should be made a 32 bit variable! ********
2340 * But the base system needs to have full 32 bit support, div and mul, etc.
2350 * Input buffer offset/cursor.
2352 FCC 'I' ; 'IN' : scan pointer for input line buffer
2360 * Output buffer offset/cursor.
2370 * Screen currently being edited, once we have an editor running.
2377 * ######>> screen 37 <<
2381 * Sector offset for LOADing screens,
2382 * set by DRIVE to make a new drive the default.
2383 * This should also be 32 bit or bigger.
2385 FCC 'OFFSE' ; 'OFFSET'
2393 * Current context of interpretation (vocabulary root).
2395 FCC 'CONTEX' ; 'CONTEXT' : points to pointer to vocab to search first
2403 * Current context of definition (vocabulary root).
2405 FCC 'CURREN' ; 'CURRENT' : points to ptr. to vocab being extended
2413 * Compiler/interpreter state.
2415 FCC 'STAT' ; 'STATE' : 1 if compiling, 0 if not
2423 * Numeric conversion base.
2425 FCC 'BAS' ; 'BASE' : number base for all input & output
2433 * Decimal point location for output.
2443 * Field width for I/O formatting.
2453 * Compiler stack mark for stack check.
2463 * Editing cursor location.
2473 * Pointer to last HELD character in PAD.
2481 * ======>> 82.5 <<== SPECIAL
2483 * Line width of active terminal.
2485 FCC 'COLUMN' ; 'COLUMNS' : line width of terminal
2491 * ######>> screen 38 <<
2492 ** Could make an incrementer compiling word:
2494 ** { n INCREMENTER name } typical input
2495 ** CREATE a header and compile the increment constant,
2496 ** then overwrite the header with a call to DOINC.
2498 * FCC 'INCREMENTE' ; INCREMENTER'
2501 * INCR FDB DOCOL,CON,PSCODE
2503 ** Characteristic of an INCREMENTER.
2505 * ADDD 2,X ; Add the increment.
2520 * ONEP FDB DOCOL,ONE,PLUS
2534 * TWOP FDB DOCOL,TWO,PLUS
2542 HERE FDB DOCOL,DICTPT,AT
2547 FCC 'ALLO' ; 'ALLOT'
2550 ALLOT FDB DOCOL,DICTPT,PSTORE
2557 COMMA FDB DOCOL,HERE,STORE,TWO,ALLOT
2565 CCOMM FDB DOCOL,HERE,CSTORE,ONE,ALLOT
2569 * ( n1 n2 --- n1-n2 )
2570 * Subtract top two words.
2579 * SUB FDB DOCOL,MINUS,PLUS
2580 * FDB SEMIS ; Costs 6 bytes and lots of cycles.
2586 EQUAL FDB DOCOL,SUB,ZEQU
2614 GREAT FDB DOCOL,SWAP,LESS
2622 ROT FDB DOCOL,TOR,SWAP,FROMR,SWAP
2627 FCC 'SPAC' ; 'SPACE'
2630 SPACE FDB DOCOL,BL,EMIT
2638 MIN FDB DOCOL,OVER,OVER,GREAT,ZBRAN
2649 MAX FDB DOCOL,OVER,OVER,LESS,ZBRAN
2660 DDUP FDB DOCOL,DUP,ZBRAN
2665 * ######>> screen 39 <<
2668 FCC 'TRAVERS' ; 'TRAVERSE'
2672 TRAV2 FDB OVER,PLUS,LIT8
2674 FDB OVER,CAT,LESS,ZBRAN
2681 FCC 'LATES' ; 'LATEST'
2684 LATEST FDB DOCOL,CURENT,AT,AT
2702 CFA FDB DOCOL,TWO,SUB
2712 FDB SUB,ONE,MINUS,TRAV
2720 PFA FDB DOCOL,ONE,TRAV,LIT8
2725 * ######>> screen 40 <<
2731 SCSP FDB DOCOL,SPAT,CSP,STORE
2736 FCC '?ERRO' ; '?ERROR'
2739 QERR FDB DOCOL,SWAP,ZBRAN
2748 FCC '?COM' ; '?COMP'
2751 QCOMP FDB DOCOL,STATE,AT,ZEQU,LIT8
2758 FCC '?EXE' ; '?EXEC'
2761 QEXEC FDB DOCOL,STATE,AT,LIT8
2768 FCC '?PAIR' ; '?PAIRS'
2771 QPAIRS FDB DOCOL,SUB,LIT8
2781 QCSP FDB DOCOL,SPAT,CSP,AT,SUB,LIT8
2788 FCC '?LOADIN' ; '?LOADING'
2791 QLOAD FDB DOCOL,BLK,AT,ZEQU,LIT8
2796 * ######>> screen 41 <<
2799 FCC 'COMPIL' ; 'COMPILE'
2802 COMPIL FDB DOCOL,QCOMP,FROMR,TWOP,DUP,TOR,AT,COMMA
2809 LBRAK FDB DOCOL,ZERO,STATE,STORE
2816 RBRAK FDB DOCOL,LIT8
2823 FCC 'SMUDG' ; 'SMUDGE'
2826 SMUDGE FDB DOCOL,LATEST,LIT8
2844 FCC 'DECIMA' ; 'DECIMAL'
2849 FCB 10 note: hex "A"
2853 * ######>> screen 42 <<
2856 FCC '(;CODE' ; '(;CODE)'
2859 PSCODE FDB DOCOL,FROMR,TWOP,LATEST,PFA,CFA,STORE
2864 FCC ';COD' ; ';CODE'
2867 SEMIC FDB DOCOL,QCSP,COMPIL,PSCODE,SMUDGE,LBRAK,QSTACK
2869 * note: "QSTACK" will be replaced by "ASSEMBLER" later
2871 * ######>> screen 43 <<
2874 FCC '<BUILD' ; '<BUILDS'
2877 BUILDS FDB DOCOL,ZERO,CON
2882 FCC 'DOES' ; 'DOES>'
2885 DOES FDB DOCOL,FROMR,TWOP,LATEST,PFA,STORE
2889 LDX RP make room on return stack
2893 STA 2,X push return address
2895 LDX W get addr of pointer to run-time code
2898 STX N stash it in scratch area
2901 CLRA ; get address of parameter
2905 PSHS B ; and push it on data stack
2909 * ######>> screen 44 <<
2912 FCC 'COUN' ; 'COUNT'
2915 COUNT FDB DOCOL,DUP,ONEP,SWAP,CAT
2923 TYPE FDB DOCOL,DDUP,ZBRAN
2925 FDB OVER,PLUS,SWAP,XDO
2926 TYPE2 FDB I,CAT,EMIT,XLOOP
2935 FCC '-TRAILIN' ; '-TRAILING'
2938 DTRAIL FDB DOCOL,DUP,ZERO,XDO
2939 DTRAL2 FDB OVER,OVER,PLUS,ONE,SUB,CAT,BL
2954 PDOTQ FDB DOCOL,R,TWOP,COUNT,DUP,ONEP
2955 FDB FROMR,PLUS,TOR,TYPE
2968 FDB COMPIL,PDOTQ,WORD
2969 FDB HERE,CAT,ONEP,ALLOT,BRAN
2971 DOTQ1 FDB WORD,HERE,COUNT,TYPE
2974 * ######>> screen 45 <<
2975 * ======>> 126 <<== MACHINE DEPENDENT
2977 FCC '?STAC' ; '?STACK'
2980 QSTACK FDB DOCOL,LIT8
2982 FDB PORIG,AT,TWO,SUB,SPAT,LESS,ONE
2984 * prints 'empty stack'
2987 * Here, we compare with a value at least 128
2988 * higher than dict. ptr. (DICTPT)
2995 * prints 'full stack'
2999 * ======>> 127 << this word's function
3000 * is done by ?STACK in this version
3005 *QFREE FDB DOCOL,SPAT,HERE,LIT8
3007 * FDB PLUS,LESS,TWO,QERR,SEMIS
3009 * ######>> screen 46 <<
3012 FCC 'EXPEC' ; 'EXPECT'
3015 EXPECT FDB DOCOL,OVER,PLUS,OVER,XDO
3016 EXPEC2 FDB KEY,DUP,LIT8
3018 FDB PORIG,AT,EQUAL,ZBRAN
3021 FCB 8 ( backspace character to emit )
3022 FDB OVER,I,EQUAL,DUP,FROMR,TWO,SUB,PLUS
3026 FCB $D ( carriage return )
3029 FDB LEAVE,DROP,BL,ZERO,BRAN
3032 EXPEC5 FDB I,CSTORE,ZERO,I,ONEP,STORE
3033 EXPEC6 FDB EMIT,XLOOP
3040 FCC 'QUER' ; 'QUERY'
3043 QUERY FDB DOCOL,TIB,AT,COLUMS
3044 FDB AT,EXPECT,ZERO,IN,STORE
3048 FCB $C1 immediate < carriage return >
3051 NULL FDB DOCOL,BLK,AT,ZBRAN
3054 FDB ZERO,IN,STORE,BLK,AT,BSCR,MOD
3056 * check for end of screen
3059 FDB QEXEC,FROMR,DROP
3062 NULL2 FDB FROMR,DROP
3065 * ######>> screen 47 <<
3071 FILL FDB DOCOL,SWAP,TOR,OVER,CSTORE,DUP,ONEP
3072 FDB FROMR,ONE,SUB,CMOVE
3077 FCC 'ERAS' ; 'ERASE'
3080 ERASE FDB DOCOL,ZERO,FILL
3085 FCC 'BLANK' ; 'BLANKS'
3088 BLANKS FDB DOCOL,BL,FILL
3096 HOLD FDB DOCOL,LIT,$FFFF,HLD,PSTORE,HLD,AT,CSTORE
3104 PAD FDB DOCOL,HERE,LIT8
3109 * ######>> screen 48 <<
3115 WORD FDB DOCOL,BLK,AT,ZBRAN
3117 FDB BLK,AT,BLOCK,BRAN
3120 WORD3 FDB IN,AT,PLUS,SWAP,ENCLOS,HERE,LIT8
3122 FDB BLANKS,IN,PSTORE,OVER,SUB,TOR,R,HERE
3123 FDB CSTORE,PLUS,HERE,ONEP,FROMR,CMOVE
3126 * ######>> screen 49 <<
3129 FCC '(NUMBER' ; '(NUMBER)'
3133 PNUMB2 FDB ONEP,DUP,TOR,CAT,BASE,AT,DIGIT,ZBRAN
3135 FDB SWAP,BASE,AT,USTAR,DROP,ROT,BASE
3136 FDB AT,USTAR,DPLUS,DPL,AT,ONEP,ZBRAN
3139 PNUMB3 FDB FROMR,BRAN
3146 FCC 'NUMBE' ; 'NUMBER'
3149 NUMB FDB DOCOL,ZERO,ZERO,ROT,DUP,ONEP,CAT,LIT8
3151 FDB EQUAL,DUP,TOR,PLUS,LIT,$FFFF
3152 NUMB1 FDB DPL,STORE,PNUMB,DUP,CAT,BL,SUB
3157 FDB SUB,ZERO,QERR,ZERO,BRAN
3159 NUMB2 FDB DROP,FROMR,ZBRAN
3166 FCC '-FIN' ; '-FIND'
3169 DFIND FDB DOCOL,BL,WORD,HERE,CONTXT,AT,AT
3170 FDB PFIND,DUP,ZEQU,ZBRAN
3172 FDB DROP,HERE,LATEST,PFIND
3175 * ######>> screen 50 <<
3178 FCC '(ABORT' ; '(ABORT)'
3181 PABORT FDB DOCOL,ABORT
3186 FCC 'ERRO' ; 'ERROR'
3189 ERROR FDB DOCOL,WARN,AT,ZLESS
3191 * note: WARNING is -1 to abort, 0 to print error #
3192 * and 1 to print error message from disc
3195 ERROR2 FDB HERE,COUNT,TYPE,PDOTQ
3198 FDB MESS,SPSTOR,IN,AT,BLK,AT,QUIT
3206 IDDOT FDB DOCOL,PAD,LIT8
3209 FCB $5F ( underline )
3210 FDB FILL,DUP,PFA,LFA,OVER,SUB,PAD
3211 FDB SWAP,CMOVE,PAD,COUNT,LIT8
3216 * ######>> screen 51 <<
3219 FCC 'CREAT' ; 'CREATE'
3222 CREATE FDB DOCOL,DFIND,ZBRAN
3231 CREAT2 FDB HERE,DUP,CAT,WIDTH,AT,MIN
3232 FDB ONEP,ALLOT,DUP,LIT8
3234 FDB TOGGLE,HERE,ONE,SUB,LIT8
3236 FDB TOGGLE,LATEST,COMMA,CURENT,AT,STORE
3240 * ######>> screen 52 <<
3243 FCC '[COMPILE' ; '[COMPILE]'
3246 BCOMP FDB DOCOL,DFIND,ZEQU,ZERO,QERR,DROP,CFA,COMMA
3251 FCC 'LITERA' ; 'LITERAL'
3254 LITER FDB DOCOL,STATE,AT,ZBRAN
3256 FDB COMPIL,LIT,COMMA
3261 FCC 'DLITERA' ; 'DLITERAL'
3264 DLITER FDB DOCOL,STATE,AT,ZBRAN
3266 FDB SWAP,LITER,LITER
3269 * ######>> screen 53 <<
3272 FCC 'INTERPRE' ; 'INTERPRET'
3276 INTER2 FDB DFIND,ZBRAN
3286 INTER5 FDB HERE,NUMB,DPL,AT,ONEP,ZBRAN
3290 INTER6 FDB DROP,LITER
3291 INTER7 FDB QSTACK,BRAN
3293 * FDB SEMIS never executed
3296 * ######>> screen 54 <<
3299 FCC 'IMMEDIAT' ; 'IMMEDIATE'
3302 IMMED FDB DOCOL,LATEST,LIT8
3309 FCC 'VOCABULAR' ; 'VOCABULARY'
3312 VOCAB FDB DOCOL,BUILDS,LIT,$81A0,COMMA,CURENT,AT,CFA
3313 FDB COMMA,HERE,VOCLIN,AT,COMMA,VOCLIN,STORE,DOES
3314 DOVOC FDB TWOP,CONTXT,STORE
3319 * Note: FORTH does not go here in the rom-able dictionary,
3320 * since FORTH is a type of variable.
3325 FCC 'DEFINITION' ; 'DEFINITIONS'
3328 DEFIN FDB DOCOL,CONTXT,AT,CURENT,STORE
3335 PAREN FDB DOCOL,LIT8
3340 * ######>> screen 55 <<
3346 QUIT FDB DOCOL,ZERO,BLK,STORE
3349 * Here is the outer interpretter
3350 * which gets a line of input, does it, prints " OK"
3352 QUIT2 FDB RPSTOR,CR,QUERY,INTERP,STATE,AT,ZEQU
3360 * FDB SEMIS ( never executed )
3364 FCC 'ABOR' ; 'ABORT'
3367 ABORT FDB DOCOL,SPSTOR,DEC,QSTACK,DRZERO,CR,PDOTQ
3372 * FDB SEMIS never executed
3375 * ######>> screen 56 <<
3376 * bootstrap code... moves rom contents to ram :
3383 CENT LDS #REND-1 top of destination
3384 LDX #ERAM top of stuff to move
3387 PSHS A ; move TASK & FORTH to ram
3391 LDS #XFENCE-1 put stack at a safe place for now
3404 WENT LDS #XFENCE-1 top of destination
3405 LDX #FENCIN top of stuff to move
3414 STX UP init user ram pointer
3417 NOP Here is a place to jump to special user
3418 NOP initializations such as I/0 interrups
3421 * For systems with TRACE:
3423 STX TRLIM clear trace mode
3425 STX BRKPT clear breakpoint address
3426 JMP RPSTOR+2 start the virtual machine running !
3428 * Here is the stuff that gets copied to ram :
3431 RAM FDB $3000,$3000,0,0
3435 FCC 'FORT' ; 'FORTH'
3438 RFORTH FDB DODOES,DOVOC,$81A0,TASK-7
3440 FCC "(C) Forth Interest Group, 1979"
3445 RTASK FDB DOCOL,SEMIS
3446 ERAM FCC "David Lion"
3449 * ######>> screen 57 <<
3455 STOD FDB DOCOL,DUP,ZLESS,MINUS
3478 SLMOD FDB DOCOL,TOR,STOD,FROMR,USLASH
3485 SLASH FDB DOCOL,SLMOD,SWAP,DROP
3493 MOD FDB DOCOL,SLMOD,DROP
3498 FCC '*/MO' ; '*/MOD'
3501 SSMOD FDB DOCOL,TOR,USTAR,FROMR,USLASH
3509 SSLASH FDB DOCOL,SSMOD,SWAP,DROP
3514 FCC 'M/MO' ; 'M/MOD'
3517 MSMOD FDB DOCOL,TOR,ZERO,R,USLASH
3518 FDB FROMR,SWAP,TOR,USLASH,FROMR
3526 ABS FDB DOCOL,DUP,ZLESS,ZBRAN
3536 DABS FDB DOCOL,DUP,ZLESS,ZBRAN
3541 * ######>> screen 58 <<
3564 FDB PLUS,DUP,LIMIT,EQUAL,ZBRAN
3567 PBUF2 FDB DUP,PREV,AT,SUB
3572 FCC 'UPDAT' ; 'UPDATE'
3575 UPDATE FDB DOCOL,PREV,AT,AT,LIT,$8000,OR,PREV,AT,STORE
3580 FCC 'EMPTY-BUFFER' ; 'EMPTY-BUFFERS'
3583 MTBUF FDB DOCOL,FIRST,LIMIT,OVER,SUB,ERASE
3591 DRZERO FDB DOCOL,ZERO,OFSET,STORE
3594 * ======>> 174 <<== system dependant word
3599 DRONE FDB DOCOL,LIT,$07D0,OFSET,STORE
3602 * ######>> screen 59 <<
3605 FCC 'BUFFE' ; 'BUFFER'
3608 BUFFER FDB DOCOL,USE,AT,DUP,TOR
3609 BUFFR2 FDB PBUF,ZBRAN
3611 FDB USE,STORE,R,AT,ZLESS
3614 FDB R,TWOP,R,AT,LIT,$7FFF,AND,ZERO,RW
3615 BUFFR3 FDB R,STORE,R,PREV,STORE,FROMR,TWOP
3618 * ######>> screen 60 <<
3621 FCC 'BLOC' ; 'BLOCK'
3624 BLOCK FDB DOCOL,OFSET,AT,PLUS,TOR
3625 FDB PREV,AT,DUP,AT,R,SUB,DUP,PLUS,ZBRAN
3627 BLOCK3 FDB PBUF,ZEQU,ZBRAN
3629 FDB DROP,R,BUFFER,DUP,R,ONE,RW,TWO,SUB
3630 BLOCK4 FDB DUP,AT,R,SUB,DUP,PLUS,ZEQU,ZBRAN
3633 BLOCK5 FDB FROMR,DROP,TWOP
3636 * ######>> screen 61 <<
3639 FCC '(LINE' ; '(LINE)'
3642 PLINE FDB DOCOL,TOR,LIT8
3644 FDB BBUF,SSMOD,FROMR,BSCR,STAR,PLUS,BLOCK,PLUS,LIT8
3650 FCC '.LIN' ; '.LINE'
3653 DLINE FDB DOCOL,PLINE,DTRAIL,TYPE
3658 FCC 'MESSAG' ; 'MESSAGE'
3661 MESS FDB DOCOL,WARN,AT,ZBRAN
3667 FDB OFSET,AT,BSCR,SLASH,SUB,DLINE,BRAN
3671 FCC 'err # ' ; 'err # '
3677 FCC 'LOA' ; 'LOAD' : input:scr #
3680 LOAD FDB DOCOL,BLK,AT,TOR,IN,AT,TOR,ZERO,IN,STORE
3681 FDB BSCR,STAR,BLK,STORE
3682 FDB INTERP,FROMR,IN,STORE,FROMR,BLK,STORE
3690 ARROW FDB DOCOL,QLOAD,ZERO,IN,STORE,BSCR
3691 FDB BLK,AT,OVER,MOD,SUB,BLK,PSTORE
3696 * ######>> screen 63 <<
3697 * The next 4 subroutines are machine dependent, and are
3698 * called by words 13 through 16 in the dictionary.
3700 * ======>> 182 << code for EMIT
3701 * output using rom CHROUT: redirectable to printer
3703 PEMITW TFR B,A ; Coco ROM wants it in A.
3704 PSHS Y,U,DP ; Save everything important!
3706 TFR B,DP ; Give the ROM it's direct page.
3707 JSR [$A002] ; Output the character in A.
3709 * PEMIT STB N save B
3712 * BITB #2 check ready bit
3713 * BEQ PEMIT+4 if not ready for more data
3716 * STB IOSTAT-UORIG,X
3717 * LDB N recover B & X
3719 * RTS only A register may change
3720 * PEMIT JMP $E1D1 for MIKBUG
3721 * PEMIT FCB $3F,$11,$39 for PROTO
3722 * PEMIT JMP $D286 for Smoke Signal DOS
3724 * ======>> 183 << code for KEY
3725 * wait for key from POLCAT
3727 LDA #$CF ; a cursor of sorts
3737 PKEYR CLRB ; for the break flag
3740 COMB ; for the break flag
3744 SETDP IUPDP ******** Check this when I get here again. *********
3749 * BCC PKEY+4 no incoming data yet
3751 * ANDA #$7F strip parity bit
3753 * STB IOSTAT+1-UORIG,X
3757 * PKEY JMP $E1AC for MIKBUG
3758 * PKEY FCB $3F,$14,$39 for PROTO
3759 * PKEY JMP $D289 for Smoke Signal DOS
3761 * ######>> screen 64 <<
3762 * ======>> 184 << code for ?TERMINAL
3763 * check break key using POLCAT
3767 JSR [$A000] ; Look but don't wait.
3769 * PQTER LDA ACIAC Test for 'break' condition
3770 * ANDA #$11 mask framing error bit and
3773 * LDA ACIAD clear input buffer
3780 * ======>> 185 << code for CR
3781 * For Coco just output a CR.
3784 * PCR LDA #$D carriage return
3790 * LDB XDELAY+1-UORIG,X
3792 * BMI PQTER2 return if minus
3793 * PSHS B ; save counter
3794 * BSR PEMIT print RUBOUTs to delay.....
3801 * ######>> screen 66 <<
3804 FCC '?DIS' ; '?DISC'
3810 * ######>> screen 67 <<
3813 FCC 'BLOCK-WRIT' ; 'BLOCK-WRITE'
3819 * ######>> screen 68 <<
3822 FCC 'BLOCK-REA' ; 'BLOCK-READ'
3828 *The next 3 words are written to create a substitute for disc
3829 * mass memory,located between $3210 & $3FFF in ram.
3836 FDB MEMEND a system dependent equate at front
3844 FDB MEMTOP ( $3FFF in this version )
3846 * ######>> screen 69 <<
3852 RW FDB DOCOL,TOR,BBUF,STAR,LO,PLUS,DUP,HI,GREAT,ZBRAN
3856 FCC ' Range ?' ; ' Range ?'
3864 * ######>> screen 72 <<
3869 TICK FDB DOCOL,DFIND,ZEQU,ZERO,QERR,DROP,LITER
3874 FCC 'FORGE' ; 'FORGET'
3877 FORGET FDB DOCOL,CURENT,AT,CONTXT,AT,SUB,LIT8
3879 FDB QERR,TICK,DUP,FENCE,AT,LESS,LIT8
3881 FDB QERR,DUP,ZERO,PORIG,GREAT,LIT8
3883 FDB QERR,DUP,NFA,DICTPT,STORE,LFA,AT,CONTXT,AT,STORE
3886 * ######>> screen 73 <<
3892 BACK FDB DOCOL,HERE,SUB,COMMA
3897 FCC 'BEGI' ; 'BEGIN'
3900 BEGIN FDB DOCOL,QCOMP,HERE,ONE
3905 FCC 'ENDI' ; 'ENDIF'
3908 ENDIF FDB DOCOL,QCOMP,TWO,QPAIRS,HERE
3909 FDB OVER,SUB,SWAP,STORE
3917 THEN FDB DOCOL,ENDIF
3925 DO FDB DOCOL,COMPIL,XDO,HERE,THREE
3933 LOOP FDB DOCOL,THREE,QPAIRS,COMPIL,XLOOP,BACK
3938 FCC '+LOO' ; '+LOOP'
3941 PLOOP FDB DOCOL,THREE,QPAIRS,COMPIL,XPLOOP,BACK
3946 FCC 'UNTI' ; 'UNTIL' : ( same as END )
3949 UNTIL FDB DOCOL,ONE,QPAIRS,COMPIL,ZBRAN,BACK
3952 * ######>> screen 74 <<
3963 FCC 'AGAI' ; 'AGAIN'
3966 AGAIN FDB DOCOL,ONE,QPAIRS,COMPIL,BRAN,BACK
3971 FCC 'REPEA' ; 'REPEAT'
3974 REPEAT FDB DOCOL,TOR,TOR,AGAIN,FROMR,FROMR
3983 IF FDB DOCOL,COMPIL,ZBRAN,HERE,ZERO,COMMA,TWO
3991 ELSE FDB DOCOL,TWO,QPAIRS,COMPIL,BRAN,HERE
3992 FDB ZERO,COMMA,SWAP,TWO,ENDIF,TWO
3997 FCC 'WHIL' ; 'WHILE'
4000 WHILE FDB DOCOL,IF,TWOP
4003 * ######>> screen 75 <<
4006 FCC 'SPACE' ; 'SPACES'
4009 SPACES FDB DOCOL,ZERO,MAX,DDUP,ZBRAN
4012 SPACE2 FDB SPACE,XLOOP
4021 BDIGS FDB DOCOL,PAD,HLD,STORE
4029 EDIGS FDB DOCOL,DROP,DROP,HLD,AT,PAD,OVER,SUB
4037 SIGN FDB DOCOL,ROT,ZLESS,ZBRAN
4048 DIG FDB DOCOL,BASE,AT,MSMOD,ROT,LIT8
4066 DIGS2 FDB DIG,OVER,OVER,OR,ZEQU,ZBRAN
4070 * ######>> screen 76 <<
4076 DOTR FDB DOCOL,TOR,STOD,FROMR,DDOTR
4084 DDOTR FDB DOCOL,TOR,SWAP,OVER,DABS,BDIGS,DIGS,SIGN
4085 FDB EDIGS,FROMR,OVER,SUB,SPACES,TYPE
4093 DDOT FDB DOCOL,ZERO,DDOTR,SPACE
4100 DOT FDB DOCOL,STOD,DDOT
4107 QUEST FDB DOCOL,AT,DOT
4110 * ######>> screen 77 <<
4116 LIST FDB DOCOL,DEC,CR,DUP,SCR,STORE,PDOTQ
4122 LIST2 FDB CR,I,THREE
4123 FDB DOTR,SPACE,I,SCR,AT,DLINE,XLOOP
4130 FCC 'INDE' ; 'INDEX'
4133 INDEX FDB DOCOL,CR,ONEP,SWAP,XDO
4134 INDEX2 FDB CR,I,THREE
4135 FDB DOTR,SPACE,ZERO,I,DLINE
4145 FCC 'TRIA' ; 'TRIAD'
4148 TRIAD FDB DOCOL,THREE,SLASH,THREE,STAR
4149 FDB THREE,OVER,PLUS,SWAP,XDO
4151 FDB LIST,QTERM,ZBRAN
4161 * ######>> screen 78 <<
4164 FCC 'VLIS' ; 'VLIST'
4167 VLIST FDB DOCOL,LIT8
4169 FDB OUT,STORE,CONTXT,AT,AT
4170 VLIST1 FDB OUT,AT,COLUMS,AT,LIT8
4174 FDB CR,ZERO,OUT,STORE
4175 VLIST2 FDB DUP,IDDOT,SPACE,SPACE,PFA,LFA,AT
4176 FDB DUP,ZEQU,QTERM,OR,ZBRAN
4186 NOOP FDB NEXT a useful no-op
4187 ZZZZ FDB 0,0,0,0,0,0,0,0 end of rom program
4190 * These things, up through the lable 'REND', are overwritten
4191 * at time of cold load and should have the same contents
4195 FCC 'FORT' ; 'FORTH'
4198 FORTH FDB DODOES,DOVOC,$81A0,TASK-7
4201 FCC "(C) Forth Interest Group, 1979"
4207 TASK FDB DOCOL,SEMIS
4209 REND EQU * ( first empty location in dictionary )