-- 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 w0 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[]; }; }.