<> <> <> <> 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.