ImagerTerminalExtrasImpl.mesa
This implements control over DCBs and color map for the Dorado color display.
Copyright © 1984 by Xerox Corporation. All rights reserved.
Last Edited by:
Crow — May 25, 1984 12:14:02 pm PDT
DIRECTORY
Basics        USING [LowHalf, BITSHIFT, logBitsPerWord, LongMult],
VM       USING [Allocate, AddressForPageNumber, wordsPerPage, Pin,
           Unpin],
CountedVM     USING [Handle],
ColorDisplayHeadDorado USING [RPtr, mcb, rpNIL, ChanCB, ChanCBPtr, first64K,
           screenwidth],
ImagerPixelMaps     USING [PixelMap],
ImagerDisplay    USING [DisplayData],
ImagerDisplayExtras   USING [RGBSequence],
Atom       USING [PutPropOnList, GetPropFromList],
Terminal       USING [Virtual, ColorMode, GetColorMode, SetColor, SetRedMap,
           SetGreenMap, SetBlueMap, WaitForBWVerticalRetrace],
ImagerTerminalExtras;
ImagerTerminalExtrasImpl: CEDAR PROGRAM
IMPORTS VM, ColorDisplayHeadDorado, Basics, Atom, Terminal
EXPORTS ImagerTerminalExtras
SHARES ColorDisplayHeadDorado
~ BEGIN
PixelMap: TYPE ~ ImagerPixelMaps.PixelMap;
DisplayData: TYPE ~ ImagerDisplay.DisplayData;
ImagerTerminalExtrasError: PUBLIC SIGNAL [reason: ATOM] ~ CODE;
storage, limit: ColorDisplayHeadDorado.RPtr ← ColorDisplayHeadDorado.rpNIL;
marginOffset: CARDINAL;
leftOverBytes: NAT;
SetDCB: PROC [aChannel: BOOLEANTRUE, bitmap: LONG POINTER,
     leftMargin, width, height, wordsPerLine, whichLink: NAT] ~ TRUSTED {
Alloc: PROC [words: CARDINAL] RETURNS [pointer: ColorDisplayHeadDorado.RPtr] ~ TRUSTED{
page, count: INT;
storageTop: ColorDisplayHeadDorado.RPtr ← storage + words;
IF (storage = ColorDisplayHeadDorado.rpNIL)
OR (LOOPHOLE[storageTop, CARDINAL] > LOOPHOLE[limit, CARDINAL])
THEN {
[[page, count]] ← VM.Allocate[count: 1, partition: lowCore, in64K: TRUE];
storage ← LOOPHOLE[Basics.LowHalf[LOOPHOLE[VM.AddressForPageNumber[page]]]];
limit ← storage + VM.wordsPerPage;
};
pointer ← storage;
storage ← storage + words;
};
link: NAT ← 0;
chainPtr, lastPtr: LONG POINTER TO ColorDisplayHeadDorado.ChanCB ← NIL;
 Check for color display MCB, then DCB chain
IF ColorDisplayHeadDorado.mcb = NIL THEN {
SIGNAL ImagerTerminalExtrasError[$NoColorDisplay]; RETURN[]; };
IF aChannel THEN lastPtr ← chainPtr ←
      @ColorDisplayHeadDorado.first64K[ColorDisplayHeadDorado.mcb.achanCB]
    ELSE lastPtr ← chainPtr ←
      @ColorDisplayHeadDorado.first64K[ColorDisplayHeadDorado.mcb.bchanCB];
IF chainPtr = NIL THEN {
SIGNAL ImagerTerminalExtrasError[$NoDCBChain]; RETURN[]; };
IF whichLink > 31 THEN { SIGNAL ImagerTerminalExtrasError[$Over32DCBs]; RETURN[]; };
IF (wordsPerLine * 2 > leftOverBytes) THEN  -- check for excess leftovers at end of scan
IF (ColorDisplayHeadDorado.screenwidth - width) > leftOverBytes
THEN { SIGNAL ImagerTerminalExtrasError[$ExcessLeftOverPixels]; RETURN[]; };
 Find desired link in DCB chain
WHILE (link < whichLink) AND NOT (chainPtr = NIL) DO
link ← link + 1;
lastPtr ← chainPtr;           -- step to next link
IF chainPtr.link = ColorDisplayHeadDorado.rpNIL
THEN chainPtr ← NIL
ELSE chainPtr ← @ColorDisplayHeadDorado.first64K[chainPtr.link];
ENDLOOP;
 Load desired link; Make new links if desired link lies beyond end of chain
WHILE link <= whichLink DO
relPtr: ColorDisplayHeadDorado.ChanCBPtr ← ColorDisplayHeadDorado.rpNIL;
IF chainPtr = NIL
THEN {   -- Make new DCB, if unlinked
relPtr ← Alloc[SIZE[ColorDisplayHeadDorado.ChanCB]];
chainPtr ← @ColorDisplayHeadDorado.first64K[relPtr];
chainPtr.link ← ColorDisplayHeadDorado.rpNIL;  -- make sure chain ends here
}
ELSE relPtr ← lastPtr.link;   -- in case chain is already linked (or zeroth link)
IF (link < whichLink) OR (width = 0)       -- null DCB
THEN {
chainPtr.wordsPerLine ← 0;
chainPtr.bitmap ← NIL;
chainPtr.linesPerField ← IF link = whichLink THEN height / 2 ELSE 0;
chainPtr.pixelsPerLine ← 0;
chainPtr.leftMargin ← LAST[NAT];
chainPtr.scan ← lastPtr.scan;
}
ELSE {
chainPtr.wordsPerLine ← wordsPerLine;     -- load visible DCB
chainPtr.bitmap ← bitmap;
chainPtr.linesPerField ← height / 2;
chainPtr.pixelsPerLine ← width + 255;
chainPtr.leftMargin ← leftMargin + marginOffset;
chainPtr.scan ← lastPtr.scan;
};
lastPtr.link ← relPtr;           -- link into DCB chain after loaded
lastPtr ← chainPtr;           -- step to next link
IF chainPtr.link = ColorDisplayHeadDorado.rpNIL
THEN chainPtr ← NIL
ELSE chainPtr ← @ColorDisplayHeadDorado.first64K[chainPtr.link];
link ← link + 1;
ENDLOOP;
};
DeleteDCB: PROC [aChannel: BOOLEANTRUE, whichLink: NAT] ~ TRUSTED {
link: NAT ← 0;
chainPtr, lastPtr: LONG POINTER TO ColorDisplayHeadDorado.ChanCB ← NIL;
IF ColorDisplayHeadDorado.mcb = NIL THEN {
SIGNAL ImagerTerminalExtrasError[$NoColorDisplay]; RETURN[]; };
IF aChannel THEN lastPtr ← chainPtr ←
      @ColorDisplayHeadDorado.first64K[ColorDisplayHeadDorado.mcb.achanCB]
    ELSE lastPtr ← chainPtr ←
      @ColorDisplayHeadDorado.first64K[ColorDisplayHeadDorado.mcb.bchanCB];
IF chainPtr = NIL THEN {
SIGNAL ImagerTerminalExtrasError[$NoDCBChain]; RETURN[]; };
 Find desired link in DCB chain
WHILE (link < whichLink) AND NOT (chainPtr = NIL) DO
link ← link + 1;
lastPtr ← chainPtr;           -- step to next link
IF chainPtr.link = ColorDisplayHeadDorado.rpNIL
THEN chainPtr ← NIL
ELSE chainPtr ← @ColorDisplayHeadDorado.first64K[chainPtr.link];
ENDLOOP;
 Delete Link, if found
IF link = whichLink THEN lastPtr.link ← chainPtr.link;  -- note, no storage recovery
};
PinPixelMap: PUBLIC PROC [vt: Terminal.Virtual, data: DisplayData, overLay: BOOLEANFALSE] ~ {
Pin a pixel map to the color display, replacing whatever was there before. Overlay = TRUE causes the B-channel to be used. Overlays may have only 2 or 4 bits per pixel, 4 only if the A-channel (non-overlay) pixelmap has <= 4 bits per pixel.
logPixelsPerWord: NAT ← Basics.logBitsPerWord - data.pix[0].refRep.lgBitsPerPixel;
Catch negative origins and bite into pixelmap
bitmapPtr: LONG POINTER;
widthChange, heightChange: INTEGER ← 0;
TRUSTED {
IF data.pix[0].sOrigin >= 0 THEN bitmapPtr ← data.pix[0].refRep.pointer
ELSE {
bitmapPtr ← data.pix[0].refRep.pointer
    + Basics.LongMult[-data.pix[0].sOrigin, data.pix[0].refRep.rast];
heightChange ← data.pix[0].sOrigin;
};
IF data.pix[0].fOrigin < 0 THEN {
ptrChange: NAT ← Basics.BITSHIFT[
       Basics.BITSHIFT[ -data.pix[0].fOrigin, -(logPixelsPerWord+1)],
       1];
bitmapPtr ← bitmapPtr + ptrChange;
widthChange ← -Basics.BITSHIFT[ ptrChange, logPixelsPerWord];
};
};
Pin VM pages involved
VM.Pin[ NARROW[data.pix[0].refRep.ref, CountedVM.Handle].interval ];
Set Null DCB to move down proper distance from top of screen
SetDCB[ aChannel: NOT overLay,
   bitmap: bitmapPtr,
   leftMargin: 0,
   width: 0,
   height: MAX[0, data.pix[0].sOrigin],
   wordsPerLine: 0, 
   whichLink: 0
  ];
Set DCB representing pixelmap
SetDCB[ aChannel: NOT overLay,
   bitmap: bitmapPtr,
   leftMargin: MAX[0, data.pix[0].fOrigin],
   width: MAX[0, Basics.BITSHIFT[ data.pix[0].refRep.rast, logPixelsPerWord] + widthChange],
   height: MAX[0, data.pix[0].refRep.lines + heightChange],
   wordsPerLine: data.pix[0].refRep.rast,
   whichLink: 1
  ];
IF overLay
THEN data.props ← Atom.PutPropOnList[data.props, $PixelMapStatus, $OnAChannel]
ELSE data.props ← Atom.PutPropOnList[data.props, $PixelMapStatus, $OnBChannel];
};
ReleasePixelMap: PUBLIC PROC [vt: Terminal.Virtual, data: DisplayData] ~ {
Remove a pixel map from the color display
IF Atom.GetPropFromList[data.props, $PixelMapStatus] = $OnAChannel
THEN { DeleteDCB[TRUE, 1];
   data.props ← Atom.PutPropOnList[data.props, $PixelMapStatus, $Allocated];
  }
ELSE IF Atom.GetPropFromList[data.props, $PixelMapStatus] = $OnBChannel
THEN { DeleteDCB[FALSE, 1];
   data.props ← Atom.PutPropOnList[data.props, $PixelMapStatus, $Allocated];
  }
ELSE SIGNAL ImagerTerminalExtrasError[$UnDisplayedPixelMap];
VM.Unpin[ NARROW[data.pix[0].refRep.ref, CountedVM.Handle].interval ];  -- release storage
};
LoadRGBColorMap: PUBLIC PROC [vt: Terminal.Virtual,
         entries: REF ImagerDisplayExtras.RGBSequence, start: NAT ← 0] ~ {
mode: Terminal.ColorMode ← vt.GetColorMode;
vt.WaitForBWVerticalRetrace[]; -- await vt selection and top of scan (to control update rate)
IF mode.full = FALSE           -- pseudocolor mapped display
THEN IF mode.bitsPerPixelChannelB = 2        -- 4 tables each 256 entries
THEN { FOR i: NAT IN [start..entries.length) DO
index: NAT ← i MOD 256; table: NAT ← i / 256;
vt.SetColor[index, table, entries[i].r, entries[i].g, entries[i].b];
ENDLOOP; }
ELSE { FOR i: NAT IN [start..entries.length) DO     -- 16 tables each 16 entries
index: NAT ← i MOD 16; table: NAT ← i / 16;
vt.SetColor[index, table, entries[i].r, entries[i].g, entries[i].b];
ENDLOOP ; }
ELSE FOR index: NAT IN [start..entries.length) DO      -- full-color 24-bit display
vt.SetRedMap[index, entries[index].r];
vt.SetGreenMap[index, entries[index].g];
vt.SetBlueMap[index, entries[index].b];
ENDLOOP;
};
{   -- initialize: set left margin assuming monitor type from resolution (potentially wrong)
SELECT ColorDisplayHeadDorado.screenwidth FROM
640 =>  { marginOffset ← 54;    -- Hitachi 13" monitors, or Conrac @525 lines
   leftOverBytes ← 460; };   -- Exceeding this causes unstable raster
1024 => { marginOffset ← 71;    -- Conrac @768 lines (may be 0, actually)
   leftOverBytes ← 0; };
ENDCASE;
};
END.