\ The Rest is Silence 26Sep83map************************************************************* ************************************************************* *** *** *** Please direct all questions, comments, and *** *** miscellaneous personal abuse to: *** *** *** *** Henry Laxen or Michael Perry *** *** 1259 Cornell Avenue 1125 Bancroft Way *** *** Berkeley, California Berkeley, California *** *** 94706 94702 *** *** *** *** (415) 525-8582 (415) 644-3421 *** *** *** ************************************************************* ************************************************************* \ Load Screen for 8080 Dependent Code 07Apr84map ONLY FORTH ALSO DEFINITIONS DECIMAL 3 LOAD ( The Assembler ) 9 LOAD ( The Low Level for the Debugger ) 15 LOAD ( The Low Level for the MultiTasker ) 18 LOAD ( The Machine Dependent IO words ) CR .( 8080 Machine Dependent Code Loaded ) \ 8080 Assembler Load Screen 09Apr84mapONLY FORTH ALSO DEFINITIONS 1 4 +THRU ONLY FORTH ALSO DEFINITIONS EXIT The 8080 Assembler is largely due to John Cassady, who recently published it in Forth Dimensions. It implements the full 8080 instruction set as well as structured conditionals. To create an Assembler language definition, use the defining word CODE. It may, but does not have to be, terminated with C;. How the assembler operates is a very interesting example of the power of CREATE DOES> Basically, the instructions are categoriezed and a defining word is created for each category. When the mnemonic for the instruction is interpreted, it compiles itself. \ 8080 Assembler Defining Words & Registers 11Apr84map: LABEL CREATE ASSEMBLER ; 205 CONSTANT DOES-OP 3 CONSTANT DOES-SIZE : DOES? (S IP -- IP' F ) DUP DOES-SIZE + SWAP C@ DOES-OP = ; ASSEMBLER DEFINITIONS : C; END-CODE ; : INIT ; DEFER C, FORTH ' C, ASSEMBLER IS C, DEFER , FORTH ' , ASSEMBLER IS , DEFER ?>MARK FORTH ' ?>MARK ASSEMBLER IS ?>MARK DEFER ?>RESOLVE FORTH ' ?>RESOLVE ASSEMBLER IS ?>RESOLVE DEFER ?NEXT 1- CONSTANT HPUSH >NEXT 2- CONSTANT DPUSH 7 CONSTANT A DPUSH CONSTANT WPUSH 0 CONSTANT B 1 CONSTANT C 2 CONSTANT D 3 CONSTANT E 0 CONSTANT I 1 CONSTANT I' 2 CONSTANT W 3 CONSTANT W' 0 CONSTANT IP 1 CONSTANT IP' 4 CONSTANT H 5 CONSTANT L 6 CONSTANT M 6 CONSTANT PSW 6 CONSTANT SP 6 CONSTANT S : 1MI CREATE C, DOES> C@ C, ; : 2MI CREATE C, DOES> C@ + C, ; : 3MI CREATE C, DOES> C@ SWAP 8* + C, ; : 4MI CREATE C, DOES> C@ C, C, ; : 5MI CREATE C, DOES> C@ C, , ; \ 8080 Assembler mnemonics 09MAR83HHLHEX 00 1MI NOP 76 1MI HLT F3 1MI DI FB 1MI EI 07 1MI RLC 0F 1MI RRC 17 1MI RAL 1F 1MI RAR E9 1MI PCHL EB 1MI XCHG C9 1MI RET C0 1MI RNZ C8 1MI RZ D0 1MI RNC D8 1MI RC 2F 1MI CMA 37 1MI STC 3F 1MI CMC F9 1MI SPHL E3 1MI XTHL E0 1MI RPO E8 1MI RPE F8 1MI RM 27 1MI DAA 80 2MI ADD 88 2MI ADC 90 2MI SUB 98 2MI SBB A0 2MI ANA A8 2MI XRA B0 2MI ORA B8 2MI CMP 02 3MI STAX 04 3MI INR 03 3MI INX 09 3MI DAD 0B 3MI DCX C1 3MI POP C5 3MI PUSH C7 3MI RST 05 3MI DCR 0A 3MI LDAX D3 4MI OUT DB 4MI IN C6 4MI ADI CE 4MI ACI D6 4MI SUI DE 4MI SBI E6 4MI ANI EE 4MI XRI F6 4MI ORI FE 4MI CPI 22 5MI SHLD CD 5MI CALL 2A 5MI LHLD 32 5MI STA 3A 5MI LDA C3 5MI JMP C2 5MI JNZ CA 5MI JZ D2 5MI JNC DA 5MI JC E2 5MI JPO EA 5MI JPE F2 5MI JP FA 5MI JM \ 8080 Assembler Branches 08Apr84mapDA CONSTANT C0= D2 CONSTANT C0<> D2 CONSTANT CS C2 CONSTANT 0= CA CONSTANT 0<> E2 CONSTANT PE F2 CONSTANT 0< FA CONSTANT 0>= : NOT 8 [ FORTH ] XOR ; : NEXT >NEXT JMP ; : MOV 8* 40 + + C, ; : MVI 8* 6 + C, C, ; : LXI 8* 1+ C, , ; : IF C, ?>MARK ; : THEN ?>RESOLVE ; : ELSE C3 ( JMP ) IF 2SWAP THEN ; : BEGIN ? VARIABLE CNT VARIABLE 'DEBUG ASSEMBLER LABEL SSUB ( HL = HL - DE ) L A MOV E SUB A L MOV ( LOW BYTE ) H A MOV D SBB A H MOV ( HI BYTE ) RET LABEL ?RANGE ( COMPARE DE WITH LOW & HI ) ( RETURNS CS IF IN RANGE ) LHLD SSUB CALL CMC RET \ Subroutine to Patch NEXT 26MAY83HHLASSEMBLER HEX LABEL FNEXT 0A A MVI >NEXT STA ( B LDAX ) 03 A MVI >NEXT 1+ STA ( B INX ) 6F A MVI >NEXT 2+ STA ( A L MOV ) RET LABEL DNEXT B LDAX B INX A L MOV B LDAX B INX A H MOV HERE M E MOV H INX M D MOV XCHG PCHL CONSTANT DNEXT1 DECIMAL \ Debug version of Next 04Apr84mapASSEMBLER LABEL DEBNEXT B D MOV C E MOV ?RANGE CALL CS IF CNT LDA A INR CNT STA 2 CPI 0= IF A XRA CNT STA FNEXT CALL B PUSH 'DEBUG LHLD DNEXT1 JMP THEN THEN DNEXT JMP \ Patch and Fix NEXT 13Apr84mapHEX CODE PNEXT C3 A MVI >NEXT STA DEBNEXT H LXI >NEXT 1+ SHLD >NEXT JMP C; FORTH DEFINITIONS CODE UNBUG (S -- ) BUG FNEXT ASSEMBLER CALL >NEXT JMP C; DECIMAL \ Load Screen for the MultiTasker 18APR83HHLONLY FORTH ALSO DEFINITIONS 1 2 +THRU CR .( MultiTasker Low Level Loaded ) ONLY FORTH ALSO DEFINITIONS EXIT The MultiTasker is loaded as an application on top of the regular Forth System. There is support for it in the nucleus in the form of USER variables and PAUSEs inserted inside of KEY EMIT and BLOCK. The Forth multitasking scheme is co-operative instead of interruptive. All IO operations cause a PAUSE to occur, and the multitasking loop looks around at all of the current task for something to do. \ Multitasking low level 30Sep83mapCODE (PAUSE) (S -- ) B PUSH ( IP to stack ) RP LHLD H PUSH ( RP to stack ) 0 H LXI SP DAD XCHG ( SP in DE ) UP LHLD E M MOV H INX D M MOV H INX ( SP to USER area ) H INX PCHL ( Jump to USER+3 ) C; CODE RESTART (S -- ) -3 H LXI D POP D DAD UP SHLD ( Set UP to new user ) M E MOV H INX M D MOV XCHG SPHL ( Restore stack ) H POP RP SHLD ( Return stack ) B POP ( Restore IP ) NEXT C; HEX C3CF ENTRY ! ( RST1 then JMP ) DECIMAL ENTRY LINK ! ( only task points to itself ) \ Manipulate Tasks 12Oct83map: LOCAL (S base addr -- addr' ) UP @ - + ; : @LINK (S -- addr ) LINK @ ; : !LINK (S addr -- ) LINK ! ; : SLEEP (S addr -- ) 0 SWAP ENTRY LOCAL C! ; : WAKE (S addr -- ) 207 SWAP ENTRY LOCAL C! ; : STOP (S -- ) UP @ SLEEP PAUSE ; : SINGLE (S -- ) ['] PAUSE >BODY ['] PAUSE ! ; : MULTI (S -- ) 195 ( JMP ) 8 C! ['] RESTART @ 9 ! ['] (PAUSE) @ ['] PAUSE ! ; \ Load Screen for Machine Dependent IO Words 04Apr84mapONLY FORTH ALSO DEFINITIONS 1 1 +THRU CR .( Machine Dependent IO Words Loaded ) ONLY FORTH ALSO DEFINITIONS EXIT Since the 8080 has a seperate IO path, we define a Forth interface to it. Use PC@ and PC! to read or write directly to the 8080 IO ports. \ Machine dependent IO words 04Apr84mapCODE PC@ (S port# -- n ) D POP HERE 5 + H LXI ( Sorry ) E M MOV 0 IN A L MOV 0 H MVI HPUSH JMP C; CODE PC! (S n port# -- ) D POP HERE 7 + H LXI ( Sorry again ) E M MOV H POP L A MOV 0 OUT NEXT C; \ Load Screen for 8080 Dependent Code 26MAY83HHL All of the Machine Dependent Code for a Particular Forth Implementation is factored out and placed into this file. For The 8080 there are 3 different components. The 8080 assembler, The run time debugger, which must have knowledge of how NEXT is implemented, and the MultiTasker, which uses code words to WAKE tasks and put them to SLEEP. \ 8080 Assembler Defining Words & Registers 11Apr84mapLABEL marks the start of a subroutine whose name returns its address. DOES-OP Is the op code of the call instruction used for DOES> U C; A synonym for END-CODE INIT does nothing for the 8080. Deferring the definitions of the commas, marks, and resolves allows the same assembler to serve for both the system and the Meta-Compiler. \ 8080 Assembler Defining Words & Registers 09MAR83HHL On the 8080, register names are constants. Nearly all instructions fall into the one of the five classes 1MI thru 5MI. \ 8080 Assembler mnemonics 26MAY83HHL Each mnemonic is defined as a member of a class, with an associated op code byte. \ 8080 Assembler Branches 26MAY83HHLIt is convenient to rename some of the branches for use with the structured conditionals. NEXT is a macro which assembles a jump to >NEXT. There are a few special case instructions not handled in the 1MI thru 5MI schema. The structured conditionals make it easier to write correct and understandable code, and reduce the need for forward reference and meaningless labels with silly names. \ 16 Bit Subtract Subroutine 04Apr84mapBUG The vocabulary that holds the Debugging Words The range of IP values we are interested in CNT is a pass counter. 'DEBUG contains the address of the TRACE routine. SSUB A machine language subroutine that performs a 16 bit subtract. Thank you Intel for making it so simple! ?RANGE A machine language subroutine that sets the carry flag if the IP is in the Range we are interested in. \ Subroutine to Patch NEXT 26MAY83HHL FNEXT A machine language subroutine that Fixes NEXT back to the way it used to be. DNEXT A copy of next that gets exeucted instead of the normal one. DNEXT1 The rest of NEXT \ Debug version of Next 26MAY83HHL DEBNEXT is the debugger's version of next If the IP is between then the contents of the execution variable 'DEBUG are executed. First the IP is pushed onto the parameter stack. The word pointed to by 'DEBUG can be any high or low level word so long as it discards the IP that was pushed before it is called, and it must terminate by callingPNEXT to patch next once again for more tracing. \ Patch and Fix NEXT 26MAY83HHL PNEXT patches Forth's Next to jump to DEBNEXT. This puts us into DEBUG mode and allows for tracing. FIX restores Forth's Next to its original condition. Effectively disabling tracing. \ Multitasking low level 26MAY83HHL(PAUSE) (S -- ) Puts a task to sleep by storing the IP and the RP on the parameter stack. It then saves the pointer to the parameter stack in the user area and jumps to the code pointed at by USER+3, switching tasks. RESTART (S -- ) Sets the user pointer to point to a new user area and restores the parameter stack that was previously saved in the USER area. Then pops the RP and IP off of the stack and resumes execution. The inverse of PAUSE. Initialize current User area to a single task. \ Manipulate Tasks 12Oct83mapLOCAL Map a User variable from the current task to another task@LINK Return a pointer the the next tasks entry point !LINK Set the link field of the current task (perhaps relative)SLEEP makes a task pause indefinitely. WAKE lets a task start again. STOP makes a task pause indefinitely. SINGLE removes the multi-tasker's scheduler/dispatcher loop. MULTI installs the multi-tasker's scheduler/dispatcher loop. By patching the appropriate INT vector and enabling PAUSE. \ Machine dependent IO words 04Apr84mapPC@ (S port# -- n ) Fetch the value at the given input port and push it onto the stack. Sorry about the self modifying code!. PC! (S n port# -- ) Write the value to the specified port number. See P@ for apology.