DIRECTORY Basics USING [BITSHIFT, bitsPerWord, LongMult, LowHalf, LongDivMod], PrincOps USING [PageNumber, PageCount, wordsPerPage], VM USING [Allocate, AddressForPageNumber, wordsPerPage, Interval, Pin, Free], ColorDisplayFace USING [Mode], ColorDisplayFaceExtras USING [DisplayType], ColorDisplayHeadDorado; ColorDisplayHeadDoradoExtras: PROGRAM IMPORTS Basics, ColorDisplayHeadDorado, VM EXPORTS ColorDisplayFaceExtras SHARES ColorDisplayHeadDorado = BEGIN OPEN ColorDisplayHeadDorado; rpAChan2, rpBChan2: ChanCBPtr _ rpNIL; achan2: LONG POINTER TO ChanCB _ NIL; bchan2: LONG POINTER TO ChanCB _ NIL; monitorType: ColorDisplayFaceExtras.DisplayType _ none; monitorWidth, monitorHeight: NAT _ 0; leftMarginBase: NAT _ 0; widthA, widthB, heightA, heightB: NAT _ 0; ColorDisplayHeadError: PUBLIC SIGNAL [reason: ATOM] ~ CODE; LPFromPage: PROC[page: PrincOps.PageNumber] RETURNS[LONG POINTER] = INLINE { RETURN[LOOPHOLE[Basics.LongMult[page, PrincOps.wordsPerPage]]] }; WordsForPages: PROC[pages: CARDINAL] RETURNS[LONG CARDINAL] = INLINE { RETURN[Basics.LongMult[pages,PrincOps.wordsPerPage]] }; PagesForWords: PROC[words: LONG CARDINAL] RETURNS[CARDINAL] = INLINE { q,r: CARDINAL; [q,r] _ Basics.LongDivMod[words,PrincOps.wordsPerPage]; RETURN[IF r>0 THEN q+1 ELSE q] }; Exp: PROC[lg: Lg] RETURNS[CARDINAL] = INLINE { RETURN[Basics.BITSHIFT[1,lg]] }; -- 2^lg PagesForMode: PUBLIC PROC[mode: ColorDisplayFace.Mode] RETURNS[PrincOps.PageCount] = { a,b: CARDINAL _ 0; -- bits per pixel words: LONG CARDINAL _ 0; wordsPerLineA, wordsPerLineB: NAT _ 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 }; wordsPerLineA _ (a*widthA)/Basics.bitsPerWord; IF ((a*widthA) MOD Basics.bitsPerWord) # 0 THEN wordsPerLineA _ wordsPerLineA + 1; wordsPerLineB _ (b*widthB)/Basics.bitsPerWord; IF ((b*widthB) MOD Basics.bitsPerWord) # 0 THEN wordsPerLineB _ wordsPerLineB + 1; words _ words + Basics.LongMult[ wordsPerLineA, heightA ] + Basics.LongMult[ wordsPerLineB, heightB ]; RETURN[PagesForWords[words]]; }; SetMonitorType: PUBLIC PROC [ newMonitorType: ColorDisplayFaceExtras.DisplayType, newWidth, newHeight: NAT ] ~ { monitorWidth _ screenwidth _ width _ widthA _ widthB _ newWidth; monitorHeight _ screenheight _ height _ heightA _ heightB _ newHeight; monitorType _ newMonitorType; }; SetDisplaySize: PUBLIC PROC [ newWidthA, newHeightA: NAT, newWidthB, newHeightB: NAT _ 0 ] ~ { screenwidth _ width _ MAX[newWidthA, newWidthB]; screenheight _ height _ MAX[newHeightA, newHeightB]; widthA _ newWidthA; heightA _ newHeightA; widthB _ newWidthB; heightB _ newHeightB; }; SetAOffsets: PUBLIC PROC [ xOffset, yOffset: NAT ] ~ { IF achan.link = rpNIL THEN ColorDisplayHeadError[$UnMoveableChannel]; IF xOffset > monitorWidth - widthA THEN xOffset _ monitorWidth - widthA; achan.linesPerField _ yOffset/2; achan2.leftMargin _ leftMarginBase + xOffset; }; SetBOffsets: PUBLIC PROC [ xOffset, yOffset: NAT ] ~ { IF bchan.link = rpNIL THEN ColorDisplayHeadError[$UnMoveableChannel]; IF xOffset > monitorWidth - widthB THEN xOffset _ monitorWidth - widthB; bchan.linesPerField _ yOffset/2; bchan2.leftMargin _ leftMarginBase + xOffset; }; SwitchChannels: PUBLIC PROC [] ~ { IF heightA # heightB OR widthA # widthB OR bppA # bppB THEN ColorDisplayHeadError[$UnswitchableChannels]; IF mcb.achanCB = rpAChan THEN mcb.achanCB _ rpBChan ELSE mcb.achanCB _ rpAChan; }; Connect: PUBLIC PROC [ mode: ColorDisplayFace.Mode, firstPage: PrincOps.PageNumber, nPages: PrincOps.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] = { p: LONG POINTER _ allocBegin + allocCount; allocCount _ allocCount + words; IF allocCount>allocLimit THEN ErrorHalt[]; RETURN[p] }; AllocBitmap: PROC[bpl, height: CARDINAL] RETURNS [LONG POINTER] = { wordsPerLine: NAT _ bpl/Basics.bitsPerWord; IF (bpl MOD Basics.bitsPerWord) # 0 THEN wordsPerLine _ wordsPerLine + 1; RETURN[Alloc[Basics.LongMult[wordsPerLine,height]]] }; IF NOT initialized OR -- NOT HasMode[mode] OR -- connected THEN ErrorHalt[]; width _ screenwidth; height _ screenheight; -- normally done by SetSize FreeDcbChain[]; -- clean up any stray DCB chain storage (should be in Disconnect) SELECT monitorType FROM ramtek714, hitachi2713 => { color.vcontrol _ [VBtoVS: 0, VStoVS: 3, VStoVB: 16, VisibleLines: 240]; color.hcontrol _ [HRamMaxAddr: 378, HBLeadLength: 3, HSTrailAddr: 32, HBTrailLength: 23]; color.ccontrol _ [mul: 90, div: 12]; leftMarginBase _ 49; pixelsPerInch _ 64; }; conrac7211Lo => { color.vcontrol _ [VBtoVS: 0, VStoVS: 3, VStoVB: 16, VisibleLines: 240]; color.hcontrol _ [HRamMaxAddr: 378, HBLeadLength: 3, HSTrailAddr: 32, HBTrailLength: 23]; color.ccontrol _ [mul: 90, div: 12]; leftMarginBase _ 54; pixelsPerInch _ 42; }; conrac7211Hi => { color.vcontrol _ [VBtoVS: 0, VStoVS: 3, VStoVB: 18, VisibleLines: 384]; color.hcontrol _ [HRamMaxAddr: 601, HBLeadLength: 3, HSTrailAddr: 50, HBTrailLength: 35]; color.ccontrol _ [mul: 54, div: 14]; leftMarginBase _ 115; -- might be 109? pixelsPerInch _ 68; }; ENDCASE => ErrorHalt[]; IF mode.full THEN { SELECT monitorType FROM ramtek714, hitachi2713, conrac7211Lo => { color.ccontrol _ [mul: 90, div: 14]; -- double the pixel clock rate 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; }; conrac7211Hi => { IF height > 384 OR width > 512 THEN ERROR ColorDisplayHeadError[$ExcessHeightOrWidth]; pixelsPerInch _ 34; }; ENDCASE => ErrorHalt[]; tchan.scan _ [mode24: TRUE, aChannelOnly: FALSE, bBypass: TRUE, a8b2: TRUE]; baseA _ AllocBitmap[bplA _ 2*8*width, heightA]; -- double pixels in bitmap A baseB _ AllocBitmap[bplB _ 8*width, heightB]; bppA _ bppB _ 8; showA _ showB _ TRUE; color.aTable _ atable _ Alloc[SIZE[ATableImage]]; color.bTable _ btable _ Alloc[SIZE[BCTableImage]]; color.cTable _ ctable _ Alloc[SIZE[BCTableImage]]; FOR i: NAT IN ATableIndex DO atable[i] _ [ -- ensure that zeroL and zeroH fields redH: color.aTable[i].redH, -- are defaulted to zero redL: color.aTable[i].redL, blue: color.aTable[i].blue, green: color.aTable[i].green ]; ENDLOOP; FOR i: NAT IN BCTableIndex DO btable[i] _ [value: color.bTable[i].value]; ENDLOOP; FOR i: NAT IN BCTableIndex DO ctable[i] _ [value: color.cTable[i].value]; ENDLOOP; fullmode _ TRUE; } ELSE { tchan.scan _ [ mode24: FALSE, aChannelOnly: ~mode.useB, bBypass: FALSE, a8b2: ~mode.lgBitsPerPixelB=2 ]; IF mode.lgBitsPerPixelA > 0 THEN { bppA _ Exp[mode.lgBitsPerPixelA]; bplA _ width*bppA; baseA _ AllocBitmap[bplA, heightA]; IF mode.useA THEN showA _ TRUE }; IF mode.lgBitsPerPixelB > 0 THEN { bppB _ Exp[mode.lgBitsPerPixelB]; bplB _ width*bppB; baseB _ AllocBitmap[bplB, heightB]; IF mode.useB AND (bppB = 2 OR mode.full) THEN showB _ TRUE; }; color.aTable _ atable _ Alloc[SIZE[ATableImage]]; FOR i: NAT IN ATableIndex DO atable[i] _ [ -- ensure that zeroL and zeroH fields redH: color.aTable[i].redH, -- are defaulted to zero redL: color.aTable[i].redL, blue: color.aTable[i].blue, green: color.aTable[i].green ]; ENDLOOP; mapmode _ TRUE }; 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 }; IF bppA>0 AND heightA/2 < color.vcontrol.VisibleLines THEN { space: NAT _ (color.vcontrol.VisibleLines - heightA/2) / 2; achan^ _ [ wordsPerLine: 0, linesPerField: space, pixelsPerLine: 0, leftMargin: leftMarginBase, scan: tchan.scan ]; achan2 _ @first64K[rpAChan2 _ RPAlloc[SIZE[ChanCB]]]; -- get pointer for another DCB } ELSE achan2 _ achan; IF bppB>0 AND heightB/2 < color.vcontrol.VisibleLines THEN { space: NAT _ (color.vcontrol.VisibleLines - heightB/2) / 2; bchan^ _ [ wordsPerLine: 0, linesPerField: space, pixelsPerLine: 0, leftMargin: leftMarginBase, scan: tchan.scan ]; bchan2 _ @first64K[rpBChan2 _ RPAlloc[SIZE[ChanCB]]]; } ELSE bchan2 _ bchan; IF bppA>0 THEN { achan2^ _ tchan^; achan2.bitmap _ baseA; achan2.leftMargin _ leftMarginBase + (monitorWidth - widthA) / 2; achan2.pixelsPerLine _ widthA+pplOffset; achan2.linesPerField _ heightA/2; achan2.wordsPerLine _ bplA/Basics.bitsPerWord; IF (bplA MOD Basics.bitsPerWord) # 0 THEN achan2.wordsPerLine _ achan2.wordsPerLine +1; achan2.scan.size _ bppA }; IF bppB>0 THEN { bchan2^ _ tchan^; bchan2.bitmap _ baseB; bchan2.leftMargin _ leftMarginBase + (monitorWidth - widthB) / 2; bchan2.pixelsPerLine _ widthB+pplOffset; bchan2.linesPerField _ heightB/2; bchan2.wordsPerLine _ bplB/Basics.bitsPerWord; IF (bplB MOD Basics.bitsPerWord) # 0 THEN bchan2.wordsPerLine _ bchan2.wordsPerLine +1; bchan2.scan.size _ bppB }; IF achan2 # achan THEN achan.link _ rpAChan2; -- set up pointers to centered DCBs IF bchan2 # bchan THEN bchan.link _ rpBChan2; tchan.pixelsPerLine _ 0 + pplOffset; -- now make tchan a dummy control block IF fullmode THEN { -- achan fetches two bitmap pixels per screen pixel achan2.pixelsPerLine _ bchan2.pixelsPerLine _ 2*width+pplOffset; bchan2.scan.res _ half; --make B channel run at half speed for full color IF monitorType = conrac7211Hi THEN { -- zoomed image on hi-res (1024x768) monitor achan2.leftMargin _ leftMarginBase + (monitorWidth/2 - widthA); bchan2.leftMargin _ leftMarginBase + (monitorWidth/2 - widthB); achan.linesPerField _ (color.vcontrol.VisibleLines - heightA) / 2; -- go fix offset DCB bchan.linesPerField _ (color.vcontrol.VisibleLines - heightB) / 2; BuildZoomedDCBList[achan2]; BuildZoomedDCBList[bchan2]; -- set up DCBs for replicating scanlines } ELSE { -- adjust leftMargin to compensate for the faster pixel clock achan2.leftMargin _ 2*achan2.leftMargin + 40B--HWindow-- + 40B--marginCounter--; bchan2.leftMargin _ 2*bchan2.leftMargin + 40B + 40B; }; }; connected _ TRUE; IF achan2.scan.res = half THEN achan2.pixelsPerLine _ 2 * (achan2.pixelsPerLine / 2); IF achan2.scan.res = quarter THEN achan2.pixelsPerLine _ 4 * (achan2.pixelsPerLine / 4); }; BuildZoomedDCBList: PUBLIC PROC [lastDcbPtr: LONG POINTER TO ChanCB] = { dcbRPtr: RPtr; dcbPtr: LONG POINTER TO ChanCB; loopEnd: NAT _ lastDcbPtr.linesPerField * 2; lastDcbPtr.linesPerField _ 1; FOR i: NAT IN [1..loopEnd) DO dcbPtr _ @first64K[dcbRPtr _ RPAlloc[SIZE[ChanCB]]]; -- get pointer for new DCB dcbPtr^ _ lastDcbPtr^; -- copy last chain entry dcbPtr.bitmap _ dcbPtr.bitmap + dcbPtr.wordsPerLine; -- move bitmap by one scan lastDcbPtr.link _ dcbRPtr; lastDcbPtr _ dcbPtr; -- link into chain ENDLOOP; }; zoomList: LIST OF VM.Interval _ NIL; allocRPtr, limitRPtr: RPtr _ rpNIL; -- pointers to display control block storage RPAlloc: PROC[words: CARDINAL] RETURNS[pointer: RPtr] = { interval: VM.Interval; storageTop: RPtr _ allocRPtr + words; IF (allocRPtr = rpNIL) -- is there room in a currently allocated page? OR (LOOPHOLE[storageTop, CARDINAL] > LOOPHOLE[limitRPtr, CARDINAL]) THEN { -- allocate a page, pin it and list it for later recovery interval _ VM.Allocate[count: 1, partition: lowCore, in64K: TRUE]; VM.Pin[ interval]; zoomList _ CONS[interval, zoomList]; allocRPtr _ LOOPHOLE[ Basics.LowHalf[ LOOPHOLE[VM.AddressForPageNumber[interval.page]] ]]; limitRPtr _ allocRPtr + VM.wordsPerPage; }; pointer _ allocRPtr; allocRPtr _ allocRPtr + words; }; FreeDcbChain: PROC[] ~ { WHILE zoomList # NIL DO VM.Free[ zoomList.first ]; zoomList _ zoomList.rest; ENDLOOP; allocRPtr _ limitRPtr _ rpNIL; }; END. nColorDisplayHeadDoradoExtras.mesa Last Edited by: Frank Crow, October 9, 1984 12:32:50 pm PDT Inlines copied from ColorDisplayHeadDorado IF NOT HasMode[mode] THEN RETURN[0]; Set color display size and monitor type Set color display window size Set DCB fields to offset displayed position of A channel from upper left corner Set DCB fields to offset displayed position of B channel from upper left corner Put A channel on B channel and vice versa Establishes the specified mode; allocates bitmap(s) and colormap(s) from a client-supplied block of nPages pages of mapped virtual memory. If mode.full=TRUE, nPages may be less than PagesForMode[mode]; in this case, the raster size will be reduced to fit. Subsequent changes to the bitmap or color map will affect the color image, but the image will not appear on the screen until TurnOn is called. IF NOT SetSize[mode,nPages] THEN ErrorHalt[]; Allocate bitmaps first; they must begin at even addresses Full-color Mode horizontal control is measured in pixel clock periods Pseudocolor Mode set up for MapIndex set up channel control blocks; use tchan for a template Set up top spacer to center undersized bitmap Disallow dangling pixels when using zoom (Causes atable register to not get cleared) Does vertical zoom by factor of 2. Produces a 2-line DCB for each scan line. Larger Zooms will require a change in Dorado microcode Ê ƒ˜šœ!™!J™;—J˜šÏk ˜ Jšœ œœ.˜JJšœ œ'˜:Jšœœ9˜GJšœ˜Jšœœ˜!Jšœœ˜,Jšœ˜J˜—šœœ˜&š˜Jšœ ˜"—Jšœ˜Jšœ˜—J˜š˜Jšœ˜—J˜J˜&Jš œœœœ œ˜%Jš œœœœ œ˜%Jšœ7˜7Jšœœ˜%Jšœœ˜Jšœ"œ˜+š œœœ œœ˜;J™Jšœ*™*—š Ïn œœœœœœ˜LJšœœ2˜A—šž œœœœœœœ˜FJšœ1˜7—šž œœœœœœœ˜FJšœœ9˜FJšœœœœ˜!—šžœœ œœœœœ Ïc˜WJ™—šž œœœœ˜VJšœœŸ˜$Jšœœœ˜Jšœœ˜&Jšœœœœ™$JšœœŸ˜4šœ œ˜JšœŸ˜,JšœœŸ˜AJ˜—šœ˜Jšœ œ Ÿ ˜J˜—šœ˜šœœ ˜Jšœœ,˜7—Jšœ˜J˜—Jšœ˜—Jš œœœ œœ˜LJšœ0Ÿ˜LJšœ-˜-Jšœ!œ˜&Jšœœ˜1Jšœœ˜2Jšœœ˜2šœœœ œ5˜QJšœ;˜;Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜ —Jš œœœœ.œ˜SJš œœœœ.œ˜SJšœ œ˜Jšœ˜—J™šœ˜šœ˜Jšœœ%œ˜VJšœ˜—šœœ˜"J˜!J˜Jšœ#˜#Jšœ œ œ˜Jšœ˜—šœœ˜"J˜!J˜Jšœ#˜#Jš œ œ œ œ œ˜;Jšœ˜—Jšœœ˜1šœœœ œ5˜QJšœ;˜;Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜—Jšœ œ˜J˜—Jšœ™JšœœD˜[JšœŸ œG˜\šœ7™7J™-—šœœ)˜6šœ˜Jšœœ1˜;JšœD˜DJšœ4˜4Jšœ&œ Ÿ˜VJšœ˜—Jšœ˜—šœœ)œ˜