-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathcmforth.dow
executable file
·1 lines (1 loc) · 31 KB
/
cmforth.dow
1
cmFORTH shadow blocks (1987 December). Addresses are hex; word timing in parentheses after ; ( cycles) . 1 LOAD compiles the compacting compiler (blocks 4-6). Block 6 exits in COMPILER vocabulary, anticipating additions. 0< is redefined to resolve timing conflict. END terminates a definition. REMEMBER; saves vocabulary heads (at compile time). FORTH puts following words in interpretive vocabulary. -MOD provides modular arithmetic. It does a subtract if the result is non-negative. THRU loads a sequence of blocks. EMPTY empties the dictionary except for compacting compiler. H' holds the next available address in the target dictionary. 2000 relocates target addresses from RAM (2000) to PROM (0). { } switches between host and target dictionary by exchanging pointers and relocation offsets. COMPILER } compiles an indirect reference for a headless word.forget smudges a word that cannot execute in target dictionary. RECOVER recovers a return (after AGAIN ). SCAN finds the next word in target dictionary. TRIM relocates the vocabulary link and erases the smudge bit. CLIP constructs a target vocabulary and stores its head. PRUNE relinks the target dictionary to produce a stand-alone application (fixing the end-of-vocabulary word) and restores the host dictionary. 3 LOAD recompiles cmFORTH. EMPTY clears dictionary for a new application. 2 LOAD compiles the target compiler. Target is compiled at 2000 which is initialized to 0. BOOT copies PROM to RAM at power-up. The reference to -1 disables PROM and enables RAM (setting A15 clocks 74). Low RAM (16-24) is initialized (see block 12). # is the bottom of the target dictionary. PRUNE changes its name to null and link to 0. This version of EXIT marks the end of both vocabulary chains. The address of RESET is relocated into the end of BOOT . The end of target program is stored into TIB and HERE . COMPILER head is selected for PRUNE . GO emulates BOOT for testing: 3 LOAD GO FORTH sets interpretive vocabulary for both searches and definitions. Words are compiled in definitions. COMPILER sets immediate vocabulary. Words are executed in : .uCODE names a NC4016 micro-coded instruction. Compiled on use.\ compiles a following compiler directive (that would normally be executed). Named [COMPILE] in FORTH-83. 4016 instructions: !- stores and decrements. I@! exchanges stack®ister. NOP delays 1 cycle. TWO delays 2 cycles. 0+c Adds 0 with carry. MOD' conditionally subtracts R4. N! stores and saves data. -1 fetches register 3 DUP? compacts preceeding DUP with current instruction. Used to redefine I! and PUSH (previously >R ). PACK sets the return bit, if an instruction does not reference the Return stack. Otherwise it compiles a return. It exits from EXIT with POP DROP . EXIT optimizes return if permitted ( ?CODE nonzero): For instructions (bit-15 = 1) it calls PACK except for jump or 2-cycle instructions; for calls to the same 4K page, it substitutes a jump. ; is redefined to use the new EXIT . CONSTANT is redefined to take advantage of the new EXIT for 5-bit literals. BINARY defines and compacts ALU instructions. If the previous instruction was a fetch (ALU code 7) and not a store or DROP the ALU code is merged; stack push is inhibited. Otherwise a new instruction is compiled. ?CODE holds address of candidate for compaction. SHIFT defines and compacts shift instructions. Shift left ( 2* ) and right ( 2/) may be merged with an arithmetic instruction; sign propagate ( 0< ) only with DUP . DROP OR XOR AND + - SWAP- are redefined. 2* 2/ 0< likewise. ROT is a slow way to reference into the stack. 0= returns false (0) if stack non-zero; otherwise true ( -1). NOT same as 0=. FORTH-83 wants one's complement. < > subtract and test sign bit. Range of difference limited to 15 bits (-20000 is not less-than 20000). = equality tested by XOR. U< unsigned compare with 16-bit range (0 is less-than 40000). { ... } surround words defined into host dictionary. Used during compilation, they will not be in target dictionary. 4016 instructions: *' multiply step *- signed multiply step D2* 32-bit left shift D2/ 32-bit right shift /' divide step /'' final divide step F* fraction multiply S' square-root step M/MOD 30-bit dividend; 15-bit divisor, quotient, remainder. M/ signed dividend; 15-bit divisor, quotient. VNEGATE negates both multiplier and multiplicand. M* 32-bit signed product; multiplier (on top) must be even. /MOD 15-bit dividend, divisor, quotient, remainder. MOD 15-bit dividend, divisor, remainder. U*+ 15-bit multiplier, multiplicand, addend; 30-bit product. */ signed multiplier, multiplicand, result; 15-bit divisor; multiplier (in middle) must be even. * signed product; multiplier (on top) must be even. / signed dividend, quotient; 15-bit divisor. 2/MOD 16-bit unsigned dividend; 15-bit quotient, remainder. \\ (break compaction) used to combine + 2/ ; +! adds to memory. Byte address is 2* cell address; high byte is byte 0. Range restricted to low RAM (0-7FFF). C! stores 8-bit data into byte address; other byte unaffected. C@ fetches 8-bits from byte address. 2@ fetches 2 16-bit numbers; lower address on top. 2! stores 2 16-bit numbers. MOVE the fastest move that does not stream to-from stack. FILL fills RAM with constant. EXECUTE executes code at an address by returning to it. CYCLES delays n+4 cycles - count 'em. ?DUP copies stack if non-zero. 2DUP copies 32-bit (2 16-bit) stack item. 2DROP DROP DROP ; is faster and usually no longer. WITHIN returns true if number within low (inclusive) and high (non-inclusive) limits; all numbers 16 bits or signed. ABS returns positive number (15-bits). MAX returns larger of pair; 15-bit range. MIN returns smaller. Intertwining code saves 2 cells; left in as illustration of obscure but efficient code. ARRAY defines an array that adds an index from stack in only 2 cycles. Similar to VARIABLE . These low-RAM variables are used by cmFORTH (0-F are unused). Change them cautiously! In particular, make sure a variable is not used during compilation. For example, HEX is redefined to set BASE . It can be used if BASE has not moved; otherwise it must be forgetted. Non-standard variables: ?CODE address of last instruction compiled. Zero indicates no compaction permitted (ie, after THEN ). dA offset to be added to compiled addresses. Normally 0. Relocated code cannot be executed! CURSOR tracks cursor (terminal dependent); used by EXPECT . S0 serial output polarity; 1FF or 200. C/B cycles/bit for serial I/O. EMIT sets Xmask to 1E so that only X0 can be changed. Start/ stop bits are added and polarity set. I! emits bits at C/B rate thru X0. CR emits carriage-return and line-feed. TYPE types a string with prefixed count byte. It returns an incremented cell address. This is not FORTH-83 standard. RX reads a bit from pin X4. KEY reads 8-bits from X4. It waits for a start bit, then delays until the middle of the first data bit. Each bit is sampled then ored into bit 7 of the accumulated byte. It does not exit until the stop bit (low) is detected. SPACE emits a space. SPACES emits n>0 spaces. HOLD holds characters on the stack, maintaining a count. It reverses the digits resulting from number conversion. EXPECT accepts keystrokes and buffers them (at TIB ). An 8 will discard a character and emit a backspace; a D will emit a space and exit; all other keys are stored and echoed until the count is exhausted. Actual count is in SPAN . DIGIT converts a digit (0-F) into an ASCII character. <# starts conversion by tucking a count under the number. #> ends conversion by emitting the string of digits. SIGN stacks a minus sign, if needed. # converts the low-order digit of a 16-bit number. #S converts non-zero digits, at least one. (.) formats a signed number. . displays a 16-bit signed integer, followed by a space. U.R displays a right-justified 16-bit unsigned number. U. displays an unsigned number. DUMP displays an address and 8 numbers from memory. It returns an incremented address for a subsequent DUMP . HERE returns next address in dictionary. abort" types the current word (at HERE ) and an error message (at I ) It also returns the current BLK to locate an error during LOAD . It will end with QUIT , when defined. It is a headless definition, referenced only by ABORT" . dot" types a message whose address is pulled off the return stack, incremented and replaced. ABORT" compiles abort" and the following string. This is a host COMPILER definition. The target definition is in block 30. ." compiles dot" and the following string. BUFFERS returns indexed address of buffer ID. PREV current buffer number (0-NB). OLDEST last buffer read. Next buffer is OLDEST @ 1 + . ADDRESS calculates a buffer address from buffer number. NB is 1. If increased, ADDRESS and BUFFERS must be also. ABSENT returns the block number when the requested block isn't already in RAM. Otherwise it returns the buffer address and exits from BLOCK . UPDATED returns the buffer address and current block number if the pending buffer has been UPDATEd . Otherwise it returns the buffer address and exits from the calling routine ( BLOCK or BUFFER ). Pending means oldest but not just used. UPDATE marks the current buffer ( PREV ) to be rewritten. ESTABLISH stores the block number of the current buffer. IDENTIFY stores a block number into the current buffer. Used to copy blocks. ## emits 3 bytes to host to start a block transfer; 0 followed by block number. buffer transmits an updated block and awaits acknowledgement. BUFFER returns address of an empty (but assigned) buffer. block reads a block. BLOCK returns the buffer address of a specified block, writing and reading as necessary. FLUSH forces buffers to be written. EMPTY-BUFFERS clears buffer IDs, without writing. LETTER moves a string of characters from cell address a to byte address b . Terminated by count ( # ) or delimitor (register 6). Input pointer >IN is advanced. -LETTER scans the source string for a non-delimiter. If found, calls LETTER . WORD locates text in either block buffer or TIB ( BLK is 0). Reads word into HERE prefixing count and suffixing a space (in case count even). SAME compares the string at HERE with a name field. Cell count is in register 6. High bit of each cell is ignored. Returns address of parameter field; requires indirect reference if high bit of count set (separated head). COUNT extracts the cell count from the first word of a string. HASH returns the address of the head of a vocabulary. -FIND searches a vocabulary for match with HERE . Fails with zero link field. -DIGIT converts an ASCII character to a digit (0-Z). Failure generates an error message. C@+ increments address in register 6 and fetches character. 10*+ multiplies number by BASE and adds digit. NUMBER converts given string to binary; stores BASE in R4; saves minus sign; terminates on count; applies sign -' searches vocabulary for following word. ' returns address of following word in current vocabulary Error message on failure. forget to use host version. INTERPRET accepts block number and offset. Searches FORTH and executes words found; otherwise converts to binary. QUIT accepts a character string into the text input buffer, interprets and replies ok to signify success; repeats. The address of QUIT is relocated into the end of abort" . FORGET restores HERE and vocabulary heads to values saved at compile time (by REMEMBER; ). BPS awaits a start bit, assumes only the first data bit is zero and computes C/B . Type a B or other even letter. RS232 examines the serial input line and inverts serial I/O if an inverting buffer is used (line rests low). reset is executed at power-up or reset. Carefully initializes I/O registers to avoid glitches. Empties buffers at power-up only ( TIB contains garbage). Calibrates serial I/O. Cheerful hi and awaits command. This is the beginning of the compiler. A turn-key application might need only the code above. Common words are defined for both interpreter and compiler. Number base words defined together; DECIMAL required. LOAD saves current input pointers, calls INTERPRET , restores input pointers and returns to DECIMAL . >IN and BLK are treated as a 32-bit pointer. forget so that host LOAD will be used. \\ breaks code compaction. ALLOT increments the dictionary pointer to allot memory. , compiles a number into the dictionary. ,C compiles an instruction available for compaction. ,A compiles a address relocated by dA . LITERAL compiles a number as a short literal, if possible. [ stops compilation by popping the return stack, thus returning out of the infinite ] loop. ] unlike INTERPRET , searches both vocabularies before falling into NUMBER . When a word is found in COMPILER it is executed; if found in FORTH it is compiled. If it is a single instruction, it is placed in-line; otherwise its address is compiled for a call. PREVIOUS returns the address and count of the name field of the word just defined. USE assigns to the previous word a specified code field. DOES provides a behavior for a newly defined word. It is executed when that word is defined. SMUDGE smudges the name field to avoid recursion. EXIT returns from a definition early ( FORTH version). COMPILE pops the address of the following word and compiles it. 7FFF AND masks the carry bit from the return stack. EXIT compiles a return instruction ( COMPILER version). RECURSIVE unsmudges the name field so a new word can be found. ; terminates a definition. forget permits more definitions. CREATE creates an entry in the dictionary. It saves space for the link field, then fetches a word terminated by space. It links the word into the proper vocabulary, allots space for the name field and compiles the return-next-address instruction appropriate for a variable. : creates a definition; -1 ALLOT recovers the instruction compiled by CREATE ; ] compiles the definition in its place. forget permits more definitions. CONSTANT names a number by compiling a literal. VARIABLE initializes its variable to zero. -SHORT checks if last instruction was a 5-bit literal. FIX merges 5-bit literal with new instruction. SHORT requires 5-bit literal (register, address or increment) for current instruction. Error message. @ and ! compile 5-bit or stack address instructions. I@ and I! compile 5-bit register instuctions. @+ and !+ compile 5-bit increment instructions. PUSH and POP push and pop the return stack. They are usually designated >R and R> . I copies the return stack onto the parameter stack. TIMES pushes the return stack to repeat the next instruction for n + 2 cycles. OR, compiles a 12-bit address with a backward jump instruction.BEGIN saves HERE for backward jumps. UNTIL compiles a conditional backward jump. AGAIN compiles an unconditional backward jump. THEN adds 12-bit current address into forward jump. IF compiles a conditional forward jump. WHILE compiles a conditional forward jump - out of structure. REPEAT resolves a BEGIN ... WHILE ... loop. ELSE inserts false clause in an IF ... THEN conditional. FOR compiles return stack push for a down-counting loop. NEXT compiles a backward decrement-and-jump. STRING compiles a character string with a specified delimiter. ABORT" DOT" are target versions of previously-defined host words. ( skips over a comment. It must be defined in both FORTH and COMPILER . RESET restores dictionary to power-up status. It must be the last word in the dictionary. It is called by reset . Insert application code before this block, to avoid using these common target words. Alternatively, forget them.