\ 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 Dependant Code 08SEP83HHL 3 VIEW# C! ( Set up as view file# 3 ) 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 Dependant IO words ) CR .( 8080 Machine Dependant Code Loaded ) \ 8080 Assembler Load Screen 18APR83HHLONLY FORTH ALSO DEFINITIONS 1 4 +THRU ONLY FORTH ALSO DEFINITIONS EXIT The 8080 Assembler is largely due to John Cassidy, 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 06Oct83map: LABEL CREATE ASSEMBLER ; 205 CONSTANT DOES-OP ASSEMBLER DEFINITIONS : C; END-CODE ; 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 ?<MARK FORTH ' ?<MARK ASSEMBLER IS ?<MARK DEFER ?<RESOLVE FORTH ' ?<RESOLVE ASSEMBLER IS ?<RESOLVE \ 8080 Assembler Defining Words & Registers 09MAR83HHL>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 12Sep84bibD2 CONSTANT C0= DA CONSTANT C0<> D2 CONSTANT CS C2 CONSTANT 0= CA CONSTANT 0<> E2 CONSTANT PE F2 CONSTANT 0< FA CONSTANT 0>= : NOT 8 [ FORTH ] XOR ; : MOV 8* 40 + + C, ; : MVI 8* 6 + C, C, ; : LXI 8* 1+ C, , ; : NEXT >NEXT JMP ; : IP>HL B H MOV C L MOV ; : IF C, ?>MARK ; : THEN ?>RESOLVE ; : ELSE C3 ( JMP ) IF 2SWAP THEN ; : BEGIN ?<MARK ; : UNTIL C, ?<RESOLVE ; : AGAIN C3 ( JMP ) C, ?<RESOLVE ; : WHILE IF ; : REPEAT 2SWAP AGAIN THEN ; FORTH DEFINITIONS DECIMAL ( source destination MOV ) \ Load Screen for Debugger Utility 18APR83HHLONLY FORTH ALSO DEFINITIONS 1 4 +THRU CR .( Debugger Low Level Loaded ) ONLY FORTH ALSO DEFINITIONS EXIT The debugger is designed to let the user single step the execution of a high level definition. To invoke the debugger, type DEBUG XXX where XXX is the name of the word you wish to trace. When XXX executes, you will get a single step trace showing you the word within XXX that is about to execute, and the contents of the parameter stack. If you wish to poke around, type F and you can interpret Forth commands until you type RESUME, and execution of XXX will continue where it left off. This debugger works by patching the NEXT routine, so it is highly machine and implementation dependant. The same idea should work however on any Forth system with a centralized NEXT routine. \ 16 Bit Subtract Subroutine 10MAY83HHLVOCABULARY BUG ALSO BUG ALSO DEFINITIONS 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 VARIABLE <IP VARIABLE IP> LABEL ?RANGE ( COMPARE DE WITH LOW & HI ) ( RETURNS CS IF IN RANGE ) <IP LHLD SSUB CALL RNC IP> 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 26MAY83HHLASSEMBLER VARIABLE 'DEBUG 0 C, LABEL DEBNEXT B D MOV C E MOV ?RANGE CALL CS IF 'DEBUG 2+ LDA A INR 'DEBUG 2+ STA 2 CPI 0= IF A XRA 'DEBUG 2+ STA FNEXT CALL B PUSH 'DEBUG LHLD DNEXT1 JMP THEN THEN DNEXT JMP \ Patch and Fix NEXT 26MAY83HHLHEX CODE PNEXT C3 A MVI >NEXT STA DEBNEXT H LXI >NEXT 1+ SHLD >NEXT JMP C; FORTH DEFINITIONS CODE FIX (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 Dependant IO Words 28AUG83HHLONLY FORTH ALSO DEFINITIONS 1 1 +THRU CR .( Machine Dependant IO Words Loaded ) ONLY FORTH ALSO DEFINITIONS EXIT Since the 8080 has a seperate IO path, we define a Forth interface to it. Use P@ and P! to read or write directly to the 8080 IO ports. \ Machine dependant IO words 28AUG83HHLCODE P@ (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 P! (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 Dependant Code 26MAY83HHL All of the Machine Dependant 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 06Oct83mapLABEL 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 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 26MAY83HHLBUG The vocabulary that holds the Debugging Words SSUB A machine language subroutine that performs a 16 bit subtract. Thank you Intel for making it so simple! <IP IP> The range of IP values we are interested in ?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 <IP and IP> 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 dependant IO words 28AUG83HHLP@ (S port# -- n ) Fetch the value at the given input port and push it onto the stack. Sorry about the self modifying code!. P! (S n port# -- ) Write the value to the specified port number. See P@ for apology.