-- XDisplay.mesa
-- Mesa 6 version (won't work on Alto)
-- Last changed by Doug Wyatt, May 31, 1980  10:16 PM

DIRECTORY
	XDisplayDefs USING [BankIndex, BBAPtr, BBArray, BBDest, BBPtr, BMPtr,
		BitBlt, DcbArray, dcbChain, dcbNIL, DcbPtr, FirstDcb, LPBank, LPPtr,
		NextDcb, pBitBlt],
	AltoHardware USING [BankRegisters, Task],
	BitBltDefs USING [BITBLT],
	ImageDefs USING [AddCleanupProcedure, AllReasons, CleanupItem, CleanupProcedure],
	SegmentDefs,
	SystemDefs USING [PagesForWords];

XDisplay: PROGRAM
IMPORTS XDisplayDefs,BitBltDefs,ImageDefs,SegmentDefs,SystemDefs
EXPORTS XDisplayDefs SHARES XDisplayDefs =
BEGIN OPEN XDisplayDefs;

XDisplayError: PUBLIC SIGNAL = CODE;

dBank: PUBLIC BankIndex←0;

-- AltoIIXM bank registers

Task: TYPE = AltoHardware.Task;
-- The display word task (DWT) is the one that reads words
-- out of the bitmap; its bank register supplies the high order
-- bits of the long pointer used to address those words.

SelectDBank: PROCEDURE[config: SegmentDefs.MemoryConfig] RETURNS[BankIndex] =
	BEGIN
--	b: BankIndex;
--	FOR b IN (0..LAST[BankIndex]]
--		DO
--		IF InlineDefs.BITAND[config.banks,bankMasks[b]]#0 THEN RETURN[b];
--		ENDLOOP;
	RETURN[0];
	END;

EnableDBank: PROCEDURE[BOOLEAN] ← NoopEnableDBank;

NoopEnableDBank: PROCEDURE[BOOLEAN] = BEGIN END;

AltoEnableDBank: PROCEDURE[on: BOOLEAN] =
	BEGIN AltoHardware.BankRegisters[DWT].normal←IF on THEN dBank ELSE 0 END;

AllocDSegment: PUBLIC PROCEDURE[pages: CARDINAL]
	RETURNS[LONG POINTER] =
	BEGIN OPEN SegmentDefs;
	RETURN[LongSegmentAddress[NewDataSegment[
		base: DefaultXMBase, pages: pages]]];
	END;

FreeDSegment: PUBLIC PROCEDURE[lp: LONG POINTER] =
	BEGIN OPEN SegmentDefs;
	DeleteDataSegment[LongVMtoDataSegment[lp]];
	END;


-- Bitmaps

BMSize: PUBLIC PROCEDURE[bm: BMPtr, width,height: CARDINAL] =
	BEGIN
	w: CARDINAL←(width+15)/16; -- words required for width
	bm↑←[base: NIL, raster: w, lines: height];
	END;
BMDisplaySize: PUBLIC PROCEDURE[bm: BMPtr, width,height: CARDINAL] =
	BEGIN
	dw: CARDINAL←(width+31)/32; -- double words required for width
	dl: CARDINAL←(height+1)/2; -- double scanlines required for height
	bm↑←[base: NIL, raster: 2*dw, lines: 2*dl];
	END;

AllocBitmap: PUBLIC PROCEDURE[bm: BMPtr] =
	BEGIN
	pages: CARDINAL←SystemDefs.PagesForWords[bm.raster*bm.lines];
	IF pages>0 THEN
		BEGIN bm.base←AllocDSegment[pages]; ClearBitmap[bm] END
	ELSE bm.base←NIL;
	END;

FreeBitmap: PUBLIC PROCEDURE[bm: BMPtr] =
	BEGIN
	IF bm.base#NIL THEN
		BEGIN FreeDSegment[bm.base]; bm.base←NIL END;
	END;

ClearBitmap: PUBLIC PROCEDURE[bm: BMPtr] =
	BEGIN
	bba: BBArray;
	bbt: BBPtr←BBInit[@bba];
	IF bm.base=NIL THEN RETURN;
	BBDest[bbt,bm]; bbt.dw←bm.raster*16; bbt.dh←bm.lines;
	BitBlt[bbt];
	END;


-- Display Control Blocks

Even: PROCEDURE[p: POINTER] RETURNS[POINTER] =
	INLINE BEGIN RETURN[p+(LOOPHOLE[p,CARDINAL] MOD 2)] END;

dcbSeal: POINTER = LOOPHOLE[177423B];
-- The D-machines will regard dcb.lbitmap as the bitmap pointer only if
--  dcb.tag=long AND dcb.bitmap=dcbSeal

DcbInit: PUBLIC PROCEDURE[dcba: POINTER TO DcbArray] RETURNS[DcbPtr] =
	BEGIN
	dcb: DcbPtr←Even[dcba];
	dcb↑←[]; -- use default initialization in XDisplayDefs
	RETURN[dcb];
	END;

EnumerateDcbs: PUBLIC PROCEDURE
	[Proc: PROCEDURE[DcbPtr] RETURNS[BOOLEAN]]
	RETURNS[DcbPtr] =
	BEGIN
	dcb: DcbPtr;
	FOR dcb←FirstDcb[],NextDcb[dcb] UNTIL dcb=dcbNIL
		DO IF Proc[dcb] THEN EXIT ENDLOOP;
	RETURN[dcb];
	END;

LinesAbove: PUBLIC PROCEDURE[dcb: DcbPtr] RETURNS[CARDINAL] =
	BEGIN
	lines: CARDINAL←0;
	CountLines: PROCEDURE[tdcb: DcbPtr] RETURNS[BOOLEAN] =
		BEGIN
		IF tdcb=dcb THEN RETURN[TRUE]
		ELSE BEGIN lines←lines+2*tdcb.height; RETURN[FALSE] END;
		END;
	[]←EnumerateDcbs[CountLines];
	RETURN[lines];
	END;

InsertDcb: PUBLIC PROCEDURE[dcb,otherdcb: DcbPtr] =
	BEGIN
	Ins: PROCEDURE[tdcb: DcbPtr] RETURNS[BOOLEAN] =
		BEGIN found: BOOLEAN←(tdcb.next=otherdcb);
		IF found THEN tdcb.next←dcb;
		RETURN[found];
		END;
	dcb.next←otherdcb;
	IF otherdcb=dcbChain↑ THEN dcbChain↑←dcb
	ELSE []←EnumerateDcbs[Ins];
	END;

RemoveDcb: PUBLIC PROCEDURE[dcb: DcbPtr] =
	BEGIN
	Rem: PROCEDURE[tdcb: DcbPtr] RETURNS[BOOLEAN] =
		BEGIN found: BOOLEAN←(tdcb.next=dcb);
		IF found THEN tdcb.next←dcb.next;
		RETURN[found];
		END;
	IF dcb=dcbChain↑ THEN dcbChain↑←dcb.next
	ELSE []←EnumerateDcbs[Rem];
	dcb.next←dcbNIL;
	END;

Displayed: PUBLIC PROCEDURE[dcb: DcbPtr] RETURNS[BOOLEAN] =
	BEGIN
	Match: PROCEDURE[tdcb: DcbPtr] RETURNS[BOOLEAN] =
		BEGIN RETURN[tdcb=dcb] END;
	RETURN[EnumerateDcbs[Match]=dcb];
	END;

DcbBitmapProc: PROCEDURE[DcbPtr,BMPtr] ← ShortDcbBitmap;
pDcbBitmap: PUBLIC POINTER TO PROCEDURE[DcbPtr,BMPtr] ← @DcbBitmapProc;

ShortDcbBitmap: PROCEDURE[dcb: DcbPtr, bm: BMPtr] =
	BEGIN
	IF bm.base#NIL AND LPBank[bm.base]#dBank THEN
		BEGIN SIGNAL XDisplayError; RETURN END; -- Bitmap not in dBank
	dcb.width←0;
	dcb.tag←short;
	dcb.bitmap←LPPtr[bm.base];
	dcb.height←bm.lines/2;
	dcb.width←(bm.raster/2)*2;
	END;

LongDcbBitmap: PROCEDURE[dcb: DcbPtr, bm: BMPtr] =
	BEGIN
	dcb.width←0;
	dcb.tag←long;
	dcb.bitmap←dcbSeal;
	dcb.lbitmap←bm.base;
	dcb.height←bm.lines/2;
	dcb.width←(bm.raster/2)*2;
	END;

-- BitBlt

BBInit: PUBLIC PROCEDURE[bba: BBAPtr] RETURNS[BBPtr] =
	BEGIN
	bb: BBPtr←Even[bba];
	bb↑←[]; -- use default initialization in XDisplayDefs
	RETURN[bb];
	END;

BitBltProc: PROCEDURE[BBPtr,BankIndex] ← AltoBitBlt;
pBitBlt: PUBLIC POINTER TO PROCEDURE[BBPtr,BankIndex] ← @BitBltProc;

AltoBitBlt: PROCEDURE[bbt: BBPtr, altbank: BankIndex] =
	BEGIN
	ERROR XDisplayError; -- AltoBitBlt not implemented
	END;

D0BitBlt: PROCEDURE[bbt: BBPtr, altbank: BankIndex] =
	BEGIN
	bbt.ptrs←D0;
	BitBltDefs.BITBLT[LOOPHOLE[bbt]];
	bbt.ptrs←Alto;
	END;


Reconfigure: PROCEDURE =
	BEGIN
	bankreg,dmachine: BOOLEAN;
	config: SegmentDefs.MemoryConfig←SegmentDefs.GetMemoryConfig[];
	bankreg←config.AltoType=AltoIIXM; -- only AltoIIXM has bank registers
	dmachine←config.AltoType=D0 OR config.AltoType=Dorado;
	EnableDBank←IF bankreg THEN AltoEnableDBank ELSE NoopEnableDBank;
	BitBltProc←IF dmachine THEN D0BitBlt ELSE AltoBitBlt;
	DcbBitmapProc←IF dmachine THEN LongDcbBitmap ELSE ShortDcbBitmap;
	dBank←SelectDBank[config]; EnableDBank[TRUE];
	END;

XDisplayCleanupItem: ImageDefs.CleanupItem ← [link:,
	proc: XDisplayCleanupProc, mask: ImageDefs.AllReasons];

XDisplayCleanupProc: ImageDefs.CleanupProcedure =
	BEGIN
	SELECT why FROM
		Finish,Abort => BEGIN dcbChain↑ ← dcbNIL; EnableDBank[FALSE] END;
		Save,Checkpoint => EnableDBank[FALSE];
		InLd => EnableDBank[TRUE];
		Restore,Continue => Reconfigure;
		ENDCASE;
  END;

XDisplayCleanupProc[Restore];
ImageDefs.AddCleanupProcedure[@XDisplayCleanupItem];

END.