4 * ASSEMBLY SOURCE LISTING
8 * WITH COMPILER SECURITY
9 * AND VARIABLE LENGTH NAMES
10 * Returning to non-RTS mode
12 * Adapted by Joel Matthew Rees
13 * from fig-FORTH for 6800 by Dave Lion, et. al.
15 * This free/libre/open source publication is provided
16 * through the courtesy of:
21 * and other interested parties.
24 * P.O. Box 8231 - San Jose, CA 95155 - (408) 277-0668
25 * URL: http://www.forth.org
26 * Further distribution must include this notice.
28 NAM Copyright: FORTH Interest Group, original authors, and Joel Matthew Rees
30 * filename fig-forth-auto6809opt.asm
31 * === FORTH-6809 {date} {time}
34 * Permission is hereby granted, free of charge, to any person obtaining a copy
35 * of this software and associated documentation files (the "Software"), to deal
36 * in the Software without restriction, including without limitation the rights
37 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
38 * copies of the Software, and to permit persons to whom the Software is
39 * furnished to do so, subject to the following conditions:
41 * The above copyright notice and this permission notice shall be included in
42 * all copies or substantial portions of the Software.
44 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
45 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
46 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
47 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
48 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
49 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
52 * "Associated documentation" for this declaration of license
53 * shall be interpreted to include only the comments in this file,
54 * or, if the code is split into multiple files,
55 * all files containing the complete source.
57 * This is the MIT model license, as published by the Open Source Consortium,
58 * with associated documentation defined.
59 * It was chosen to reflect the spirit of the original
60 * terms of use, which used archaic legal terminology.
63 * Authors of the 6800 model:
64 * === Primary: Dave Lion,
68 * === The Forth Interest Group
70 * === San Carlos, CA 94070
72 * === Unbounded Computing
73 * === 1134-K Aster Ave.
74 * === Sunnyvale, CA 94086
76 NATWID EQU 2 ; bytes per natural integer/pointer
77 * The original version was developed on an AMI EVK 300 PROTO
78 * system using an ACIA for the I/O.
79 * This version is developed targeting the Tandy Color Computer.
82 * is done in three subroutines:
83 * PEMIT ( word # 182 )
87 * The FORTH words for disc related I/O follow the model
88 * of the FORTH Interest Group, but have not yet been
89 * tested using a real disc.
91 * Addresses in the 6800 implementation reflect the fact that,
92 * on the development system, it was convenient to
93 * write-protect memory at hex 1000, and leave the first
94 * 4K bytes write-enabled. As a consequence, code from
95 * location $1000 to lable ZZZZ could be put in ROM.
96 * Minor deviations from the model were made in the
97 * initialization and words ?STACK and FORGET
98 * in order to do this.
99 * Those deviations will be altered in this
100 * implementation for the 6809 -- Color Computer.
103 * MEMORY MAP for this 16K|32K system:
104 * ( delineated so that systems with 4k byte write-
105 * protected segments can write protect FORTH )
107 * addr. contents pointer init by
108 * **** ******************************* ******* ******
111 * ACIAC EQU $FBCE the ACIA control address and
112 * ACIAD EQU ACIAC+1 data address for PROTO
114 MEMT32 EQU $7FFF ; Theoretical absolute end of all ram
115 MEMT16 EQU $3FFF ; 16K is too tight until we no longer need disc emulation.
122 * substitute for disc mass memory
123 RAMSCR EQU 8 ; addresses calculate as 2 (Too much for 16K in RAM only.)
126 MASSLO EQU MASSHI-RAMSCR*SCRSZ+1
131 * "end" of "usable ram" (If disc mass memory emulation is removed, actual end.)
136 USERSZ EQU 256 ; (Addressable by DP, must be 256 on even boundary)
137 USER16 EQU 1 ; We can change these for ROMPACK or 64K.
138 USER32 EQU 2 ; maybe?
140 USERLO EQU MEMEND-USERSZ*USERCT
143 * user tables of variables
144 * registers & pointers for the virtual machine
145 * scratch area for potential use in something, maybe?
149 * This is a really awkward place to define the disk buffer records.
151 * 4 buffer sectors of VIRTUAL MEMORY
152 NBLK EQU 4 ; # of disc buffer blocks for virtual memory
153 * Should NBLK be SCRSZ/SECTSZ?
154 * each block is SECTSZ+SECTRL bytes in size,
155 * holding SECTSZ characters
157 SECTRL EQU 2*NATWID ; Currently held sector number, etc.
158 BUFSZ EQU (SECTSZ+SECTRL)*NBLK
159 BUFBAS EQU USERLO-BUFSZ
160 * *BUG* SECTRL is hard-wired into several definitions.
161 * It will take a bit of work to ferret them out.
162 * It is too small, and it should not be hard-wired.
163 * SECTSZ was also hard-wired into several definitions,
164 * will I find them all?
170 * Don't want one return too many to destroy the disc buffers.
173 * 32D8|71D8 <== RP RINIT
175 IRP EQU BUFBAS-RPBUMP
177 RSTK16 EQU $50*NATWID ; 80 max levels nesting calls
178 RSTK32 EQU $90*NATWID ; 144 max
183 SFTBND EQU IRP-RSTKSZ ; (false boundary between TIB and return stack)
185 * holds up to TIBSZ characters
186 * and is scanned upward by IN
189 ITIB EQU SFTBND-TIBSZ
191 * 3148|6FB8 <== IN TIB
193 * Don't want terminal input and parameter underflow collisions
198 * 3140|6FB0 <== SP SP0,SINIT
200 * | grows downward from 3140|6FB0
205 * I DICTIONARY grows upward
207 * >>>>>>--------Two words to start RAMmable dictionary--------<<<<<<
210 * ???? end of ram-dictionary. <== DICTPT DPINIT
213 * ???? "FORTH" ( a word ) <=, <== CONTEXT
215 * start of ram-dictionary.
217 * >>>>>> memory from here up must be in RAM area <<<<<<
220 * 6k of romable "FORTH" <== IP ABORT
222 * the VIRTUAL FORTH MACHINE
224 * 1208 initialization tables
225 * 1204 <<< WARM START ENTRY >>>
226 * 1200 <<< COLD START ENTRY >>>
227 * 1200 lowest address used by FORTH
232 * >>>>>> memory from here down left alone <<<<<<
233 * >>>>>> so we can safely call ROM routines <<<<<<
239 * CONVENTIONS USED IN THIS PROGRAM ARE AS FOLLOWS :
241 * IP (hardware Y) points to the current instruction ( pre-increment mode )
242 * RP (hardware S) points to last return address pushedin return stack
243 * SP (hardware U) points to last byte pushed in data stack
245 * Y must be IP when NEXT is entered (if using the inner loop).
247 * When A and B hold one 16 bit FORTH data word,
248 * A contains the high byte, B, the low byte.
250 * UP (hardware DP) is the base of per-task ("user") variables.
251 * (Be careful of the stray semantics of "user".)
253 * W (hardware X) is the pointer to the "code field" address of native CPU
254 * machine code to be executed for the definition of the dictionary word
255 * to be executed/currently executing.
256 * The following natural integer (word) begins any "parameter section"
257 * (body) -- similar to a "this" pointer, but not the same.
258 * It may be native CPU machine code, or it may be a global variable,
259 * or it may be a list of Forth definition words (addresses).
262 * This implementation uses the native subroutine architecture
263 * rather than a postponed-push call that the 6800 model VM uses
264 * to save code and time in leaf routines.
266 * This should allow directly calling many of the Forth words
267 * from assembly language code.
268 * (Be aware of the need for a valid W in some cases.)
269 * It won't allow mixing assembly language directly into Forth word lists.
273 * 0 is false, anything else is true.
274 * Most places in this model that set a boolean flag set true as 1.
275 * This is in contrast to many models that set a boolean flag as -1.
280 * This system is shown with one user (task),
281 * but additional users (tasks) may be added
282 * by allocating additional user tables:
286 UBASEX RMB USERSZ data table for extra users
288 * Some of this stuff gets initialized during
289 * COLD start and WARM start:
290 * [ names correspond to FORTH words of similar (no X) name ]
294 * A few useful VM variables
295 * Will be removed when they are no longer needed.
296 * All are replaced by 6809 registers.
298 N RMB 10 used as scratch by (FIND),ENCLOSE,CMOVE,EMIT,KEY,
299 * SP@,SWAP,DOES>,COLD
302 * These locations are used by the TRACE routine :
304 TRLIM RMB 1 the count for tracing without user intervention
305 TRACEM RMB 1 non-zero = trace mode
306 BRKPT RMB 2 the breakpoint address at which
307 * the program will go into trace mode
308 VECT RMB 2 vector to machine code
309 * (only needed if the TRACE routine is resident)
312 * Registers used by the FORTH virtual machine:
316 W RMB 2 the instruction register points to 6800 code
317 * This is not exactly accurate. Points to the definiton body,
318 * which is native CPU machine code when it is native CPU machine code.
319 * IP RMB 2 the instruction pointer points to pointer to 6800 code
320 * RP RMB 2 the return stack pointer
321 * UP RMB 2 the pointer to base of current user's 'USER' table
322 * ( altered during multi-tasking )
324 *UORIG RMB 6 3 reserved variables
325 RMB 6 3 reserved variables
326 XSPZER RMB 2 initial top of data stack for this user
327 XRZERO RMB 2 initial top of return stack
328 XTIB RMB 2 start of terminal input buffer
329 XWIDTH RMB 2 name field width
330 XWARN RMB 2 warning message mode (0 = no disc)
331 XFENCE RMB 2 fence for FORGET
332 XDICTP RMB 2 dictionary pointer
333 XVOCL RMB 2 vocabulary linking
334 XBLK RMB 2 disc block being accessed
335 XIN RMB 2 scan pointer into the block
336 XOUT RMB 2 cursor position
337 XSCR RMB 2 disc screen being accessed ( O=terminal )
338 XOFSET RMB 2 disc sector offset for multi-disc
339 XCONT RMB 2 last word in primary search vocabulary
340 XCURR RMB 2 last word in extensible vocabulary
341 XSTATE RMB 2 flag for 'interpret' or 'compile' modes
342 XBASE RMB 2 number base for I/O numeric conversion
343 XDPL RMB 2 decimal point place
345 XCSP RMB 2 current stack position, for compile checks
348 XDELAY RMB 2 carriage return delay count
349 XCOLUM RMB 2 carriage width
350 IOSTAT RMB 2 last acia status from write/read
361 * end of user table, start of common system variables
364 * These need to be moved to where they will be
365 * initialized globals in variable space, not in the USER table.
366 * Or, more accurately, need to be turned into monitored or semaphored resources.
372 * The FORTH program ( address $1200 to about $27FF ) will be written
373 * so that it can be in a ROM, or write-protected if desired,
374 * but right now we're just getting it running.
377 * ######>> screen 3 <<
379 ***************************
380 ** C O L D E N T R Y **
381 ***************************
385 ***************************
386 ** W A R M E N T R Y **
387 ***************************
389 * JMP WENT warm-start code, keeps current dictionary intact
390 LBRA WENT warm-start code, keeps current dictionary intact
394 ******* startup parmeters **************************
396 FDB $6809,0000 cpu & revision
397 FDB 0 topmost word in FORTH vocabulary
398 * BACKSP FDB $7F backspace character for editing
399 BACKSP FDB $08 backspace character for editing
400 UPINIT FDB UORIG initial user area
401 * UPINIT FDB UORIG initial user area
402 SINIT FDB ISP ; initial top of data stack
403 * SINIT FDB ORIG-$D0 initial top of data stack
404 RINIT FDB IRP ; initial top of return stack
405 * RINIT FDB ORIG-2 initial top of return stack
406 FDB ITIB ; terminal input buffer
407 * FDB ORIG-$D0 terminal input buffer
408 FDB 31 initial name field width
409 FDB 0 initial warning mode (0 = no disc)
410 FENCIN FDB REND initial fence
411 DPINIT FDB REND cold start value for DICTPT
412 BUFINT FDB BUFBAS Start of the disk buffers area
413 VOCINT FDB FORTH+4*NATWID
414 COLINT FDB TIBSZ initial terminal carriage width
415 DELINT FDB 4 initial carriage return delay
416 ****************************************************
420 * ######>> screen 13 <<
421 * These were of questionable use anyway,
422 * kept here now to satisfy the assembler and show hints.
423 * They're too much trouble to use with native subroutine call anyway.
424 * PULABX PULS A ; 24 cycles until 'NEXT'
426 * PULABX PULU A,B ; ?? cycles until 'NEXT'
427 * STABX STA 0,X 16 cycles until 'NEXT'
429 * STABX STD 0,X ; ?? cycles until 'NEXT'
431 * GETX LDA 0,X 18 cycles until 'NEXT'
433 * GETX LDD 0,X ?? cycles until 'NEXT'
434 * PUSHBA PSHS B ; 8 cycles until 'NEXT'
436 * PUSHBA PSHU A,B ; ?? cycles until 'NEXT'
440 * "NEXT" takes ?? cycles if TRACE is removed,
442 * and ?? cycles if trace is present and NOT tracing.
444 * = = = = = = = t h e v i r t u a l m a c h i n e = = = = =
446 * NEXT itself might just completely go away.
447 * About the only reason to keep it is to allowing executing a list
448 * which allows a cheap TRACE routine.
450 * NEXT is a loop which implements the Forth VM.
451 * It basically cycles through calling the code out of code lists,
453 * Using a native CPU return for this uses a few extra cycles per call,
454 * compared to simply jumping to each definition and jumping back
455 * to the known beginning of the loop,
456 * but the loop itself is really only there for convenience.
458 * This implementation uses the native subroutine call,
459 * to break the wall between Forth code and non-Forth code.
462 * LEAX 1,X ; pre-increment mode
465 NEXT ; IP is Y, push before using, pull before you come back here.
467 * NEXT2 LDX 0,X get W which points to CFA of word to be done
468 NEXT2 LDX ,Y++ get W which points to CFA of word to be done
471 * But NEXT2 is too much trouble to use with subroutine threading anyway.
473 NEXT3 ; W is X until you use X for something else. (TOS points back here.)
474 * But NEXT3 is too much trouble to use with subroutine threading anyway.
475 * LDX 0,X get VECT which points to executable code
477 * The next instruction could be patched to JMP TRACE =
478 * if a TRACE routine is available: =
482 JMP [,X] ; Saving the postinc cycles,
483 * ; but X must be bumped NATWID to the parameters.
485 * JMP TRACE ( an alternate for the above )
486 * BSR DBGREG ( an alternate for the above )
487 * In other words, with the call and the NOP,
488 * there is room to patch the call with a JMP to your TRACE
489 * routine, which you have to provide.
511 DBGNrt PULS CC,D,X,Y,PC
522 ADDB #$C7 ; ($40-$39)-$40
539 DBGREG PSHS U,Y,X,DP,B,A,CC
554 LDD 3*NATWID+4,S ; PC:505
561 LDD 2*NATWID+4,S ; U:50E
565 LDD 1*NATWID+4,S ; Y:513
567 LDD 0*NATWID+4,S ; X at 517
579 LDD [3*NATWID+4,S] ; PC
585 LDD [2*NATWID+4,S] ; U
589 LDD [1*NATWID+4,S] ; Y
591 LDD [0*NATWID+4,S] ; X
664 DBGRdU LDY 2*NATWID+4,S
674 DBGRrt PULS CC,A,B,DP,X,Y,U,PC
675 DBGRLB FCC 'DPCC PC S U Y X A B '
681 * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
688 * Pushes the following natural width integer from the instruction stream
689 * as a literal, or immediate value.
694 * FDB LITERAL-TO-BE-PUSHED
697 * In native processor code, there should be a better way, use that instead.
698 * More specifically, DO NOT CALL THIS from assembly language code.
699 * (Note that there is no compile-only flag in the fig model.)
701 * See (FIND), or PFIND , for layout of the header format.
704 FCC 'LI' ; 'LIT' : NOTE: this is different from LITERAL
705 FCB $D4 ; 'T'|'\x80' ; character code for T, with high bit set.
706 FDB 0 ; link of zero to terminate dictionary scan
707 LIT FDB *+NATWID ; Note also that LIT is meaningless in native code.
719 * ######>> screen 14 <<
722 * Pushes the following byte from the instruction stream
723 * as a literal, or immediate value.
728 * FCB LITERAL-TO-BE-PUSHED
731 * If this is kept, it should have a header for TRACE to read.
732 * If the data bus is wider than a byte, you don't want to do this.
733 * Byte shaving like this is often counter-productive anyway.
734 * Changing the name to LIT8, hoping that will be more understandable.
735 * Also, see comments for LIT.
736 * (Note that there is no compile-only flag in the fig model.)
738 FCC 'LIT' ; 'LIT8' : NOTE: this is different from LITERAL
741 LIT8 FDB *+NATWID (this was an invisible word, with no header)
742 LDB ,Y+ ; This also is meaningless in native code.
754 * off is offset in video buffer area.
756 FCC 'SHOWTO' ; 'SHOWTOS'
785 * Jump to address on stack. Used by the "outer" interpreter to
786 * interactively invoke routines.
787 * Might be useful to have EXECUTE test the pointer, as done in BIF-6809.
789 FCC 'EXECUT' ; 'EXECUTE'
793 PULU X ; Gotta have W anyway, just in case.
794 JMP [,X] ; Tail return.
796 * LDX 0,X get code field address (CFA)
797 * LEAS 1,S ; pop stack
801 * ######>> screen 15 <<
804 * Add the following word from the instruction stream to the
805 * instruction pointer (Y++). Causes a program branch in Forth code stream.
807 * In native processor code, there should be a better way, use that instead.
808 * More specifically, DO NOT CALL THIS from assembly language code.
809 * This is only for Forth code stream.
810 * Also, see comments for LIT.
812 FCC 'BRANC' ; 'BRANCH'
815 BRAN FDB ZBYES ; Go steal code in ZBRANCH
817 * Moving code around to optimize the branch taking case in 0BRANCH.
818 ZBNO LEAY NATWID,Y ; No branch.
822 * BRANCH if flag is zero.
824 * In native processor code, there should be a better way, use that instead.
825 * More specifically, DO NOT CALL THIS from assembly language code.
826 * This is only for Forth code stream.
827 * Also, see comments for LIT.
829 FCC '0BRANC' ; '0BRANCH'
836 LEAY D,Y ; IP is postinc
840 * PSHS B ; ** emulating ABA:
844 * ZBYES LDX IP Note: code is shared with BRANCH, (+LOOP), (LOOP)
852 * ZBNO LDX IP no branch. This code is shared with (+LOOP), (LOOP).
853 * LEAX 1,X ; jump over branch delta
858 * ######>> screen 16 <<
860 ******* Continue from the LOOP variables ********
864 * ( --- ) ( limit index *** limit index+1) C
865 * ( limit index *** )
866 * Counting loop primitive. The counter and limit are the top two
867 * words on the return stack. If the updated index/counter does
868 * not exceed the limit, a branch occurs. If it does, the branch
869 * does not occur, and the index and limit are dropped from the
872 * In native processor code, there should be a better way, use that instead.
873 * More specifically, DO NOT CALL THIS from assembly language code.
874 * This is only for Forth code stream.
875 * Also, see comments for LIT.
877 FCC '(LOOP' ; '(LOOP)'
881 LDD #1 ; Borrowing from BIF-6809.
882 XLOOPA ADDD ,S ; No return address to dodge.
885 BMI ZBYES ; pseudo-signed-unsigned
887 LEAS 2*NATWID,S ; Clean up the index and limit.
890 * LDB #1 get set to increment counter by 1 (Clears N.)
891 * BRA XPLOP2 go steal other guy's code!
894 * ( n --- ) ( limit index *** limit index+n ) C
895 * ( limit index *** )
896 * Loop with a variable increment. Terminates when the index
897 * crosses the boundary from one below the limit to the limit. A
898 * positive n will cause termination if the result index equals the
899 * limit. A negative n must cause the index to become less than
900 * the limit to cause loop termination.
902 * Note that the end conditions are not symmetric around zero.
904 * In native processor code, there should be a better way, use that instead.
905 * More specifically, DO NOT CALL THIS from assembly language code.
906 * This is only for Forth code stream.
907 * Also, see comments for LIT.
909 FCC '(+LOOP' ; '(+LOOP)'
912 XPLOOP FDB *+NATWID ; Borrowing from BIF-6809.
914 BPL XLOOPA ; Steal plain loop code for forward count.
915 ADDD ,S ; No return address to dodge
918 BPL ZBYES ; pseudo-signed-unsigned
919 BRA XLOOPN ; This path might be less time-sensitive.
921 * This should work, but I want to use tested code.
922 * PULU A,B ; Get the increment.
923 * XPLOP2 PULS X ; Pre-clear the return stack.
924 * PSHU A ; Save the direction in high bit.
927 * SUBD NATWID,S ; Check limit.
929 ** I think this should work:
930 * EORA ,U+ ; dir < 0 and (count - limit) >= 0
931 * BPL XPLONO ; or dir >= 0 and (count - limit) < 0
933 * LEAY D,Y ; IP is postinc
935 * XPLONO LEAS 2*NATWID,S
936 * JMP ,X ; synthetic return
938 * This definitely should work:
939 * TST ,U+ ; Get the sign
944 * LEAY D,Y ; IP is postinc
946 * XPLOF CMPD NATWID,S
948 * XPLONO LEAS 2*NATWID,S
949 * JMP ,X ; synthetic return
951 * 6800 Probably could have used the exclusive-or method, too.:
952 * PULS A ; get increment
955 * BPL XPLOF forward looping
961 * BRA XPLONO fall through
965 * ADDB 3,X add it to counter
967 * STB 3,X store new counter value
976 * XPLONO LEAX 1,X ; done, don't branch back
981 * BRA ZBNO use ZBRAN to skip over unused delta
983 * ######>> screen 17 <<
985 * ( limit index --- ) ( *** limit index )
986 * Move the loop parameters to the return stack. Synonym for D>R.
991 XDO FDB *+NATWID This is the RUNTIME DO, not the COMPILING DO
993 PSHS D,X ; Ends up same order.
994 LBRA NEXT ; No return address to mess with.
1013 * ( --- index ) ( limit index *** limit index )
1014 * Copy the loop index from the return stack. Synonym for R.
1019 LDD ,S ; No return address to dodge.
1027 * ######>> screen 18 <<
1029 * ( c base --- false )
1030 * ( c base --- n true )
1031 * Translate C in base, yielding a translation valid flag. If the
1032 * translation is not valid in the specified base, only the false
1035 FCC 'DIGI' ; 'DIGIT'
1038 DIGIT FDB *+NATWID NOTE: legal input range is 0-9, A-Z
1039 LDD NATWID,U ; Check the whole thing.
1040 SUBD #$30 ; ascii zero
1041 BMI DIGIT2 IF LESS THAN '0', ILLEGAL
1043 BMI DIGIT0 IF '9' OR LESS
1045 BMI DIGIT2 if less than 'A'
1047 BPL DIGIT2 if greater than 'Z'
1048 SUBD #7 translate 'A' thru 'F'
1049 DIGIT0 CMPD ,U ; Check the base.
1050 BPL DIGIT2 if not less than the base
1051 STD NATWID,U ; Store converted digit. (High byte known zero.)
1052 LDD #1 ; set valid flag
1053 DIGIT1 STD ,U ; store the flag
1055 DIGIT2 LDD #0 ; set not valid flag
1056 LEAU NATWID,U ; pop base
1060 * SUBA #$30 ascii zero
1061 * BMI DIGIT2 IF LESS THAN '0', ILLEGAL
1063 * BMI DIGIT0 IF '9' OR LESS
1065 * BMI DIGIT2 if less than 'A'
1067 * BPL DIGIT2 if greater than 'Z'
1068 * SUBA #7 translate 'A' thru 'F'
1070 * BPL DIGIT2 if not less than the base
1072 * STA 3,X store digit
1073 * DIGIT1 STB 1,X store the flag
1077 * LEAS 1,S ; pop bottom number
1079 * STB 0,X make sure both bytes are 00
1082 * ######>> screen 19 <<
1084 * The word definition format in the dictionary:
1086 * (Symbol names are bracketed by bytes with the high bit set, rather than linked.)
1088 * NFA (name field address):
1089 * char-count + $80 Length of symbol name, flagged with high bit set.
1090 * char 1 Characters of symbol name.
1093 * char n + $80 symbol termination flag (char set < 128 code points)
1094 * LFA (link field address):
1095 * link high byte \___pointer to previous word in list
1096 * link low byte / -- Combined allocation/dictionary list. --
1097 * CFA (code field address):
1098 * CFA high byte \___pointer to native CPU machine code
1099 * CFA low byte / -- Consider this the characteristic code. --
1100 * PFA (parameter field address):
1101 * parameter fields -- Machine code for low-level native machine CPU code,
1102 * " instruction list for high-level Forth code,
1103 * " constant data for constants, pointers to per task variables,
1104 * " space for variables, for global variables, etc.
1106 * In the case of native CPU machine code, the address at CFA will be PFA.
1108 * Definition attributes:
1109 FIMMED EQU $40 ; Immediate word flag.
1110 FSMUDG EQU $20 ; Smudged => definition not ready.
1111 CTMASK EQU ($FF&(^($80|FIMMED))) ; For unmasking the length byte.
1112 * Note that the SMUDGE bit is not masked out.
1114 * But we really want more (Thinking for a new model, need one more byte):
1115 * FCOMPI EQU $10 ; Compile-time-only.
1116 * FASSEM EQU $08 ; Assembly-language code only.
1117 * F4THLV EQU $04 ; Must not be called from assembly language code.
1118 * These would require some significant adjustments to the model.
1119 * We also want to put the low-level VM stuff in its own vocabulary.
1122 * (FIND) ( name vocptr --- locptr length true )
1123 * ( name vocptr --- false )
1124 * Search vocabulary for a symbol called name.
1125 * name is a pointer to a high-bit bracket string with length head.
1126 * vocptr is a pointer to the NFA of the tail-end (LATEST) definition
1127 * in the vocabulary to be searched.
1128 * Hidden (SMUDGEd) definitions are lexically not equal to their name strings.
1130 FCC '(FIND' ; '(FIND)'
1134 PSHS Y ; Have to track two pointers.
1135 * Use the stack and registers instead of temp area N.
1136 PA0 EQU NATWID ; pointer to the length byte of name being searched against
1137 PD EQU 0 ; pointer to NFA of dict word being checked
1141 LDX PD,U ; Start in on the vocabulary (NFA).
1142 PFNDLP LDY PA0,U ; Point to the name to check against.
1143 LDB ,X+ ; get dict name length byte
1144 TFR B,A ; Save it in case it matches.
1147 CMPB ,Y+ ; Compare lengths
1151 TSTB ; ; Is high bit of character in dictionary entry set?
1155 ANDB #$7F ; Clear high bit from dictionary.
1156 CMPB ,Y+ ; Compare "last" characters.
1158 BEQ FOUND ; Matches even if dictionary actual length is shorter.
1159 PFNDLN LDX ,X++ ; Get previous link in vocabulary.
1161 BNE PFNDLP ; Continue if link not=0
1164 LEAU NATWID,U ; Return only false flag.
1172 PFNDCH CMPB ,Y+ ; Compare characters.
1176 PFNDSC LDB ,X+ ; scan forward to end of this name in dictionary
1184 FOUND LEAX 2*NATWID,X
1199 * NOP ; Probably leftovers from a debugging session.
1201 * PD EQU N ptr to dict word being checked
1207 * PFIND0 PULS A ; loop to get arguments
1214 * PFNDLP LDB 0,X get count dict count
1220 * LDA 0,X get count from arg
1222 * STX PA intialize PA
1223 * PSHS B ; ** emulating CBA:
1224 * CMPA ,S+ ; compare lengths
1234 * TSTB ; is dict entry neg. ?
1236 * ANDB #$7F clear sign
1237 * PSHS B ; ** emulating CBA:
1240 * PFNDLN LDX 0,X get new link
1241 * BNE PFNDLP continue if link not=0
1248 * PFNDCH PSHS B ; ** emulating CBA:
1252 * PFNDSC LDB 0,X scan forward to end of this name
1259 * FOUND LDA PD compute CFA
1272 * PSHS A ; Left over from a stray copy-paste, I guess.
1278 * ######>> screen 20 <<
1280 * ( buffer ch --- buffer symboloffset delimiteroffset scancount )
1281 * ( buffer ch --- buffer symboloffset nuloffset scancount ) ( Scan count == nuloffset )
1282 * ( buffer ch --- buffer nuloffset onepast scancount )
1283 * Scan buffer for a symbol delimited by ch or ASCII NUL,
1284 * return the length of the buffer region scanned,
1285 * the offset to the trailing delimiter,
1286 * and the offset of the first character of the symbol.
1287 * Leave the buffer on the stack.
1288 * Scancount is also offset to first character not yet looked at.
1289 * If no symbol in buffer, scancount and symboloffset point to NUL
1290 * and delimiteroffset points one beyond for some reason.
1291 * On trailing NUL, delimiteroffset == scancount.
1292 * (Buffer is the address of the buffer array to scan.)
1293 * (This is a bit too tricky, really.)
1295 FCC 'ENCLOS' ; 'ENCLOSE'
1299 LDA 1,U ; Delimiter character to match against in A.
1300 LDX NATWID,U ; Buffer to scan in.
1301 CLRB ; Initialize offset. (Buffer < 256 wide!)
1302 * Scan to a non-delimiter or a NUL
1303 ENCDEL TST B,X ; NUL ?
1305 CMPA B,X ; Delimiter?
1307 INCB ; count character
1309 * Found first character. Save the offset.
1310 ENC1ST STB 1,U ; Found first non-delimiter character --
1311 CLR ,U ; store the count, zero high byte.
1312 * Scan to a delimiter or a NUL
1313 ENCSYM TST B,X ; NUL ?
1315 CMPA B,X ; delimiter?
1319 * Found end of symbol. Push offset to delimiter found.
1320 ENCEND CLRA ; high byte -- buffer < 255 wide!
1321 PSHU A,B ; Offset to seen delimiter.
1322 * Advance and push address of next character to check.
1323 ADDD #1 ; In case offset was 255.
1326 * Found NUL before non-delimiter, therefore there is no word
1327 ENCNUL CLRA ; high byte -- buffer < 255 wide!
1328 STD ,U ; offset to NUL.
1329 ADDD #1 ; Point after NUL to allow (FIND) to match it.
1331 SUBD #1 ; Next is not passed NUL.
1332 PSHU A,B ; Stealing code will save only one byte.
1334 * Found NUL following the word instead of delimiter.
1339 PSHU A,B ; Save offset to first after symbol (NUL)
1341 PSHU A,B ; and count scanned.
1346 * FC means offset (bytes) to First Character of next word
1347 * EW " " to End of Word
1348 * NC " " to Next Character to start next enclose at
1349 * ENCLOS FDB *+NATWID
1351 * PULS B ; now, get the low byte, for an 8-bit delimiter
1355 * * wait for a non-delimiter or a NUL
1358 * PSHS B ; ** emulating CBA:
1359 * CMPA ,S+ ; CHECK FOR DELIM
1364 * * found first character. Push FC
1365 * ENC1ST LDA N found first char.
1369 * wait for a delimiter or a NUL
1372 * PSHS B ; ** emulating CBA:
1373 * CMPA ,S+ ; ckech for delim.
1378 * * found EW. Push it
1383 * * advance and push NC
1386 * found NUL before non-delimiter, therefore there is no word
1387 * ENCNUL LDB N found NUL
1391 * BRA ENC0TR+2 ; ********** POTENTIAL BUG HERE *******
1392 * ******** Should use labels in case opcodes change! ********
1393 * found NUL following the word instead of SPACE
1397 * ENCL8 LDB N save NC
1402 * ######>> screen 21 <<
1403 * The next 4 words call system dependant I/O routines
1404 * which are listed after word "-->" ( lable: "arrow" )
1405 * in the dictionary.
1409 * Write c to the output device (screen or printer).
1410 * ROM Uses the ECB device number at address $6F,
1411 * -2 is printer, 0 is screen.
1418 LBSR PEMIT ; PEMIT expects the character in D.
1427 * INC XOUT+1-UORIG,X
1429 * ****WARNING**** HARD OFFSET: *+4 ****
1436 * Wait for a key from the keyboard.
1437 * If the key is BREAK, set the high byte (result $FF03).
1443 LBSR PKEY ; PKEY leaves the key/break code in D.
1454 * Scan keyboard, but do not wait.
1455 * Return 0 if no key,
1456 * BREAK ($ff03) if BREAK is pressed,
1457 * or key currently pressed.
1459 FCC '?TERMINA' ; '?TERMINAL'
1463 LBSR PQTER ; PQTER leaves the flag/key in D.
1468 * JMP PUSHBA stack the flag
1472 * EMIT a Carriage Return (ASCII CR).
1479 LBSR PCR ; Nothing really to do here.
1484 * ######>> screen 22 <<
1486 * ( source target count --- )
1487 * Copy/move count bytes from source to target.
1488 * Moves ascending addresses,
1489 * so that overlapping only works if the source is above the destination.
1491 FCC 'CMOV' ; 'CMOVE' : source, destination, count
1495 * Another way ; takes ( 42+17*count+9*(count/256) cycles )
1497 SUBD ,U++ ; #2~9 ; invert the count
1508 CMOVEX PULS A,Y ; #2~8
1530 * One way: ; takes ( 37+17*count+9*(count/256) cycles )
1531 * PSHS Y ; #2~7 ; Gotta have our pointers.
1534 * PULU D,X,Y ; #2~11
1535 * PSHS A ; #2~6 ; Gotta have our pointers.
1546 * BPL CMOVLP ; #2~3 ; If this actually works, it is limited to 32k here.
1550 * Yet another way ; takes ( 37+29*count cycles )
1552 * LDX NATWID,U ; #2~6
1553 * LDY NATWID,U ; #3~7
1563 * LEAU 3*NATWID,U ; #2~5
1566 * Yet another way ; takes ( 44+24*odd+33*count/2 cycles )
1568 * LDX NATWID,U ; #2~6
1569 * LDY 2*NATWID,U ; #3~7
1587 * LEAU 3*NATWID,U ; #2~5
1590 * From the 6800 model:
1591 * CMOVE FDB *+2 takes ( 43+47*count cycles ) on 6800
1595 * STA 0,X move parameters to scratch area
1617 * ######>> screen 23 <<
1620 * Multiplies the top two unsigned integers,
1621 * yielding a double integer product.
1622 * Significantly faster than a bit method.
1629 LDA 2*NATWID+1,U ; least
1633 LDA 2*NATWID,U ; most
1637 LDD 2*NATWID+1,U ; first inner (u2 lo, u1 hi)
1643 LDA 2*NATWID,U ; second inner (u2 hi)
1644 LDB 3*NATWID,U ; (u1 lo)
1661 * The following is a subroutine which
1662 * multiplies top 2 words on stack,
1663 * leaving 32-bit result: high order word in A,B
1664 * low order word in 2nd word of stack.
1667 * USTARS LDA #16 bits/word counter
1670 * USTAR2 ROR 2,U shift multiplier
1677 * RORB ; shift result
1679 * USTAR4 LEAS 1,S ; dump counter
1682 * From the 6800 model:
1683 * USTARS LDA #16 bits/word counter
1688 * USTAR2 ROR 5,X shift multiplier
1696 * RORB ; shift result
1698 * USTAR4 LEAS 1,S ; dump counter
1701 * ######>> screen 24 <<
1703 * ( ud u --- uremainder uquotient )
1704 * Divides the top unsigned integer
1705 * into the second and third words on the stack
1706 * as a single unsigned double integer,
1707 * leaving the remainder and quotient (quotient on top)
1708 * as unsigned integers.
1710 * The smaller the divisor, the more likely dropping the high word
1711 * of the quotient loses significant bits. See M/MOD .
1720 LDD NATWID,U ; dividend
1721 USLDIV CMPD ,U ; divisor
1723 ANDCC #~1 ; carry clear
1726 ORCC #1 ; quotient, (carry set)
1727 USLBIT ROL 2*NATWID+1,U ; save it
1753 * USL2 ANDCC #~$01 ; CLC :
1771 * JMP SWAP+4 reverse quotient & remainder
1773 * ######>> screen 25 <<
1776 * Bitwise and the top two integers.
1796 * Bitwise or the top two integers.
1816 * Bitwise exclusive or the top two integers.
1834 * ######>> screen 26 <<
1837 * Fetch the parameter stack pointer (before it is pushed).
1838 * This points at whatever was on the top of stack before.
1848 * STX N scratch area
1853 * ( whatever --- nothing )
1854 * Initialize the parameter stack pointer from the USER variable S0.
1855 * Effectively clears the stack.
1864 * LDX XSPZER-UORIG,X
1865 * TFR X,S ; TXS : watch it ! X and S are not equal on 6800.
1868 * ( whatever *** nothing )
1869 * Initialize the return stack pointer from the initialization table
1870 * instead of the user variable R0, for some reason.
1871 * Quite possibly, this should be from R0.
1872 * Effectively aborts all in process definitions, except the active one.
1873 * An emergency measure, to be sure.
1874 * The routine that calls this must never execute a return.
1875 * So this should never be executed from the terminal, I guess.
1876 * This is another that should be compile-time only, and in a separate vocabulary.
1885 * LDX RINIT initialize from rom constant
1891 * Pop IP from return stack (return from high-level definition).
1892 * Can be used in a screen to force interpretion to terminate.
1893 * Must not be executed when temporaries are saved on top of the return stack.
1900 PULS Y ; saved IP in Y.
1908 * LDX 0,X get address we have just finished.
1909 * JMP NEXT+2 increment the return address & do next word
1911 * ######>> screen 27 <<
1913 * ( limit index *** index index )
1914 * Force the terminating condition for the innermost loop by
1915 * copying its index to its limit.
1916 * Termination is postponed until the next
1917 * LOOP or +LOOP instruction is executed.
1918 * The index remains available for use until
1919 * the LOOP or +LOOP instruction is encountered.
1920 * Note that the assumption is that the current count is the correct count
1921 * to end at, rather than pushing the count to the final count.
1923 FCC 'LEAV' ; 'LEAVE'
1927 LDD ,S ; No return address to dodge.
1940 * Move top of parameter stack to top of return stack.
1962 * Move top of return stack to top of parameter stack.
1982 * Copy the top of return stack to top of parameter stack.
1994 * ######>> screen 28 <<
1997 * Logically invert top of stack;
1998 * or flag true if top is zero, otherwise false.
2008 * Logically invert top of stack;
2009 * or flag true if top is zero, otherwise false.
2027 *ZEQU2 TFR S,X ; TSX :
2032 * Flag true if top is negative (MSbit set), otherwise false.
2045 * LDA #$80 check the sign bit
2054 * ######>> screen 29 <<
2056 * ( n1 n2 --- n1+n2 )
2057 * Add top two words.
2065 LBRA NEXT ; #1~5 =#7~23
2074 * ( d1 d2 --- d1+d2 )
2075 * Add top two double integers.
2091 * ANDCC #~$01 ; CLC :
2107 * Negate (two's complement) top of stack.
2109 FCC 'MINU' ; 'MINUS'
2116 LBRA NEXT ; #1~5 = #8~18
2118 * from 6800 model code:
2129 * Negate (two's complement) top two words on stack as a double integer.
2131 FCC 'DMINU' ; 'DMINUS'
2136 SUBD NATWID,U ; #2~7
2142 LBRA NEXT ; #1~5 = #17~39
2156 * ######>> screen 30 <<
2158 * ( n1 n2 --- n1 n2 n1 )
2159 * Push a copy of the second word on stack.
2175 * Discard the top word on stack.
2188 * ( n1 n2 --- n2 n1 )
2189 * Swap the top two words on stack.
2213 * Push a copy of the top word on stack.
2228 * ######>> screen 31 <<
2231 * Add the second word on stack to the word at the adr on top of stack.
2246 * PULS A ; get stack data
2248 * ADDB 1,X add & store low byte
2250 * ADCA 0,X add & store hi byte
2256 * Exclusive or byte at adr with low byte of top word.
2258 FCC 'TOGGL' ; 'TOGGLE'
2266 * Using the model code would be less likely to introduce bugs,
2267 * but that would sort-of defeat my purposes here.
2268 * Anyway, I can borrow from theoretically known good bif-6809 code
2269 * and it's fewer bytes and much faster code this way.
2271 * FDB DOCOL,OVER,CAT,XOR,SWAP,CSTORE
2274 * ######>> screen 32 <<
2277 * Replace address on stack with the word at the address.
2286 * LDX 0,X get address
2293 * Replace address on top of stack with the byte at the address.
2294 * High byte of result is clear.
2316 * Store second word on stack at address on top of stack.
2326 * LDX 0,X get address
2333 * Store low byte of second word on stack at address on top of stack.
2334 * High byte is ignored.
2345 * LDX 0,X get address
2354 * ######>> screen 33 <<
2357 * { : name sundry-activities ; } typical input
2358 * If executing (not compiling),
2359 * record the data stack mark in CSP,
2360 * Set the CONTEXT vocabulary to CURRENT,
2362 * set state to compile,
2363 * and compile the call to the trailing native CPU machine code DOCOL.
2365 * This would not be hard to flatten to native code.
2366 * But that's not the purpose of a model.
2370 COLON FDB DOCOL,QEXEC,SCSP,CURENT,AT,CONTXT,STORE
2374 * Here is the IP pusher for allowing
2375 * nested words in the virtual machine:
2376 * ( ;S is the equivalent un-nester )
2379 * Characteristic of a colon (:) definition.
2380 * Begins execution of a high-level definition,
2381 * i. e., nests the definition and begins processing icodes.
2382 * Mechanically, it pushes the IP (Y register)
2383 * and loads the Parameter Field Address of the definition which
2384 * called it into the IP.
2385 DOCOL PSHS Y ; Nest the old IP.
2386 LEAY NATWID,X ; W still in X, bump to parameters, load as new IP.
2387 LBRA NEXT ; No return, just jump.
2389 * DOCOL LDX RP make room in the stack
2395 * STA 2,X Store address of the high level word
2396 * STB 3,X that we are starting to execute
2397 * LDX W Get first sub-word of that definition
2398 * JMP NEXT+2 and execute it
2402 * { : name sundry-activities ; } typical input
2403 * ERROR check data stack against mark in CSP,
2405 * unSMUDGE LATEST definition,
2406 * and set state to interpretation.
2407 FCB $C1 ; imnediate code
2410 SEMI FDB DOCOL,QCSP,COMPIL,SEMIS,SMUDGE,LBRAK
2413 * ######>> screen 34 <<
2416 * { value CONSTANT name } typical input
2419 * compile the constant value,
2420 * and compile the call to the trailing native CPU machine code DOCON.
2422 FCC 'CONSTAN' ; 'CONSTANT'
2425 CON FDB DOCOL,CREATE,SMUDGE,COMMA,PSCODE
2427 * Characteristic of a CONSTANT.
2428 * A CONSTANT simply loads its value from its parameter field
2429 * and pushes it on the stack.
2430 DOCON LDD NATWID,X ; Get the first natural width word of the parameter field.
2435 * LDB 3,X A & B now contain the constant
2438 * Not in model, needed for abstraction:
2440 * The byte width of objects on stack.
2442 FCC 'NATWI' ; 'NATWID'
2448 * Not in model, needed for abstraction:
2449 * Note that this is not defined as an INCREMENTER!
2450 * Coded to increment by the exact constant returned by NATWID
2451 * ( n --- n+NATWID )
2458 ADDD NATWCV,PCR ; Looking ahead, does not have to be PCRelative.
2461 * How this might have been done for 6800 model:
2462 * CLRA ; We know the natural width is less than 255, LOL.
2471 * { init VARIABLE name } typical input
2472 * Use CONSTANT to CREATE a header and compile the initial value, init,
2473 * then overwrite the characteristic to point to DOVAR.
2475 FCC 'VARIABL' ; 'VARIABLE'
2478 VAR FDB DOCOL,CON,PSCODE
2480 * Characteristic of a VARIABLE.
2481 * A VARIABLE pushes its PFA address on the stack.
2482 * The parameter field of a VARIABLE is the actual allocation of the variable,
2483 * so that pushing its address allows its contents to be @ed (fetched).
2484 * Ordinary arrays and strings that do not subscript themselves
2485 * may be allocated by defining a variable
2486 * and immediately ALLOTting the remaining needed space.
2487 * VARIABLES are global to all users,
2488 * and thus should be hidden in resource monitors, but aren't.
2489 DOVAR LEAX NATWID,X ; Point to the first natural width word of the parameters.
2495 * ADCA #0 A,B now contain the address of the variable
2500 * { uboffset USER name } typical input
2501 * CREATE a header and compile the unsigned byte offset in the per-USER table,
2502 * then overwrite the header with a call to DOUSER.
2503 * The USER is entirely responsible for maintaining allocation!
2508 USER FDB DOCOL,CON,PSCODE
2510 * Characteristic of a per-USER variable.
2511 * USER variables are similiar to VARIABLEs,
2512 * but are allocated (by hand!) in the per-user table.
2513 * A USER variable's parameter field contains its offset in the per-user table.
2514 DOUSER TFR DP,A ; Make a pointer to the direct page.
2516 * See Alternative -- alternatives start from this point.
2517 ADDD NATWID,X ; Add it to the offset to the per-user variable.
2519 TFR D,X ; Cache the pointer in X for the caller.
2521 * Hey, the per-user table could actually be larger than 256 bytes!
2522 * But we knew that. It's just not as esthetic to calculate it this way.
2524 * LDX NATWID,X ; Keep the offset
2525 * EXG D,X ; Prepare for EA
2530 * PSHS Y ; Get Y free for calculations.
2531 * TFR D,Y ; Y points to the UP base
2532 * LDD NATWID,X ; Get the offset
2533 * LEAX D,Y ; Leave the pointer cached in X.
2537 * From the 6800 model:
2538 * DOUSER LDX W get offset into user's table
2541 * ADDB UP+1 add to users base address
2543 * JMP PUSHBA push address of user's variable
2545 * ######>> screen 35 <<
2580 * ASCII SPACE character
2585 BL FDB DOCON ascii blank
2589 * This really shouldn't be a CONSTANT.
2591 * The base of the disk buffer space.
2593 FCC 'FIRS' ; 'FIRST'
2598 * FDB MEMEND-528 (132 * NBLK)
2601 * This really shouldn't be a CONSTANT.
2603 * The limit of the disk buffer space.
2605 FCC 'LIMI' ; 'LIMIT' : ( the end of memory +1 )
2610 * In 6800 model, was
2614 * ( --- sectorsize )
2615 * The size, in bytes, of a buffer control region.
2617 FCC 'B/CT' ; 'B/CTL' : (bytes/control region)
2623 * ( --- sectorsize )
2624 * The size, in bytes, of a buffer.
2626 FCC 'B/BU' ; 'B/BUF' : (bytes/buffer)
2631 * Hardcoded in 6800 model:
2635 * ( --- blocksperscreen )
2636 * The size, in blocks, of a screen.
2637 * Should this be the same as NBLK, the number of block buffers maintained?
2639 FCC 'B/SC' ; 'B/SCR' : (blocks/screen)
2644 * Hardcoded in 6800 model as:
2646 * blocks/screen = 1024 / "B/BUF" = 8, if sectors are 128 bytes.
2650 * Calculate the address of entry (#n/2) in the boot-up parameter table.
2651 * (Adds the base of the boot-up table to n.)
2653 FCC '+ORIGI' ; '+ORIGIN'
2656 PORIG FDB DOCOL,LIT,ORIG,PLUS
2659 * ######>> screen 36 <<
2662 * This is the per-task variable recording the initial parameter stack pointer.
2672 * This is the per-task variable recording the initial return stack pointer.
2682 * Terminal Input Buffer address.
2683 * Note that this is a variable, so users may allocate their own buffers, but it must be @ed.
2692 * ( --- maxnamewidth )
2693 * This is the maximum width to which symbol names will be recorded.
2695 FCC 'WIDT' ; 'WIDTH'
2703 * Availability of error messages on disk.
2704 * Contains 1 if messages available,
2706 * -1 if a disk error has occurred.
2708 FCC 'WARNIN' ; 'WARNING'
2716 * Boundary for FORGET.
2718 FCC 'FENC' ; 'FENCE'
2726 * Dictionary pointer, fetched by HERE.
2728 FCC 'D' ; 'DP' : points to first free byte at end of dictionary
2735 * ( --- vadr ) ******* Need to check what this is!
2736 * Used in maintaining vocabularies.
2737 * I think it points to the "parent" vocabulary, but I'm not sure.
2738 * Or maybe this is the CONTEXT vocabulary. I'll have to come back here. *****
2740 FCC 'VOC-LIN' ; 'VOC-LINK'
2748 * Disk block being interpreted.
2749 * Zero refers to terminal.
2750 * ******** Should be made a 32 bit user variable! ********
2751 * But the base system needs to have full 32 bit support, div and mul, etc.
2752 * before we can do that.
2762 * Input buffer offset/cursor.
2764 FCC 'I' ; 'IN' : scan pointer for input line buffer
2772 * Output buffer offset/cursor.
2782 * Screen currently being edited, once we have an editor running.
2789 * ######>> screen 37 <<
2793 * Sector offset for LOADing screens,
2794 * set by DRIVE to make a new drive the default.
2795 * This should also be 32 bit or bigger.
2797 FCC 'OFFSE' ; 'OFFSET'
2805 * Current context of interpretation (vocabulary root).
2807 FCC 'CONTEX' ; 'CONTEXT' : points to pointer to vocab to search first
2815 * Current context of definition (vocabulary root).
2817 FCC 'CURREN' ; 'CURRENT' : points to ptr. to vocab being extended
2825 * Compiler/interpreter state.
2827 FCC 'STAT' ; 'STATE' : 1 if compiling, 0 if not
2835 * Numeric conversion base.
2837 FCC 'BAS' ; 'BASE' : number base for all input & output
2845 * Decimal point location for output.
2855 * Field width for I/O formatting.
2865 * Compiler stack mark for stack check.
2875 * Editing cursor location.
2885 * Pointer to last HELD character in PAD.
2893 * ======>> 82.5 <<== SPECIAL
2895 * Line width of active terminal.
2897 FCC 'COLUMN' ; 'COLUMNS' : line width of terminal
2903 * ######>> screen 38 <<
2905 ** An INCREMENTER probably should not be defined without a defined CONSTANT?
2907 ** Make an INCREMENTER compiling word (not in model):
2909 ** { n INCREMENTER name } typical input
2910 ** CREATE a header and compile the increment constant,
2911 ** then overwrite the header with a call to DOINC.
2913 * FCC 'INCREMENTE' ; 'INCREMENTER'
2916 * INCR FDB DOCOL,CON,PSCODE
2918 ** Characteristic of an INCREMENTER.
2919 ** This is too naive:
2921 * ADDD NATWID,X ; Add the increment.
2924 * Compiling word should check that it is compiling a CONSTANT.
2932 * Using the model keeps things semantically connected for other processors:
2933 ONEP FDB DOCOL,ONE,PLUS
2935 ** Greedy alternative:
2941 * Naive alternative:
2944 * Naive alternative:
2947 * ADDD #1 ; It's hard to imagine 1+ being other than 1.
2957 * Using the model keeps things semantically connected for other processors:
2958 TWOP FDB DOCOL,TWO,PLUS
2960 ** Greedy alternative:
2963 * ADDD TWOV,PCR ; See NAT+ (NATP)
2966 * Naive alternative:
2969 * Naive alternative:
2972 * ADDD #2 ; See NAT+ (NATP)
2978 * Get the DICTPT allocation, like a USER constant.
2979 * Should check the stack and heap for collision.
2984 HERE FDB DOCOL,DICTPT,AT
2989 * Increase/decrease heap (add n to DP),
2990 * Should ERROR check stack/heap.
2992 FCC 'ALLO' ; 'ALLOT'
2995 ALLOT FDB DOCOL,DICTPT,PSTORE
3000 * Store word n at DP++,
3001 * Should ERROR check stack/heap.
3005 COMMA FDB DOCOL,HERE,STORE,NATWC,ALLOT
3007 * COMMA FDB DOCOL,HERE,STORE,TWO,ALLOT
3012 * Store byte b at DP+,
3013 * Should ERROR check stack/heap.
3018 CCOMM FDB DOCOL,HERE,CSTORE,ONE,ALLOT
3022 * ( n1 n2 --- n1-n2 )
3023 * Subtract top two words.
3031 LBRA NEXT ; #1~5 = #7~25
3032 * SUB FDB DOCOL,MINUS,PLUS
3033 * FDB SEMIS ; Costs 6 bytes and lots of cycles.
3036 * ( n1 n2 --- n1==n2 )
3037 * Return flag true if n1 and n2 are equal, otherwise false.
3041 EQUAL FDB DOCOL,SUB,ZEQU
3045 * ( n1 n2 --- n1<n2 )
3046 * Return flag true if n1 is less than n2, otherwise false.
3067 * CMPB 1,X ; Why not sub, sbc, bge?
3077 * ( n1 n2 --- n1>n2 )
3078 * Return flag true if n1 is greater than n2, false otherwise.
3082 GREAT FDB DOCOL,SWAP,LESS
3086 * ( n1 n2 n3 --- n2 n3 n1 )
3087 * Rotate the top three words on stack,
3088 * bringing the third word to the top.
3100 * ROT FDB DOCOL,TOR,SWAP,FROMR,SWAP
3107 FCC 'SPAC' ; 'SPACE'
3110 SPACE FDB DOCOL,BL,EMIT
3114 * ( n0 n1 --- min(n0,n1) )
3115 * Leave the minimum of the top two integers.
3116 * Being too greedy here, but, whatever.
3127 * MIN FDB DOCOL,OVER,OVER,GREAT,ZBRAN
3134 * ( n0 n1 --- max(n0,n1) )
3135 * Leave the maximum of the top two integers.
3136 * Really should leave this as in the model.
3147 * MAX FDB DOCOL,OVER,OVER,LESS,ZBRAN
3161 DDUP FDB *+NATWID ; Just being greedy for speed.
3166 * DDUP FDB DOCOL,DUP,ZBRAN
3167 * FDB DDUP2-*-NATWID
3171 * ######>> screen 39 <<
3176 * Change top integer to its sign.
3178 FCC 'SIGNU' ; 'SIGNUM'
3186 SIGNUP SEX ; Couldn't they have called SignEXtend EXT instead?
3187 STD ,U ; Am I too much of a prude?
3189 * 6800 model version should be something like this:
3200 * ( adr1 direction --- adr2 )
3201 * TRAVERSE the symbol name.
3202 * If direction is 1, find the end.
3203 * If direction is -1, find the beginning.
3205 FCC 'TRAVERS' ; 'TRAVERSE'
3209 * BSR SIGNUE ; Convert negative to -, zero or positive to 1.
3210 * LDD ,U++ ; Still in D, but we have to pop it anyway.
3211 * LDX ,U ; If D is 1 or -1, so is B.
3213 * TRAVLP LEAX B,X ; Don't look at the one we start at.
3214 * CMPA ,X ; Not sure why we aren't just doing LDA ,X ; BPL.
3218 * Doing this in 6809 just because it can be done was getting too greedy.
3220 TRAV2 FDB OVER,PLUS,LIT8
3222 FDB OVER,CAT,LESS,ZBRAN
3229 * Fetch CURRENT as a per-USER constant.
3231 FCC 'LATES' ; 'LATEST'
3234 LATEST FDB DOCOL,CURENT,AT,AT
3236 * LATEST FDB *+NATWID
3237 * Getting too greedy:
3242 * LDD CURENT+NATWID,PCR
3244 * PSHU X ; Leave the address in X.
3253 * Too greedy, too many smantic holes to fall through.
3254 * If the address at the CFA is made relative,
3255 * this is part of the code that would be affected
3256 * if it is in native CPU code.
3259 * Wanted to do these as INCREMENTERs,
3260 * but I need to stick with the model as much as possible,
3261 * (mostly, LOL) adding code only to make the model more clear.
3263 * Convert PFA to LFA, unchecked. (Bump back from contents to allocation link.)
3276 * Convert PFA to CFA, unchecked. (Bump back from contents to characterist code link.)
3281 * CFA FDB DOCOL,TWO,SUB
3282 CFA FDB DOCOL,NATWC,SUB
3287 * Convert PFA to NFA. (Bump back from contents to beginning of symbol name.)
3295 FDB SUB,ONE,MINUS,TRAV
3300 * Convert NFA to PFA. (Bump up from beginning of symbol name to contents.)
3305 PFA FDB DOCOL,ONE,TRAV,LIT8
3311 * ######>> screen 40 <<
3314 * Save the parameter stack pointer in CSP for compiler checks.
3319 SCSP FDB DOCOL,SPAT,CSP,STORE
3323 * ( 0 n --- ) ( *** )
3324 * ( true n --- IN BLK ) ( anything *** nothing )
3325 * If flag is false, do nothing.
3326 * If flag is true, issue error MESSAGE and QUIT or ABORT, via ERROR.
3327 * Leaves cursor position (IN)
3328 * and currently loading block number (BLK) on stack, for analysis.
3330 * This one is too important to be high-level Forth codes.
3331 * When we have an error, we want to disturb as little as possible.
3332 * But fixing that cascades through ERROR and MESSAGE
3333 * into the disk block system.
3334 * And we aren't ready for that yet.
3336 FCC '?ERRO' ; '?ERROR'
3344 ** this doesn't work anyway: QERROR LBRA ERROR
3345 QERR FDB DOCOL,SWAP,ZBRAN
3353 * STATE is compiling:
3355 * STATE is not compiling:
3356 * ( --- IN BLK ) ( anything *** nothing )
3357 * ERROR if not compiling.
3359 FCC '?COM' ; '?COMP'
3362 QCOMP FDB DOCOL,STATE,AT,ZEQU,LIT8
3368 * STATE is executing:
3370 * STATE is not executing:
3371 * ( --- IN BLK ) ( anything *** nothing )
3372 * ERROR if not executing.
3374 FCC '?EXE' ; '?EXEC'
3377 QEXEC FDB DOCOL,STATE,AT,LIT8
3383 * ( n1 n1 --- ) ( *** )
3384 * ( n1 n2 --- IN BLK ) ( anything *** nothing )
3385 * ERROR if top two are unequal.
3386 * MESSAGE says compiled conditionals do not match.
3388 FCC '?PAIR' ; '?PAIRS'
3391 QPAIRS FDB DOCOL,SUB,LIT8
3397 * CSP and parameter stack are balanced (equal):
3399 * CSP and parameter stack are not balanced (unequal):
3400 * ( --- IN BLK ) ( anything *** nothing )
3401 * ERROR if return/control stack is not at same level as last !CSP.
3402 * Usually indicates that a definition has been left incomplete.
3407 QCSP FDB DOCOL,SPAT,CSP,AT,SUB,LIT8
3415 * No active BLK input:
3416 * ( --- IN BLK ) ( anything *** nothing )
3417 * ERROR if not loading, i. e., if BLK is zero.
3419 FCC '?LOADIN' ; '?LOADING'
3422 QLOAD FDB DOCOL,BLK,AT,ZEQU,LIT8
3427 * ######>> screen 41 <<
3430 * Compile an in-line literal value from the instruction stream.
3432 FCC 'COMPIL' ; 'COMPILE'
3435 * COMPIL FDB DOCOL,QCOMP,FROMR,TWOP,DUP,TOR,AT,COMMA
3436 * COMPIL FDB DOCOL,QCOMP,FROMR,NATP,DUP,TOR,AT,COMMA
3437 COMPIL FDB DOCOL,QCOMP,FROMR,DUP,NATP,TOR,AT,COMMA
3442 * Clear the compile state bit(s) (shift to interpret).
3446 LBRAK FDB DOCOL,ZERO,STATE,STORE
3453 * Set the compile state bit(s) (shift to compile).
3457 RBRAK FDB DOCOL,LIT8
3464 * Toggle SMUDGE bit of LATEST definition header,
3465 * to hide it until defined or reveal it after definition.
3467 FCC 'SMUDG' ; 'SMUDGE'
3470 SMUDGE FDB DOCOL,LATEST,LIT8
3477 * Set the conversion base to sixteen (b00010000).
3484 FCB 16 ; decimal sixteen
3490 * Set the conversion base to ten (b00001010).
3492 FCC 'DECIMA' ; 'DECIMAL'
3497 FCB 10 ; decimal ten
3501 * ######>> screen 42 <<
3503 * ( --- ) ( IP *** )
3504 * Pop the saved IP and use it to
3505 * compile the latest symbol as a reference to a ;CODE definition;
3506 * overwrite the code field of the symbol found by LATEST
3507 * with the address of the low-level characteristic code
3508 * provided in the defining definition.
3509 * Look closely at where things return, consider the operation of R> and >R .
3511 * The machine-level code which follows (;CODE) in the instruction stream
3512 * is not executed by the defining symbol,
3513 * but becomes the characteristic of the defined symbol.
3514 * This is the usual way to generate the characteristics of VARIABLEs,
3515 * CONSTANTs, COLON definitions, etc., when FORTH compiles itself.
3517 * Finally, note that, if code shifts from low level back to high
3518 * (native CPU machine code calling into a list of FORTH codes),
3519 * the low level code can't just call a high-level definition.
3520 * Leaf definitions can directly call other leaf definitions,
3521 * but not non-leafs.
3522 * It will need an anonymous list, probably embedded in the low-level code,
3523 * and Y and X will have to be set appropriately before entering the list.
3525 FCC '(;CODE' ; '(;CODE)'
3528 * PSCODE FDB DOCOL,FROMR,TWOP,LATEST,PFA,CFA,STORE
3529 PSCODE FDB DOCOL,FROMR ; Y/IP is post-inc, needs no adjustment.
3530 FDB LATEST,PFA,CFA,STORE
3535 * ?CSP to see if there are loose ends in the defining definition
3536 * before shifting to the assembler,
3537 * compile (;CODE) in the defining definition's instruction stream,
3538 * shift to interpreting,
3539 * make the ASSEMBLER vocabulary current,
3540 * and !CSP to mark the stack
3541 * in preparation for assembling low-level code.
3542 * Note that ;CODE, unlike DOES>, is IMMEDIATE,
3543 * and compiles (;CODE),
3544 * which will do the actual work of changing
3545 * the LATEST definition's characteristic when the defining word runs.
3546 * Assembly is done by the interpreter, rather than the compiler.
3547 * I could have avoided the anomalous three-byte code fields by
3549 * Note that the ASSEMBLER is not part of the model (at this time).
3550 * That means that, until the assembler is ready,
3551 * if you want to define low-level words,
3552 * you have to poke (comma) in hand-assembled stuff.
3555 FCC ';COD' ; ';CODE'
3558 SEMIC FDB DOCOL,QCSP,COMPIL,PSCODE,SMUDGE,LBRAK,QSTACK
3560 * note: "QSTACK" will be replaced by "ASSEMBLER" later
3562 * ######>> screen 43 <<
3565 * Make the word currently being defined
3566 * build a header for DOES> definitions.
3567 * Actually just compiles a CONSTANT zero
3568 * which can be overwritten later by DOES>.
3569 * Since the fig models were established, this technique has been deprecated.
3571 * Note that <BUILDS is not IMMEDIATE,
3572 * and therefore executes during a definition's run-time,
3573 * rather than its compile-time.
3574 * It is not intended to be used directly,
3575 * but rather so that one definition word can build another.
3576 * Also, note that nothing particularly special happens
3577 * in the defining definition until DOES> executes.
3578 * The name <BUILDS is intended to be a reminder of what is about to occur.
3580 * <BUILDS probably should have compiled an ERROR instead of a ZERO CONSTANT.
3582 FCC '<BUILD' ; '<BUILDS'
3585 BUILDS FDB DOCOL,ZERO,CON
3589 * ( --- ) ( IP *** ) C
3590 * Define run-time behavior of definitions compiled/defined
3591 * by a high-level defining definition --
3592 * the FORTH equivalent of a compiler-compiler.
3593 * DOES> assumes that the LATEST symbol table entry
3594 * has at least one word of parameter field,
3595 * which <BUILDS provides.
3596 * Note that DOES> is also not IMMEDIATE.
3598 * When the defining word containing DOES> executes the DOES> icode,
3599 * it overwrites the LATEST symbol's CFA with jsr <XDOES,
3600 * overwrites the first word of that symbol's parameter field with its own IP,
3601 * and pops the previous IP from the return stack.
3602 * The icodes which follow DOES> in the stream
3603 * do not execute at the defining word's run-time.
3605 * Examining XDOES in the virtual machine shows
3606 * that the defined word will execute those icodes
3607 * which follow DOES> at its own run-time.
3609 * The advantage of this kind of behaviour,
3610 * which you will also note in ;CODE,
3611 * is that the defined word can contain
3612 * both operations and data to be operated on.
3613 * This is how FORTH data objects define their own behavior.
3615 * Finally, note that the effective parameter field for DOES> definitions
3616 * starts two NATWID words after the CFA, instead of just one
3617 * (four bytes instead of two in a sixteen-bit addressing Forth).
3619 * VOCABULARYs will use this. See definition of word FORTH.
3621 FCC 'DOES' ; 'DOES>'
3624 * DOES FDB DOCOL,FROMR,TWOP,LATEST,PFA,STORE
3625 DOES FDB DOCOL,FROMR ; Y/IP is post-inc, needs no adjustment.
3626 FDB LATEST,PFA,STORE
3629 * ( --- PFA+NATWID ) ( *** IP )
3630 * Characteristic of a DOES> defined word.
3631 * The characteristics of DOES> definitions are written in high-level
3632 * Forth codes rather than native CPU machine level code.
3633 * The first parameter word points to the high-level characteristic.
3634 * This routine's job is to push the IP,
3635 * load the high level characteristic pointer in IP,
3636 * and leave the address following the characteristic pointer on the stack
3637 * so the parameter field can be accessed.
3638 DODOES PSHS Y ; Save/nest the current IP on the return stack.
3639 LDY NATWID,X ; First parameter is new IP.
3640 LEAX 2*NATWID,X ; Address of second parameter.
3642 LBRA NEXT ; No return, just jump.
3644 * From the 6800 model:
3647 * LDX RP make room on return stack
3651 * STA 2,X push return address
3653 * LDX W get addr of pointer to run-time code
3656 * STX N stash it in scratch area
3657 * LDX 0,X get new IP
3659 * CLRA ; get address of parameter
3663 * PSHS B ; and push it on data stack
3667 * ######>> screen 44 <<
3669 * ( strptr --- strptr+1 count )
3670 * Convert counted string to string and count.
3671 * (Fetch the byte at strptr, post-increment.)
3673 FCC 'COUN' ; 'COUNT'
3676 COUNT FDB DOCOL,DUP,ONEP,SWAP,CAT
3680 * ( strptr count --- )
3681 * EMIT count characters at strptr.
3686 TYPE FDB DOCOL,DDUP,ZBRAN
3688 FDB OVER,PLUS,SWAP,XDO
3689 TYPE2 FDB I,CAT,EMIT,XLOOP
3697 * ( strptr count1 --- strptr count2 )
3698 * Supress trailing blanks (subtract count of trailing blanks from strptr).
3700 FCC '-TRAILIN' ; '-TRAILING'
3703 DTRAIL FDB DOCOL,DUP,ZERO,XDO
3704 DTRAL2 FDB OVER,OVER,PLUS,ONE,SUB,CAT,BL
3716 * TYPE counted string out of instruction stream (updating IP).
3721 * PDOTQ FDB DOCOL,R,TWOP,COUNT,DUP,ONEP
3722 * PDOTQ FDB DOCOL,R,NATP,COUNT,DUP,ONEP
3723 PDOTQ FDB DOCOL,R,COUNT,DUP,ONEP ; IP/Y is post-inc.
3724 FDB FROMR,PLUS,TOR,TYPE
3729 * { ." something-to-be-printed " } typical input
3730 * Use WORD to parse to trailing quote;
3731 * if compiling, compile XDOTQ and string parsed,
3732 * otherwise, TYPE string.
3742 FDB COMPIL,PDOTQ,WORD
3743 FDB HERE,CAT,ONEP,ALLOT,BRAN
3745 DOTQ1 FDB WORD,HERE,COUNT,TYPE
3748 * ######>> screen 45 <<
3749 * ======>> 126 <<== MACHINE DEPENDENT
3751 * ( --- IN BLK ) ( anything *** nothing )
3752 * ERROR if parameter stack out of bounds.
3754 * But checking whether the stack is in bounds or not
3755 * really should not use the stack.
3756 * And there really should be a ?RSTACK, as well.
3758 FCC '?STAC' ; '?STACK'
3761 QSTACK FDB DOCOL,LIT8
3764 * But why use that instead of XSPZER (S0)?
3765 * Multi-user or multi-tasking would not want that.
3767 * FDB PORIG,AT,TWO,SUB,SPAT,LESS,ONE
3768 FDB PORIG,AT,SPAT,LESS,ONE ; Not post-decrement push.
3770 * prints 'empty stack'
3773 * Here, we compare with a value at least 128
3774 * higher than dict. ptr. (DICTPT)
3776 * FCB $80 ; This is a rough check anyway, leave it as is.
3777 * But shouldn't it be the terminal width?
3781 FDB TWO ; NOT the NATWID constant!
3783 * prints 'full stack'
3787 * ======>> 127 << this word's function
3788 * is done by ?STACK in this version
3793 *QFREE FDB DOCOL,SPAT,HERE,LIT8
3795 * FDB PLUS,LESS,TWO,QERR,SEMIS ; This TWO is not NATWID!
3797 * ######>> screen 46 <<
3800 * ***** Check that this is how it works here:
3801 * Get up to n-1 characters from the keyboard,
3802 * storing at buffer and echoing, with backspace editing,
3803 * quitting when a CR is read.
3804 * Terminate it with a NUL.
3806 FCC 'EXPEC' ; 'EXPECT'
3809 EXPECT FDB DOCOL,OVER,PLUS,OVER,XDO ; brace the buffer area
3810 * EXPEC2 FDB KEY,DUP,LIT8
3812 * FDB LIT,$1C,SHOTOS ; DBG
3815 FDB PORIG,AT,EQUAL,ZBRAN ; check for backspacing
3818 FCB 8 ( backspace character to emit )
3819 FDB OVER,I,EQUAL,DUP,FROMR,TWO,SUB,PLUS ; back I up TWO characters
3823 FCB $D ( carriage return )
3826 FDB LEAVE,DROP,BL,ZERO,BRAN ; I think this is the NUL terminator.
3829 EXPEC5 FDB I,CSTORE,ZERO,I,ONEP,STORE
3830 EXPEC6 FDB EMIT,XLOOP
3837 * EXPECT 128 (TWID) characters to TIB.
3839 FCC 'QUER' ; 'QUERY'
3842 QUERY FDB DOCOL,TIB,AT,COLUMS
3843 FDB AT,EXPECT,ZERO,IN,STORE
3848 * End interpretation of a line or screen, and/or prepare for a new block.
3849 * Note that the name of this definition is an empty string,
3850 * so it matches on the terminating NUL in the terminal or block buffer.
3851 FCB $C1 immediate < carriage return >
3854 NULL FDB DOCOL,BLK,AT,ZBRAN
3857 FDB ZERO,IN,STORE,BLK,AT,BSCR,MOD
3859 * check for end of screen
3862 FDB QEXEC,FROMR,DROP
3865 NULL2 FDB FROMR,DROP
3868 * ######>> screen 47 <<
3871 * Fill n bytes at adr with b.
3872 * This relies on CMOVE having a certain lack of parameter checking,
3873 * where overlapping regions are not properly inverted in copy.
3874 * And this really should be done in low-level.
3875 * None of the advantages of doing things in high-level apply to fill.
3880 FILL FDB DOCOL,SWAP,TOR,OVER,CSTORE,DUP,ONEP
3881 FDB FROMR,ONE,SUB,CMOVE
3886 * Fill n bytes with 0.
3888 FCC 'ERAS' ; 'ERASE'
3891 ERASE FDB DOCOL,ZERO,FILL
3896 * Fill n bytes with ASCII SPACE.
3898 FCC 'BLANK' ; 'BLANKS'
3901 BLANKS FDB DOCOL,BL,FILL
3906 * Format a character at the left of the HLD output buffer.
3911 HOLD FDB DOCOL,LIT,$FFFF,HLD,PSTORE,HLD,AT,CSTORE
3916 * Give the address of the output PAD buffer.
3917 * PAD points to the end of a 68 byte buffer for numeric conversion.
3922 PAD FDB DOCOL,HERE,LIT8
3927 * ######>> screen 48 <<
3930 * Scan a string terminated by the character c or ASCII NUL out of input;
3931 * store symbol at WORDPAD with leading count byte and trailing ASCII NUL.
3932 * Leading c are passed over, per ENCLOSE.
3933 * Scans from BLK, or from TIB if BLK is zero.
3934 * May overwrite the numeric conversion pad,
3935 * if really long (length > 31) symbols are scanned.
3940 WORD FDB DOCOL,BLK,AT,ZBRAN
3942 FDB BLK,AT,BLOCK,BRAN
3945 WORD3 FDB IN,AT,PLUS,SWAP,ENCLOS,HERE,LIT8
3947 FDB BLANKS,IN,PSTORE,OVER,SUB,TOR,R,HERE
3948 FDB CSTORE,PLUS,HERE,ONEP,FROMR,CMOVE
3951 * ######>> screen 49 <<
3953 * ( d1 string --- d2 adr )
3954 * Convert the text at string into a number, accumulating the result into d1,
3955 * leaving adr pointing to the first character not converted.
3956 * If DPL is non-negative at entry,
3957 * accumulates the number of characters converted into DPL.
3959 FCC '(NUMBER' ; '(NUMBER)'
3963 PNUMB2 FDB ONEP,DUP,TOR,CAT,BASE,AT,DIGIT,ZBRAN
3965 FDB SWAP,BASE,AT,USTAR,DROP,ROT,BASE
3966 FDB AT,USTAR,DPLUS,DPL,AT,ONEP,ZBRAN
3969 PNUMB3 FDB FROMR,BRAN
3976 * Convert text at ctstr to a double integer,
3977 * taking the 0 ERROR if the conversion is not valid.
3978 * If a decimal point is present,
3979 * accumulate the count of digits to the decimal point's right into DPL
3980 * (negative DPL at exit indicates single precision).
3981 * ctstr is a counted string
3982 * -- the first byte at ctstr is the length of the string,
3983 * but NUMBER ignores the count and expects a NUL terminator instead.
3985 FCC 'NUMBE' ; 'NUMBER'
3988 NUMB FDB DOCOL,ZERO,ZERO,ROT,DUP,ONEP,CAT,LIT8
3990 FDB EQUAL,DUP,TOR,PLUS,LIT,$FFFF
3991 NUMB1 FDB DPL,STORE,PNUMB,DUP,CAT,BL,SUB
3996 FDB SUB,ZERO,QERR,ZERO,BRAN
3998 NUMB2 FDB DROP,FROMR,ZBRAN
4004 * ( --- locptr length true ) { -FIND name } typical input
4006 * Parse a word, then FIND,
4007 * first in the definition vocabulary,
4008 * then in the CONTEXT (interpretation) vocabulary, if necessary.
4009 * Returns what (FIND) returns, flag and optional location and length.
4011 FCC '-FIN' ; '-FIND'
4014 DFIND FDB DOCOL,BL,WORD,HERE,CONTXT,AT,AT
4015 FDB PFIND,DUP,ZEQU,ZBRAN
4017 FDB DROP,HERE,LATEST,PFIND
4020 * ######>> screen 50 <<
4022 * ( anything --- nothing ) ( anything *** nothing )
4023 * An indirection for ABORT, for ERROR,
4024 * which may be modified carefully.
4026 FCC '(ABORT' ; '(ABORT)'
4029 PABORT FDB DOCOL,ABORT
4034 FCC 'ERRO' ; 'ERROR'
4037 * This really should not be high level, according to best practices.
4038 * But fixing that cascades through MESSAGE,
4039 * requiring re-architecting the disk block system.
4040 * First, we need to get this transliteration running.
4041 ERROR FDB DOCOL,WARN,AT,ZLESS
4046 * 0 to print error #
4047 * and 1 to print error message from disc
4049 ERROR2 FDB HERE,COUNT,TYPE,PDOTQ
4052 FDB MESS,SPSTOR,IN,AT,BLK,AT,QUIT
4057 * Mask byte at adr with n.
4058 * Not in FIG, don't need it for 8 bit characters after all.
4060 * FCC 'CMAS' ; 'CMASK'
4063 * CMASK FDB *+NATWID
4071 * Mask high bit of tail of name in PAD buffer.
4072 * Not in FIG, need it for 8 bit characters.
4074 FCC 'IDFLA' ; 'IDFLAT'
4079 LDB ,X ; get the count
4081 LDA B,X ; point to the tail
4082 ANDA #$7F ; Clear the EndOfName flag bit.
4087 * Print definition's name from its NFA.
4092 IDDOT FDB DOCOL,PAD,LIT8
4095 FCB $5F ( underline )
4096 FDB FILL,DUP,PFA,LFA,OVER,SUB,PAD
4097 * FDB SWAP,CMOVE,PAD,COUNT,LIT8
4105 * ######>> screen 51 <<
4107 * ( --- ) { CREATE name } input
4108 * Parse a name (length < 32 characters) and create a header,
4109 * reporting first duplicate found in either the defining vocabulary
4110 * or the context (interpreting) vocabulary.
4111 * Install the header in the defining vocabulary
4112 * with CFA dangerously pointing to the parameter field.
4113 * Leave the name SMUDGEd.
4115 FCC 'CREAT' ; 'CREATE'
4118 CREATE FDB DOCOL,DFIND,ZBRAN
4127 CREAT2 FDB HERE,DUP,CAT,WIDTH,AT,MIN
4128 FDB ONEP,ALLOT,DUP,LIT8
4129 FCB ($80|FSMUDG) ; Bracket the name.
4130 FDB TOGGLE,HERE,ONE,SUB,LIT8
4132 FDB TOGGLE,LATEST,COMMA,CURENT,AT,STORE
4133 * FDB HERE,TWOP,COMMA
4137 * ######>> screen 52 <<
4140 * { [COMPILE] name } typical use
4141 * -DFIND next WORD and COMPILE it, literally;
4142 * used to compile immediate definitions into words.
4144 FCC '[COMPILE' ; '[COMPILE]'
4147 BCOMP FDB DOCOL,DFIND,ZEQU,ZERO,QERR,DROP,CFA,COMMA
4151 * ( n --- ) if compiling. P
4152 * ( n --- n ) if interpreting.
4153 * Compile n as a literal, if compiling.
4155 FCC 'LITERA' ; 'LITERAL'
4158 LITER FDB DOCOL,STATE,AT,ZBRAN
4160 FDB COMPIL,LIT,COMMA
4164 * ( d --- ) if compiling. P
4165 * ( d --- d ) if interpreting.
4166 * Compile d as a double literal, if compiling.
4168 FCC 'DLITERA' ; 'DLITERAL'
4171 DLITER FDB DOCOL,STATE,AT,ZBRAN
4173 FDB SWAP,LITER,LITER ; Just two literals in the right order.
4176 * ######>> screen 53 <<
4179 * Interpret or compile, according to STATE.
4180 * Searches words parsed in dictionary first, via -FIND,
4181 * then checks for valid NUMBER.
4182 * Pushes or COMPILEs double literal if NUMBER leaves DPL non-negative.
4183 * ERROR checks the stack via ?STACK before returning to its caller.
4185 FCC 'INTERPRE' ; 'INTERPRET'
4189 INTER2 FDB DFIND,ZBRAN
4199 INTER5 FDB HERE,NUMB,DPL,AT,ONEP,ZBRAN
4203 INTER6 FDB DROP,LITER
4204 INTER7 FDB QSTACK,BRAN
4206 * FDB SEMIS never executed
4209 * ######>> screen 54 <<
4212 * Toggle precedence bit of LATEST definition header.
4213 * During compiling, most symbols scanned are compiled.
4214 * IMMEDIATE definitions execute whenever the outer INTERPRETer scans them,
4215 * but may be compiled via ' (TICK).
4217 FCC 'IMMEDIAT' ; 'IMMEDIATE'
4220 IMMED FDB DOCOL,LATEST,LIT8
4226 * ( --- ) { VOCABULARY name } input
4227 * Create a vocabulary entry with a flag for terminating vocabulary searches.
4228 * Store the current search context in it for linking.
4229 * At run-time, VOCABULARY makes itself the CONTEXT vocabulary.
4231 FCC 'VOCABULAR' ; 'VOCABULARY'
4234 VOCAB FDB DOCOL,BUILDS,LIT,$81A0,COMMA,CURENT,AT,CFA
4235 FDB COMMA,HERE,VOCLIN,AT,COMMA,VOCLIN,STORE,DOES
4236 * DOVOC FDB TWOP,CONTXT,STORE
4237 DOVOC FDB NATP,CONTXT,STORE
4242 * Note: FORTH does not go here in the rom-able dictionary,
4243 * since FORTH is a type of variable.
4245 * (Should make a proper architecture for this at some point.)
4250 * Makes the current interpretation CONTEXT vocabulary
4251 * also the CURRENT defining vocabulary.
4253 FCC 'DEFINITION' ; 'DEFINITIONS'
4256 DEFIN FDB DOCOL,CONTXT,AT,CURENT,STORE
4261 * Parse out a comment and toss it away.
4262 * Leaves the leading characters in WORDPAD, which may or may not be useful.
4266 PAREN FDB DOCOL,LIT8
4271 * ######>> screen 55 <<
4273 * ( anything *** nothing )
4274 * Clear return stack.
4275 * Then INTERPRET and, if not compiling, prompt with OK,
4281 QUIT FDB DOCOL,ZERO,BLK,STORE
4284 * Here is the outer interpretter
4285 * which gets a line of input, does it, prints " OK"
4287 QUIT2 FDB RPSTOR,CR,QUERY,INTERP,STATE,AT,ZEQU
4295 * FDB SEMIS ( never executed )
4298 * ( anything --- nothing ) ( anything *** nothing )
4299 * Clear parameter stack,
4300 * set STATE to interpret and BASE to DECIMAL,
4301 * return to input from terminal,
4302 * restore DRIVE OFFSET to 0,
4303 * print out "Forth-68",
4304 * set interpret and define vocabularies to FORTH,
4305 * and finally, QUIT.
4306 * Used to force the system to a known state
4307 * and return control to the initial INTERPRETer.
4309 FCC 'ABOR' ; 'ABORT'
4312 ABORT FDB DOCOL,SPSTOR,DEC,QSTACK,DRZERO,CR,PDOTQ
4314 FCC "fig-Forth-6809"
4317 * FDB SEMIS never executed
4320 * ######>> screen 56 <<
4321 * bootstrap code... moves rom contents to ram :
4328 * Ultimately, we want position indepence,
4329 * so I'm using PCR where it seems reasonable.
4330 CENT LDS RINIT,PCR ; Get a useable return stack, at least.
4331 LDU SINIT,PCR ; Get a useable parameter stack, too.
4332 LDA #IUPDP ; This is not relative to PC.
4333 TFR A,DP ; And a useable direct page, too.
4334 SETDP IUPDP ; (For good measure.)
4339 * We'll keep this here for the time being.
4340 * There are better ways to do this, of course.
4341 * Re-architect, re-architect.
4342 LEAX ERAM,PCR ; end of stuff to move
4343 STX <XFENCE ; Borrow this variable for a loop terminator.
4344 LDY #RBEG ; bottom of open-ended destination
4345 LEAX RAM,PCR ; bottom of stuff to move
4347 STA ,Y+ ; move TASK & FORTH to ram
4351 * Leaves USE and PREV uninitialized.
4356 * STX <XFENCE ; Borrow this variable for a loop terminator.
4357 * LEAY REND,PCR ; top of destination (included XUSE and XPREV)
4358 * LEAX ERAM,PCR ; top of stuff to move (included initializers for XUSE and XPREV)
4360 * STA ,-Y ; move TASK & FORTH to ram
4364 * CENT LDS #REND-1 top of destination
4365 * LDX #ERAM top of stuff to move
4368 * PSHS A ; move TASK & FORTH to ram
4372 * LDS #XFENCE-1 put stack at a safe place for now
4373 * But that is taken care of.
4395 WENT LDS SINIT,PCR ; Get a useable return stack, at least.
4396 LDA #IUPDP ; This is not relative to PC.
4397 TFR A,DP ; And a useable direct page, too.
4398 SETDP IUPDP ; (For good measure.)
4401 PSHS X ; for loop termination
4402 CLRB ; Yes, I'm being a little ridiculous. Only a little.
4404 LEAY XFENCE-UORIG,Y ; top of destination
4405 LEAX FENCIN,PCR ; top of stuff to move
4406 WARM2 LDD ,--X ; All entries are 16 bit.
4411 LEAS 2,S ; But we'll reset the return stack shortly, anyway.
4412 LDU <XSPZER ; So we can clear the hole above the TOS
4413 * WENT LDS #XFENCE-1 top of destination
4414 * LDX #FENCIN top of stuff to move
4422 * S is already there.
4424 * STX UP init user ram pointer
4425 * UP is already there (DP).
4428 LEAY ABORT+NATWID,PCR ; IP never points to DOCOL!
4430 NOP Here is a place to jump to special user
4431 NOP initializations such as I/0 interrups
4434 * For systems with TRACE:
4436 STX ,U The hole above the parameter stack
4437 * STX TRLIM clear trace mode
4438 STX <TRLIM clear trace mode (both bytes)
4440 * STX BRKPT clear breakpoint address
4441 STX <BRKPT ; clear breakpoint address
4442 * JMP RPSTOR+2 start the virtual machine running !
4443 JMP [RPSTOR,PCR] ; start the virtual machine running !
4444 * RPSTOR's NEXT will pick up the IP in Y, set above, and start ABORT.
4445 * LBSR RPSTOR+NATWID ; start the virtual machine running !
4446 * LEAX WENT,PCR ; But we must also give RP! someplace to return.
4447 * STX ,S ; This rail might get walked on by (DO).
4449 * RP! sets up the return stack pointer, then Y references abort.
4451 * Here is the stuff that gets copied to ram :
4452 * (not * at address $140:)
4453 * at an appropriate address:
4455 * RAM FDB $3000,$3000,0,0
4456 * RAM FDB BUFBAS,BUFBAS,0,0 ; ... except the direct page has moved.
4457 * These initialization values for USE and PREV were here to help pack the code.
4458 * They don't belong here unless we move the USER table
4459 * back below the writable dictionary,
4460 * *and* move these USER variables to the end of the direct page --
4461 * *or* let these definitions exist in the USER table.
4466 * Makes FORTH the current interpretation vocabulary.
4467 * In order to make this ROMmable, this entry is set up as the tail-end,
4468 * and copied to RAM in the start-up code.
4469 * We want a more elegant solution to this, too. Greedy, maybe.
4471 FCC 'FORT' ; 'FORTH'
4473 FDB NOOP-7 ; Note that this does not link to COLD!
4474 RFORTH FDB DODOES,DOVOC,$81A0,TASK-7
4476 FCC "Copyright 1979 Forth Interest Group, David Lion,"
4478 FCC "Parts Copyright 2019 Joel Matthew Rees"
4484 RTASK FDB DOCOL,SEMIS
4486 ERAMSZ EQU *-RAM ; So we can get a look at it.
4489 * ######>> screen 57 <<
4492 * Sign extend n0 to a double integer.
4496 FDB COLD-7 ; Note that this does not link to FORTH (RFORTH)!
4497 STOD FDB DOCOL,DUP,ZLESS,MINUS
4503 * ( multiplier multiplicand --- product )
4504 * Signed word multiply.
4509 FDB USTAR,DROP,SEMIS ; Drop high word.
4511 * LBSR USTAR+NATWID ; or [USTAR,PCR]?
4512 * LEAU NATWID,U ; Drop high word. Seems like magic, doesn't it?
4520 * ( dividend divisor --- remainder quotient )
4521 * M/ in word-only form, i. e., signed division of 2nd word by top word,
4522 * yielding signed word quotient and remainder.
4523 * Except *BUG* it isn't signed.
4528 SLMOD FDB DOCOL,TOR,STOD,FROMR,USLASH
4532 * ( dividend divisor --- quotient )
4533 * Signed word divide without remainder.
4534 * Except *BUG* it isn't signed.
4538 SLASH FDB DOCOL,SLMOD,SWAP,DROP
4542 * ( dividend divisor --- remainder )
4543 * Remainder function, result takes sign of dividend.
4548 MOD FDB DOCOL,SLMOD,DROP
4552 * ( multiplier multiplicand divisor --- remainder quotient )
4553 * Signed precise division of product:
4554 * multiply 2nd and 3rd words on stack
4555 * and divide the 31-bit product by the top word,
4556 * leaving both quotient and remainder.
4557 * Remainder takes sign of product.
4558 * Guaranteed not to lose significant bits in 16 bit integer math.
4560 FCC '*/MO' ; '*/MOD'
4563 SSMOD FDB DOCOL,TOR,USTAR,FROMR,USLASH
4567 * ( multiplier multiplicand divisor --- quotient )
4568 * */MOD without remainder.
4573 SSLASH FDB DOCOL,SSMOD,SWAP,DROP
4577 * ( ud1 u1 --- u2 ud2 )
4578 * U/ with an (unsigned) double quotient.
4579 * Guaranteed not to lose significant bits in 32 bit / 16 bit bit integer math,
4580 * if you are prepared to deal with the extra 16 bits of result.
4582 FCC 'M/MO' ; 'M/MOD'
4585 MSMOD FDB DOCOL,TOR,ZERO,R,USLASH
4586 FDB FROMR,SWAP,TOR,USLASH,FROMR
4592 * Convert the top of stack to its absolute value.
4597 ABS FDB DOCOL,DUP,ZLESS,ZBRAN
4605 * Convert the top double to its absolute value.
4610 DABS FDB DOCOL,DUP,ZLESS,ZBRAN
4615 * ######>> screen 58 <<
4619 * Least Recently Used buffer.
4620 * Really should be with FIRST and LIMIT in the per-task table.
4629 * Most Recently Used buffer.
4630 * Really should be with FIRST and LIMIT in the per-task table.
4638 * ( buffer1 --- buffer2 f )
4639 * Bump to next buffer,
4640 * flag false if result is PREVious buffer,
4641 * otherwise flag true.
4642 * Used in the LRU allocation routines.
4647 * PBUF FDB DOCOL,LIT8
4648 * FCB $84 ; This was a hard-wiring bug.
4649 PBUF FDB DOCOL,BBUF,BCTL,PLUS ; Size of the buffer record.
4650 * FDB PLUS,DUP,LIMIT,EQUAL,ZBRAN
4651 FDB PLUS,DUP,LIMIT,LESS,ZEQU,OVER,FIRST,LESS,OR,ZBRAN
4652 FDB PBUF2-*-NATWID ; Use defensive programming.
4654 PBUF2 FDB DUP,PREV,AT,SUB
4659 * Flag to mark a buffer dirty, in need of being written out.
4660 * This flag limits the max number of sectors in a disk to ((256^NATWID)/2)-1.
4661 * It also hard-codes an implicit test which is used elsewhere.
4663 FCC 'UPDATE-BI' ; 'UPDATE-BIT'
4670 * Mark PREVious buffer dirty, in need of being written out.
4672 FCC 'UPDAT' ; 'UPDATE'
4675 * UPDATE FDB DOCOL,PREV,AT,AT,LIT,$8000,OR,PREV,AT,STORE
4676 UPDATE FDB DOCOL,PREV,AT,AT,UPDBIT,OR,PREV,AT,STORE
4681 * Mark the buffer addressed as empty.
4682 * Have to add code to avoid block 0 appearing to be in a buffer from COLD.
4683 * Usually, there is no sector 0 (?), but the RAM buffers are too simple.
4684 * Note that without this block number being made illegal,
4685 * about 8 binaryMegabytes (256 bytes/block) of disk can be addressed total.
4686 * With this block number made illegal, the max is 1 block less,
4687 * still about 8 biMeg.
4689 FCC 'KILL-BUFFE' ; 'KILL-BUFFER'
4692 KILBUF FDB *+NATWID ; DOCOL,UPDBIT,ONE,SUB,SWAP,STORE
4694 LDD UPDBIT+NATWID,PCR
4701 * Mark all buffers empty.
4703 FCC 'KILL-BUFFER' ; 'KILL-BUFFERS'
4706 KLBFS FDB DOCOL,FIRST,LIT8
4707 FCB 4 ; Want to make sure it's only four.
4708 FDB ZERO,XDO ; It would be "cleaner" to let +BUF control the loop.
4709 FDB DUP,KILBUF,PBUF,DROP,XLOOP
4711 * KLBFS FDB *+NATWID
4714 * LDD FIRST+NATWID,PCR
4722 * ADDD BBUF+NATWID,PCR
4723 * ADDD BCTL+NATWID,PCR
4734 * Erase and mark all buffers empty.
4735 * Standard method of discarding changes.
4737 FCC 'EMPTY-BUFFER' ; 'EMPTY-BUFFERS'
4740 MTBUF FDB DOCOL,FIRST,LIMIT,OVER,SUB,ERASE
4741 * FDB FIRST,DUP,KILBUF,PBUF,DROP,DUP,KILBUF
4742 * FDB PBUF,DROP,DUP,KILBUF,PBUF,DROP,KILBUF
4748 * Clear the current offset to the block numbers in the drive interface.
4749 * The drives need to be re-architected.
4750 * Would be cool to have RAM and ROM drives supported
4751 * in addition to regular physical persistent store.
4756 DRZERO FDB DOCOL,ZERO,OFSET,STORE
4759 * ======>> 174 <<== system dependant word
4761 * Set the current offset in the drive interface to reference the second drive.
4762 * The hard-coded number in there needs to be in a table.
4767 DRONE FDB DOCOL,LIT,$07D0,OFSET,STORE
4768 ; **** hard-codes the size of the disc !!!!
4771 * ######>> screen 59 <<
4774 * Get a free buffer,
4775 * assign it to block n,
4776 * return buffer address.
4777 * Will free a buffer by writing it, if necessary.
4778 * Does not actually read the block.
4779 * A bug in the fig LRU algorithm, which I have not fixed,
4780 * gives the PREVious buffer if USE gets set to PREVious.
4781 * (The bug is that USE sometimes gets set to PREVious.)
4782 * This bug sometimes causes sector moves to become sector fills.
4784 FCC 'BUFFE' ; 'BUFFER'
4787 BUFFER FDB DOCOL,USE,AT,DUP,TOR
4788 BUFFR2 FDB PBUF,ZBRAN
4790 FDB USE,STORE,R,AT,ZLESS
4793 * FDB R,TWOP,R,AT,LIT,$7FFF,AND,ZERO,RW
4794 FDB R,NATP,R,AT,UPDBIT,LNOT,AND,ZERO,RW
4795 * BUFFR3 FDB R,STORE,R,PREV,STORE,FROMR,TWOP
4796 BUFFR3 FDB R,STORE,R,PREV,STORE,FROMR,NATP
4799 * ######>> screen 60 <<
4802 * Get BUFFER containing block n, relative to OFFSET.
4803 * If block n is not in a buffer, bring it in.
4804 * Returns buffer address.
4806 FCC 'BLOC' ; 'BLOCK'
4809 BLOCK FDB DOCOL,OFSET,AT,PLUS,TOR
4810 FDB PREV,AT,DUP,AT,R,SUB,DUP,PLUS,ZBRAN
4812 BLOCK3 FDB PBUF,ZEQU,ZBRAN
4814 * FDB DROP,R,BUFFER,DUP,R,ONE,RW,TWO,SUB
4815 FDB DROP,R,BUFFER,DUP,R,ONE,RW,NATWC,SUB
4816 BLOCK4 FDB DUP,AT,R,SUB,DUP,PLUS,ZEQU,ZBRAN
4819 * BLOCK5 FDB FROMR,DROP,TWOP
4820 BLOCK5 FDB FROMR,DROP,NATP
4823 * ######>> screen 61 <<
4825 * ( line screen --- buffer C/L)
4826 * Bring in the sector containing the specified line of the specified screen.
4827 * Returns the buffer address and the width of the screen.
4828 * Screen number is relative to OFFSET.
4829 * The line number may be beyond screen 4,
4830 * (LINE) will get the appropriate screen.
4832 FCC '(LINE' ; '(LINE)'
4835 PLINE FDB DOCOL,TOR,LIT8
4837 FDB BBUF,SSMOD,FROMR,BSCR,STAR,PLUS,BLOCK,PLUS,LIT8
4842 * ( line screen --- )
4843 * Print the line of the screen as found by (LINE), suppress trailing BLANKS.
4845 FCC '.LIN' ; '.LINE'
4848 DLINE FDB DOCOL,PLINE,DTRAIL,TYPE
4853 * If WARNING is 0, print "MESSAGE #n";
4854 * otherwise, print line n relative to screen 4,
4855 * the line number may be negative.
4856 * Uses .LINE, but counter-adjusts to be relative to the real drive 0.
4858 FCC 'MESSAG' ; 'MESSAGE'
4861 MESS FDB DOCOL,WARN,AT,ZBRAN
4867 FDB OFSET,AT,BSCR,SLASH,SUB,DLINE,BRAN
4871 FCC 'err # ' ; 'err # '
4877 * Begin interpretation of screen (block) n.
4878 * See also ARROW, SEMIS, and NULL.
4880 FCC 'LOA' ; 'LOAD' : input:scr #
4883 LOAD FDB DOCOL,BLK,AT,TOR,IN,AT,TOR,ZERO,IN,STORE
4884 FDB BSCR,STAR,BLK,STORE
4885 FDB INTERP,FROMR,IN,STORE,FROMR,BLK,STORE
4890 * Continue interpreting source code on the next screen.
4895 ARROW FDB DOCOL,QLOAD,ZERO,IN,STORE,BSCR
4896 FDB BLK,AT,OVER,MOD,SUB,BLK,PSTORE
4901 * ######>> screen 63 <<
4902 * The next 4 subroutines are machine dependent, and are
4903 * called by words 13 through 16 in the dictionary.
4905 * ======>> 182 << code for EMIT
4906 * ( --- ) No parameter stack effect.
4907 * Interfaces directly with ROM. Expects output character in D (therefore, B).
4908 * Output using rom CHROUT: redirectable to a printer on Coco.
4909 * Outputs the character on stack (low byte of 1 bit word/cell).
4910 PEMIT PSHS Y,U,DP ; Save everything important! (For good measure, only.)
4911 TFR B,A ; Coco ROM wants it in A.
4913 TFR B,DP ; Give the ROM its direct page.
4914 JSR [$A002] ; Output the character in A.
4916 * PEMIT STB N save B
4919 * BITB #2 check ready bit
4920 * BEQ PEMIT+4 if not ready for more data
4923 * STB IOSTAT-UORIG,X
4924 * LDB N recover B & X
4926 * RTS only A register may change
4927 * PEMIT JMP $E1D1 for MIKBUG
4928 * PEMIT FCB $3F,$11,$39 for PROTO
4929 * PEMIT JMP $D286 for Smoke Signal DOS
4931 * ======>> 183 << code for KEY
4932 * ( --- ) No parameter stack effect.
4933 * Returns character or break flag in D, since this interfaces with Coco ROM.
4934 * Wait for key from POLCAT on Coco.
4935 * Returns the character code for the key pressed.
4936 PKEY PSHS Y,U,DP ; Must save everything important for this one.
4937 LDA #$CF ; a cursor of sorts
4949 PKEYR CLRB ; for the break flag, shares code with PQTER
4952 COMB ; for the break flag
4953 PKEYGT EXG A,B ; Leave it in D for return.
4954 PULS Y,U,DP,PC ; Shares exit with PQTER
4960 * BCC PKEY+4 no incoming data yet
4962 * ANDA #$7F strip parity bit
4964 * STB IOSTAT+1-UORIG,X
4968 * PKEY JMP $E1AC for MIKBUG
4969 * PKEY FCB $3F,$14,$39 for PROTO
4970 * PKEY JMP $D289 for Smoke Signal DOS
4972 * ######>> screen 64 <<
4973 * ======>> 184 << code for ?TERMINAL
4974 * ( --- f ) Should change this to no stack effect.
4975 * check break key using POLCAT
4976 * Returns a flag to tell whether the break key was pressed or not.
4980 JSR [$A000] ; Look but don't wait.
4982 * PQTER LDA ACIAC Test for 'break' condition
4983 * ANDA #$11 mask framing error bit and
4986 * LDA ACIAD clear input buffer
4993 * ======>> 185 << code for CR
4994 * ( --- ) No stack effect.
4995 * Interfaces directly with ROM.
4996 * For Coco just output a CR.
4997 * Also subject to redirection in Coco BASIC ROM.
4999 BRA PEMIT ; Just steal the code.
5000 * PCR LDA #$D carriage return
5006 * LDB XDELAY+1-UORIG,X
5008 * BMI PQTER2 return if minus
5009 * PSHS B ; save counter
5010 * BSR PEMIT print RUBOUTs to delay.....
5017 * ######>> screen 66 <<
5020 * Query the disk, I suppose.
5021 * Not sure what the model had in mind for this stub.
5023 FCC '?DIS' ; '?DISC'
5029 * ######>> screen 67 <<
5032 * Write one block of data to disk.
5033 * Parameters unspecified in model. Stub in model.
5035 FCC 'BLOCK-WRIT' ; 'BLOCK-WRITE'
5041 * ######>> screen 68 <<
5044 * Read one block of data from disk.
5045 * Parameters unspecified in model. Stub in model.
5047 FCC 'BLOCK-REA' ; 'BLOCK-READ'
5053 *The next 3 words are written to create a substitute for disc
5054 * mass memory,located between MASSLO & MASSHI in ram --
5055 * ($3210 and $3fff in the 6800 model).
5062 FDB MEMEND a system dependent equate at front
5070 FDB MEMTOP ( $3FFF or $7FFF in this version )
5072 * ######>> screen 69 <<
5074 * ( buffer sector f --- )
5075 * Read or Write the specified (absolute -- ignores OFFSET) sector
5076 * from or to the specified buffer.
5077 * A zero flag specifies write,
5078 * non-zero specifies read.
5079 * Sector is an unsigned integer,
5080 * buffer is the buffer's address.
5081 * Will need to use the CoCo ROM disk routines.
5082 * For now, provides a virtual disk in RAM.
5087 RW FDB DOCOL,TOR,BBUF,STAR,LO,PLUS,DUP,HI,GREAT,ZBRAN
5091 FCC ' Range ?' ; ' Range ?'
5101 * LDY $C006 control table
5102 * LDX #DROFFS+7 ; This is BIF's table of drive sizes.
5104 * RWD SUBD ,X++ sectors
5106 * BVC RWR table end?
5110 * RWR ADDD ,--X back one
5113 * LDD #18 sectors/track
5123 * PULS D table entry
5136 * JSR [$C004] ROM handles timeout
5137 * PULS Y,U,DP if IRQ enabled
5140 * LDB 6,X coco status
5150 * ######>> screen 72 <<
5152 * ( --- ) compiling P
5153 * ( --- adr ) interpreting
5155 * Parse a symbol name from input and search the dictionary for it, per -FIND;
5156 * compile the address as a literal if compiling,
5157 * otherwise just push it.
5161 TICK FDB DOCOL,DFIND,ZEQU,ZERO,QERR,DROP,LITER
5165 * ( --- ) { FORGET name } input
5166 * Parse out name of definition to FORGET to, -DFIND it,
5167 * then lop it and everything that follows out of the dictionary.
5168 * In fig Forth, CURRENT and CONTEXT have to be the same to FORGET.
5170 FCC 'FORGE' ; 'FORGET'
5173 FORGET FDB DOCOL,CURENT,AT,CONTXT,AT,SUB,LIT8
5175 FDB QERR,TICK,DUP,FENCE,AT,LESS,LIT8
5177 FDB QERR,DUP,ZERO,PORIG,GREAT,LIT8
5179 FDB QERR,DUP,NFA,DICTPT,STORE,LFA,AT,CONTXT,AT,STORE
5182 * ######>> screen 73 <<
5185 * Calculate a back reference from HERE and compile it.
5190 * BACK FDB DOCOL,HERE,SUB,COMMA
5191 BACK FDB DOCOL,HERE,NATP,SUB,COMMA
5196 * typical use: BEGIN code-loop test UNTIL
5197 * typical use: BEGIN code-loop AGAIN
5198 * typical use: BEGIN code-loop test WHILE code-true REPEAT
5199 * ( --- adr n ) compile time P,C
5200 * Push HERE for BACK reference for general (non-counting) loops,
5201 * with BEGIN construct flag.
5202 * A better flag: $4245 (ASCII for 'BE').
5204 FCC 'BEGI' ; 'BEGIN'
5207 BEGIN FDB DOCOL,QCOMP,HERE,ONE ; ONE is a flag for BEGIN loops.
5212 * typical use: test IF code-true ELSE code-false ENDIF
5213 * ENDIF is just a sort of intersection piece,
5214 * marking where execution resumes after both branches.
5215 * ( adr n --- ) compile time
5216 * Check the mark and resolve the IF.
5217 * A better flag: $4846 (ASCII for 'IF').
5219 FCC 'ENDI' ; 'ENDIF'
5222 ENDIF FDB DOCOL,QCOMP,TWO,QPAIRS,HERE ; This TWO is a flag for IF.
5223 * FDB OVER,SUB,SWAP,STORE
5224 FDB OVER,NATP,SUB,SWAP,STORE
5229 * typical use: test IF code-true ELSE code-false ENDIF
5236 THEN FDB DOCOL,ENDIF
5240 * ( limit index --- ) runtime
5241 * typical use: DO code-loop LOOP
5242 * typical use: DO code-loop increment +LOOP
5243 * Counted loop, index is initial value of index.
5244 * Will loop until index equals (positive going)
5245 * or passes (negative going) limit.
5246 * ( --- adr n ) compile time P,C
5247 * Compile (DO), push HERE for BACK reference,
5248 * and push DO control construct flag.
5249 * A better flag: $444F (ASCII for 'DO').
5254 DO FDB DOCOL,COMPIL,XDO,HERE,THREE ; THREE is a flag for DO loops.
5259 * typical use: DO code-loop LOOP
5260 * Increments the index by one and branches back to beginning of loop.
5261 * Will loop until index equals limit.
5262 * ( adr n --- ) compile time P,C
5263 * Check the mark and compile (LOOP), fill in BACK reference.
5264 * A better flag: $444F (ASCII for 'DO').
5269 LOOP FDB DOCOL,THREE,QPAIRS,COMPIL,XLOOP,BACK ; THREE for DO loops.
5274 * typical use: DO code-loop increment +LOOP
5275 * Increments the index by n and branches back to beginning of loop.
5276 * Will loop until index equals (positive going)
5277 * or passes (negative going) limit.
5278 * ( adr n --- ) compile time P,C
5279 * Check the mark and compile (+LOOP), fill in BACK reference.
5280 * A better flag: $444F (ASCII for 'DO').
5282 FCC '+LOO' ; '+LOOP'
5285 PLOOP FDB DOCOL,THREE,QPAIRS,COMPIL,XPLOOP,BACK ; THREE for DO loops.
5290 * typical use: BEGIN code-loop test UNTIL
5291 * Will loop until UNTIL tests true.
5292 * ( adr n --- ) compile time P,C
5293 * Check the mark and compile (0BRANCH), fill in BACK reference.
5294 * A better flag: $4245 (ASCII for 'BE').
5296 FCC 'UNTI' ; 'UNTIL' : ( same as END )
5299 UNTIL FDB DOCOL,ONE,QPAIRS,COMPIL,ZBRAN,BACK ; ONE for BEGIN loops.
5302 * ######>> screen 74 <<
5305 * typical use: BEGIN code-loop test END
5317 * typical use: BEGIN code-loop AGAIN
5319 * (or until something uses R> DROP to force the current definition to die,
5320 * or perhaps ABORT or ERROR or some such other drastic means stops things).
5321 * ( adr n --- ) compile time P,C
5322 * Check the mark and compile (0BRANCH), fill in BACK reference.
5323 * A better flag: $4245 (ASCII for 'BE').
5325 FCC 'AGAI' ; 'AGAIN'
5328 AGAIN FDB DOCOL,ONE,QPAIRS,COMPIL,BRAN,BACK ; ONE for BEGIN loops.
5333 * typical use: BEGIN code-loop test WHILE code-true REPEAT
5334 * Will loop until WHILE tests false, skipping code-true on end.
5335 * REPEAT marks where execution resumes after the WHILE find a false flag.
5336 * ( aadr1 n1 adr2 n2 --- ) compile time P,C
5337 * Check the marks for WHILE and BEGIN,
5338 * compile BRANCH and BACK fill adr1 reference,
5339 * FILL-IN 0BRANCH reference at adr2.
5340 * Better flags: $4245 (ASCII for 'BE') and $5747 (ASCII for 'WH').
5342 FCC 'REPEA' ; 'REPEAT'
5345 REPEAT FDB DOCOL,TOR,TOR,AGAIN,FROMR,FROMR ; ONE for BEGIN loops.
5346 FDB TWO,SUB,ENDIF ; TWO is for IF, 4 is for WHILE.
5351 * typical use: test IF code-true ELSE code-false ENDIF
5352 * Will pass execution to the true part on a true flag
5353 * and to the false part on a false flag.
5354 * ( --- adr n ) compile time P,C
5355 * Compile a 0BRANCH and dummy offset
5356 * and push IF reference to fill in and
5357 * IF control construct flag.
5358 * A better flag: $4946 (ASCII for 'IF').
5363 IF FDB DOCOL,COMPIL,ZBRAN,HERE,ZERO,COMMA,TWO ; TWO is a flag for IF.
5368 * typical use: test IF code-true ELSE code-false ENDIF
5369 * ELSE is just a sort of intersection piece,
5370 * marking where execution resumes on a false branch.
5371 * ( adr1 n --- adr2 n ) compile time P,C
5373 * compile BRANCH with dummy offset,
5374 * resolve IF reference,
5375 * and leave reference to BRANCH for ELSE.
5376 * A better flag: $4946 (ASCII for 'IF').
5381 ELSE FDB DOCOL,TWO,QPAIRS,COMPIL,BRAN,HERE
5382 FDB ZERO,COMMA,SWAP,TWO,ENDIF,TWO ; TWO is a flag for IF.
5387 * typical use: BEGIN code-loop test WHILE code-true REPEAT
5388 * Will loop until WHILE tests false, skipping code-true on end.
5389 * ( --- adr n ) compile time P,C
5390 * Compile 0BRANCH with dummy offset (using IF),
5391 * push WHILE reference.
5392 * BEGIN flag will sit underneath this.
5393 * Better flags: $4245 (ASCII for 'BE') and $5747 (ASCII for 'WH').
5395 FCC 'WHIL' ; 'WHILE'
5398 WHILE FDB DOCOL,IF,TWOP ; TWO is a flag for IF, 4 is for WHILE.
5401 * ######>> screen 75 <<
5404 * EMIT count spaces, for non-zero, non-negative counts.
5406 FCC 'SPACE' ; 'SPACES'
5409 SPACES FDB DOCOL,ZERO,MAX,DDUP,ZBRAN
5412 SPACE2 FDB SPACE,XLOOP
5418 * Initialize HLD for converting a double integer.
5419 * Stores the PAD address in HLD.
5424 BDIGS FDB DOCOL,PAD,HLD,STORE
5428 * ( d --- string length )
5429 * Terminate numeric conversion,
5430 * drop the number being converted,
5431 * leave the address of the conversion string and the length, ready for TYPE.
5436 EDIGS FDB DOCOL,DROP,DROP,HLD,AT,PAD,OVER,SUB
5441 * Put sign of n (as a flag) at the head of the conversion string.
5442 * Drop the sign flag.
5447 SIGN FDB DOCOL,ROT,ZLESS,ZBRAN
5456 * Generate next most significant digit in the conversion BASE,
5457 * putting the digit at the head of the conversion string.
5461 DIG FDB DOCOL,BASE,AT,MSMOD,ROT,LIT8
5475 * Convert d to a numeric string using # until the result is zero.
5476 * Leave the double result on the stack for #> to drop.
5482 DIGS2 FDB DIG,OVER,OVER,OR,ZEQU,ZBRAN
5486 * ######>> screen 76 <<
5489 * Print n on the output device in the current conversion base,
5491 * right aligned in a field at least width wide.
5496 DOTR FDB DOCOL,TOR,STOD,FROMR,DDOTR
5501 * Print d on the output device in the current conversion base,
5503 * right aligned in a field at least width wide.
5508 DDOTR FDB DOCOL,TOR,SWAP,OVER,DABS,BDIGS,DIGS,SIGN
5509 FDB EDIGS,FROMR,OVER,SUB,SPACES,TYPE
5514 * Print d on the output device in the current conversion base,
5516 * in free format with trailing space.
5521 DDOT FDB DOCOL,ZERO,DDOTR,SPACE
5526 * Print n on the output device in the current conversion base,
5528 * in free format with trailing space.
5532 DOT FDB DOCOL,STOD,DDOT
5537 * Print signed word at adr, per DOT.
5541 QUEST FDB DOCOL,AT,DOT
5544 * ######>> screen 77 <<
5547 * Print out screen n as a field of ASCII,
5548 * with line numbers in decimal.
5549 * Needs a console more than 70 characters wide.
5554 LIST FDB DOCOL,DEC,CR,DUP,SCR,STORE,PDOTQ
5560 LIST2 FDB CR,I,THREE
5561 FDB DOTR,SPACE,I,SCR,AT,DLINE,XLOOP
5568 * Print comment lines (line 0, and line 1 if C/L < 41) of screens
5569 * from start to end.
5570 * Needs a console more than 70 characters wide.
5572 FCC 'INDE' ; 'INDEX'
5575 INDEX FDB DOCOL,CR,ONEP,SWAP,XDO
5576 INDEX2 FDB CR,I,THREE
5577 FDB DOTR,SPACE,ZERO,I,DLINE
5587 * List a printer page full of screens.
5588 * Line and screen number are in current base.
5589 * Needs a console more than 70 characters wide.
5591 FCC 'TRIA' ; 'TRIAD'
5594 TRIAD FDB DOCOL,THREE,SLASH,THREE,STAR
5595 FDB THREE,OVER,PLUS,SWAP,XDO
5597 FDB LIST,QTERM,ZBRAN
5607 * ######>> screen 78 <<
5610 * Alphabetically list the definitions in the current vocabulary.
5611 * Expects to output to printer, not TRS80 Color Computer screen.
5613 FCC 'VLIS' ; 'VLIST'
5616 VLIST FDB DOCOL,LIT8
5618 FDB OUT,STORE,CONTXT,AT,AT
5619 VLIST1 FDB OUT,AT,COLUMS,AT,LIT8
5623 FDB CR,ZERO,OUT,STORE
5624 VLIST2 FDB DUP,IDDOT,SPACE,SPACE,PFA,LFA,AT
5625 FDB DUP,ZEQU,QTERM,OR,ZBRAN
5630 * Need some utility stuff that isn't in the fig FORTH:
5632 * Emit dot if c is less than blank, else emit c
5634 FCC 'BEMI' ; 'BEMIT'
5638 FDB DUP,BL,LESS,ZBRAN
5646 * Output n in hexadecimal field width.
5652 FDB BASE,AT,TOR,HEX,DOTR,FROMR,BASE,STORE
5656 * Dump a line of 4 bytes in memory, in hex and as characters.
5658 FCC 'BLIN' ; 'BLINE'
5665 BLINEX FDB I,CAT,THREE,XDOTR,XLOOP
5671 BLINEC FDB I,CAT,BEMIT,XLOOP
5676 * Dump 4 byte lines from start to end.
5678 FCC 'BDUM' ; 'BDUMP'
5696 * Mostly for place holding (fig Forth).
5703 * NOOP NEXT a useful no-op
5704 ZZZZ FDB 0,0,0,0,0,0,0,0 end of rom program
5707 * These things, up through the lable 'REND', are overwritten
5708 * at time of cold load and should have the same contents
5711 * This can be moved whereever the bottom of the
5712 * user's dictionary is going to be put.
5716 FCC 'FORT' ; 'FORTH'
5719 FORTH FDB DODOES,DOVOC,$81A0,TASK-7
5722 FCC "Copyright 1979 Forth Interest Group, David Lion,"
5724 FCC "Parts Copyright 2019 Joel Matthew Rees"
5731 TASK FDB DOCOL,SEMIS
5733 REND EQU * ( first empty location in dictionary )
5734 RSIZE EQU *-RBEG ; So we can look at it.
5738 * "0 1 2 3 4 5 6 " ;
5739 * "0123456789012345678901234567890123456789012345678901234567890123" ;
5740 FCC " 0) Index page " ; 0
5741 FCC " 1) empty line on line 1 of screen 0 block 0 " ; 1
5742 FCC " 2) Title and copyright " ; 2
5743 FCC " 3) empty line on line 3 of screen 0 block 0 " ; 3
5744 FCC " 4) Error messages 1st screen " ; 4
5745 FCC " 5) Error messages 2nd screen " ; 5
5746 FCC " 6) empty line 3 screen 0 block 1 " ; 6
5747 FCC " 7) empty line 4 " ; 7
5748 FCC " 8) and line 1 of block 2 " ; 8
5749 FCC " 9) line 2 of block 2 screen 0 is pretty much empty too " ; 9
5750 FCC " 10) listen to this. Line three of block two is too " ; 10
5751 FCC " 11) and so is line 4 4 4 4 4 4 4 4 4 4 b2s0 " ; 11
5752 FCC " 12) screen zero block three first line " ; 12
5753 FCC " 13) second line fourth block (block three) screen 0 " ; 13
5754 FCC " 14) block three screen zero line 3 3 3 3 3 3 3 3 3 " ; 14
5755 FCC " 15) fourth line block three screen 0 0 0 0 0 0 0 0 0 0 " ; 15
5756 * "0 1 2 3 4 5 6 " ;
5757 * "0123456789012345678901234567890123456789012345678901234567890123" ;
5758 FCC " test 10 b0s1 aaaa " ; 0
5759 FCC " test 11 b0s1 ee ee ee ee " ; 1
5760 FCC " test 12 b0s1 oo oo oo oo oo " ; 2
5761 FCC " test 13 b0s1 eh ehe he eh eh " ; 3
5762 FCC " ( block 1 ) b1s1 oh ohoo oh oh oh " ; 4
5763 FCC " 15 test b1s1 " ; 5
5764 FCC " 16 test b1s1 " ; 6
5765 FCC " 17 test b1s1 " ; 7
5766 FCC " 18 test b2s1 " ; 8
5767 FCC " 19 test b2s1 " ; 9
5768 FCC " 1A test b2s1 " ; 10
5769 FCC " 1B test b2ws1 " ; 11
5770 FCC " 1C test b3s1 " ; 12
5771 FCC " 1D test b3s1 " ; 13
5772 FCC " 1e this completes our second screen b3s1 " ; 14
5773 FCC " 1F test b3s1 " ; 15
5774 * "0 1 2 3 4 5 6 " ;
5775 * "0123456789012345678901234567890123456789012345678901234567890123" ;
5777 FCC " fig Forth High Level Model Code " ; 1
5779 FCC " Copyright 2018 Joel Matthew Rees " ; 3
5780 FCC " ( block 2 ) " ; 4
5792 * "0 1 2 3 4 5 6 " ;
5793 * "0123456789012345678901234567890123456789012345678901234567890123" ;
5798 FCC " ( block 3 ) " ; 4
5810 * "0 1 2 3 4 5 6 " ;
5811 * "0123456789012345678901234567890123456789012345678901234567890123" ;
5816 FCC " ( block 4 ) " ; 4
5828 * "0 1 2 3 4 5 6 " ;
5829 * "0123456789012345678901234567890123456789012345678901234567890123" ;
5830 FCC " ( ERROR MESSAGES ) " ; 0
5831 FCC " DATA STACK UNDERFLOW " ; 1
5832 FCC " DICTIONARY FULL " ; 2
5833 FCC " ADDRESS RESOLUTION ERROR " ; 3
5834 FCC " HIDES DEFINITION IN " ; 4
5846 * "0 1 2 3 4 5 6 " ;
5847 * "0123456789012345678901234567890123456789012345678901234567890123" ;
5848 FCC " more test data 2 3 4 5 6 " ; 0
5849 FCC "0123456789012345678901234567890123456789012345678901234567890123" ; 1
5850 FCC "Test data for the RAM disc emulator buffers. " ; 2
5852 FCC " ( block 6 ) " ; 4