$MOD186
$PAGELENGTH (72)
$PAGEWIDTH  (136)

;Copyright (C) 1984, 1985 by Xerox Corporation. All rights reserved.


;-- This program implements the mesa processor handler and mesa client task.

;-- stored as [Iris]<WMicro>Dove>MesaUpDn.asm
;
;-- last edited by:

;--	RTK			24-Feb-87 12:15:46	;Add 16 Bit IO Operations
;--	RTK			 6-Jan-87 14:29:27	:Add readIOPBus - writeOptBus
;--	JPM			 2-Oct-85  8:38:44	:Test for display size.
;--	JPM			13-Aug-85 16:43:05	:Add ReadPCType.
;--	JPM			12-Aug-85  9:16:42	:Change IOPEInRAM alignment to WORD.
;--	JPM			 3-Aug-85  8:11:16	:Convert for new ReadEEProm macro
;--	JPM			30-Jul-85 12:27:35	:Fix bugs in DownNotify
;--	JPM			26-Jul-85 12:45:40	:Opie redesign conversion
;--	JPM			17-Jun-85 16:40:30	:Implemented PerformBoot (using opieReentry)
;--	KEK		 	23-May-85 17:27:49	:added explicit Enable after ThisTaskServices.
;--	JPM			 5-Dec-84 17:36:34	:Made init proc NEAR; changed to RAM macros
;--	JPM			29-Nov-84 13:14:35	:Halt/start Mesa processor during task init
;--	JPM			26-Oct-84 11:15:02	:Added IN instrs. to clear Mesa interrupt
;--	JPM			18-Oct-84 12:05:52	:Fixed bug in command check
;--	JPM			17-Oct-84 13:30:18	:Added more commands, made jump table
;--	JPM			 4-Oct-84 13:51:43	:Added commands, PCE notify
;--	JPM			28-Sep-84 15:30:34	:Made separate proc to initialize tasks
;--	JPM			23-Jul-84 13:06:37	:Creation

NAME			MesaUpDn
;--------------------------------------------------------------------------------
; 
$NOLIST
$INCLUDE		(IOPDefs.asm)
$INCLUDE		(HardDefs.asm)
$INCLUDE		(MesaDefs.asm)
$INCLUDE		(ROMEEP.asm)
$INCLUDE		(RAMEEP.asm)
$INCLUDE		(OpieDefs.asm)
$INCLUDE		(IOPMacro.asm)
$LIST

EXTRN			MesaProcessorHandlerID: ABS
EXTRN			mesaProcessorInterrupt: ABS
EXTRN			DisplayHandlerID: ABS

;********************************************************************************

IOPELocalRAM		SEGMENT	AT 0

EXTRN			IOROpieSegmentAddress: WORD	; we take short cut
EXTRN			VMMFirstPage: WORD, VMMSizeInPages: WORD
EXTRN			firstRealPageInVM: WORD, lastRealPageInVM: WORD
EXTRN			countRealPagesInVM: WORD
EXTRN			firstDisplayBankPage: WORD, countDisplayBankPages: WORD
EXTRN			opieReentry: WORD

IOPELocalRAM		ENDS

;********************************************************************************

MesaProcessorIOR	SEGMENT		COMMON 

EXTRN			mesaProcessorTask: TaskContextBlock
EXTRN			mesaClientTask: TaskContextBlock

EXTRN			notifiersLockMask: WORD
EXTRN			upNotifyBits: WORD
EXTRN			downNotifyBits: WORD
EXTRN			wordsForDownNotify: ABS

EXTRN			mesaProcessorCommand: BYTE
EXTRN			mesaProcessorData: WORD

EXTRN			mesaClientCondition: Condition
EXTRN			mesaClientMask: WORD

MesaProcessorIOR	ENDS

;********************************************************************************

MesaProcessorSTK	SEGMENT		COMMON 

EXTRN			MesaProcessorStack: WORD
EXTRN			MesaClientStack: WORD

MesaProcessorSTK	ENDS

;********************************************************************************

OpieIOR			SEGMENT		COMMON

EXTRN			workNotifierCondition: Condition
EXTRN			workNotifierBitsPtr: WORD

EXTRN			timeOfDay: TimeOfDayFormat

OpieIOR			ENDS

;--------------------------------------------------------------------------------

DisplayIOR		SEGMENT		COMMON 

EXTRN			numberQuadWords: WORD

DisplayIOR		ENDS

;--------------------------------------------------------------------------------
; 
;
;********************************************************************************

IOPEInRAM		SEGMENT	WORD PUBLIC
			ASSUME	CS:IOPEInRAM

PUBLIC			MesaProcessorInit

MesaProcessorInit	PROC FAR
			%InitializeTask (MesaProcessorHandlerID,OFFSET mesaProcessorTask,MesaProcessorStart,OFFSET MesaProcessorStack)	; initialize down-notify task
			%InitializeTask	(MesaProcessorHandlerID,OFFSET mesaClientTask,MesaClientStart,OFFSET MesaClientStack)		; initialize up-notify task
			RET
MesaProcessorInit	ENDP

;--------------------------------------------------------------------------------

MesaProcessorStart:

; initialization for interrupt watcher (down-notify task)
			ASSUME	DS:MesaProcessorIOR

			MOV	AX, haltMesa		; halt the
			OUT	WriteCSReg, AX		;  Mesa processor
			%GetLockMask			; acquire software lock mask for notifiers
			MOV	notifiersLockMask, AX	;  and store away
			MOV	BX, OFFSET downNotifyBits
			MOV	CX, wordsForDownNotify
ZeroDownNotifyBits:	MOV	WORD PTR [BX], 0
			ADD	BX, 2
			LOOP	ZeroDownNotifyBits

			%LoadOpieSegment	(ES,AX)	; get direct access to Opie
			ASSUME	ES:OpieIOR
			IN	AX, ClrMesaIntr		; clear Mesa interrupt

; initialization complete, now attach this task to MesaProcessorInterrupt
			%ThisTaskServices	(MesaProcessorInterrupt,RecoveryNoOp)
			%DisableInterruptsTillNextWait	; don't allow interrupt
			%Enable(MesaProcessorInterrupt)

			MOV	AX, noHaltMesa		; start the
			OUT	WriteCSReg, AX		;  Mesa processor

MesaProcessorWait:

; task waits for MesaProcessorInterrupt, picks up locked data, ORs into workNotifierBits and
;  notifies system-level task to do individual notifies
; it also does a command from Mesa if requested

			%WaitForInterrupt (noTimeout)	; (MesaProcessorInterrupt)
			IN	AX, ClrMesaIntr		; clear Mesa interrupt
			MOV	BL, mesaProcessorCommand; load command
			ADD	BL, BL			; make word offset
			JZ	DownNotify		; if no command, go to down notify
			XOR	BH, BH			; clear high half of BX
			CMP	BX, 2*lastCommand	; check for valid command
			JG	ResetCommand		; if not valid, reset
			MOV	BX, CS:CommandTable[BX-2]	; load command routine addr
			JMP	BX			; execute command routine

CommandTable		DW	OFFSET ReadGMT		; cmd=readGMTtoData
			DW	OFFSET WriteGMT		; cmd=writeGMTfromData
			DW	OFFSET ReadHostID	; cmd=readHostIDtoData
			DW	OFFSET ReadVMMapDesc	; cmd=readVMMapDesctoData
			DW	OFFSET ReadRealMemDesc	; cmd=readRealMemDesctoData
			DW	OFFSET ReadDisplayDesc	; cmd=readDisplayDesctoData
			DW	OFFSET ReadKeyboardType	; cmd=readKeyboardTypetoData
			DW	OFFSET ReadPCType	; cmd=readPCTypetoData
			DW	OFFSET PerformBoot	; cmd=bootButton
			DW	OFFSET ReadIOP		; cmd=readIOPBus
			DW	OFFSET WriteIOP		; cmd=writeIOPBus
			DW	OFFSET ReadOpt		; cmd=readOptBus
			DW	OFFSET WriteOpt		; cmd=writeOptBus
			DW	OFFSET IORead16		; cmd=ioread16
			DW	OFFSET IOWrite16	; cmd=iowrite16

ResetCommand:		MOV	mesaProcessorCommand, noCommand	; reset command

DownNotify:		MOV	BX, OFFSET downNotifyBits
			MOV	DI, workNotifierBitsPtr
			MOV	CX, wordsForDownNotify
			MOV	BP, Null
DownNotifyLoop:		XOR	AX, AX		; prepare to do locked exchange of downNotifyBits with 0
			CMP	DS:[BX], AX	; any bits set?
			JE	DownNotifyLoopEnd ; if not, jump around
			MOV	BP, CX		; save CX (also makes BP > Null)
			%MesaLockedOut	(XCHG,BX,AX,notifiersLockMask)	; do exchange
			MOV	CX, BP		; restore CX
			OR	ES:[DI], AX	; set bits for work notify
DownNotifyLoopEnd:	ADD	BX, 2		; increment source and
			ADD	DI, 2		;  destination ptrs
			LOOP	DownNotifyLoop	; loop through all words

			CMP	BP, Null	; any exchanges happen?
			JE	MesaProcessorWait ; if not, go back and wait
			%NotifyHandlerCondition	(opieHandlerID,OFFSET workNotifierCondition)	; notify system-level task
			JMP	MesaProcessorWait	; go back and wait

;-- command procs

ReadGMT:		MOV	AX, timeOfDay.lowWord	; pick up both words
			MOV	mesaProcessorData, AX	;  of GMT
			MOV	AX, timeOfDay.highWord	;  and store them
			MOV	mesaProcessorData+2, AX	;  in mesaProcessorData
			JMP	ResetCommand

WriteGMT:		MOV	AX, mesaProcessorData	; pick up first 2 words
			MOV	timeOfDay.lowWord, AX	;  of mesaProcessorData
			MOV	AX, mesaProcessorData+2	;  and store them
			MOV	timeOfDay.highWord, AX	;  in GMT
			JMP	ResetCommand

ReadHostID:		MOV	DX, ReadHostProm	; load 1st I/O addr of host prom
			MOV	BX, OFFSET mesaProcessorData	; and addr of mesaProcessorData
			MOV	CX, sizeHostID		; set up loop count
ReadHostIDLoop:		IN	AL, DX			; read byte of host prom
			MOV	DS:[BX], AL		;  and store it
			INC	BX			; increment data addr
			ADD	DX, 2			;  and I/O addr
			LOOP	ReadHostIDLoop		; loop
			JMP	ResetCommand

ReadVMMapDesc:		MOV	AX, IOPELocalRAM	; switch to
			MOV	ES, AX			;  local RAM segment
			ASSUME	ES:IOPELocalRAM
			MOV	AX, VMMFirstPage	; get VMM first page
			MOV	mesaProcessorData, AX	;  and store in mesaProcessorData
			MOV	AX, VMMSizeInPages	; get VMM size
			MOV	mesaProcessorData+2, AX	;  and store in mesaProcessorData
			MOV	ES, IOROpieSegmentAddress ; restore ES
			ASSUME	ES:OpieIOR
			JMP	ResetCommand

ReadRealMemDesc:	MOV	AX, IOPELocalRAM	; switch to
			MOV	ES, AX			;  local RAM segment
			ASSUME	ES:IOPELocalRAM
			MOV	AX, firstRealPageInVM	; get first real page
			MOV	mesaProcessorData, AX	;  and store in mesaProcessorData
			MOV	AX, lastRealPageInVM	; get last real page
			MOV	mesaProcessorData+2, AX	;  and store in mesaProcessorData
			MOV	AX, countRealPagesInVM	; get real page count
			MOV	mesaProcessorData+4, AX	;  and store in mesaProcessorData
			MOV	ES, IOROpieSegmentAddress ; restore ES
			ASSUME	ES:OpieIOR
			JMP	ResetCommand

ReadDisplayDesc:	%EstablishHandlerAccess	(displayHandlerID)
			ASSUME	ES:DisplayIOR
			MOV	AX, numberQuadWords	; get display size
Test15InchBW:		CMP	AX, 13			; value for 15" b/w
			JNE	Test19InchBW
			MOV	AX, 1			; display present, b/w, small
			JMP	SHORT GoodDisplayDesc
Test19InchBW:		CMP	AX, 18			; value for 19" b/w
			JNE	GetEEPromDisplayInfo
			MOV	AX, 5			; display present, b/w, large
			JMP	SHORT GoodDisplayDesc
GetEEPromDisplayInfo:	%ReadEEProm (eePromDispType,1)	; read word from EEProm
			JNC	GoodDisplayDesc		;  (if not good read,
			MOV	AX, 0			;   assume no display)
GoodDisplayDesc:	MOV	mesaProcessorData, AX	; store in mesaProcessorData
			MOV	AX, IOPELocalRAM	; switch to
			MOV	ES, AX			;  local RAM segment
			ASSUME	ES:IOPELocalRAM
			MOV	AX, firstDisplayBankPage ; get first display page
			MOV	mesaProcessorData+2, AX	;  and store in mesaProcessorData
			MOV	AX, countDisplayBankPages ; get display page count
			MOV	mesaProcessorData+4, AX	;  and store in mesaProcessorData
			MOV	ES, IOROpieSegmentAddress ; restore ES
			ASSUME	ES:OpieIOR
			JMP	ResetCommand

ReadKeyboardType:	%ReadEEProm (eePromKBType,1)	; read word from EEProm
			JNC	GoodKeyboardType	;  (if not good read,
			MOV	AX, 1			;   use American)
GoodKeyboardType:	MOV	mesaProcessorData, AX	;  and store in mesaProcessorData
			JMP	ResetCommand

ReadPCType:		%ReadEEProm (eePromPCEMemSize,1) ; read word from EEProm
			JNC	GoodPCType		;  (if not good read,
			MOV	AX, 0			;   use null)
GoodPCType:		MOV	mesaProcessorData, AX	;  and store in mesaProcessorData
			JMP	ResetCommand

PerformBoot:		MOV	AX, IOPELocalRAM	; jump to Opie's
			MOV	ES, AX			;  reentry point (addr in
			JMP	DWORD PTR ES:opieReentry ;  local RAM)

ReadIOP:		MOV	BP, mesaProcessorData	; get the IOP offset
			MOV	BX, ES	; save ES
			MOV	ES, mesaProcessorData+2	; get the IOP segment
			MOV	AL, ES:[BP]		; get a byte
                       MOV	AH,0
			MOV	mesaProcessorData+4, AX	; store the byte					
			MOV	ES, BX ; restore ES
			JMP	ResetCommand

WriteIOP:		MOV	BP, mesaProcessorData	; get the IOP offset
			MOV	BX, ES	; save ES
			MOV	ES, mesaProcessorData+2	; get the IOP segment
			MOV	AX, mesaProcessorData+4	; get the byte					
			MOV	ES:[BP], AL			; write the byte
			MOV	ES, BX ; restore ES
			JMP	ResetCommand

ReadOpt:		MOV	DX, mesaProcessorData	; get the IO address
			IN	AL, DX			; get a byte
                       MOV     AH,0
			MOV	mesaProcessorData+4, AX	; store the byte			
			JMP	ResetCommand

WriteOpt:		
			MOV	DX, mesaProcessorData	; get the IO addres
			MOV	AX, mesaProcessorData+4	; get the byte			      
			OUT	DX, AL			; write the byte
			JMP	ResetCommand

IORead16:		MOV	DX, mesaProcessorData	; get IO address
			IN	AX, DX			; get the word
			MOV	mesaProcessorData+4, AX	; store the word
			JMP	ResetCommand

IOWrite16:		MOV	DX, mesaProcessorData	; get IO address
			MOV	AX, mesaProcessorData+4	; get the word
			OUT	DX, AX			; write the word
			JMP	ResetCommand


;--------------------------------------------------------------------------------


; interrupt error recovery proc
RecoveryNoOp		PROC	FAR
			RET	; no interrupt recovery (should not be needed, because task is always ready
RecoveryNoOp		ENDP	;  for interrupt and does not use watch dog timeout)

;--------------------------------------------------------------------------------
MesaClientStart:

; initialization for up-notify task

			MOV	upNotifyBits, 0		; reset upNotifyBits
			MOV	mesaClientMask, 0	;  and local source

MesaClientWait:

; main task waits for condition notify, picks up local bits,
;  ORs into locked data, and interrupts the Mesa processor

			%WaitForCondition	(OFFSET mesaClientCondition,noTimeout)
			XOR	AX, AX			; prepare to exchange local data with 0
			XCHG	mesaClientMask, AX	; do exchange
			%MesaLockedOut	(OR,OFFSET upNotifyBits,AX,notifiersLockMask)	; OR into locked data
			MOV	AX, noInterruptMesa	; interrupt the Mesa processor
			OUT	WriteCSReg, AX		;  by resetting bit in CS reg.
			MOV	AX, interruptMesa	;   then setting it
			OUT	WriteCSReg, AX		;    (bit is latched for Mesa)
			JMP	MesaClientWait		; loop


IOPEInRAM		ENDS


			END