; GateDisplay.mu -- Display and cursor tasks with 2 R-registers bummed out

;	Last modified September 16, 1978  7:14 PM

; This microcode is entirely compatible with the standard Alto microcode,
; but does not use R-registers HTAB and CURDATA.

; **** DVT, DHT, DWT, and CURT must all be run in the Ram
; (these are tasks 14B, 13B, 11B, and 12B respectively).
; **** MRT must also be modified to remove cursor processing (in particular,
; the code that updates YPOS and sets CURDATA).

;The Display Controller

; its R-Registers:
$CBA		$R22;
$AECL		$R23;
$SLC		$R24;
; $HTAB		$R26;	Required by standard microcode but not by this
$YPOS		$R27;
$DWA		$R30;
$CURX		$R20;
; $CURDATA	$R21;	Required by standard microcode but not by this

; its task specific functions:
$EVENFIELD	$L024010,000000,000000; F2 = 10 DHT DVT
$SETMODE	$L024011,000000,000000; F2 = 11 DHT
$DDR		$L026010,000000,124100; F2 = 10 DWT

$NWW	$R4;
$400	$400;

!1,2,DVT1,DVT11;
!1,2,MOREB,NOMORE;
!1,2,NORMX,HALFX;
!1,2,NODD,NEVEN;
!1,2,DHT0,DHT1;
!1,2,NORMODE,HALFMODE;
!1,2,DoTab,NoTab;
!1,2,2Tab,1Tab;
!1,1,NoTab1;
!1,2,NWgr0,NWeq0;
!1,2,NWgr2,NWeq2;
!1,2,XNOMORE,DOMORE;
!1,1,NWeq0a;

;Display Vertical Task

DVT:	MAR← L← DASTART+1;
	CBA← L, L← 0;
	SLC← L;
	T← NWW;			CAUSE A VERTICAL FIELD INTERRUPT
	L← MD OR T;
	MAR← CURLOC;		SET UP THE CURSOR
	NWW← L, T← 0-1;
	L← MD XOR T;		HARDWARE EXPECTS X COMPLEMENTED
	T← MD, EVENFIELD;
	CURX← L, :DVT1;

DVT1:	L← 177677-T-1, TASK, :DVT2;	BIAS THE Y COORDINATE 
DVT11:	L← 177677-T, TASK;

DVT2:	YPOS← L, :DVT;

;Display Horizontal Task.
;11 cycles if no block change, 17 if new control block.

DHT:	MAR← CBA-1;
	L← SLC -1, BUS=0;
	SLC← L, :DHT0;

DHT0:	T← 37777;		MORE TO DO IN THIS BLOCK
	SINK← MD;
	T← MD . T, SETMODE;
	L← 177400+T, :NORMODE;	HTab-1 in left half

NORMODE: T← 377 . T, :REST;
HALFMODE: T← 0;

REST:	AECL← L;
	L← DWA + T,TASK;	INCREMENT DWA BY 0 OR NWRDS
NDNX:	DWA← L, :DHT;

DHT1:	L← T← MD+1, BUS=0;
	CBA← L, MAR← T, :MOREB;

NOMORE:	BLOCK, :DNX;
MOREB:	T← 37777;
	T← MD . T, SETMODE;
	MAR← CBA+1, :NORMX, EVENFIELD;

NORMX:	L← 177400+T, :NODD;	HTab-1 in left half
HALFX:	L← 177400+T, :NEVEN;

NODD:	T← 377 . T, :XREST;	ODD FIELD, FULL RESOLUTION
NEVEN:	T←0;			EVEN FIELD OR HALF RESOLUTION

XREST:	AECL← L;
	L← MD+T;
	T←MD-1;
DNX:	DWA←L, L←T, TASK;
	SLC←L, :DHT;

;Display Word Task
; Enters with DWA = address of first word of scan line
;	AECL = HTab-1 ,, NWords

; Caution: must not execute DDR← in a microinstruction that stops the clock
; (e.g., ←MD before the memory is ready).  Count instructions carefully!

; Horizontal tab loop -- outputs 2 tabs per iteration (except maybe the last)
DWT:	L← T← AECL-1;
	L← T← 177400+T+1, SH<0;		T← current HTab-1, test for none
	L← 177400+T, SH<0, :DoTab;	[DoTab, NoTab] L← current HTab-2
DoTab:	AECL← L, L← T, DDR← 0, TASK, :2Tab; [2Tab, 1Tab] Output first tab word
2Tab:	DDR← 0, :DWT;			Output second tab word

; There was only one tab word left
1Tab:	NOP;				TASK pending
	T← AECL;

; Set up for data word loop -- T has garbage ,, NWords
NoTab:	L← T← 377 . T;			[NoTab1] Extract NWords
NoTab1:	L← T← -3+T+1, SH=0;		T← NWords-2, test for NWords=0
	L← DWA+T, SH=0, :NWgr0;		[NWgr0, NWeq0] L← DWA+NWords-2

; There are at least two words.  Start fetch of first doubleword
NWgr0:	MAR← T← DWA, :NWgr2;		[NWgr2, NWeq2] Branch if only 2 words
NWgr2:	AECL← L, L← 0;			More than 2, AECL← last doubleword adr
	L← 2+T, SH=0, :DWTLp2;		Advance DWT, force branch

; Exactly two words -- output them and block
NWeq2:	L← 0, :DWTLp1;			Force carry=0 at DWTLp1

; Main data word loop
DWTLp:	MAR←T←DWA;
	L←AECL-T-1;
DWTLp1:	ALUCY, L←2+T;
DWTLp2:	DWA←L, :XNOMORE;		[XNOMORE, DOMORE]

DOMORE:	DDR←MD, TASK;
	DDR←MD, :DWTLp;

XNOMORE:DDR← MD, BLOCK;
	DDR← MD, TASK, :DWTF;

; Exit sequences
NWeq0:	BLOCK;				[NWeq0a]
NWeq0a:	TASK;
DWTF:	:DWT;

;CURSOR TASK

;Cursor task specific functions
$XPREG		$L026010,000000,124000; F2 = 10
$CSR		$L026011,000000,124000; F2 = 11

!1,2,ShowC,WaitC;
!1,2,~CLast,CLast;
!1,1,WaitC1;

CURT:	L← T← YPOS-1;			Check cursor Y counter
	L← 16-T-1, SH<0;		Reached cursor top?
	L← 3+T, SH<0, :ShowC;		[ShowC, WaitC] Reached cursor bottom?

; Within cursor, output a word of cursor data
ShowC:	MAR← CLOCKLOC+T+1, :~CLast;	[~CLast, CLast] Fetch the right word
CLast:	BLOCK;				Last line, block until next field
~CLast:	XPREG← CURX;			Output cursor X
	YPOS← L, TASK;			Update cursor Y counter
	CSR← MD, :CURT;			Output cursor data

; Haven't reached cursor yet
WaitC:	YPOS← L, TASK;			[WaitC1] Update cursor Y counte
WaitC1:	CSR← 0, :CURT;			Blank cursor during this scan line