{  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