{ File: [Iris]DLion>BookKeepingTask.asm Dennis Grundler 1-Sep-84 16:53:30 :Add copyright notice. Dennis Grundler 26-Sep-83 22:48:43 :Fold in Hal Murray's changes for Burdock. Dennis Grundler 10-Nov-82 20:10:15 : make mouse update quicker and shorter. Also make read host address shorter and cleaner. Jim Frandeen October 15, 1982 2:23 PM: Add Voice commands. Jim Frandeen August 9, 1982 3:04 PM: new IO Page format. Add support for keyset. Add support for ReadBlock and WriteBlock processor commands. Jim Frandeen July 20, 1982 11:08 AM: reread the whole Mouse CSB to fix the cursor jumping problem. Jim Frandeen May 25, 1982 8:23 AM Written by Jim Frandeen April 1, 1982 9:21 AM } { Copyright (C) 1982, 1983 by Xerox Corporation. All rights reserved.} get "SysDefs" ;System defs get "CommonDefs" ;Common defs IMP ClearMiscControl1Bit ;From Common IMP Copy ;From Common IMP DoBurdockCmd ;From Buffer IMP DoMiscClock ;From Common IMP ErrorReport ;From Common IMP KeyMap ;From FloppyTask IMP OldReadUmbilical ;From Buffer IMP OldWriteUmbilical ;From Buffer IMP ReadCPBuffer ;From CPSubs IMP SetMiscControl1Bit ;From Common IMP Wait ;From Common IMP WriteCPBuffer ;From CPSubs IMP ZeroCommand ;From Common EXP BurdockIOCB EXP CommandData EXP FloppyIocbAddr EXP FloppyIocbAddrHi EXP GetTOD EXP LSEPData EXP LSEPStatus EXP MPNumber EXP PortBusyFlag EXP ProcData0 EXP ProcData1 EXP ProcData2 EXP MainLoop EXP ReadKeyboard EXP ResetProcessorCommand EXP RS232CGetFlag EXP RS232CMiscCommand EXP RS232CMiscFlag EXP RS232CPutFlag EXP TransferProcessorCSB EXP TTYCommand EXP TTYOutData EXP TTYOutStatus EXP VoiceCommand EXP VoiceGetCommand EXP VoicePutCommand ; CommandData: {The following command data from the IOPage is read from CP memory each time around the main loop. This command data indicates what tasks are to be performed. Each task has a one-word command. In general, the the command word is set to a non zero value by the CP when there is something for the IOP task to do. In addition, the CP may specify parameters in the CSB associated with the command. It is important that the CP set up the parameters before setting the command word. When the IOP task has completed, it sets the command word to zero.} LSEPData: {When LSEPData is non zero, it means we have a control character to send to the LSEP. The LSEPTask sets it back to zero when the operation is complete. The CP waits for this word to be non-zero before it stores a new control character here.} DS 1 ;14010 low DS 1 ;14010 High order byte is not used LSEPStatus: {When the LSEP Task has a new status byte to send to the CP, it stores it here. When LSEPStatus is zero, it means the last status sent to the CP has been processed. When the LSEP Task has a new status byte to send to the CP, it checks to be sure LSEPStatus is zero. If not, it sets the status to overrun.} DS 1 ;14011 low DS 1 ;14011 High byte is not used MPNumber: {This is the maintenance panel number to be displayed. When the CP wants to set the maintenance panel, it stores the number here. Each time through its main loop, the MPTask checks to see if MPNumber is different from the number currently in the maintenance panel. If so, it sets the maintenance panel to the new number.} DS 2 ;14012 FloppyIocbAddr: {If the virtual address is non zero, activate the Floppy Task. When the Floppy Task has completed the operation, it sets this word back to zero.} DS 1 ;14013 low FloppyIocbAddrHi: DS 1 ;14013 High TTYOutData: {When the command is Put, the data byte to be sent is in the low byte of the TTY command word. When the command is SetParameter, the low byte specifies what prameters to set.} TTYOutStatus: {When the Out command has completed, the status is returned in the low order byte of the word, replacing the Data byte.} DS 1 ;14014 low byte TTYCommand: {The high bit of this word is set nonzero when there is something for the TTY Task to do. The low 7 bits of the command byte specify the command.} DS 1 ;14014 high byte ProcCommand: {The Processor Command is set to a non zero value when there is a command to be processed. The command is set back to zero by the IOP when the command has been processed.} DS 1 ;14015 low byte DS 1 ;14015 High order byte is not used {The Mouse Change Flag is set by the CP when it is necessary to set new mouse coordinates. The flag word is set back to zero by the IOP when the new coordinates have been set.} DS 1 ;14016 low byte is not used MouseChangeFlag: DS 1 ;14016 High order byte ToneCommand: {ToneCommandFlag is set by the CP when a Tone Command is to be executed. The command is set back to zero by the IOP when the command has been processed.} DS 1 ;14017 low byte ToneCommandFlag: DS 1 ;14017 High order RS232CMiscCommand: {The RS232CMisc Flag high order bit is set when there is a Misc command to be executed. The command is specified in the low order byte of the word. The word is set back to zero by the IOP when the command has been executed. The low 7 bits of MiscFlag are used to set the Baud rate.} DS 1 ;14018 low byte VoiceCommand: {VoiceCommand is the same byte as RS232CMiscFlag.} RS232CMiscFlag: DS 1 ;14018 High has flag in high bit DS 1 ;14019 low byte is not used VoicePutCommand: {VoicePutCommand is the same byte as RS232CPutFlag.} RS232CPutFlag: {This flag is set by the CP when a Put IOCB is ready. It is reset by the CP when the Put command has been completed.} DS 1 ;14019 High order byte DS 1 ;1401A low byte is not used VoiceGetCommand: {VoiceGetCommand is the same byte as RS232CGetFlag.} RS232CGetFlag: {This flag is set by the CP when an IOCB is ready for a Get. It is reset by the IOP when the Get has completed.} DS 1 ;1401A High order byte {This flag is set by the CP when Burdock has work to do.} BurdockIOCB: DS 1 ;1401B low byte BurdockFlag: DS 1 ;1401B high byte => IOCB Can't be in first page ;End of Command data that is read in each time around the loop ; ProcessorCSB: ProcData2: DS 2 ;14026 ProcData1: DS 2 ;14027 ProcData0: DS 1 ;14028 low ProcData0Hi: DS 1 ;14028 high MouseChgCSB: MouseChgX: DS 2 ;14029 MouseChgY: DS 2 ;1402A ToneCSB: ToneFreq: ;1402B DS 2 ;Frequency constant (1843.2/f, f in kHz) { Time-of Day storage @ 14037. Note that the High word is stored twice to allow the CP to determine whether the full state has been written.} TODValid: ;14037 DS 1 ;TOD data valid (0 = invalid, -1 = valid) TODValidHi DS 1 ;14037 high byte TODLo: DS 2 ;14038 TOD data low word TODHi: DS 1 ;14039 TOD data high word TODMost: DS 1 ;TOD data most significant byte TODLoX: DS 2 ;1403A TOD data high word (copy of Lo above) ; Mouse and Keyboard state. MouseXPosition: ;CP Mouse address = 1403B DW 0 ;MouseX coordinate (16 bits) MouseYPosition: DW 0 ;1403C MouseY coordinate (16 bits) MouseSwitches: DW 0FFFFH ;1403D Mouse switches ; (MSw: bit 5: Sw1, bit 6: Sw3, bit 7: Sw2) ; (MSw+1: 0) ; KeysetPresentFlag: {This flag is set by a ProcessorCommand. If the Keyset is present, the MouseTask will read the keyset.} DB 0 IOPagePCB: ;Control Block to transfer command data from IOPage DW CommandLoc ;CP buffer pointer (low): Start of commands DW CPIOPageHi ;CP buffer pointer (high) DW CommandDataSize ;CP buffer count (bytes) DW CommandData ;Pointer to start of IOP command area TODPCB: ;Control Block for TOD transfer to IOPage DW TODLoc ;CP buffer pointer (low): TOD state DW CPIOPageHi ;CP buffer pointer (high) DW TODSize ;CP buffer count (words) DW TODValid ;Pointer to IOP buffer MouseChangeFlagPCB: ;Control Block to transfer MouseChangeFlag to IOPage DW MouseChangeFlagLoc ;CP pointer (low): MouseChg CSB.Flag DW CPIOPageHi ;CP buffer pointer (high) DW 2 ;CP buffer count (bytes): Flag word DW ZeroCommand ;Pointer to IOP buffer MouseChgPCB: ;Control Block to transfer Mouse Change PCB from IOPage into MouseXPosition and MouseYPosition DW MouseChgCSBLoc ;CP pointer (low): MouseChg CSB.MouseChgX DW CPIOPageHi ;CP buffer pointer (high) DW MouseChgCSBSize ;CP buffer count (4 bytes) DW MouseXPosition ;Pointer to IOP buffer MousePCB: ;Control Block for transfer of mouse data to IOPage. DW MXLoc ;CP buffer pointer (low): Mouse state DW CPIOPageHi ;CP buffer pointer (high) DW MStateSize ;CP buffer count (3 words) DW MouseXPosition ;Pointer to IOP buffer KBTaskPCB: ;Control Block to transfer keyboard map to IOPage. DW KBLoc ;CP buffer pointer (low): Keyboard map DW CPIOPageHi ;CP buffer pointer (high) DW KeyMapSize ;CP buffer count DW KeyMap ;Pointer to IOP buffer ZeroProcessorPCB: ;Port Control Block values to zero Processor Command. DW ProcCommandLoc ;CP buffer pointer (low): Processor CSB DW CPIOPageHi ;CP buffer pointer (high) DW 2 ;CP buffer count (bytes) DW ZeroCommand ;Pointer to IOP buffer ProcPCB: ;Port Control Block values for Processor CSB transfer. DW ProcessorCSBLoc ;CP buffer pointer (low): Processor CSB DW CPIOPageHi ;CP buffer pointer (high) DW ProcessorCSBSize ;CP buffer count (words) DW ProcData2 ;Pointer to IOP buffer ZeroToneCommand: DW ToneCommandLoc ;CP buffer pointer (low): ToneCSB.ToneCommand DW CPIOPageHi ;CP buffer pointer (high) DW 2 ;CP buffer count (bytes) DW ZeroCommand ;Pointer to IOP buffer TonePCB: ;PCB to read Tone CSB from IOPage DW ToneCSBLoc ;CP buffer pointer (low): ToneCSB.ToneCommand DW CPIOPageHi ;CP buffer pointer (high) DW ToneCSBSize ;CP buffer count (bytes) DW ToneCSB ;Pointer to IOP buffer RST0Loc equ 0 ;Start of EProm boot code ; ; Keyboard tables: ; The index table provides a table lookup between the keyboard event byte, ; and the KeyMap byte index. KBIndex: ; 00H: db 00H,00H,00H,00H ;No key db 00H,00H,00H,00H ;No key db 00H,00H,00H,00H ;No key db 00H,00H,00H,00H ;No key ; 10H: db 0BH,0AH,0AH,0AH ;D1, T10, T9, T8. db 0BH,6H,0BH,5H ;T7, R6, T6, L12. db 6H,8H,0BH,0BH ;L9, L6, T5, T4. db 0BH,0BH,0BH,00H ;T3, T2, T1, . ; 20H: db 8H,00H,4H,8H ;R4, , R1, R2. db 9H,0AH,00H,9H ;R5, R3, , L10. db 9H,9H,9H,00H ;L7, L4, L1, . db 00H,9H,00H,00H ;, A9, , . ; 30H: db 8H,1H,2H,0H ;R7, R10, R11, R8. db 9H,6H,6H,2H ;R9, R12, A7, L11. db 0H,8H,8H,4H ;L8, L5, L2, L3. db 8H,0AH,00H,00H ;A8, A11, , . ; 40H: db 00H,0AH,6H,0H ;, A12, A6, /. db 4H,2H,7H,7H ;., , m, n. db 5H,1H,5H,2H ;b, v, c, x. db 4H,00H,0AH,00H ;z, , 47, . ; 50H: db 4H,4H,2H,4H ;A4, 46, 43, :. db 2H,0H,5H,7H ;l, k, j, h. db 7H,5H,1H,3H ;g, f, d, s. db 3H,00H,6H,4H ;a, , A3, A5. ; 60H: db 0AH,2H,6H,0H ;A10, 45 , 42, p. db 2H,3H,1H,7H ;o, i, u, y. db 7H,7H,1H,3H ;t, r, e, w. db 3H,5H,00H,8H ;q, A1, , D2. ; 70H: db 0H,6H,0H,0H ;A2, =, -, 0 db 3H,7H,1H,1H ;9, 8, 7, 6. db 1H,1H,3H,3H ;5, 4, 3, 2. db 5H,5H,00H,00H ;1, 48, , . ; The mask table gives the bit mask within the KeyMap byte. KBMask: ; 00H: db 00H,00H,00H,00H ;No key db 00H,00H,00H,00H ;No key db 00H,00H,00H,00H ;No key db 00H,00H,00H,00H ;No key ; 10H: db 80H,40H,4H,80H ;D1, T10, T9, T8. db 1H,1H,2H,8H ;T7, R6, T6, L12. db 2H,40H,4H,8H ;L9, L6, T5, T4. db 10H,40H,20H,00H ;T3, T2, T1, . ; 20H: db 2H,00H,1H,8H ;R4, , R1, R2. db 80H,20H,00H,20H ;R5, R3, , L10. db 10H,8H,4H,00H ;L7, L4, L1. db 00H,2H,00H,00H ;, A9, , . ; 30H: db 4H,1H,1H,4H ;R7, R10, R11, R8. db 40H,4H,40H,2H ;R9, R12, A7, L11. db 2H,20H,10H,2H ;L8, L5, L2, L3. db 80H,2H,00H,00H ;A8, A11, , . ; 40H: db 00H,1H,8H,8H ;, A12, A6, /. db 20H,10H,1H,2H ;., , m, n. db 1H,1H,4H,80H ;b, v, c, x. db 80H,00H,10H,00H ;z, , 47, . ; 50H: db 8H,4H,8H,10H ;A4, 46, 43, :. db 20H,40H,2H,8H ;l, k, j, h. db 20H,10H,4H,8H ;g, f, d, s. db 4H,00H,80H,40H ;a, , A3, A5. ; 60H: db 8H,4H,20H,10H ;A10, 45 , 42, p. db 40H,1H,2H,10H ;o, i, u, y. db 40H,80H,10H,20H ;t, r, e, w. db 10H,20H,00H,1H ;q, A1, , D2. ; 70H: db 1H,10H,20H,80H ;A2, =, -, 0 db 2H,4H,8H,20H ;9, 8, 7, 6. db 80H,40H,80H,40H ;5, 4, 3, 2. db 80H,40H,00H,00H ;1, 48, , . ; Internal definitions: SetTimeWait equ 30000 ;Wait value of ~ 200 msec for MP KBDataWait equ 6H ;Wait value of ~ 50 usec for KB Data ; KB Bell programming SC1 equ 40H ;Counter 1 RL3 equ 30H ;Read/Load least significant, then most significant data Mode3 equ 6 ;Mode 3 - square generator KBBellMode equ SC1+RL3+Mode3 ;Mode byte for 8253 KBBell Clk ; ; Subroutine: ReadMouse ; Read the Mouse hardware and check for CS Parity error. ; Updates MouseXPosition and MouseYPosition ; Stores switches in MouseSwitches. ; On exit: ; Condition code = 0: No change in mouse position or switches. ; Condition code = #0: Change in mouse position or switches. ReadMouse: LDA MouseSwitches MOV D,A ;Save old MouseSwitches in D LHLD 8000H+MouseX ;Memory-mapped I/O: L ¬ MouseX, H ¬ MouseYPosition OUT MouseClr ;Clear Mouse hardware counters IN MiscInput1 ;Read switches CMA ;Mouse sense complemented ANI MouseSwMask MOV E,A ;Save Mouse Switches in E ANI CSParityMask ;Check for CS Parity error JNZ CSParityError ReadKeyset: LDA KeysetPresentFlag ORA A JZ UpdateSwitches {Read the Keyset. The keyset has the following format: bit 0: Keyset 0 (leftmost switch) bit 1: Keyset 1 bit 2: Keyset 2 bit 3: Keyset 3 bit 4: Keyset 4 } IN Keyset {The value of a keyset bit is: 0 = not depressed (up), 1 = depressed (down). Reverse the bits.} UpdateSwitches: CMA ANI 0F8H ORA E ;OR in MouseSwitches STA MouseSwitches ;Store new mouse switches XRA D ;Compare to old mouse switches MOV D,A ;D=0 if no change in switches {HL = change in mouse position. See if there was a change.} MOV A,L ;A ¬ mouse change X ORA H ;OR in mouse change Y JNZ MouseChanged {Continue if the mouse position did not change. Return with condition code to indicate whether mouse buttons changed.} ORA D RET MouseChanged: {The mouse position has changed. HL = change in mouse position. Update the mouse coordinates.} PUSH H ;Save the xy change for later use. MOV E,H ;move a copy of the y change into the low register of DE for a sign extension. MVI D,0 ;assume that y change was positive. MOV A,E ;also copy the y change into the Accumulator. ORA A ;set the flags so we can check assumption. JP SaveYChange ;We were correct. DCR D ;we lose so we must correct the sign. SaveYChange: LHLD MouseYPosition ;Get old Y position. DAD D ;add in change from old position. SHLD MouseYPosition ;Save new Y position. POP D ;Bring the xy change position that we previously saved back with the x change ready for sign extension. MVI D,0 ;assume that x change was positive. MOV A,E ;also copy the x change into the Accumulator. ORA A ;set the flags so we can check assumption. JP SaveXChange ;We were correct. DCR D ;we lose so we must correct the sign. SaveXChange: LHLD MouseXPosition ;Get old X position. DAD D ;add in change from old position. SHLD MouseXPosition ;Save new X position. XRA A ;Clear the Accumulator. INR A ;make the Accumulator non-zero and reset the zero flag. RET CSParityError: IN MiscInput1 ;Read in CSParity error bit again ANI CSParityMask JNZ ReadKeyset ;z => CS parity error (active low) ; Control Store parity error detected. Stop the world. LXI H,ErrorCSParity JMP ErrorReport ; GetTOD: {Read the TOD into the TOD state in IOP memory. If the PowerFailed bit is on, clear IOPValid, otherwise set IOPValid ¬ -1.} ; First Read the time. LXI H,TODMost ;Point to most significant byte of TOD buffer CALL ReadTOD ;Read time into TODLo..TODHi LHLD TODLo ;Copy Low word SHLD TODLoX ; Read the power failed bit. IN MiscInput1 ;Read power fail bit from MiscInput1 ANI PowerFailedMask ;Mask OUT other bits JZ ValidTime ;z => no power failure ; There was a power failure. Clear the valid flag. LXI H,CheckPortBusy LXI D,0 SetTODValid: SHLD TODValidSwitch XCHG SHLD TODValid ;Store in TOD state RET ; The time is valid. Set TODValid. Set to check TOD each time through the loop. ValidTime: LXI H,CheckTOD LXI D,-1 JMP SetTODValid ReadTOD: {Read the TOD hardware clock. Read the 32 bit time into TODLo (LS word) - TODHi (MS word). Can take up to a second to do this. On entry: H,L - pointer to data buffer (most sig. byte) for time to be read into.} OUT TODClr ;Clear TOD interrupt. ; Wait for a TOD interrupt. WaitTODIntr: IN MiscInput1 ;***Rev G and higher IOP ANI TODIntMask ;TOD interrupt? JZ WaitTODIntr OUT TODClr ;Clear TOD interrupt. ; Interrupt has just come. We can now read the clock between 1 Hz pulses. MVI A,ReadTimeMode ;Set ReadTime bit in MiscControl1 CALL SetMiscControl1Bit MVI E,4 ;4 bytes of data ReadTODLoop: {Read a byte of the TOD clock. Assumes the TOD clock is in Read Mode. Bits from clock come in true, and most significant bit first. Register usage: D - time data E - data byte counter HL - pointer to data buffer} MVI D,0 ;Clear D MVI A,8 ;8 bits in byte ReadTODByteLoop: STA BitCounter MOV A,D ;Shift left partial byte RLC MOV D,A ;Store back in D IN MiscInput1 ;Read bit ANI TODDataMask RLC ;Align to bit 7 position RLC ORA D ;OR into data byte MOV D,A ;Partial back to D ; Shift TOD clock shift register PUSH D MVI D,TODRead ;Mask for TODRead clock CALL DoMiscClock POP D DB opMVIA ;A ¬ BitCounter BitCounter: DB 0 DCR A ;Done all 8 bits? JNZ ReadTODByteLoop ; TOD data byte in D. Store in memory. MOV M,D ;Store in Time buffer DCX H ;Move pointer DCR E ;last byte? JNZ ReadTODLoop ; Clear ReadTime Mode. MVI A,nReadTimeMode ;Clear ReadTime bit in MiscControl1 JMP ClearMiscControl1Bit SetTOD: {Set the time of day clock. This subrOUTine sets the TOD clock to value in SetTime[0..3]. SubrOUTine first clears the TOD clock and then sets each byte of the clock. The clock is 32 bits wide, and each byte can be set independently. On entry: HL points to a buffer where the time to be set is stored. Chunk A: Bits 24-31 (8 bits) (HL­) Chunk B: Bits 16-23 (8 bits) (HL­+1) Chunk C: Bits 8-15 (8 bits) (HL­+2) Chunk D: Bits 0-7 (8 bits) (HL­+3)} MVI A,SetTimeMode ;First clear the TOD clock. CALL SetMiscControl1Bit ;TOD clock to Set Time Mode PUSH H ;Save H,L over CALL to Wait LXI H,SetTimeWait ;Wait .4 msec CALL Wait POP H ;Restore H,L MVI A,SetTimeMode+ClearTimeMode CALL SetMiscControl1Bit ;TOD clock to Set+Clear Mode MVI A,nClearTimeMode ;Clear time CALL ClearMiscControl1Bit ;TOD clock to Set Mode {Set each byte of the counter (HL points to buffer)} MVI D,TODSetA ;Initialize clock to byte A SetTODLoop: MOV E,M ;Get data value for counter INR E ;Correct so that 0 can be set CALL SetTODByte ;Set counter byte INX H ;Point to next Time byte MOV A,D RAR ;Form next clock mask MOV D,A ;Return to D CPI 0 ;Check if the last byte was done (mask shifted off) JNZ SetTODLoop ;If not, loop for next byte ; Clock is now set. Release SetTime mode. MVI A,nSetTimeMode JMP ClearMiscControl1Bit ;TOD clock to not Set Mode ; Jump to ClearMiscControl1Bit and return. SetTODByte: {Set one counter in the TOD clock. Assumes that the TOD clock is in SetMode. Assumes that the particular counter has been cleared. The subroutine counts up the counter to the desired value. On entry: D has mask of particular SetClk to use E has value for counter +1 (so zero can be set).} DCR E ;Decrement counter RZ CALL DoMiscClock ;D has mask for TOD Set clock JMP SetTODByte ; DoProcCmd: {This subroutine is called when a command is detected in the CSB. The comands are: 1 = Set Time-of-Day clock (time in ProcData2, ProcData1) 2 = Read Time-of-Day clock (hw) (time returned in TODValid, TODLo, TODHi) 3 = Read Host address (host address returned in ProcData2, ProcData1, ProcData0) 4 = Boot 5 = Read IOP Byte 6 = Write IOP Byte 7 = Read Umbilical Block 8 = Write Umbilical Block 9 = Turn On Keyset 10 = Turn Off Keyset On entry: The Processor CSB has the command (and data if neccessary). The CP port is already acquired.} LXI H,ProcPCB ;Pointer to Processor CPport control block CALL ReadCPBuffer ;Read CP main memory LDA ProcCommand ;Check command CPI 1 JZ DoSetTODCmd CPI 2 JZ DoReadTODCmd CPI 3 JZ DoReadHAddrCmd CPI 4 {Command 4: Do Boot. This command causes a jump to the start of the EProm boot code. The default boot will be executed. The entry point in the EProm is the same as if the boot button had been pressed, except that the hardware reset was not done.} JZ RST0Loc CPI 5 JZ DoReadIOPCmd CPI 6 JZ DoWriteIOPCmd CPI 7 JZ OldReadUmbilical CPI 8 JZ OldWriteUmbilical CPI 9 JZ UpdateKeysetPresentFlag CPI 10 JZ TurnOffKeyset LXI H,ErrorInvProcCmd JMP ErrorReport ;Report the error DoReadIOPCmd: {Command 5: Do Read IOP Command. The address of the byte to read is in ProcData2. The byte read will be returned in the low byte of ProcData1.} LHLD ProcData2 ;HL ¬ memory address MOV A,M ;A ¬ byte STA ProcData1 JMP TransferProcessorCSB DoWriteIOPCmd: {Command 6: Do Write IOP Command. The address of the byte to write is in ProcData2. The low byte of ProcData1 contains the byte to write.} LHLD ProcData2 ;HL ¬ memory address LDA ProcData1 ;A ¬ byte to write MOV M,A ;Write byte to IOP memory JMP ResetProcessorCommand TurnOffKeyset: XRA A UpdateKeysetPresentFlag: STA KeysetPresentFlag JMP ResetProcessorCommand DoSetTODCmd: {Command 1: Set the Time-of Day hardware.} LXI H,ProcData2 ;Point to the time buffer CALL SetTOD ;Set the time CALL GetTOD ;Re-initialize the TOD state in memory LDA TODValidHi ORA A JNZ ResetProcessorCommand ;z => time still invalid {There was an error in setting the TOD hardware. The PF bit was still on.} LXI H,ErrorSetTOD JMP ErrorReport ;Report the error DoReadTODCmd: {Command 2: Read the Time-of Day hardware.} CALL GetTOD ;Read the TOD into TOD state LXI H,TODValid ; Copy from TODValid LXI D,ProcData2 ; to ProcData2 MVI A,6 ; Copy 6 bytes CALL Copy JMP TransferProcessorCSB DoReadHAddrCmd: {Command 3: Read the Host Address into ProcData. Read the host address from the host address prom. The prom has 12 nibbles containing the 48-bit host address, plus an 8-bit checksum. (Checksum is currently unimplemented.) Current realization: Only the high word is in the prom with the Processor ID. The middle and low words, which are constant, are generated in software. Register usage: HL - buffer pointer DE - Host address prom pointer} LXI H,ProcData0Hi ;Point to last byte in ProcData in CSB PUSH H ;Save this address on the stack for now. LXI H,8000H+HostAddr ;Point to the HAddr prom MVI D,6 ;Count of 6 bytes ReadHAddrLoop: MOV A,M ;Get low nybble of byte ANI 0FH ;Mask off high nybble. MOV E,A ;Save temporary results INX H ;Advance pointer to point to the high nybble. MOV A,M ;Get high nybble of byte ADD A ;double the value of accumulator (Along with the next 3 adds we zero out the low nybble) ADD A ADD A ADD A ORA E ;combine the low & high nybbles to form a byte XTHL ;swap pointers MOV M,A ;save byte DCX H ;Set pointer to next location in CSB XTHL ;swap pointers again INX H ;adjust pointer to the next low nybble. DCR D ;Decrement the loop count. JNZ ReadHAddrLoop ;nz => still more to do POP H ;smash pointers and cleanup the stack TransferProcessorCSB: LXI H,ProcPCB CALL WriteCPBuffer ResetProcessorCommand: LXI H,ZeroProcessorPCB JMP WriteCPBuffer ;Write CP main memory and RET ; ReadKeyboard: { Read one byte from the keyboard. Assumes that the data is ready in the keyboard (i.e. KBReq is active). Note: MiscControl1Val is used to get other bits' state, but is not modified.} MVI A,pReadKBData ;Set ReadKB bit high CALL SetMiscControl1Bit LXI H,KBDataWait ;Set up delay CALL Wait ;Wait ~50 usec MVI A,npReadKBData ;Keyboard data latch clock bit low (>RevG) CALL ClearMiscControl1Bit ;Keyboard data is latched IN KBData ;Read in data from latch CMA ;Comes in complemented STA KeyEvent ;Store event UpdateKeyMap: {Insert the keyboard event into the KeyMap bitmap. On entry A (and KeyEvent) has the 8-bit keyboard event. Bit 0 =0 means downstroke, bit 0 =1 means upstroke.} ANI 7FH ;Form 7-bit index to KB tables MOV E,A ;DE has index value MVI D,0 LXI H,KBIndex ;Point to start of Index table DAD D ;Add index into table MOV A,M ;C ¬ index into KeyMap PUSH PSW ;Save IndexIntoKeyMap LXI H,KBMask ;Point to start of Mask table DAD D ;Add index into table MOV A,M ;E ¬ bitmask in KeyMap MOV E,A CMA ;D ¬ complement of bitmask in KeyMap MOV D,A LXI H,KeyMap ;Point to start of KeyMap POP PSW ;A ¬ IndexIntoKeyMap ADD L ;Add index into KeyMap MOV L,A MOV A,H ACI 0 MOV H,A DB opMVIA; ;A ¬ KeyEvent KeyEvent: DB 0 ORA A ;Set flags MOV A,M ;Get old map byte JM KeyUp ;S=1 (m) => Upstroke ; It was a down stroke. KeyDown: ANA D ;AND in new down stroke JMP SendNewMap KeyUp: ORA E ;OR in new up stroke SendNewMap: MOV M,A ;Update map LXI H,KBTaskPCB JMP WriteCPBuffer ;Write new map and RET DoToneCmd: { Come here when a command is detected in the Tone CSB. The comands are: 0 = Start Tone (frequency divisor in ToneFreq) 1 = Stop Tone On entry: The Tone CSB has the command (and data if neccessary).} LDA ToneCommand ;Check command CPI 1 JZ DoStopToneCmd ;z => Stop Tone command LXI H,TonePCB CALL ReadCPBuffer ;Read ToneCSB { Command 0: Start the Tone Generator. Set up the i8253 for the Tone frequency. Frequency divisor is in ToneFreq.} DoStartToneCmd: MVI A,KBBellMode ;Get 8253 Mode word DI ;No interrupts OUT TimerMode ;Output to Timer LHLD ToneFreq ;Get divisor MOV A,L ;Least significant byte OUT TimerCount1 ;Output to Timer MOV A,H ;Most significant byte OUT TimerCount1 ;Output to Timer EI ;Enable interrupts MVI A,KBTone ;Set KBTone bit in MiscControl1 CALL SetMiscControl1Bit ;Enable Tone { Command completed. Clear ToneCommand and transfer to main memory.} TransferToneCSB: LXI H,ZeroToneCommand ;Pointer to Port control block JMP WriteCPBuffer ;Write main memory DoStopToneCmd: {Command 1: Stop the Tone Generator.} MVI A,nKBTone ;Clear bit in MiscControl1 CALL ClearMiscControl1Bit ;Disable Tone JMP TransferToneCSB ;Clear ToneCommand ; MainLoop: { If time is valid, check for time to update TOD. This switch is set by GetTOD. If the TOD is not valid because of a power failure, we will jump to CheckPortBusy.} DB opJMP ;JMP CheckTOD TODValidSwitch: DW CheckTOD ; JMP CheckPortBusy CheckTOD: { Check for a TOD interrupt. If there was an interrupt, increment the local clock. Clears TOD interrupt before returning.} IN MiscInput1 ;***Rev G and higher IOP ANI TODIntMask ;TOD interrupt? STA TODChangeFlag JZ CheckPortBusy ;z => no interrupt, return { There was an interrupt. Clear the interrupt. Increment the local clock.} OUT TODClr ;Clear TOD interrupt. LXI D,1 LHLD TODLo DAD D ;Increment low order by 1 SHLD TODLo SHLD TODLox JNC CheckPortBusy LHLD TODHi ;If carry, DAD D ;Increment high order by 1 SHLD TODHi CheckPortBusy: DB opMVIA ;A ¬ PortBusyFlag PortBusyFlag: DB 0 ORA A JNZ BookKeepingTaskYield ;Yield if Port is busy DB opORI ;A ¬ TODChangeFlag TODChangeFlag: DB 0 JZ ReadCSB ;z => not time yet for TOD transfer XRA A STA TODChangeFlag LXI H,TODPCB ;Pointer to TOD CPport control block CALL WriteCPBuffer ;Transfer to CP main memory ReadCSB: LXI H,IOPagePCB ;Point to CPport Control Block CALL ReadCPBuffer ;Read CP main memory ; {Check to see if the CP says the mouse coordinates have changed. If so, update the mouse X and Y coordinates, and clear MouseChgCSB.Full in main memory.} LDA MouseChangeFlag ORA A ;Set Flags JZ CheckMouseHardware ;Jump if CP says no Mouse change CALL ReadMouse ;Clear mouse hardware {Reread the mouse change CSB to assure that the data is valid. Read MouseChgX into MouseXPosition and MouseChgY into MouseYPosition} LXI H,MouseChgPCB ;Pointer to MP CPport control block CALL ReadCPBuffer LXI H,MouseChangeFlagPCB CALL WriteCPBuffer ;Write CSB to CP memory JMP UpdateMousePosition CheckMouseHardware: {Check mouse hardware to see if the mouse moved.} CALL ReadMouse ;Coord. to MXTemp, MYTemp, switches in MouseSwitches JZ CheckKeyboard UpdateMousePosition: {Transfer the mouse state to the CP. Mouse state to be transferred: MouseXPosition, MouseYPosition, MouseSwitches (3 words)} LXI H,MousePCB ;Pointer to Mouse CPport control block CALL WriteCPBuffer ;Transfer to CP main memory CheckKeyboard: IN IntReq ;Read interupt port ANI KBReqMask ;KB request? CZ ReadKeyboard ;z => request CheckProcCSB: LDA ProcCommand ;Check if bit 0 #0 (full) ORA A ;Set Flags CNZ DoProcCmd ;Do the Processor CSB command CheckToneCSB: LDA ToneCommandFlag ;Check if bit 0 #0 (full) ORA A ;Set Flags CNZ DoToneCmd ;Do the Tone CSB command CheckBurdock: LDA BurdockFlag ; #0 => command to do ORA A CNZ DoBurdockCmd BookKeepingTaskYield: {Pass control to the next task specified in Domino.cfg} DS 0 END BookKeepingTask