-- ColorDisplayHeadDorado.mesa -- Last edited by Doug Wyatt on 31-Mar-82 23:12:06 DIRECTORY ColorDisplayFace USING [Color, Mode], DeviceCleanup USING [Await, Item, Reason], DoradoInputOutput USING [InputNoPE, RWMufMan], Environment USING [Base, bitsPerWord, first64K, PageCount, PageNumber, wordsPerPage], HeadStartChain USING [Start], Inline USING [BITAND, BITOR, BITSHIFT, LongDiv, LongDivMod, LongMult], ProcessorFace USING [GetClockPulses, microsecondsPerHundredPulses], RuntimeInternal USING [WorryCallDebugger]; ColorDisplayHeadDorado: PROGRAM IMPORTS DeviceCleanup, DoradoInputOutput, RemainingHeads: HeadStartChain, Inline, ProcessorFace, RuntimeInternal EXPORTS ColorDisplayFace, HeadStartChain = { ErrorHalt: PROC = {RuntimeInternal.WorryCallDebugger["Error in ColorDisplayHeadDorado"L]}; RPtr: TYPE = Environment.Base RELATIVE POINTER; -- relative to absolute address 0 rpNIL: RPtr = LOOPHOLE[0]; Mode: TYPE = ColorDisplayFace.Mode; Color: TYPE = ColorDisplayFace.Color; CSBState: TYPE = MACHINE DEPENDENT RECORD [mcb: MCBPtr]; csb: LONG POINTER TO CSBState = LOOPHOLE[LONG[177414B]]; -- Monitor control block MCBPtr: TYPE = Environment.Base RELATIVE POINTER TO MCB; -- in first64k MCB: TYPE = MACHINE DEPENDENT RECORD [ seal: CARDINAL ← mcbSeal, flags: MCBFlags, achanCB: ChanCBPtr, bchanCB: ChanCBPtr, colorCB: ColorCBPtr ]; mcbSeal: CARDINAL = 177456B; Flag: TYPE = BOOLEAN ← FALSE; MCBFlags: TYPE = MACHINE DEPENDENT RECORD [ unused: [0..777B] ← 0, m: Flag, -- minimixer (unimplemented) vc: Flag, -- vertical control hc: Flag, -- horizontal control clk: Flag, -- clock a: Flag, -- A table b: Flag, -- B table c: Flag -- C table ]; -- Channel control block ChanCBPtr: TYPE = Environment.Base RELATIVE POINTER TO ChanCB; -- in first64k ChanCB: TYPE = RECORD [ link: ChanCBPtr ← rpNIL, -- next ChanCB in chain, or NIL wordsPerLine: CARDINAL, -- words per bitmap scanline bitmap: LONG POINTER ← NIL, -- pointer to bitmap bits (must be even) linesPerField: CARDINAL, -- scan lines per field (bitmap height / 2) pixelsPerLine: CARDINAL, -- visible pixels/scanline + 377B leftMargin: CARDINAL, -- left margin + marginOffset[monitortype] scan: ScanControl -- scan control word (see below) ]; pplOffset: CARDINAL = 377B; -- offset for pixelsPerLine -- Margin offsets for various monitors -- AltoTerminal: 107B, Ramtek525: 66B, Ramtek1000: 0, -- ConracRQB525: 66B, ConracRQB875: 107B, ConracRQB1225: 0, -- Scan control word ScanControl: TYPE = MACHINE DEPENDENT RECORD [ unused: [0..77B] ← 0, mode24: BOOLEAN, -- 24 bit per pixel mode aChannelOnly: BOOLEAN, -- if TRUE, disable B channel bBypass: BOOLEAN, -- B channel bypassed to BTable a8b2: BOOLEAN, -- 8 bits from A, 2 bits from B (a6b4 if FALSE) res: ScanRes ← full, -- resolution size: [0..17B] ← 1 -- bits per pixel; must be 1, 2, 4, or 8 ]; ScanRes: TYPE = MACHINE DEPENDENT{quarter(0), half(2), full(3)}; -- Color control block ColorCBPtr: TYPE = Environment.Base RELATIVE POINTER TO ColorCB; -- in first64k ColorCB: TYPE = MACHINE DEPENDENT RECORD [ aTable(0:0..31): LONG POINTER TO ATableImage, -- pointer to color table A bTable(2:0..31): LONG POINTER TO BCTableImage, -- pointer to color table B cTable(4:0..31): LONG POINTER TO BCTableImage, -- pointer to color table C miniMixer(6:0..31): LONG POINTER TO MiniMixerImage ← NIL, -- pointer to MiniMixer table vcontrol(10B:0..47): VControl, -- vertical control hcontrol(13B:0..47): HControl, -- horizontal control ccontrol(16B:0..15): CControl, -- clock control reserved(17B:0..15): CARDINAL ← 0 ]; -- Vertical control information (loaded via vc flag) VControl: TYPE = MACHINE DEPENDENT RECORD [ VBtoVS: [0..377B], VStoVS: [0..377B], VStoVB: CARDINAL, VisibleLines: CARDINAL]; -- Horizontal control information (loaded via hc flag) HControl: TYPE = MACHINE DEPENDENT RECORD [ HRamMaxAddr: CARDINAL, HBLeadLength: [0..377B], HSTrailAddr: [0..377B], HBTrailLength: CARDINAL]; -- Clock control information (loaded via clk flag) CControl: TYPE = MACHINE DEPENDENT RECORD [ zero: [0..17B] ← 0, mul: [0..377B], div: [0..17B]]; ATableIndex: TYPE = [0..1024); ATableImage: TYPE = ARRAY ATableIndex OF ATableEntry; BCTableIndex: TYPE = [0..256); BCTableImage: TYPE = ARRAY BCTableIndex OF BCTableEntry; MiniMixerIndex: TYPE = [0..256); MiniMixerImage: TYPE = ARRAY MiniMixerIndex OF MiniMixerEntry; ATableEntry: TYPE = MACHINE DEPENDENT RECORD [ zeroL(0:0..3): [0..17B] ← 0, -- always zero redL(0:4..7): [0..17B], -- low order 4 bits of red value blue(0:8..15): [0..377B], -- blue value zeroH(1:0..3): [0..17B] ← 0, -- always zero green(1:4..11): [0..377B], -- green value redH(1:12..15): [0..17B] -- high order 4 bits of red value ]; BCTableEntry: TYPE = MACHINE DEPENDENT RECORD [ zero(0:0..7): [0..377B] ← 0, -- always zero value(0:8..15): [0..377B] -- table value ]; MiniMixerEntry: TYPE = MACHINE DEPENDENT RECORD [ address(0:0..7): [0..377B], data(0:8..15): [0..377B]]; -- Interface variables -- The following are valid as soon as the module start code has run (see Start) globalStateSize: PUBLIC CARDINAL ← SIZE[MCB]+3*SIZE[ChanCB]+SIZE[ColorCB]; -- for Initialize displayType: PUBLIC CARDINAL ← 0; -- display type; 0 means display not available oldRev: BOOLEAN ← FALSE; -- TRUE if color board has an old revision level (less than Cj) Standard525: CARDINAL = 1; -- displayType for Ramtek or Hitachi 525 line monitor Hitachi3619: CARDINAL = 2; -- displayType for Hitachi UHR monitor pixelsPerInch: PUBLIC CARDINAL ← 0; -- Size of a pixel mixedRG: PUBLIC BOOLEAN ← TRUE; -- in fullmode, red and green alternate in A bitmap width,height: PUBLIC CARDINAL ← 0; -- Dimensions of current raster in pixels baseA,baseB,baseC: PUBLIC LONG POINTER ← NIL; -- bitmap addresses bplA,bplB,bplC: PUBLIC CARDINAL ← 0; -- bitmap bits per line -- Internal globals screenwidth,screenheight: CARDINAL; -- screen dimensions in pixels initialized: BOOLEAN ← FALSE; -- control blocks are allocated connected: BOOLEAN ← FALSE; -- bitmaps and tables are allocated, globals are set turnedon: BOOLEAN ← FALSE; -- display is on, bitmaps and tables are resident fullmode: BOOLEAN ← FALSE; -- connected in 24 bit per pixel mode mapmode: BOOLEAN ← FALSE; -- connected in a mapped mode -- The following globals are valid when initialized=TRUE (see Initialize) -- first64k-relative pointers to global state: rpMCB: MCBPtr ← rpNIL; rpTChan: ChanCBPtr ← rpNIL; rpAChan: ChanCBPtr ← rpNIL; rpBChan: ChanCBPtr ← rpNIL; rpColor: ColorCBPtr ← rpNIL; -- long pointers to same: mcb: LONG POINTER TO MCB ← NIL; tchan: LONG POINTER TO ChanCB ← NIL; achan: LONG POINTER TO ChanCB ← NIL; bchan: LONG POINTER TO ChanCB ← NIL; color: LONG POINTER TO ColorCB ← NIL; -- The following globals are valid when connected=TRUE (see Connect) bppA,bppB: [0..LAST[INTEGER]] ← 0; -- bits per pixel showA,showB: BOOLEAN ← FALSE; -- to be shown atable: LONG POINTER TO ATableImage ← NIL; btable,ctable: LONG POINTER TO BCTableImage ← NIL; -- used only in fullmode ashift,bshift: INTEGER ← 0; amask,bmask: WORD ← 0; Initialize: PUBLIC PROC [globalState: RPtr] = { alloc: RPtr ← globalState; end: RPtr ← globalState+globalStateSize; Alloc: PROC[words: CARDINAL] RETURNS[RPtr] = INLINE { p: RPtr ← alloc; alloc ← alloc + words; RETURN[p] }; IF initialized THEN ErrorHalt[]; -- Allocate from globalState block: mcb ← @Environment.first64K[rpMCB ← Alloc[SIZE[MCB]]]; tchan ← @Environment.first64K[rpTChan ← Alloc[SIZE[ChanCB]]]; achan ← @Environment.first64K[rpAChan ← Alloc[SIZE[ChanCB]]]; bchan ← @Environment.first64K[rpBChan ← Alloc[SIZE[ChanCB]]]; color ← @Environment.first64K[rpColor ← Alloc[SIZE[ColorCB]]]; IF LOOPHOLE[alloc,CARDINAL]>LOOPHOLE[end,CARDINAL] THEN ErrorHalt[]; tchan↑ ← [link: rpNIL, wordsPerLine: 0, bitmap: NIL, linesPerField: 0, pixelsPerLine: pplOffset, leftMargin: 0, scan: ]; color↑ ← [aTable: NIL, bTable: NIL, cTable: NIL, vcontrol: , hcontrol: , ccontrol: ]; mcb↑ ← [flags: [], achanCB: rpNIL, bchanCB: rpNIL, colorCB: rpColor]; initialized ← TRUE; }; Lg: TYPE = [0..4); -- logarithm base 2 lg1: Lg = 0; lg2: Lg = 1; lg4: Lg = 2; lg8: Lg = 3; Exp: PROC[lg: Lg] RETURNS[CARDINAL] = INLINE { RETURN[Inline.BITSHIFT[1,lg]] }; -- 2↑lg PagesForWords: PROC[words: LONG CARDINAL] RETURNS[CARDINAL] = INLINE { q,r: CARDINAL; [q,r] ← Inline.LongDivMod[words,Environment.wordsPerPage]; RETURN[IF r>0 THEN q+1 ELSE q] }; WordsForPages: PROC[pages: CARDINAL] RETURNS[LONG CARDINAL] = INLINE { RETURN[Inline.LongMult[pages,Environment.wordsPerPage]] }; LPFromPage: PROC[page: Environment.PageNumber] RETURNS[LONG POINTER] = INLINE { RETURN[LOOPHOLE[Inline.LongMult[page, Environment.wordsPerPage]]] }; -- words per line, guaranteed to be even; resulting width in pixels >= w Wpl: PROC[w: CARDINAL, lbpp: Lg] RETURNS[CARDINAL] = INLINE { bits: CARDINAL ← w*Exp[lbpp]; RETURN[((bits+31)/32)*2] }; WordsForBitmap: PROC[w,h: CARDINAL, lbpp: Lg] RETURNS[LONG CARDINAL] = INLINE { RETURN[Inline.LongMult[Wpl[w,lbpp],h]] }; HasMode: PUBLIC PROC[mode: Mode] RETURNS[BOOLEAN] = { IF displayType=0 THEN RETURN[FALSE]; -- no display -- old revision boards can't run both channels at the same time IF oldRev AND (mode.full OR (mode.useA AND mode.useB)) THEN RETURN[FALSE]; IF mode.full THEN { SELECT displayType FROM Standard525 => RETURN[TRUE]; Hitachi3619 => RETURN[FALSE]; ENDCASE; -- drop through } ELSE { a,b: CARDINAL ← 0; -- bits per pixel IF mode.useA THEN a ← Exp[mode.lgBitsPerPixelA]; IF mode.useB THEN b ← Exp[mode.lgBitsPerPixelB]; IF a>8 OR b>4 OR (a+b)>10 THEN RETURN[FALSE]; -- limits of Dorado hardware SELECT displayType FROM Standard525 => RETURN[TRUE]; -- all possible modes supported Hitachi3619 => RETURN[a<8 OR b=0]; -- can't use B channel if a=8 ENDCASE; -- drop through }; ErrorHalt[]; -- bogus displayType ("can't happen") RETURN[FALSE]; }; PagesForMode: PUBLIC PROC[mode: Mode] RETURNS[Environment.PageCount] = { a,b: CARDINAL ← 0; -- bits per pixel words: LONG CARDINAL ← 0; IF NOT HasMode[mode] THEN RETURN[0]; words ← SIZE[ATableImage]; -- atable always required IF mode.full THEN { a ← 16; b ← 8; -- bitmap A has double pixels words ← words + 2*SIZE[BCTableImage]; -- need 2 more color tables } ELSE { IF mode.useA THEN a ← Exp[mode.lgBitsPerPixelA]; -- bitmap A IF mode.useB THEN b ← Exp[mode.lgBitsPerPixelB]; -- bitmap B }; words ← words + Inline.LongMult[(a+b)*screenwidth/Environment.bitsPerWord,screenheight]; RETURN[PagesForWords[words]]; }; MapIndex: PROC[a,b: CARDINAL] RETURNS[ATableIndex] = INLINE { OPEN Inline; RETURN[BITOR[BITAND[BITSHIFT[a,ashift],amask],BITAND[BITSHIFT[b,bshift],bmask]]] }; SetSize: PROC[mode: Mode, pages: Environment.PageCount] RETURNS[BOOLEAN] = { w: CARDINAL ← screenwidth; h: CARDINAL ← screenheight; avail: LONG CARDINAL ← 0; extra: CARDINAL ← 0; IF pages>=PagesForMode[mode] THEN { width ← w; height ← h; RETURN[TRUE] }; IF NOT mode.full THEN RETURN[FALSE]; avail ← WordsForPages[pages]; -- available words extra ← SIZE[ATableImage] + 2*SIZE[BCTableImage]; -- overhead for tables IF avail>extra THEN avail ← avail - extra ELSE RETURN[FALSE]; -- Shrink the raster width, observing necessary constraints. -- Bitmaps must have an even number of words per line, so width must shrink -- in steps of 4 pixels. Each 4 pixels of width require 6*h words. w ← 4*Inline.LongDiv[avail,6*h]; IF w<screenwidth/2 THEN { w ← screenwidth/2; -- Shrink the raster height. Bitmaps must have an even number of lines, -- so height must shrink in steps of 2. Each 2 lines require 3*w words. h ← 2*Inline.LongDiv[avail,3*w]; }; IF h>0 THEN { width ← w; height ← h; RETURN[TRUE] } ELSE RETURN[FALSE]; }; Connect: PUBLIC PROC [mode: Mode, firstPage: Environment.PageNumber, nPages: Environment.PageCount] = { allocBegin: LONG POINTER ← LPFromPage[firstPage]; -- beginning address allocLimit: LONG CARDINAL = WordsForPages[nPages]; -- maximum words available allocCount: LONG CARDINAL ← 0; -- words allocated so far Alloc: PROC[words: LONG CARDINAL] RETURNS[LONG POINTER] = INLINE { p: LONG POINTER ← allocBegin + allocCount; allocCount ← allocCount + words; IF allocCount>allocLimit THEN ErrorHalt[]; RETURN[p] }; AllocBitmap: PROC[bpl: CARDINAL] RETURNS [LONG POINTER] = INLINE { RETURN[Alloc[Inline.LongMult[bpl/Environment.bitsPerWord,height]]] }; IF NOT initialized OR NOT HasMode[mode] OR connected THEN ErrorHalt[]; IF NOT SetSize[mode,nPages] THEN ErrorHalt[]; SELECT displayType FROM Standard525 => { color.vcontrol ← [VBtoVS: 3B, VStoVS: 3B, VStoVB: 20B, VisibleLines: 240]; color.hcontrol ← [HRamMaxAddr: 379, HBLeadLength: 6, HSTrailAddr: 28, HBTrailLength: 25]; color.ccontrol ← [mul: 130B, div: 14B]; tchan.leftMargin ← 65B }; Hitachi3619 => { color.vcontrol ← [VBtoVS: 3B, VStoVS: 3B, VStoVB: 14B, VisibleLines: 512]; color.hcontrol ← [HRamMaxAddr: 629, HBLeadLength: 6, HSTrailAddr: 61, HBTrailLength: 49]; color.ccontrol ← [mul: 163B, div: 17B]; tchan.leftMargin ← 172 -- a guess -- }; ENDCASE => ErrorHalt[]; -- Allocate bitmaps first; they must begin at even addresses IF mode.full THEN { -- double the pixel clock rate SELECT displayType FROM Standard525 => color.ccontrol ← [mul: 130B, div: 16B]; ENDCASE => ErrorHalt[]; tchan.scan ← [mode24: TRUE, aChannelOnly: FALSE, bBypass: TRUE, a8b2: TRUE]; -- adjust leftMargin to compensate for the faster pixel clock tchan.leftMargin ← 2*tchan.leftMargin + 40B--HWindow-- + 40B--marginCounter--; baseA ← AllocBitmap[bplA ← 2*8*width]; -- double pixels in bitmap A baseB ← AllocBitmap[bplB ← 8*width]; bppA ← bppB ← 8; showA ← showB ← TRUE; color.aTable ← atable ← Alloc[SIZE[ATableImage]]; color.bTable ← btable ← Alloc[SIZE[BCTableImage]]; color.cTable ← ctable ← Alloc[SIZE[BCTableImage]]; atable↑ ← ALL[[redH: 0, redL: 0, blue: 0, green: 0]]; btable↑ ← ALL[[value: 0]]; ctable↑ ← ALL[[value: 0]]; fullmode ← TRUE } ELSE { tchan.scan ← [mode24: FALSE, aChannelOnly: ~mode.useB, bBypass: FALSE, a8b2: bppB<=2]; IF mode.useA THEN { bppA ← Exp[mode.lgBitsPerPixelA]; bplA ← width*bppA; baseA ← AllocBitmap[bplA]; showA ← TRUE }; IF mode.useB THEN { bppB ← Exp[mode.lgBitsPerPixelB]; bplB ← width*bppB; baseB ← AllocBitmap[bplB]; showB ← TRUE }; color.aTable ← atable ← Alloc[SIZE[ATableImage]]; atable↑ ← ALL[[redH: 0, redL: 0, blue: 0, green: 0]]; mapmode ← TRUE }; -- set up for MapIndex IF tchan.scan.a8b2 THEN { ashift ← 10-bppA; amask ← 1774B; bshift ← 2-bppB; bmask ← 0003B } ELSE { -- a6b4 -- ashift ← 10-bppA; amask ← 1760B; bshift ← 4-bppB; bmask ← 0017B }; -- set up channel control blocks; use tchan for a template tchan.pixelsPerLine ← width+pplOffset; tchan.linesPerField ← height/2; IF bppA>0 THEN { achan↑ ← tchan↑; achan.bitmap ← baseA; achan.wordsPerLine ← bplA/Environment.bitsPerWord; achan.scan.size ← bppA }; IF bppB>0 THEN { bchan↑ ← tchan↑; bchan.bitmap ← baseB; bchan.wordsPerLine ← bplB/Environment.bitsPerWord; bchan.scan.size ← bppB }; tchan.pixelsPerLine ← 0 + pplOffset; -- now make tchan a dummy control block IF fullmode THEN { -- achan fetches two bitmap pixels per screen pixel -- bchan runs at half resolution: 2 pixel clocks for each pixel from the bitmap achan.pixelsPerLine ← bchan.pixelsPerLine ← 2*width+pplOffset; bchan.scan.res ← half; -- horizontal control is measured in pixel clock periods color.hcontrol.HRamMaxAddr ← 2*color.hcontrol.HRamMaxAddr; color.hcontrol.HBLeadLength ← 2*color.hcontrol.HBLeadLength; color.hcontrol.HSTrailAddr ← 2*color.hcontrol.HSTrailAddr; color.hcontrol.HBTrailLength ← 2*color.hcontrol.HBTrailLength; }; connected ← TRUE; }; Disconnect: PUBLIC PROC = { IF NOT connected THEN ErrorHalt[]; IF turnedon THEN TurnOff[]; color.aTable ← NIL; color.bTable ← color.cTable ← NIL; achan.bitmap ← bchan.bitmap ← NIL; width ← height ← 0; baseA ← baseB ← NIL; bplA ← bplB ← 0; bppA ← bppB ← 0; showA ← showB ← FALSE; atable ← NIL; btable ← ctable ← NIL; fullmode ← mapmode ← connected ← FALSE; }; TurnOn: PUBLIC PROC = { IF (NOT connected) OR turnedon THEN RETURN; mcb.flags ← [vc: TRUE, hc: TRUE, clk: TRUE, a: TRUE]; mcb.achanCB ← rpTChan; -- plug in dummy control block to establish scan mode csb.mcb ← rpMCB; WHILE mcb.flags.a DO ENDLOOP; -- wait for microcode to notice everything IF fullmode THEN mcb.flags ← [b: TRUE, c: TRUE]; mcb.achanCB ← (IF showA THEN rpAChan ELSE rpNIL); -- show bitmap A mcb.bchanCB ← (IF showB THEN rpBChan ELSE rpNIL); -- show bitmap B turnedon ← TRUE; }; TurnOff: PUBLIC PROC = { asave: ATableEntry; bsave,csave: BCTableEntry; IF NOT turnedon THEN RETURN; mcb.achanCB ← mcb.bchanCB ← rpNIL; -- disable bitmaps asave ← atable[0]; atable[0] ← [redH: 0, redL: 0, green: 0, blue: 0]; -- black mcb.flags.a ← TRUE; IF fullmode THEN { bsave ← btable[0]; csave ← ctable[0]; btable[0] ← ctable[0] ← [value: 0]; mcb.flags.b ← mcb.flags.c ← TRUE; }; Wait[]; -- be sure the microcode is no longer touching bitmaps or color tables csb.mcb ← rpNIL; atable[0] ← asave; IF fullmode THEN { btable[0] ← bsave; ctable[0] ← csave }; turnedon ← FALSE; }; Show: PUBLIC PROC[a,b,c: BOOLEAN] = { IF bppA>0 THEN showA ← a; IF bppB>0 THEN showB ← b; IF turnedon THEN { mcb.achanCB ← (IF showA THEN rpAChan ELSE rpNIL); mcb.bchanCB ← (IF showB THEN rpBChan ELSE rpNIL); }; }; GetColor: PUBLIC PROC[pixelA,pixelB: CARDINAL] RETURNS[r,g,b: Color] = { IF mapmode THEN { index: ATableIndex ← MapIndex[pixelA,pixelB]; entry: ATableEntry ← atable[index]; RETURN[r: entry.redH*16+entry.redL, g: entry.green, b: entry.blue]; } ELSE RETURN[0,0,0]; }; SetColor: PUBLIC PROC[pixelA,pixelB: CARDINAL, r,g,b: Color] = { IF mapmode THEN { index: ATableIndex ← MapIndex[pixelA,pixelB]; atable[index] ← [redH: r/16, redL: r MOD 16, blue: b, green: g]; IF turnedon THEN mcb.flags.a ← TRUE; }; }; GetRedMap: PUBLIC PROC[in: Color] RETURNS[out: Color] = { IF fullmode THEN { index: ATableIndex ← MapIndex[in,0]; entry: ATableEntry ← atable[index]; RETURN[entry.redH*16+entry.redL] } ELSE RETURN[0]; }; GetGreenMap: PUBLIC PROC[in: Color] RETURNS[out: Color] = { IF fullmode THEN RETURN[ctable[in].value] ELSE RETURN[0]; }; GetBlueMap: PUBLIC PROC[in: Color] RETURNS[out: Color] = { IF fullmode THEN RETURN[btable[in].value] ELSE RETURN[0]; }; SetRedMap: PUBLIC PROC[in,out: Color] = { IF fullmode THEN { index: ATableIndex ← MapIndex[in,0]; atable[index] ← [redH: out/16, redL: out MOD 16, green: 0, blue: 0]; IF turnedon THEN mcb.flags.a ← TRUE; }; }; SetGreenMap: PUBLIC PROC[in,out: Color] = { IF fullmode THEN { ctable[in] ← [value: out]; IF turnedon THEN mcb.flags.c ← TRUE; }; }; SetBlueMap: PUBLIC PROC[in,out: Color] = { IF fullmode THEN { btable[in] ← [value: out]; IF turnedon THEN mcb.flags.b ← TRUE; }; }; -- Initialization minFPS: CARDINAL = 30; -- minimum number of frames per second maxPulsesPerRefresh: LONG CARDINAL = 2* --for safety-- (LONG[100]* --pulsesPerHundredPulses-- 1000000 --microsecondsPerSecond--)/ (LONG[minFPS]*ProcessorFace.microsecondsPerHundredPulses); Wait: PROC = INLINE { timeDone: LONG CARDINAL ← ProcessorFace.GetClockPulses[]; WHILE ProcessorFace.GetClockPulses[] - timeDone < maxPulsesPerRefresh DO ENDLOOP }; InitializeCleanup: PUBLIC PROC = { OPEN DeviceCleanup; item: Item; reason: Reason; state: CSBState; DO reason ← Await[@item]; SELECT reason FROM turnOff => { state ← csb↑; csb.mcb ← rpNIL; Wait[] }; turnOn => { csb↑ ← state }; ENDCASE; ENDLOOP; }; -- HeadStartChain Start: PUBLIC PROC = { hasColorBoard: BOOLEAN ← (DoradoInputOutput.InputNoPE[360B] # 0); IF hasColorBoard THEN { device: MACHINE DEPENDENT RECORD[type: [0..17B], junk: [0..7777B]] ← DoradoInputOutput.InputNoPE[361B]; SELECT device.type FROM 17B => { displayType ← Standard525; screenwidth ← 640; -- must be a multiple of 32 screenheight ← 480; -- must be a multiple of 2 pixelsPerInch ← 64; -- *** approximate *** }; 16B => { displayType ← Hitachi3619; screenwidth ← 1024; -- must be a multiple of 32 screenheight ← 1024; -- must be a multiple of 2 pixelsPerInch ← 72; -- *** approximate *** }; ENDCASE => ErrorHalt[]; -- unknown display type -- determine whether an old rev DispY board is installed oldRev ← (DoradoInputOutput.RWMufMan[[useDMD: FALSE, dMuxAddr: 3107B]].dMuxData # 0); }; csb↑ ← [mcb: rpNIL]; RemainingHeads.Start[]; }; }.