DIRECTORY Basics USING [BITAND, BITOR, BITSHIFT, bitsPerWord, LongDiv, LongMult], ColorDisplayDefs USING [ChannelsVisible, ChannelValue, ColorDisplayType, ColorMode, ColorValue], ColorDisplayDorado USING [AEntry, AIndex, ATable, Base, base0, BCDatum, BCTable, bMapRegister, ChannelControlBlock, ClockControl, cMapRegister, ColorControlBlock, ColorCSB, csb, Flags, HorizontalControl, MixerDatum, mixerRegister, MonitorControlBlock, pixelsPerLineOffset, RNIL, ScanControl, VerticalControl], ColorDisplayFace USING [nullMode], DeviceCleanup USING [Await, Item, Reason], DoradoInputOutput USING [DMuxAddr, InputNoPE, IOAddress, MufManResult, Output, RWMufMan], PrincOpsUtils USING [HighHalf, LowHalf], ProcessorFace USING [GetClockPulses, microsecondsPerHundredPulses]; ColorDisplayHeadDorado: PROGRAM IMPORTS Basics, DeviceCleanup, DoradoInputOutput, PrincOpsUtils, ProcessorFace EXPORTS ColorDisplayFace ~ BEGIN OPEN ColorDisplayFace, ColorDisplayDefs, ColorDisplayDorado; ErrorHalt: PROC ~ { ERROR }; displayType: PUBLIC ColorDisplayType _ none; -- display type, "none" if display not available width: PUBLIC NAT _ 0; -- raster width in pixels height: PUBLIC NAT _ 0; -- raster height in pixels pixelsPerInch: PUBLIC NAT _ 0; -- approximate pixel size globalStateSize: PUBLIC NAT _ SIZE[MonitorControlBlock]+2*SIZE[ChannelControlBlock]+SIZE[ColorControlBlock]; oldRev: BOOL _ FALSE; -- TRUE if color board has an old revision level (less than Cj) vControl: VerticalControl _ [0, 0, 0, 0]; hControl: HorizontalControl _ [0, 0, 0, 0]; clkControl: ClockControl _ [mul: 0, div: 0]; clkControlDouble: ClockControl _ [mul: 0, div: 0]; marginOffset: CARDINAL _ 0; mcb: LONG POINTER TO MonitorControlBlock _ NIL; channelA: LONG POINTER TO ChannelControlBlock _ NIL; channelB: LONG POINTER TO ChannelControlBlock _ NIL; color: LONG POINTER TO ColorControlBlock _ NIL; currentMap: ColorMap _ NIL; turnOnFlags: Flags _ []; showA, showB: BOOL _ FALSE; state: {uninitialized, disconnected, connected, displayed} _ uninitialized; SetDisplayType: PUBLIC SAFE PROC [type: ColorDisplayType] RETURNS [ok: BOOL] ~ CHECKED { SELECT type FROM standard => { width _ 640; -- must be a multiple of 32 height _ 480; -- must be a multiple of 2 pixelsPerInch _ 42; -- *** approximate *** vControl _ [VBtoVS: 3B, VStoVS: 3B, VStoVB: 20B, VisibleLines: 240]; hControl _ [HRamMaxAddr: 379, HBLeadLength: 6, HSTrailAddr: 28, HBTrailLength: 25]; clkControl _ [mul: 130B, div: 14B]; clkControlDouble _ [mul: 130B, div: 16B]; marginOffset _ 65B; }; highResolution => { width _ 1024; -- must be a multiple of 32 height _ 768; -- must be a multiple of 2 pixelsPerInch _ 72; -- *** approximate *** vControl _ [VBtoVS: 0, VStoVS: 3, VStoVB: 18, VisibleLines: 384]; hControl _ [HRamMaxAddr: 601, HBLeadLength: 3, HSTrailAddr: 50, HBTrailLength: 35]; clkControl _ [mul: 54, div: 14]; marginOffset _ 111; }; ENDCASE => RETURN[FALSE]; displayType _ type; RETURN[TRUE]; }; RP: PROC[p: LONG POINTER] RETURNS[Base RELATIVE POINTER] ~ INLINE { RETURN[LOOPHOLE[PrincOpsUtils.LowHalf[p]]] -- assumes high half is zero }; Initialize: PUBLIC PROC [globalState: LONG POINTER] = { allocated: NAT _ 0; -- words allocated from globalState block Allocate: PROC[size: NAT] RETURNS[LONG POINTER] ~ INLINE { p: LONG POINTER ~ globalState+allocated; allocated _ allocated+size; RETURN[p]; }; IF state#uninitialized THEN ErrorHalt[]; IF NOT SetDisplayType[displayType] THEN ErrorHalt[]; IF PrincOpsUtils.HighHalf[globalState]#0 THEN ErrorHalt[]; mcb _ Allocate[SIZE[MonitorControlBlock]]; channelA _ Allocate[SIZE[ChannelControlBlock]]; channelB _ Allocate[SIZE[ChannelControlBlock]]; color _ Allocate[SIZE[ColorControlBlock]]; IF allocated>globalStateSize THEN ErrorHalt[]; mcb^ _ [flags: [], channelA: RNIL, channelB: RNIL, color: RP[color]]; channelA^ _ channelB^ _ nullChannelControlBlock; color^ _ [tableA: NIL, tableB: NIL, tableC: NIL, vc: vControl, hc: hControl, clk: clkControl]; state _ disconnected; }; HasMode: PUBLIC SAFE PROC[mode: ColorMode] RETURNS[BOOL] ~ CHECKED { a: NAT ~ mode.bitsPerPixelChannelA; b: NAT ~ mode.bitsPerPixelChannelB; IF displayType=none THEN RETURN[FALSE]; -- no color display IF mode.full THEN RETURN[displayType=standard]; IF a=0 AND b=0 THEN RETURN[FALSE]; SELECT a FROM 0, 1, 2, 4, 8 => NULL ENDCASE => RETURN[FALSE]; SELECT b FROM 0, 1, 2, 4 => NULL ENDCASE => RETURN[FALSE]; IF (a+b)>10 THEN RETURN[FALSE]; IF oldRev AND a#0 AND b#0 THEN RETURN[FALSE]; RETURN[TRUE]; }; NextMode: PUBLIC SAFE PROC [mode: ColorMode] RETURNS [ColorMode] ~ CHECKED { Next: SAFE PROC [mode: ColorMode] RETURNS [ColorMode] ~ CHECKED { a: NAT ~ mode.bitsPerPixelChannelA; b: NAT ~ mode.bitsPerPixelChannelB; IF mode.full THEN RETURN[nullMode]; IF b<4 THEN RETURN[[FALSE, a, b*2]]; IF a<8 THEN RETURN[[FALSE, a*2, 0]]; RETURN[[TRUE, 0, 0]]; }; IF NOT(mode=nullMode OR HasMode[mode]) THEN RETURN[nullMode]; -- illegal mode FOR next: ColorMode _ Next[mode], Next[next] UNTIL next=nullMode DO IF HasMode[next] THEN RETURN[next]; ENDLOOP; RETURN[nullMode]; }; nullScanControl: ScanControl ~ [mode24: FALSE, aChannelOnly: FALSE, bBypass: FALSE, pixelMode: VAL[0], resolution: VAL[0], bitsPerPixel: 0]; nullChannelControlBlock: ChannelControlBlock ~ [link: RNIL, wordsPerLine: 0, address: NIL, linesPerField: 0, pixelsPerLine: 0, leftMargin: 0, scanControl: nullScanControl]; bitsPerWord: NAT ~ Basics.bitsPerWord; Connect: PUBLIC PROC[mode: ColorMode, baseA, baseB: LONG POINTER, map: ColorMap] ~ { vc: VerticalControl _ vControl; hc: HorizontalControl _ hControl; clk: ClockControl _ clkControl; template: ChannelControlBlock _ nullChannelControlBlock; template.linesPerField _ height/2; template.pixelsPerLine _ width+pixelsPerLineOffset; template.leftMargin _ marginOffset; template.scanControl.resolution _ full; IF mode.full THEN { template.scanControl.mode24 _ TRUE; template.scanControl.aChannelOnly _ FALSE; template.scanControl.bBypass _ TRUE; template.scanControl.pixelMode _ a8b2; clk _ clkControlDouble; hc.HRamMaxAddr _ 2*hc.HRamMaxAddr; hc.HBLeadLength _ 2*hc.HBLeadLength; hc.HSTrailAddr _ 2*hc.HSTrailAddr; hc.HBTrailLength _ 2*hc.HBTrailLength; template.leftMargin _ 2*marginOffset + 40B--HWindow-- + 40B--marginCounter--; template.pixelsPerLine _ 2*width+pixelsPerLineOffset; channelA^ _ template; channelA.address _ baseA; channelA.wordsPerLine _ (width*16)/bitsPerWord; channelA.scanControl.bitsPerPixel _ 8; channelB^ _ template; channelB.address _ baseB; channelB.wordsPerLine _ (width*8)/bitsPerWord; channelB.scanControl.resolution _ half; channelB.scanControl.bitsPerPixel _ 8; color.tableA _ LOOPHOLE[@map.tableA]; color.tableB _ LOOPHOLE[@map.tableB]; color.tableC _ LOOPHOLE[@map.tableC]; turnOnFlags _ [vc: TRUE, hc: TRUE, clk: TRUE, a: TRUE, b: TRUE, c: TRUE]; } ELSE { bitsPerPixelA: NAT ~ mode.bitsPerPixelChannelA; bitsPerPixelB: NAT ~ mode.bitsPerPixelChannelB; template.scanControl.mode24 _ FALSE; template.scanControl.aChannelOnly _ (bitsPerPixelB=0); template.scanControl.bBypass _ FALSE; template.scanControl.pixelMode _ (IF bitsPerPixelB>2 THEN a6b4 ELSE a8b2); channelA^ _ channelB^ _ template; IF bitsPerPixelA=0 THEN channelA.address _ NIL ELSE { channelA.address _ baseA; channelA.wordsPerLine _ (width*bitsPerPixelA)/bitsPerWord; channelA.scanControl.bitsPerPixel _ bitsPerPixelA; }; IF bitsPerPixelB=0 THEN channelB.address _ NIL ELSE { channelB.address _ baseB; channelB.wordsPerLine _ (width*bitsPerPixelB)/bitsPerWord; channelB.scanControl.bitsPerPixel _ bitsPerPixelB; }; color.tableA _ LOOPHOLE[@map.tableA]; color.tableB _ NIL; color.tableC _ NIL; turnOnFlags _ [vc: TRUE, hc: TRUE, clk: TRUE, a: TRUE]; }; color.vc _ vc; color.hc _ hc; color.clk _ clk; currentMap _ map; state _ connected; }; setBlack: BOOL _ TRUE; Disconnect: PUBLIC SAFE PROC = TRUSTED { IF state=displayed THEN TurnOff[]; IF state#connected THEN ErrorHalt[]; IF setBlack THEN { MixerOutput: PROC [datum: MixerDatum] ~ INLINE {DoradoInputOutput.Output[datum: LOOPHOLE[datum], register: mixerRegister]}; BMapOutput: PROC [datum: BCDatum] ~ INLINE {DoradoInputOutput.Output[datum: LOOPHOLE[datum], register: bMapRegister]}; CMapOutput: PROC [datum: BCDatum] ~ INLINE {DoradoInputOutput.Output[datum: LOOPHOLE[datum], register: cMapRegister]}; MixerOutput[[keep: T, body: null[]]]; MixerOutput[[keep: T, load: T, body: addr[addr: 0, select: lo]]]; MixerOutput[[keep: T, write: T, body: data[data: 0]]]; MixerOutput[[keep: T, load: T, body: addr[addr: 0, select: hi]]]; MixerOutput[[keep: T, write: T, body: data[data: 0]]]; MixerOutput[[keep: F, body: null[]]]; BMapOutput[[keep: T, body: null[]]]; BMapOutput[[keep: T, load: T, body: addr[addr: 0]]]; BMapOutput[[keep: T, write: T, body: data[data: 0]]]; BMapOutput[[keep: F, body: null[]]]; CMapOutput[[keep: T, body: null[]]]; CMapOutput[[keep: T, load: T, body: addr[addr: 0]]]; CMapOutput[[keep: T, write: T, body: data[data: 0]]]; CMapOutput[[keep: F, body: null[]]]; }; color.tableA _ NIL; color.tableB _ color.tableC _ NIL; channelA.address _ channelB.address _ NIL; currentMap _ NIL; turnOnFlags _ []; state _ disconnected; }; TurnOn: PUBLIC PROC = { IF state#connected THEN RETURN; mcb.flags _ turnOnFlags; mcb.channelA _ (IF showA AND channelA.address#NIL THEN RP[channelA] ELSE RNIL); mcb.channelB _ (IF showB AND channelB.address#NIL THEN RP[channelB] ELSE RNIL); base0[csb].mcb _ RP[mcb]; state _ displayed; }; TurnOff: PUBLIC SAFE PROC = TRUSTED { IF state#displayed THEN RETURN; base0[csb].mcb _ RNIL; Wait[]; -- be sure the microcode is no longer touching bitmaps or color tables state _ connected; }; SetVisibility: PUBLIC SAFE PROC [visibility: ChannelsVisible] ~ CHECKED { SELECT visibility FROM none => { showA _ showB _ FALSE }; aOnly => { showA _ TRUE; showB _ FALSE }; bOnly => { showA _ FALSE; showB _ TRUE }; all => { showA _ showB _ TRUE }; ENDCASE; IF state=displayed THEN TRUSTED { mcb.channelA _ (IF showA AND channelA.address#NIL THEN RP[channelA] ELSE RNIL); mcb.channelB _ (IF showB AND channelB.address#NIL THEN RP[channelB] ELSE RNIL); }; }; ColorMap: TYPE ~ LONG POINTER TO ColorMapRep; ColorMapRep: PUBLIC TYPE ~ RECORD[ shiftA, shiftB: INTEGER _ 0, maskA, maskB: WORD _ 0, unused: ARRAY [4..256) OF WORD _ ALL[0], tableA: ATable _ ALL[[redH: 0, redL: 0, blue: 0, green: 0]], tableB: BCTable _ ALL[[value: 0]], tableC: BCTable _ ALL[[value: 0]] ]; wordsForColorMap: PUBLIC NAT _ SIZE[ColorMapRep]; InitializeColorMap: PUBLIC PROC [mode: ColorMode, pointer: LONG POINTER] RETURNS [ColorMap] ~ { map: ColorMap ~ LOOPHOLE[pointer]; map^ _ []; IF NOT mode.full THEN { IF mode.bitsPerPixelChannelB>2 THEN { map.shiftA _ 4+(6-mode.bitsPerPixelChannelA); map.shiftB _ 4-mode.bitsPerPixelChannelB; } ELSE { map.shiftA _ 2+(8-mode.bitsPerPixelChannelA); map.shiftB _ 2-mode.bitsPerPixelChannelB; }; map.maskA _ Basics.BITSHIFT[1, mode.bitsPerPixelChannelA]-1; map.maskB _ Basics.BITSHIFT[1, mode.bitsPerPixelChannelB]-1; }; RETURN[map]; }; SetColor: PUBLIC PROC[map: ColorMap, pixelA, pixelB: ChannelValue, r, g, b: ColorValue] ~ { index: AIndex ~ Basics.BITOR[ Basics.BITSHIFT[Basics.BITAND[pixelA, map.maskA], map.shiftA], Basics.BITSHIFT[Basics.BITAND[pixelB, map.maskB], map.shiftB] ]; entry: AEntry ~ [redH: r/16, redL: r MOD 16, green: g, blue: b]; map.tableA[index] _ entry; IF map=currentMap AND state=displayed THEN mcb.flags.a _ TRUE; }; GetColor: PUBLIC SAFE PROC[map: ColorMap, pixelA, pixelB: ChannelValue] RETURNS [r, g, b: ColorValue] ~ TRUSTED { index: AIndex ~ Basics.BITOR[ Basics.BITSHIFT[Basics.BITAND[pixelA, map.maskA], map.shiftA], Basics.BITSHIFT[Basics.BITAND[pixelB, map.maskB], map.shiftB] ]; entry: AEntry ~ map.tableA[index]; RETURN[r: entry.redH*16+entry.redL, g: entry.green, b: entry.blue]; }; SetR: PUBLIC PROC[map: ColorMap, in: ChannelValue, out: ColorValue] ~ { index: AIndex ~ Basics.BITSHIFT[in, 2]; entry: AEntry ~ [redH: out/16, redL: out MOD 16, green: 0, blue: 0]; map.tableA[index] _ entry; IF map=currentMap AND state=displayed THEN mcb.flags.a _ TRUE; }; SetG: PUBLIC PROC[map: ColorMap, in: ChannelValue, out: ColorValue] ~ { map.tableC[in] _ [value: out]; IF map=currentMap AND state=displayed THEN mcb.flags.c _ TRUE; }; SetB: PUBLIC PROC[map: ColorMap, in: ChannelValue, out: ColorValue] ~ { map.tableB[in] _ [value: out]; IF map=currentMap AND state=displayed THEN mcb.flags.b _ TRUE; }; GetR: PUBLIC SAFE PROC[map: ColorMap, in: ChannelValue] RETURNS [out: ColorValue] ~ TRUSTED { index: AIndex ~ Basics.BITSHIFT[in, 2]; entry: AEntry ~ map.tableA[index]; RETURN[entry.redH*16+entry.redL]; }; GetG: PUBLIC SAFE PROC[map: ColorMap, in: ChannelValue] RETURNS [out: ColorValue] ~ TRUSTED { RETURN[map.tableC[in].value]; }; GetB: PUBLIC SAFE PROC[map: ColorMap, in: ChannelValue] RETURNS [out: ColorValue] ~ TRUSTED { RETURN[map.tableB[in].value]; }; hundredPulsesPerSecond: CARDINAL ~ Basics.LongDiv[ 1000000, -- microsecondsPerSecond ProcessorFace.microsecondsPerHundredPulses -- (assumed >15) ]; pulsesPerField: CARDINAL ~ Basics.LongDiv[ Basics.LongMult[hundredPulsesPerSecond, 100], -- pulsesPerSecond (assumed <3932160) 60 -- fieldsPerSecond (approximate) ]; waitPulses: LONG CARDINAL ~ Basics.LongMult[pulsesPerField, 3]; -- 3 fields, just to be sure Wait: PROC ~ INLINE { -- inline, because device cleanup must not do procedure call startPulses: LONG CARDINAL ~ ProcessorFace.GetClockPulses[]; WHILE (ProcessorFace.GetClockPulses[]-startPulses) { csbState _ base0[csb]; base0[csb].mcb _ RNIL; Wait[]; }; turnOn => { IF state=displayed THEN mcb.flags _ turnOnFlags; base0[csb] _ csbState; }; ENDCASE; ENDLOOP; }; colorBoardAddr: DoradoInputOutput.IOAddress ~ 360B; colorDeviceAddr: DoradoInputOutput.IOAddress ~ 361B; colorRevAddr: DoradoInputOutput.DMuxAddr ~ 3107B; colorBoardData: WORD _ 0; colorDeviceData: MACHINE DEPENDENT RECORD[type: [0..17B], junk: [0..7777B]] _ [0, 0]; colorRevData: DoradoInputOutput.MufManResult _ [0, 0]; base0[csb] _ [mcb: RNIL]; colorBoardData _ DoradoInputOutput.InputNoPE[colorBoardAddr]; IF colorBoardData#0 THEN { -- Color display board is installed colorDeviceData _ LOOPHOLE[DoradoInputOutput.InputNoPE[colorDeviceAddr]]; SELECT colorDeviceData.type FROM 17B => displayType _ standard; 16B => displayType _ highResolution; ENDCASE; -- unknown display type colorRevData _ DoradoInputOutput.RWMufMan[[useDMD: FALSE, dMuxAddr: colorRevAddr]]; oldRev _ (colorRevData.dMuxData=1); }; END. BColorDisplayHeadDorado.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Doug Wyatt, May 2, 1985 6:40:22 pm PDT Russ Atkinson (RRA) June 17, 1985 4:38:05 pm PDT Public interface variables (valid as soon as the head has been started) Internal globals. Not enough bandwidth to handle 24 bits per pixel at high resolution. Old revision boards can't run both channels at the same time. channelA fetches two pixel values per screen pixel channelB runs at half resolution: 2 pixel clocks for each pixel from the frame buffer double the pixel clock rate horizontal control is measured in pixel clock periods adjust leftMargin to compensate for the faster pixel clock Initialization Since the runtime support may be in a delicate state when the heads are started, this code avoids software-implemented operations like long integer multiply or divide. Start The following determines whether an old rev DispY board is installed. Margin offsets for various monitors... AltoTerminal: 107B, Ramtek525: 66B, Ramtek1000: 0, ConracRQB525: 66B, ConracRQB875: 107B, ConracRQB1225: 0, Κ˜codešœ™Kšœ Οmœ1™Kšœžœžœ ˜=K˜—Kšœ%žœ˜@Kšœ˜Kšžœžœžœžœ˜>K˜K˜—š  œžœžœžœ/žœžœ˜ršœžœ˜Kšœžœžœ!˜>Kšœžœžœ ˜=K˜—Kšœ"˜"Kšžœ=˜CK˜K˜—š œžœžœ6˜GKšœžœ˜'Kšœ)žœ˜DKšœ˜Kšžœžœžœžœ˜>K˜—š œžœžœ6˜GKšœ˜Kšžœžœžœžœ˜>K˜—š œžœžœ6˜GKšœ˜Kšžœžœžœžœ˜>K˜K˜—š  œžœžœžœ#žœžœ˜^Kšœžœ˜'Kšœ"˜"Kšžœ˜!K˜—š  œžœžœžœ#žœžœ˜^Kšžœ˜K˜—š  œžœžœžœ#žœžœ˜^Kšžœ˜K˜K˜—Kšœ™K˜K™§K™Kšœžœ‘œ+‘œ˜“KšœžœA‘&œ‘!œ˜₯Kšœ žœžœ'‘˜\K˜š œžœžœ‘<˜RKšœ žœžœ"˜Kšœžœ/˜Išžœž˜ Kšœ˜Kšœ$˜$Kšžœ‘˜ —KšœE™EKšœ3žœ˜SKšœ#˜#K˜—K˜šœ&™&Kšœ2™2Kšœ8™8—K˜Kšžœ˜—…—9N`