{ File: [Iris]<WMicro>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