*-----------------------------------------------------------
Title[DisplayAux.mc.....November 22, 1982  5:49 PM...Taft];
*** Pilot-only version ***
* Auxiliary Dorado display microcode -- required both by emulators and
* by Bootstrap/Initial microcode.
*-----------------------------------------------------------

*-----------------------------------------------------------
DisplayInitConfig:
* Terminal configuration initialization, called from emulator task.
* Sets DisplayConfig as follows:
*	Bit 0		0 = DispY controls terminal, 1 = DispM controls terminal
*	Bits 14:15	0 = Alto monitor
*			1 = LF monitor using entire screen
* Returns RBase[THTRegion];
* Clobbers T
*-----------------------------------------------------------
Subroutine;
Set[XTask, IP[EMU]];

	RBase← RBase[THTRegion];
	T← TStatus;			* Select Status register on DispM
	TIOA← T;
	DisplayConfig← InputNoPE;	* Nonzero => DispM board installed
	T← Statics;			* Select Statics registry on DispY
	TIOA← T;
	T← LShift[106, 10]C;		* Select muffler 106
	Output← T;
	PD← DisplayConfig, TIOA[DDCStatus]; * Select Status registry on DispY

* Input from Status register returns:
*   Bit 0 = keyboard data bit
*   Bits 1:14 = 0
*   Bit 15 = muffler data bit = 1 iff an LF monitor is connected
	T← Input, Branch[.+2, ALU#0];
	DisplayConfig← T AND (1C), Return; * DispY controls terminal
	DisplayConfig← T OR (100000C), Return; * DispM controls terminal

*-----------------------------------------------------------
InitHRam:
* Initialize the HRam with standard waveforms for Alto or LF monitor.
* Entry: RBase = THTRegion or DHTRegion
*	TIOA selects some DispY register
*	DisplayConfig[14:15] selects monitor type (see DisplayInitConfig)
* Exit: TIOA[HRam]
*	clobbers T, xTemp0, xTemp1, xTemp2 (x = T or H)
*-----------------------------------------------------------
Subroutine;
Set[XTask, IP[DHT]];
KnowRBase[THTRegion];	* or DHTRegion

* Local register usage:
*   TTemp0 = HRam count
*   TTemp1 = address of current HRamTable entry in IM
*   TTemp2 = return link

	TTemp2← Link;
TopLevel;

	TIOA[HRam], Call[AfterHRamTable]; * Link← HRamTable

* Check consistency of horizontal waveforms defined in DisplayDefs.mc
M[WFCheck,
  Set[T1, #1] Set[T2, #2] Set[T3, #3] Set[T4, #4]
  IfE[And[T1, 3], 0, , WFEr1[#5]]  IfE[And[T2, 3], 0, , WFEr2[#5]]
  IfE[And[T3, 1], 0, , WFEr3[#5]]  IfE[And[T4, 1], 0, , WFEr4[#5]]
  IfE[And[Sub[T1, T2, T3], 3], 2, , WFEr5[#5]]
  ];
M[WFEr1, ER[#1.pixels/scanline.not.multiple.of.4, 2]];
M[WFEr2, ER[#1.visible.pixels.not.multiple.of.4, 2]];
M[WFEr3, ER[#1.visible.to.sync.distance.not.even, 2]];
M[WFEr4, ER[#1.sync.width.not.even, 2]];
M[WFEr5, ER[#1.horizontal.blanking.on.odd.clock, 2]];
HorizontalWaveforms[WFCheck];

* Each entry in this table describes a group of consecutive HRam locations:
* Byt0 = number of locations for Alto monitor.
* Byt1 = number of locations for LF monitor using entire screen.
* Byt3 = HRam data value for those locations.
* The last entry must be located at 0 mod 10.

M[ApplyToWF,
  HorizontalWaveforms[#1]
  Data[(Byt0[RShift[WFAlto, 1]] Byt1[RShift[WFLFFull, 1]] Byt3[#2])]
  ];

HRamTable: DispTable[7, 7, 2];
	M[WF1, Set[WF#5, Sub[#4, 2]]]; ApplyToWF[WF1, Add[HSync!, HBlank!]];
	M[WF2, Set[WF#5, Sub[#1, #2, #3, #4]]]; ApplyToWF[WF2, HBlank!];
	M[WF3, Set[WF#5, Sub[Add[#2, #3], RShift[#1, 1]]]]; ApplyToWF[WF3, 0];
	M[WF4, Set[WF#5, #4]]; ApplyToWF[WF4, HalfLine!];
	M[WF5, Set[WF#5, Sub[RShift[#1, 1], #3, #4]]]; ApplyToWF[WF5, 0];
	M[WF6, Set[WF#5, #3]]; ApplyToWF[WF6, HBlank!];
	Data[(Byt0[1] Byt1[1] Byt2[1] Byt3[HSync!, HBlank!])];

* InitHRam (cont'd)

AfterHRamTable:
	TTemp1← Link;

* Must Output LoadAddress twice in case DoradoHasHRam wasn't true to begin with --
* once to turn on DoradoHasHRam and once to actually load the address !!
	T← LoadAddress;			* Keep HRam, select address 0
	Output← T, Call[OutputGetsT];

* This loop works as follows:
* We first dispatch to ConfigTable+0 or +2 according to whether
* DisplayConfig = 0 or 1; this reads Byt0 or Byt1 of the instruction
* pointed to by TTemp1.  Then we dispatch to ConfigTable+4 to read the HRam data
* from Byt3 of the word pointed to by TTemp1.
LoadHRamLoop:
	T← (DisplayConfig)+(DisplayConfig), TaskingOff;
DoHRamDisp:
	TTemp0← (TTemp0)-1, BDispatch← T;
	Link← TTemp1, Branch[ConfigTable];

ConfigTable: DispTable[6];
	T← 4C, ReadIM[0];		* DisplayConfig = 0
	TTemp0← NOT (Link), Branch[DoHRamDisp];

	T← 4C, ReadIM[1];		* DisplayConfig = 1
	TTemp0← NOT (Link), Branch[DoHRamDisp];

	ReadIM[3], TaskingOn;		* Read HRam data
	T← NOT (Link), Branch[LoadHRamRun];

* Here with TTemp0 = count-1, T = HRam data.
LoadHRamRun:
	TTemp0← (TTemp0)-1, Branch[.+2, R<0];
	TTemp0← (TTemp0)-1, Output← T, Branch[., R>=0];
	PD← (TTemp1) AND (7C);
	TTemp1← (TTemp1)+1, Branch[LoadHRamLoop, ALU#0];

	T← ReleaseRam;
	Link← TTemp2, Branch[OutputGetsT];

*-----------------------------------------------------------
ReadTerminal:
* Code to process the next terminal input bit. This subroutine must be called
* once duing every scan line. Accumulates a 32-bit message of the form:
*     1,x,x,x,MessageType[0..3],   Message[0..15],   1,0,0,0,0,0,0,0.
* (Note that we only care about the first 25 bits and can ignore the trailing
* zeroes.  The "x" bits are don't care.)  Messages are:
*	Type		Content
*	0		noop
*	1		Keyboard Word 1
*	2		Keyboard Word 2
*	3		Keyboard Word 3
*	4		Keyboard Word 4
*	5		Keyboard Word 0 (keyset and mouse buttons)
*	6		Mouse DeltaX, DeltaY (excess-128, 8 bits each)
*	7		unused
*	10		Keyboard word 5 (Star keyboard only)
*	11		Keyboard word 6 (Star keyboard only)
*	12-16		unused
*	17		Boot Message (actually, data jammed to 1 continuously)
* One bit is read every scan line from Status.00. At the 24th bit after the
* start bit, the message is completed and checked for validity (24th bit = 1).
* If valid, a dispatch on the type causes the appropriate action in memory.
* Clobbers T, Link  Uses TerminalLo, TerminalHi, and updates BootTimer
* to be the duration (in scan lines) of the most recent boot button push.
* Restores TIOA[NLCB], and decrements TFieldAreaReg in the Return instruction.
* Timing: 6 cycles if nothing interesting is going on.
*-----------------------------------------------------------
Set[XTask, IP[DHT]];
KnowRBase[THTRegion];
Subroutine;

	T← TerminalLo, TIOA[TStatus], Global;

* Test TerminalHi[8] for the presence of a start bit signifying the
* completion of a message, and read the new data bit from the terminal.
	PD← (TerminalHi) AND (200C);
	TerminalLo← InputNoPE, Branch[MsgComplete, ALU#0]; * Data = IOB[0]

* Not end of message.  Shift in the new data bit.
* TerminalLo[0] = data bit, and T has former contents of TerminalLo.
	TerminalLo← LCY[TerminalLo, T, 1];
	TerminalHi← LCY[T, TerminalHi, 1];
ReadTerminalRet:
	TFieldAreaReg← (TFieldAreaReg)-1, TIOA[TNLCB], Return;

* ReadTerminal (cont'd)

*-----------------------------------------------------------
* Have a complete new message.
* TerminalHi[12..15] = message type; T = data; TerminalLo[0] = flag bit.
* Do not process the message if the flag bit is wrong, or if we are
* in the midst of booting.
*-----------------------------------------------------------
MsgComplete:
	TerminalLo← T, Branch[MsgMalformed, R>=0];
	T← (TerminalHi) AND (17C), Branch[AmidstBoot, R<0];
	TerminalHi← Link;
TopLevel;
	BigBDispatch← T;
	TerminalHi← A0, Link← TerminalHi, Branch[TerminalTable];

TerminalTable: DispTable[20];
	TerminalLo← A0, Branch[ReadTerminalRet];		* 0 Noop, ignore
	T← Add[DCSB.keyboard!, 1]C, Branch[StoreTerminalLo];	* 1 Keyboard 1
	T← Add[DCSB.keyboard!, 2]C, Branch[StoreTerminalLo];	* 2 Keyboard 2
	T← Add[DCSB.keyboard!, 3]C, Branch[StoreTerminalLo];	* 3 Keyboard 3
	T← Add[DCSB.keyboard!, 4]C, Branch[StoreTerminalLo];	* 4 Keyboard 4
	T← Add[DCSB.keyboard!, 0]C, Branch[StoreTerminalLo];	* 5 Buttons/keyset 0
	T← DCSB.mouseXCoord, Branch[MouseXY];			* 6 Mouse change
	TerminalLo← A0, Branch[ReadTerminalRet];		* 7 unused
	T← Add[DCSB.keyboard!, 5]C, Branch[StoreTerminalLo];	* 10 Keyboard 5
	T← Add[DCSB.keyboard!, 6]C, Branch[StoreTerminalLo];	* 11 Keyboard 6
	TerminalLo← A0, Branch[ReadTerminalRet];		* 12 unused
	TerminalLo← A0, Branch[ReadTerminalRet];		* 13 unused
	TerminalLo← A0, Branch[ReadTerminalRet];		* 14 unused
	TerminalLo← A0, Branch[ReadTerminalRet];		* 15 unused
	TerminalLo← A0, Branch[ReadTerminalRet];		* 16 unused
	BootTimer← 1C, Branch[SetBootFlag];			* 17 Start of boot

Subroutine;

* Mouse change -- data is deltaX,,deltaY as two 8-bit excess-128 numbers
MouseXY:
	TerminalHi← Fetch← T;		* Fetch MouseX
	T← LDF[TerminalLo, 10, 10];	* (DeltaX+128) in left byte
	T← T-(200C);
	T← T+MD;
	T← (Store← TerminalHi)+1, DBuf← T;
	Fetch← T;			* Fetch MouseY
	TerminalLo← LDF[TerminalLo, 10, 0]; * (DeltaY+128) in right byte
	TerminalLo← (TerminalLo)-(200C);
	TerminalLo← (TerminalLo)+MD;

* Store keyboard word.  T = address, TerminalLo = data.
StoreTerminalLo:
	TerminalLo← A0, Store← T, DBuf← TerminalLo, Branch[ReadTerminalRet];

* ReadTerminal (cont'd)

*-----------------------------------------------------------
* Boot message.
*-----------------------------------------------------------
* Actually, the terminal jams the data to a one while the boot
* button is pressed in, so the message is all ones.
* 24 samples after the boot button is pressed, we will come here
* with what looks like a "boot message".  We remember that we are in the
* midst of a boot by setting TerminalHi = -1, and we start a counter
* to time how long the boot button is held down.

* During subsequent samples, it will appear that a complete message
* has arrived at every one, since the start bit is always a one.
* We get here as a result of testing TerminalHi<0 during the dispatch.
* Count up the boot timer, and stay in the "amidst boot" state.
* Note: if the timer reaches 177777, freeze it there (about 2.5 seconds).
AmidstBoot:
	PD← (BootTimer)+1;
	BootTimer← (BootTimer)+1, XorSavedCarry;
SetBootFlag:
	TerminalHi← T-T-1, Branch[ReadTerminalRet];

* When the boot button finally comes up, it will appear that we have a
* malformed message (trailer bit = 0 rather than 1).
MsgMalformed:
	TerminalHi← A0, Branch[.+2, R<0]; * Branch if booting
	TerminalLo← A0, Branch[ReadTerminalRet]; * Just flush bad message

* A boot has just happened.  But filter it out if it was too short ( <8 ms).
* The terminal may send up to 8 bits of garbage after a boot, so fake
* the start of a "noop" message that will absorb those bits.
* Finally, exit the "amidst boot" state.
	PD← (BootTimer)-(MinimumPush);
	TerminalLo← 100000C, Branch[ReadTerminalRet, Carry];
	BootTimer← A0, Branch[ReadTerminalRet]; * Too short, ignore


*-----------------------------------------------------------
OutputGetsT:
* Handy global subroutine executes Output← T.
*-----------------------------------------------------------
Subroutine;
	Output← T, Return, Global;