{ File: [Idun]<WDLion>BookKeepingTask.asm
Last change by Jim Frandeen August 9, 1982 3:04 PM: new IO Page format. Add support for keyset. Add support for ReadBlock and WriteBlock processor commands.
Last change by Jim Frandeen July 20, 1982 11:08 AM: reread the whole Mouse CSB to fix the cursor jumping problem.
Last change by Jim Frandeen May 25, 1982 8:23 AM
Written by Jim Frandeen April 1, 1982 9:21 AM
}
get "SysDefs" ;System defs
get "CommonDefs" ;Common defs
IMP BlockBuffer ;From Buffer
IMP CheckCPDmaComplete ;From CPSubs
IMP ClearMiscControl1Bit ;From Common
IMP Copy ;From Common
IMP DisableRST ;From Common
IMP DoMiscClock ;From Common
IMP DoReadIOPCmd ;From Buffer
IMP DoReadUmbilicalBlockCmd ;From Buffer
IMP DoWriteIOPCmd ;From Buffer
IMP DoWriteUmbilicalBlockCmd ;From Buffer
IMP ErrorReport ;From Common
IMP ExitInterrupt ;From RS232CSubs
IMP KeyMap ;From FloppyTask
IMP MiscControl1Val ;From Common
IMP PutMPanel ;From Common
IMP ReadCPBuffer ;From CPSubs
IMP SetMiscControl1Bit ;From Common
IMP StartCPReadDma ;From CPSubs
IMP StartCPWriteDma ;From CPSubs
IMP Wait ;From Common
IMP WriteCPBuffer ;From CPSubs
IMP ZeroCommand ;From Common
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
;
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
RS232CMiscFlag:
DS 1 ;14018 High has flag in high bit
{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 low byte is not used
RS232CPutFlag:
DS 1 ;14019 High order byte
{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 low byte is not used
RS232CGetFlag:
DS 1 ;1401A High order byte
;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.}
MOV E,L ;DE will contain X change
MOV A,L ;A ← mouse change X
ORA A ;Check direction of change
JP XChangePositive
MVI D,0FFH ;Set sign of X change negative
SaveXChange:
PUSH D ;Save X change in Stack
MOV E,H ;DE will contain Y change
MOV A,H ;A ← mouse change Y
ORA A ;Check direction of change
JP YChangePositive
MVI D,0FFH ;Set sign of Y change negative
UpdateCoordinates:
LHLD MouseYPosition
DAD D ;HL ← MouseYPosition + change Y
SHLD MouseYPosition
LHLD MouseXPosition
POP D ;DE ← X change
DAD D ;HL ← MouseXPosition + change X
SHLD MouseXPosition
MVI A,1 ;Return condition code
ORA A
RET
XChangePositive:
MVI D,0 ;Set sign of X change positive
JMP SaveXChange
YChangePositive:
MVI D,0 ;Set sign of Y change positive
JMP UpdateCoordinates
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
{ **** LimitSample is deactivated. The Tajo window package wants to do the limiting itself.
;MXMax:
; DW 1024-16 ;Maximum MouseX coordinate (1008 = 3F0H)
;MYMax:
; DW 808-16 ;Maximum MouseY coordinate (792 = 318H)
; SubrOUTine: LimitSample[].
; Limit the mouse sample for maximum and minimum values.
; On entry: B,C points to the coordinate location (high byte).
; H,L points to the maximum coordinate location (high byte).
; Algorithm used:
; Minimum: IF Hi[Coord] < 0 => Set coordinate to zero, RETURN;
; Maximum:
; IF Hi[Coord] < Hi[Max] THEN [No change, RETURN];
; IF Hi[Coord] > Hi[Max] THEN [Set to maximum, RETURN];
; IF Hi[Coord] = Hi[Max] THEN
; BEGIN
; IF Lo[Coord] < Lo[Max] THEN No change, RETURN;
; IF Lo[Coord] = Lo[Max] THEN No change, RETURN;
; IF Lo[Coord] > Lo[Max] THEN Set to maximum, RETURN;
; END;
LimitSample:
; Check minimum.
LDAx b ;Compare Hi[coord] to 0
CPI 0 ;Check sign bit
jm SetToMIN ;m => coordinate negative
; Check maximum. A has Hi[coord].
cmp m ;compare to Hi[Max]
rc ;c => Hi[Coord] < Hi[Max]: [No change, RETURN]
; Now Hi[Coord] >= Hi[Max].
JNZ SetToMax2 ;nz => Hi[Coord] > Hi[Max]: [Set to maximum, RETURN]
; Now Hi[Coord] = Hi[Max]. Check low bytes.
DCX b ;Point to low bytes
DCX h
LDAx b ;Get Lo[coord]
cmp m ;compare to Lo[Max]
rc ;c => Lo[Coord] < Lo[Max]: [No change, RETURN]
; Now Lo[Coord] >= Lo[Max].
rz ;z => Hi[Coord] = Hi[Max]: [No change, RETURN]
; Now Lo[Coord] > Lo[Max]. Set to maximum.
SetToMax1:
MOV a,m ;Get Lo[Max]
stax b ;Store in coordinate
INX h ;Point to high bytes
INX b
SetLast:
MOV a,m ;Get byte
stax b ;Store in coordinate
RET
; Pointers are set to high bytes.
SetToMax2:
MOV a,m ;Get Hi[Max]
stax b ;Store in coordinate
DCX h ;Point to high bytes
DCX b
JMP SetLast ;Do low byte
; Set coordinates to zero. Pointers are set to high bytes.
SetToMin:
xra a ;Clear A
stax b ;Store in high coordinate
DCX b
stax b ;Store in low coordinate
RET
}
;
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 DoReadUmbilicalBlockCmd
CPI 8
JZ DoWriteUmbilicalBlockCmd
CPI 9
JZ UpdateKeysetPresentFlag
CPI 10
JZ TurnOffKeyset
LXI H,ErrorInvProcCmd
JMP ErrorReport ;Report the error
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
LXI D,8000H+HostAddr ;Point to the HAddr prom
MVI A,6 ;Count of 6 bytes
ReadHAddrLoop:
STA PromByteCount
LDAX D ;Get low nibble of byte
ANI 0FH ;Mask OUT high part
STA LowNibble
INX D ;Point to next nibble
LDAX D ;Get high nibble of byte
ANI 0FH ;Mask OUT high part
INX D ;Point to next nibble
RLC ;Move to high part of byte
RLC
RLC
RLC
DB opORI ;Form byte in A
LowNibble:
DB 0
MOV M,A ;Store in buffer
DCX H ;Point to next byte up
DB opMVIA ;A ← PromByteCount
PromByteCount:
DB 0
DCR A
JNZ ReadHAddrLoop ;nz => still more to do
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
BookKeepingTaskYield:
{Pass control to the next task specified in Domino.cfg}
DS 0
END BookKeepingTask