Page# 1 C:CMFORTH.3
0 31 0 cmForth for RTX2000 and RTX2001 cmForth was originally written for NC4000 by Chuck Moore. 1 ---------------------------------------------------------------- Modified for RTX2000 by Thor-Bjorn Bladh, Lund, Sweden. 2 cmForth was originally written by Chuck Moore for NC4000 chip Source code listed restored to cmForth style by Jay Melvin. 3 and released to the public domain in March 1985. Comment screens restored by C. H. Ting. 4 Jay Melvin provided documentation for cmForth in shadow screens Stack comments: 5 in January 1986. ; ( n) indicates the cost in machine cycles when executed 6 Chuck Moore modified cmForth and the shadows in Dec. 1987. a an address, e.g. head of a thread 7 Thor-Bjorn Bladh, Lund, Sweden modified cmForth to run on n is an integer, +32767/-32768, e.g. a vocabulary mask 8 RTX2000 in November 1988. It is distributed with Bladh's u means unsigned ( < 65536 ) and d is double, i.e. 32-bit 9 INDELKO RTX Forth Kit. # loop counter (the number of iterations) or a count 10 Jay Melvin restored the RTX cmForth source code to the style h is HERE , address of WORD's buffer & dictionary pointer 11 used in the original cmForth, in January 1989. t or f indicate Boolean truth values, True=-1 False=0 12 C. H. Ting restored the shadow screen documentation for RTX , ( in comment) shows alternate effects, this or that 13 cmForth in July 1989. r is the remainder of a divide 14 Thor-Bjorn Bladh modified cmForth and the shadows in Aug. 1989 q is the quotient of a divide 15 and changed the default mode to RTX2001A in March 1990. l h means Low High (exclusive at top) limits of a range
1 32 0 ( cmForth for RTX2001A 90Mar8 by Thor-Bjorn Bladh) cmForth shadow blocks. Addresses are in hex; 1 word timing in parentheses after ; ( cycles). 2 ( Compacting) 4 LOAD 5 LOAD 6 LOAD 7 LOAD 3 LOAD compiles the compacting compiler (blocks 4-7). 3 Block 7 exits in COMPILER vocabulary, anticipates additions. 4 : END \ RECURSIVE R>DROP ; 5 : REMEMBER; CONTEXT 4 - 2@ , , \ END ; END terminates a definition. 6 REMEMBER; saves vocabulary heads (at compile time). 7 FORTH FORTH puts following words in interpretive vocabulary. 8 9 : THRU ( n n) OVER - FOR DUP LOAD 1 + NEXT DROP ; THRU loads a sequence of blocks. 10 : EMPTY FORGET REMEMBER; EMPTY empties the dictionary except for compacting compiler. 11 12 HEX 13 ( ' M* DUP DUP B097 SWAP ! BE16 SWAP 2 + ! BE37 SWAP 4 + !) Multiply patches for RTX2000. See block 9. 14 ( ' * DUP DUP B097 SWAP ! BE16 SWAP 2 + ! A060 SWAP 4 + !) 15
2 33 0 ( Separated heads) H' points to the target dictionary's next available address. 1 VARIABLE H' HEX 2000 , ( relocation) 0000 (or 2000) relocates target addresses for RAM (or PROM). 2 : { dA @ HERE H' 2@ H ! dA ! H' 2! ; { switches to host (and } to target) dictionary by exchanging 3 : } { ; dictionary pointers and relocation offsets. 4 COMPILER : } H' @ 2 * ,A \\ PREVIOUS 80 XOR SWAP C! { ; COMPILER } compiles an indirect reference for a headless word. 5 FORTH : forget SMUDGE ; forget smudges a word that cannot execute in target dictionary. 6 : RECOVER -2 ALLOT ; RECOVER recovers a return semi-colon after an infinite loop. 7 : ADR>CALL ( a - n) dA @ - U2/ ; ADR>CALL converts an address to a relocated call instruction. 8 9 : SCAN ( a - a) @ BEGIN DUP 1 2000 WITHIN WHILE @ REPEAT ; SCAN finds the next word in target dictionary. 10 : TRIM ( a a - a) DUP >R dA @ - SWAP ! R> TRIM relocates the vocabulary link and erases the smudge bit. 11 DUP 2 + DUP C@ DF AND SWAP C! ; CLIP constructs a target vocabulary and compiles its head into 12 : CLIP ( a) DUP BEGIN DUP SCAN DUP WHILE TRIM REPEAT target dictionary ( after FORGET in RESET ). 13 2212 XOR dA @ - SWAP ! @ , ; PRUNE relinks the target dictionary to produce a stand-alone 14 : PRUNE { CONTEXT 4 - DUP CLIP 2 + CLIP { application (fixing the end-of-vocabulary word) 15 20 0 2212 2! EMPTY ; and restores the host dictionary.
RTX cmForth Version 3.0, March 1990
Page# 2 C:CMFORTH.3
3 34 0 ( cmForth RTX2001A 90Mar8) EMPTY 3 LOAD recompiles cmForth. 1 ( Target compiler) 2 LOAD 2 LOAD compiles the target compiler. 2 HEX 2000 1000 0 FILL 2000 H' ! Target is compiled at 2000 which is initialized to 0. 3 : BOOT } 40 FDF FOR 0 @+ 2 !+ NEXT DROP ( reset) 0 ; BOOT copies PROM to RAM at power-up and calls reset (Block 23). 4 2040 H ! A000 , A020 , 2204 H ! 2040 2044 E0 MOVE The interrupt vector area is filled with NOPs and RETURNs. 5 ( SPAN) F7C0 , ( >IN) 0 , ( BLK) 0 , ( dA) 0 , Low RAM is initialized. See Block 12. 6 ( ?CODE) 0 , ( CURSOR) 0 , ( BASE) A , These variables will be MOVEd by reset . 7 DECIMAL # is the bottom of the target dictionary. 8 ( Nucleus) : # R>DROP ; 8 11 THRU ( Variables) 12 LOAD PRUNE changes its name to null and link to 0. 9 ( Terminal) 13 14 THRU ( Output) 15 16 THRU This version of EXIT marks the end of both vocabulary chains. 10 ( Disk) 17 18 THRU ( Interpreter) 19 22 THRU 11 ( Initialize) 23 24 THRU ' reset ADR>CALL HEX 2012 ! The address of reset is relocated into the end of BOOT. 12 DECIMAL 13 ( Compiler) 25 30 THRU } PRUNE HEX Target and host dictionaries are separated by PRUNE . 14 : GO FLUSH 40 7DF FOR DUP 2000 + @ SWAP 2 !+ NEXT GO emulates BOOT for testing: 3 LOAD GO 15 DROP 2012 >R ;
4 35 0 ( Optimizing compiler) HEX FORTH sets interpretive vocabulary for both searches 1 : FORTH 2 CONTEXT ! ; and definitions. Words are compiled in definitions. 2 : COMPILER 4 CONTEXT ! ; COMPILER sets immediate vocabulary. Words are executed in : . 3 : uCODE ( n) CREATE , DOES R> @ ,C ; uCODE names an RTX micro-coded instruction. Compiled on use. 4 \ compiles a following compiler directive that would normally 5 COMPILER : \ 4 -' IF DROP ABORT" ?" THEN ,A ; be executed. Named [COMPILE] in FORTH-83. 6 B001 uCODE R>DROP BF40 uCODE -1 A000 uCODE NOP 7 A100 uCODE INVERT E080 uCODE N! A040 uCODE SWAP-DROP RTX instructions: 8 FORTH : DUP? HERE 6 - 2@ D000 AND D000 = NOT SWAP A0C0 = AND R>DROP -1 NOP SWAP-DROP Obvious functions. 9 IF HERE 2 - @ E00 XOR -4 ALLOT ,C THEN ; N! non-destructive store (preserves data but not address). 10 INVERT one's complement of T. 11 : BRANCH? ( d s - d n t) BLOCKEND? dA @ - FC00 AND 12 OVER FC00 AND DUP DUP? compacts preceeding DUP with current instruction. 13 IF - DUP IF 400 = 600 SWAP ELSE -1 THEN BRANCH? determines if the destination address is within reach 14 ELSE 2DROP 400 -1 and if so returns the block code for a branch instruction and 15 THEN ; a true flag. Otherwise it returns a dummy and a false flag.
5 36 0 ( Defining words) HEX PACK sets the return bit. If the instruction is >R or DUP >R, 1 FORTH : PACK ( a n) B0DF AND B081 = it will be converted to PC G! or DUP PC G!. It exits from 2 IF 26 ELSE 20 THEN SWAP +! R>DROP ; EXIT ( R>DROP ). 3 COMPILER : EXIT ?CODE @ DUP 4 IF DUP @ B0FF AND B001 = OVER 2 - @ BE82 = OR NOT EXIT optimizes return if permitted ( ?CODE nonzero): 5 IF \\ DUP @ DUP 0< For instructions (bit 15 = 1) it calls PACK except 6 IF PACK for return stack pops and streamed instructions ( OF( ). 7 ELSE 2 * OVER BRANCH? For calls to a valid 1 KB page, it substitutes a branch. 8 IF SWAP 3FF AND 2 / OR 9000 OR SWAP ! EXIT Otherwise it compiles a subroutine return. 9 THEN DROP 10 THEN DROP ; is redefined to use the new EXIT. 11 THEN 12 THEN DROP A020 , ; CONSTANT is also redefined to take advantage of the new EXIT. 13 14 : ; \ RECURSIVE R>DROP \ EXIT ; 15 FORTH : CONSTANT ( n) CREATE -2 ALLOT \ LITERAL \ EXIT ;
RTX cmForth Version 3.0, March 1990
Page# 3 C:CMFORTH.3
6 37 0 ( Binary operators) HEX BINARY defines and compacts ALU instructions. 1 FORTH : BINARY ( n) CREATE , DOES R> @ ?CODE @ DUP If the current instruction is OVER or SWAP and if the 2 IF DUP 2 - 2@ FFBF AND AE80 = SWAP FFBF AND AE80 = AND previous is OVER or SWAP and not a literal, the ALU code 3 IF DUP 4 - @ D000 AND D000 XOR is merged. MAX and MIN are the only words in cmForth that 4 IF 2 - DUP 2@ - C0 AND 80 XOR benefit from this part of BINARY . See block 11. 5 >R SWAP R> XOR SWAP ! -2 DUP ALLOT ?CODE +! EXIT Caution! SWAP SWAP alu-op is compiled as OVER OVER alu-op. 6 THEN 7 ELSE DUP @ DUP B000 > SWAP F80 AND E00 = AND If the current instruction is a valid candidate and has not 8 IF SWAP F00 AND DUP 600 AND 400 = IF 800 XOR THEN already been merged, the ALU code is extracted and checked 9 SWAP DUP 4 - 2@ D000 AND D000 = NOT SWAP A0C0 = AND for - and SWAP- , which must be interchanged. 10 IF DUP @ >R DUP DUP 2 + @ SWAP ! 2 - SWAP R> If the previous cell is DUP and not a literal, it will be 11 -2 DUP ALLOT ?CODE +! compacted. Long literal values are cared for. 12 ELSE SWAP 80 XOR OVER @ 13 THEN F0FF AND XOR SWAP ! EXIT 14 THEN THEN 15 THEN DROP ,C ; If no merge takes place the ALU is compiled as defined.
7 38 0 ( Binary operators, continued) HEX SHIFT defines and compacts shift instructions. 1 FORTH Shift, rotation and sign extension can be merged with 2 : SHIFT ( n) CREATE , DOES R> @ ?CODE @ DUP ALU instructions. 3 IF @ DUP F01F AND A000 = 4 IF XOR ?CODE @ ! EXIT + - SWAP- AND OR XOR 6 basic RTX ALU functions. 5 THEN 6 THEN DROP A000 XOR ,C ; C!+ stores a byte and increment the address. 7 C@+ fetches a byte and increment the address. 8 COMPILER A840 BINARY + AA40 BINARY XOR A640 BINARY OR G! stores to a register or an ASIC peripheral device. 9 AC40 BINARY - A240 BINARY AND A440 BINARY SWAP- >R pops T and pushes it on the return stack. 10 11 : C!+ F9C0 SHORT ; : G! BE80 SHORT DUP? ; 2* 2/ 0< Obvious functions. 12 : C@+ F940 SHORT ; : >R BE81 ,C DUP? ; cU2/ shifts T right one bit and fills MSB with carry. 13 U2/ shifts T right one bit and clears MSB. 14 2 SHIFT 2* 7 SHIFT 2/ 1 SHIFT 0< 4 SHIFT cU2/ 6 SHIFT U2/ 15
8 39 0 ( Nucleus) HEX ROT is a slow way to reference into the stack. 1 : ROT ( n n n - n n n) >R SWAP R> SWAP ; ( 5) 2 0= returns false (0) if stack non-zero; otherwise true (-1). 3 : 0= ( n - t) IF 0 EXIT THEN -1 ; ( 3) NOT same as 0=. Forth-83 want's one's complement. 4 : NOT ( n - t) 0= ; ( 4) < > subtract and test sign bit. Range of difference limited 5 : < ( n n - t) - 0< ; ( 2) to 15 bits, -32768 is not less than 32767. 6 : > ( n n - t) SWAP- 0< ; ( 2) = equality test by XOR. 7 : = ( n n - t) XOR 0= ; ( 5) U< unsigned compare with 16 bit range (0 is less then 65535). 8 : U< ( u u - t) - cU2/ INVERT 0< ; ( 3) 9 { ... } surround words used by the host dictionary. 10 { COMPILER Used during compilation, they will not be in target dictionary. 11 A SHIFT D2* 12 A41A uCODE U/1' A45A uCODE U/' A458 uCODE U/'' D2* left-shifts T and N. 13 A89D uCODE *' A49D uCODE *'' U/1' U/' U/'' First, main and last divide steps. 14 FORTH } *' *'' Main and last signed multiply steps are 15 needed for RTX2001A. See block 9.
RTX cmForth Version 3.0, March 1990
Page# 4 C:CMFORTH.3
9 40 0 ( Multiply, divide) M/MOD divides d by n. Leave quotient and 1 : M/MOD ( l h u - q r) 4 G! 0 + D2* U/1' 13 OF( U/' U/'' ; remainder on stack. Order reversed from Forth-83. 2 ( 22) M/ signed double dividend by unsigned. 3 : M/ ( l h u - q) OVER 0< IF DUP >R + R> THEN M/MOD DROP ; 4 ( 26-29) 5 HEX M* multiplies two signed integers to form a double product. 6 /MOD divide unsigned integers and return both remainder 7 : M* ( n n - d) 4 G! 0 0 + E OF( *' *'' ; ( 22) and quotient. 8 ( : M* DUP 17 G! 16 G@ 17 G@ ; ( 4 RTX2000) MOD remainder of unsigned integer division. 9 : /MOD ( u u - r q) 0 SWAP M/MOD SWAP ; ( 26) 10 : MOD ( u u - r) /MOD DROP ; ( 28) */ ratio of n times n' over u. 11 * signed multiply. 12 : */ ( n n u - q) >R M* R> M/ ; ( 33-36) / signed divide. 13 : * ( n n - n) 4 G! 0 0 + E OF( *' *'' DROP ; ( 23) 14 ( : * DUP 17 G! 16 G@ SWAP-DROP ; ( 4 RTX2000) 15 : / ( n u - q) >R DUP 0< R> M/ ; ( 30-33)
10 41 0 ( Memory reference operators) +! increments the value at a by n . 1 : +! ( n a) 0 @+ >R + R> ! ; ( 8) 2 : C! ( n a) C! ; ( 2) C! stores 8 bit data into a . 3 : C@ ( a - n) C@ ; ( 2) C@ fetches 8 bit data from a . 4 : 2@ ( a - d) 2 @+ @ SWAP ; ( 6) 5 : 2! ( d a) 2 !+ ! ; ( 5) 2@ fetches 2 16 bit numbers, lower address on top. 6 2! stores 2 16 bit numbers. 7 { HEX COMPILER : -ZERO ( a - a' a) 2 + \ BEGIN 9000 , ; 8 FORTH } -ZERO skips first round in a loop. 9 10 : MOVE ( s d #) >R 4 G! BEGIN -ZERO MOVE copies a range of 16 bit integers. 11 2 @+ SWAP 4 G@ 2 !+ 4 G! THEN NEXT DROP ; ( 8* 6+) 12 FILL fills # bytes with number n , starting at a . 13 : FILL ( a # n) 4 G! FOR -ZERO 4 G@ SWAP 1 C!+ THEN NEXT 14 DROP ; ( 5* 6+) 15
11 42 0 ( Words) EXECUTE executes code at an address by returning. 1 : EXECUTE ( a) >R ; ( 1) CYCLES delays n+4 cycles. 2 : CYCLES ( n) FOR NEXT ; ( 4 n +) 3 : ?DUP ( n - n n, 0) DUP IF DUP EXIT THEN ; ( 4) 2DUP treats the registers N & T as a pair. 4 : 2DUP ( d - d d) OVER OVER ; ( 3) ?DUP frequently precludes DROP after IFs . 5 : 2DROP ( d) DROP DROP ; ( 3) 2DROP Discard 2 integers from the stack. 6 7 : WITHIN ( n l h - t) OVER - >R - R> U< ; WITHIN returns true if number within low (inclusive) and 8 : ABS ( n - u) DUP 0< IF NEGATE EXIT THEN ; ( 4) high (exclusive) limits; all numbers 16 bits and signed. 9 ABS returns positive number, 16 bits. 10 : MAX ( n n - n) OVER OVER - 0< IF BEGIN SWAP-DROP ; ( 4) MAX returns larger of pairs; 15 bit range. 11 : MIN ( n n - n) OVER OVER - 0< UNTIL THEN DROP ; ( 4) MIN returns smaller. Interwining code saves 2 cycles; 12 left in as an illustration of obscure but efficient code. 13 See block 6. 14 15
RTX cmForth Version 3.0, March 1990
Page# 5 C:CMFORTH.3
12 43 0 ( RAM allocation) HEX ARRAY defines an array that doubles an index from stack 1 { : ARRAY ( n) CONSTANT A022 USE ; in only 1 cycle. Similar to VARIABLE. 2 ( Block in each buffer) 0 ARRAY BUFFERS These low RAM variables are used by cmForth. 3 ( Last referenced buffer) 4 CONSTANT PREV Change them cautiosly!. In particular, make sure a variable 4 ( Oldest loaded buffer) 6 CONSTANT OLDEST } is not used during compilation. For example, HEX is redefined 5 to set BASE. It can be used if BASE has not moved; 6 ( Number of buffers) 2 1 - CONSTANT NB otherwise it must be 'forget'ted. 7 ( TextInputBuffer) 8 CONSTANT TIB 8 Non-standard variables: 9 ( Initialized) ?CODE address of last instruction compiled. 10 A CONSTANT SPAN C CONSTANT >IN { E CONSTANT BLK } Zero indicates no compaction permitted; e.g. after THEN. 11 10 CONSTANT dA dA offset to be added to compiled address. Normally 0. 12 12 CONSTANT ?CODE 14 CONSTANT CURSOR Relocated code cannot be executed. 13 16 CONSTANT BASE 18 CONSTANT H CURSOR tracks terminal cursor; used by EXPECT. 14 1A CONSTANT C/B 20 CONSTANT CONTEXT C/B cycles/bit for serial I/O. 15
13 44 0 ( Terminal I/O) HEX EMIT transmits a byte through the BOOT pin via bit 3 1 : EMIT ( n) 100 OR 10 * 9 FOR in the Configuration Register CR. It emits bits at C/B rate. 2 DUP 8 AND 10 OR 3 G! 2/ C/B @ A - CYCLES NEXT DROP ; 3 : CR D EMIT A EMIT ; CR emits carriage-return and line-feed. 4 EVEN aligns an odd address or count to the next even. 5 : EVEN ( n - n, n') 1 + FFFE AND ; TYPE types a string with prefixed count byte. It returns an 6 : TYPE ( a - a) 1 C@+ SWAP 1 - FOR 1 C@+ SWAP EMIT incremented address. This is not Forth-83 standard. 7 NEXT EVEN ; 8 RX reads a bit from EI1 pin. 9 { : RX ( - n) } B G@ 1C0 XOR ; KEY reads an ASCII character from EI1. 10 : KEY ( - n) 0 BEGIN RX 0= UNTIL C/B @ DUP U2/ + 7 FOR It waits for a start bit, then delays until the middle of 11 F - CYCLES 2/ RX IF 80 ELSE 0 THEN OR C/B @ NEXT the first data bit. Each bit is sampled then OR'ed into 12 BEGIN RX UNTIL DROP ; bit 7 of the accumulated byte. It does not exit until the 13 stop bit (low) is detected. 14 15
14 45 0 ( Serial EXPECT) HEX SPACE emits a space. 1 : SPACE 20 EMIT ; SPACES emits n>0 spaces. Non-positive counts do nothing. 2 : SPACES ( n) 0 MAX FOR -ZERO SPACE THEN NEXT ; HOLD holds characters on the stack, maintaining a count. 3 : HOLD ( ..# x n - ..# x) SWAP >R SWAP 1 + R> ; It reverses the digits results from number conversions. 4 5 : EXPECT ( a #) SWAP CURSOR ! EXPECT accepts keystrokes and buffers them at TIB. 6 1 - DUP FOR KEY DUP 8 XOR IF An 8 will discard a character and emit a backspace; 7 DUP D XOR IF DUP CURSOR @ 1 C!+ CURSOR ! EMIT a D will emit a space and exit; 8 ELSE SPACE DROP R> - SPAN ! EXIT THEN all other keys are stored and echoed until the count is 9 ELSE ( 8) DROP DUP I XOR [ OVER ] UNTIL exhausted. Actual count is in SPAN. 10 CURSOR @ 1 - CURSOR ! R> 2 + >R 8 EMIT 11 THEN NEXT 1 + SPAN ! ; 12 13 14 15
RTX cmForth Version 3.0, March 1990
Page# 6 C:CMFORTH.3
15 46 0 ( Numbers) DIGIT converts a digit 0-F into an ASCII character. 1 : DIGIT ( n - n) DUP 9 > 7 AND + 48 + ; <# starts conversion by tucking a count under the number. 2 : <# ( n - ..# n ) -1 SWAP ; #> ends conversion by emitting the string of digits. 3 : #> ( ..# n) DROP FOR EMIT NEXT ; SIGN stacks a minus sign, if needed. 4 : SIGN ( ..# n n - ..# n) 0< IF 45 HOLD THEN ; # converts the low-order digit of a 16 bit number. 5 : # ( ..# n - ..# n) BASE @ /MOD SWAP DIGIT HOLD ; (.) formats a signed number. 6 : #S ( ..# n - ..# 0) BEGIN # DUP 0= UNTIL ; . displays a 16 bit signed integer, followed by a space. 7 : (.) ( n - ..# n) DUP >R ABS <# #S R> SIGN ; 8 : . ( n) (.) #> SPACE ; U.R displays a right-justified 16 bit unsigned number. 9 U. displays an unsigned number. 10 : U.R ( u n) >R <# #S OVER R> SWAP- 1 - SPACES #> ; 11 : U. ( u) 0 U.R SPACE ; DUMP displays an address and 8 numbers from memory. It returns 12 : DUMP ( a - a) CR DUP 5 U.R SPACE 7 FOR an incremented address for a subsequent DUMP. 13 2 @+ SWAP 7 U.R NEXT SPACE ; 14 15
16 47 0 ( Strings) HEX HERE returns next address in dictionary. 1 : HERE ( - a) H @ ; 2 abort" types the current word at HERE and an error message 3 { : abort" ( - n,) } H @ TYPE SPACE R> TYPE 2DROP at I. It also returns the current BLK to locate an error 4 BLK @ ?DUP DROP ( QUIT) 0 ; during LOAD. It will end with QUIT, when defined. It is 5 a headless definition, referenced only by ABORT". 6 { : dot" } R> TYPE >R ; 7 dot" types a message whose address is pulled off the return 8 { COMPILER : ABORT" COMPILE abort" 22 STRING ; stack, incremented and replaced. 9 : ." COMPILE dot" 22 STRING ; 10 FORTH } ABORT" compiles abort" and the following string. 11 ." compiles dot" and the following string. 12 These are host COMPILER definitions. The target definitions 13 are in block 30. 14 15
17 48 0 ( 15-bit buffer manager) ADDRESS calculates a buffer address from buffer number. 1 { : ADDRESS ( n - a) } 62 + 1024 * ; 2 { : ABSENT ( n - n, a) } NB FOR DUP I BUFFERS @ XOR 2* WHILE ABSENT returns the block number when the requested block isn't 3 NEXT EXIT THEN R> PREV N! R>DROP SWAP-DROP ADDRESS ; already in RAM. Otherwise it returns the buffer address 4 and exits from BLOCK. 5 { : UPDATED ( - a n) } OLDEST @ BEGIN 1 + NB AND 6 DUP PREV @ XOR UNTIL OLDEST N! PREV N! UPDATED returns the buffer address and current block number if 7 DUP ADDRESS SWAP BUFFERS DUP @ the pending buffer has been UPDATEd. Otherwise it returns 8 8192 ROT ! DUP 0< NOT IF R>DROP DROP THEN ; the buffer address and exits from the calling routine 9 (BLOCK or BUFFER). Pending means oldest by not just used. 10 : UPDATE PREV @ BUFFERS 0 @+ SWAP 32768 OR SWAP ! ; 11 { : ESTABLISH ( n a - a) } SWAP OLDEST @ PREV N! ESTABLISH stores the block number of the current buffer. 12 BUFFERS ! ; 13 : IDENTIFY ( n a - a) SWAP PREV @ BUFFERS ! ; IDENTIFY stores a block number into the current buffer. 14 Used to copy blocks. 15
RTX cmForth Version 3.0, March 1990
Page# 7 C:CMFORTH.3
18 49 0 ( Disk read/write) ## emits 3 bytes to host to start a block transfer: 1 { : ## ( a n - a a #) } 0 EMIT 256 /MOD EMIT EMIT DUP 1023 ; 0 followed by a block number. 2 3 { : buffer ( n - a) } UPDATED ## FOR buffer transmits an updated block and awaits acknowledgement. 4 1 C@+ SWAP EMIT NEXT KEY 2DROP ; BUFFER returns address of an empty but assigned buffer. 5 : BUFFER ( n - a) buffer ESTABLISH ; 6 block reads a block. 7 { : block ( n a - n a) } OVER ## FOR KEY SWAP 1 C!+ BLOCK returns the buffer address of a specified block, writing 8 NEXT DROP ; and reading as necessary. 9 : BLOCK ( n - a) ABSENT buffer block ESTABLISH ; 10 FLUSH forces buffers to be written to disk. 11 : FLUSH NB FOR 8192 BUFFER DROP NEXT ; EMPTY-BUFFERS clears buffer IDs, without writing. 12 : EMPTY-BUFFERS 0 [ NB 3 + ] LITERAL 0 FILL FLUSH ; 13 14 15
19 50 0 ( Interpreter) LETTER moves a string of characters from address a to 1 { : LETTER ( b a # - b a) } FOR DUP C@ 6 G@ XOR WHILE address b. Terminated by count # or delimiter in 2 1 C@+ >R SWAP 1 C!+ R> NEXT EXIT THEN register 6. Input pointer >IN is advanced. 3 >IN @ R> - >IN ! ; 4 -LETTER scans the source string for a non-delimiter. 5 { : -LETTER ( b a # - b a) } ?DUP IF 1 - FOR If found, calls LETTER. 6 1 C@+ SWAP 6 G@ XOR 0= WHILE NEXT EXIT THEN 7 1 - R> LETTER THEN ; WORD locates text in either a block buffer or TIB (BLK=0). 8 Reads word into HERE prefixing count and suffixing a space. 9 : WORD ( n - a) >R H @ DUP DUP 1 + DUP >IN @ 10 BLK @ IF 11 BLK @ BLOCK + 1024 ELSE TIB @ + SPAN @ THEN 12 >IN @ OVER >IN ! - R> 6 G! 13 -LETTER DROP 32 OVER C! SWAP- SWAP C! ; 14 15
20 51 0 ( Dictionary search) SAME compares the string at HERE with a name field. 1 { : SAME ( h a - h a f, a t) } OVER 4 G! DUP 2 + Byte count is in register 6. High bit of each byte is 2 6 G@ FOR 1 C@+ SWAP 127 AND 4 G@ 1 C@+ 4 G! - IF ignored. Returns address of parameter field: requires 3 R>DROP 0 AND EXIT THEN indirect reference if high bit of count set (separated heads). 4 NEXT EVEN SWAP 2 + @ 0< IF @ THEN SWAP ; 5 COUNT extracts the byte count from the first byte of a string. 6 { : COUNT ( n - n) 31 AND ; } 7 { : HASH ( n - a) } CONTEXT SWAP- ; HASH returns the address of the head of a vocabulary. 8 { : -FIND ( h n - h t, a f) } HASH OVER C@ COUNT 6 G! 9 BEGIN @ DUP WHILE SAME UNTIL 0 EXIT THEN -1 XOR ; -FIND searches a vocabulary for match with HERE. Fails with 10 zero link field. 11 12 13 14 15
RTX cmForth Version 3.0, March 1990
Page# 8 C:CMFORTH.3
21 52 0 ( Number input) HEX -DIGIT converts an ASCII character to a digit 0-F. 1 : -DIGIT ( n - n) 30 - DUP 9 > Failure to convert generates an error message. 2 IF 7 - DUP A < OR THEN 3 DUP BASE @ U< IF EXIT THEN NUMBER converts given string to binary; stores BASE in 4 2DROP ABORT" ?" ; RECOVER register 4; saves minus sign; terminates on count; and 5 then applies sign. 6 : NUMBER ( a - n) BASE @ 4 G! 0 SWAP DUP 1 + C@ 2D = >R 7 DUP I - 1 + 6 G! C@ I + 1 - 8 FOR 4 G@ * 6 G@ 1 C@+ 6 G! -DIGIT + NEXT 9 R> IF NEGATE THEN ; 10 11 12 13 14 15
22 53 0 ( Control) -' searches vocabulary for following word. 1 : -' ( n - h t, a f) 32 WORD SWAP -FIND ; 2 : ' ( - a) CONTEXT @ -' IF DROP ABORT" ?" THEN ; forget ' returns address of following word in current vocabulary. 3 Displays error message on failure. 4 : INTERPRET ( n n) >IN 2! BEGIN 2 -' IF NUMBER Use 'forget' to prevent using this version in target 5 ELSE EXECUTE THEN AGAIN ; RECOVER compilation. 6 7 : QUIT BEGIN CR TIB @ 64 EXPECT INTERPRET accepts block number and offset. Searches FORTH 8 0 0 INTERPRET ." ok" AGAIN ; RECOVER and executes words found; otherwise converts to binary. 9 10 ' QUIT ADR>CALL ' dot" 2 - ! QUIT accepts a character string into the text input buffer, 11 interprets and replies 'ok' to signify success; repeats. 12 The address of QUIT is relocated into the end of abort" . 13 14 15
23 54 0 ( Initialize) HEX FORGET restores HERE and vocabulary heads to values 1 : FORGET R> DUP 4 + H ! 2@ CONTEXT 4 - 2! saved at compile time by REMEMBER; . 2 2 CONTEXT ! ; 3 BPS awaits a start bit, assumes the first data bit is 4 { : BPS } 5 BEGIN RX 0= UNTIL BEGIN 6 + RX UNTIL zero and the second is one and computes C/B. Type a 'B' 5 U2/ C/B ! ; or other ASCII code with bit pattern XXXX XX10. 6 7 { : reset } 10 3 G! 18 3 G! ( RESET) 0 reset is executed at power-up or reset. 8 204 A 7 MOVE TIB 2@ XOR Toggles BOOT pin to switch from PROM to RAM and 9 IF EMPTY-BUFFERS SPAN @ TIB ! THEN to double speed. Initializes low RAM variables. 10 BPS ." hi" QUIT ; Empties buffers at power-up only (TIB contains garbage). 11 Calibrates serial I/O. For systems with fixed baudrate, 12 BPS can be replaced with n C/B ! . For 9600 b/s at 6 MHz 13 n is 271 hex. 14 Sends cheerful 'hi' and awaits command. 15
RTX cmForth Version 3.0, March 1990
Page# 9 C:CMFORTH.3
24 55 0 ( Words) This is the beginning of the compiler. 1 : SWAP SWAP ; : OVER OVER ; A turn-key application might need only the code above. 2 : DUP DUP ; : DROP DROP ; 3 Common words are defined for both interpreter and compiler. 4 : XOR XOR ; : AND AND ; 5 : OR OR ; Number base words defined together; DECIMAL required. 6 : + + ; : - - ; 7 : 0< 0< ; : NEGATE NEGATE ; LOAD saves current input pointers, calls INTERPRET, restores 8 input pointers and returns to DECIMAL. >IN and BLK are 9 : @ @ ; : ! ! ; treated as a 32 bit pointer. Forget it so that host LOAD 10 can still be used. 11 : OCTAL 8 BASE ! ; forget 12 : DECIMAL 10 BASE ! ; forget 13 : HEX 16 BASE ! ; forget 14 : LOAD ( n -) >IN 2@ >R >R 0 INTERPRET 10 BASE ! 15 R> R> >IN 2! ; forget
25 56 0 ( Compiler) HEX \\ breaks code compaction. 1 : \\ 0 ?CODE ! ; ALLOT increments the dictionary pointer to allot memory. 2 : ALLOT ( n) H +! ; , compiles a number into the dictionary. 3 : , ( n) H @ ! 2 ALLOT ; ,C compiles an instruction available for compaction. 4 : ,C ( n) H @ ?CODE ! , ; ,A compiles an address relocated by dA as a call instruction. 5 : ,A ( a) dA @ - U2/ ,C ; LITERAL compiles a number as a short literal if possible. 6 COMPILER : LITERAL ( n) DUP -20 AND IF DE00 ,C , EXIT [ stops compilation by popping the return stack, thus 7 THEN BE40 OR ,C ; returning out of the infinite ] loop. 8 : [ R>DROP ; 9 FORTH : ] BEGIN 4 -' IF 2 -FIND IF NUMBER \ LITERAL ] unlike INTERPRET, searches both vocabularies before falling 10 ELSE DUP @ into NUMBER. When a word is found in COMPILER, it is 11 DUP A020 AND A020 = OVER F020 AND C020 = OR executed; if found in FORTH, it is compiled. If it is a 12 SWAP BE27 = XOR IF @ 20 XOR ,C ELSE ,A THEN THEN single instruction, it is placed in-line; otherwise its 13 ELSE EXECUTE THEN AGAIN ; RECOVER address is compiled as a call. 14 15
26 57 0 ( Compiler) HEX PREVIOUS returns the address and count of the name field 1 : PREVIOUS ( - a n) CONTEXT @ HASH @ 2 + 0 C@+ SWAP ; of the word just compiled in the current vocabulary. 2 : USE ( n) PREVIOUS COUNT + 1 + EVEN ! ; USE assigns to the previous word the specified code. 3 : DOES R> U2/ USE ; DOES provides a behavior for a newly defined word. It is 4 : SMUDGE PREVIOUS 20 XOR SWAP C! ; executed when that word is defined. 5 : EXIT R>DROP ; SMUDGE smudges the name field to avoid recursion. 6 EXIT returns from a definition early (FORTH version). 7 : COMPILE R> 2 @+ >R 2* ,A ; 8 COMPILE pops the address of the following word and compiles it. 9 COMPILER : EXIT A020 ,C ; EXIT compiles a return instruction (COMPILER version). 10 : RECURSIVE PREVIOUS DF AND SWAP C! ; RECURSIVE unsmudges the name field so a new word can be found. 11 : ; \ RECURSIVE R>DROP \ EXIT ; forget ; terminates a colon definition. 12 13 14 15
RTX cmForth Version 3.0, March 1990
Page# 10 C:CMFORTH.3
27 58 0 ( Defining words) HEX CREATE creates an entry in the dictionary. 1 FORTH It saves space for the link field, then fetches a word 2 : CREATE H @ 0 , 20 WORD CONTEXT @ HASH terminated by a space. It links the word into the proper 3 2DUP @ SWAP 2 - ! SWAP C@ COUNT 1 + EVEN ALLOT vocabulary, allots space for the name field and compiles 4 ! BE27 , ; return-next-address instruction appropriate for a variable. 5 : : CREATE -2 ALLOT SMUDGE \\ ] ; forget 6 : CONSTANT ( n) CREATE -2 ALLOT \ LITERAL \ EXIT ; : creates a definition; -2 ALLOT recovers instruction 7 : VARIABLE CREATE 0 , ; compiled by CREATE; ] compiles the definition in its place. 8 CONSTANT names a number by compiling a literal. 9 : BLOCKEND? ( s - s, s') DUP 3FF AND 3FE = IF 2 + THEN ; VARIABLE initializes its variable to zero. 10 11 : MEMBLOCK ( d s - n) BLOCKEND? FC00 AND OVER FC00 AND - BLOCKEND? adds 2 to a source address if it is the last cell 12 DUP IF 0< IF 200 ELSE 600 THEN of the current 1 KB block. 13 THEN SWAP 3FF AND 2/ OR ; MEMBLOCK returns a number with the memory block control code 14 and a 9 bit cell address so that a branch or loop instruction 15 can compile its destination address correctly.
28 59 0 ( uCODE) HEX -SHORT checks if last instruction was a 5 bit literal. 1 : -SHORT ( - n t) ?CODE @ @ DUP FFE0 AND BE40 XOR ; FIX merges 5 bit literal with a new instruction. 2 : FIX ( n n -) 1F AND OR ?CODE @ ! ; 3 : SHORT ( n) -SHORT IF 2DROP ABORT" n?" THEN FIX ; SHORT requires 5 bit literal for register, address or increment 4 for current instruction. 5 COMPILER 6 : @ -SHORT IF DROP EE00 ,C ELSE 2/ CE00 SWAP FIX THEN ; forget @ and ! compiles a 5 bit or stack-address instruction. 7 : ! -SHORT IF DROP EE80 ,C ELSE 2/ CE80 SWAP FIX THEN ; forget G@ and G! compile register fetch/store instructions. 8 : G@ BE00 SHORT ; @+ !+ compiles 5 bit increment instructions. 9 : G! BE80 SHORT ; R> and >R pop and push the return stack, respectively. 10 I copies the return stack onto the parameter stack. 11 : @+ E940 SHORT ; 12 : !+ E9C0 SHORT ; OF( pushes the return stack to repeat the next instruction 13 : R> BE01 ,C ; : >R BE81 ,C ; for n+1 cycles. 14 : I BE00 ,C ; : OF( BE82 ,C ; forget 15
29 60 0 ( Structures) HEX OR, compiles an address specification for a 1 FORTH { : OR, ( a n) } \\ SWAP HERE MEMBLOCK OR , ; backward jump instruction. 2 BEGIN saves HERE for a backward jump. 3 COMPILER 4 : BEGIN ( - a) H @ \\ ; UNTIL compiles a conditional backward jump. 5 : UNTIL ( a) 8800 OR, ; AGAIN compiles an unconditional backward jump. 6 : AGAIN ( a) 9000 OR, ; THEN adds address specification to a forward jump instruction. 7 : THEN ( a) \ BEGIN OVER MEMBLOCK SWAP +! ; IF compiles a conditional forward jump. 8 : IF ( - a) \ BEGIN 8800 , ; WHILE compiles a conditional forward jump out of a structure. 9 : WHILE ( a - a a) \ IF SWAP ; REPEAT resolves a BEGIN ... WHILE ... loop. 10 : REPEAT ( a a -) \ AGAIN \ THEN ; ELSE inserts a false clause in the IF ... THEN conditional. 11 : ELSE ( a - a) \ BEGIN 9000 , SWAP \ THEN ; 12 FOR compiles return stack push for a down-counting loop. 13 : FOR ( - a) \ >R \ BEGIN ; NEXT compiles a backward decrement-and-jump. 14 : NEXT ( a) 9800 OR, ; 15
RTX cmForth Version 3.0, March 1990
Page# 11 C:CMFORTH.3
30 61 0 ( Strings) HEX STRING compiles a character string with a 1 FORTH : STRING ( n ) WORD C@ 1 + EVEN ALLOT \\ ; specified delimiter. 2 COMPILER : ABORT" COMPILE abort" 22 STRING ; 3 : ." COMPILE dot" 22 STRING ; ABORT" and ." are target versions of previously defined 4 : ( 29 WORD DROP ; host words. 5 FORTH : ( \ ( ; 6 ( skips over a comment. It must be defined in both FORTH 7 and COMPILER. 8 9 RESET restores dictionary to power-up status. It must be the 10 : RESET FORGET 0 ; RECOVER ' RESET ADR>CALL ' reset 8 + ! last word in the dictionary. It is called by 'reset'. 11 12 Insert application code before this block, to avoid using 13 these common target words. Alternatively, 'forget' them. 14 15
|