DIRECTORY Atom, CD, CDApplications, CDCallSpecific, CDDialogue, CDExtras, CDInline, CDOps, CDProperties, CDSequencer, ConvertUnsafe, CornerStitching, FS, Graphics, GraphicsOps, Menus, IO, Process, Real, Rope, STPStreams, TerminalIO, VFonts, ViewerClasses, ViewerOps, ViewerSpecs; VersatecImpl: CEDAR MONITOR IMPORTS Atom, CD, CDApplications, CDCallSpecific, CDDialogue, CDExtras, CDInline, CDOps, CDProperties, CDSequencer, CornerStitching, FS, Graphics, GraphicsOps, IO, Menus, Process, Real, STPStreams, TerminalIO, VFonts, ViewerOps EXPORTS = BEGIN maxScanLineWidth: CARDINAL = 7040; -- the wide-bed Versatec scanLineWidth: CARDINAL _ maxScanLineWidth; maxPatchHeight: CARDINAL = 144; -- fits in 64k stippleRepeat: CARDINAL = 16; Nibble: TYPE = [0..16); ScanLine: TYPE = PACKED ARRAY [0..0) OF WORD; ScanLineInNibbles: TYPE = PACKED ARRAY [0..0) OF Nibble; CodedScanLine: TYPE = RECORD [ codeWordCount: CARDINAL _ 0, codeWords: REF CodeWords ]; CodeWords: TYPE = PACKED ARRAY [0..maxScanLineWidth) OF CodeWord; CodeWord: TYPE = MACHINE DEPENDENT RECORD [ repeats (0: 0..3): [1..16], pattern (0: 4..7): Nibble]; textures: ARRAY CD.Level OF REF GraphicsOps.Texture _ ALL[NIL]; PlotStateRef: TYPE = REF PlotState; PlotState: TYPE = RECORD [ text: REF CornerStitching.Tesselation _ NIL, tes: ARRAY CD.Level OF REF CornerStitching.Tesselation _ ALL[NIL], bitmap: GraphicsOps.BitmapRef _ NIL, vPatch, context: Graphics.Context _ NIL, scale: REAL _ 1.0, -- pixels per CD.DesignNumber totalPlotClip, bandClip: CD.DesignRect _ [0,0,0,0], texture: GraphicsOps.Texture _ ALL[0] ]; currentFlavor: ViewerClasses.ViewerFlavor = $ChipndaleVersatecPlot; Init: ENTRY PROC ~ { menu: Menus.Menu = Menus.CreateMenu[]; Menus.AppendMenuEntry[menu: menu, entry: Menus.CreateEntry[name: "AbortPlot", proc: AbortProc, guarded: TRUE]]; ViewerOps.RegisterViewerClass[flavor: currentFlavor, class: NEW[ViewerClasses.ViewerClassRec _ [paint: PaintVersatecStripe, menu: menu]]]; CDSequencer.ImplementCommand[a~$VPlotLocal, p~PlotDesignToLocalFile]; CDSequencer.ImplementCommand[a~$VPlotRemote, p~PlotDesignToRemoteFile]; CDSequencer.ImplementCommand[a~$VPlotPlotter, p~PlotDesignToPlotter]; CDSequencer.ImplementCommand[a~$VPlot, p~PlotDesignToAny]; signalFont _ VFonts.GraphicsFont[VFonts.EstablishFont[family: "Helvetica", size: 18, bold: TRUE]]; TerminalIO.WriteRope["ChipNDale Versatec plotter loaded\n"]; }; PlotDesignToAny: ENTRY PROC [ c: CDSequencer.Command ] = BEGIN ENABLE UNWIND => NULL; n: CARDINAL _ TerminalIO.RequestSelection[ label: "Versatec Plot", choice: LIST[" plotter", " local", " read name", " remote"] ]; SELECT n FROM 1 => PlotDesign[c: c, to: plotter]; 2 => PlotDesign[c: c, to: localFile]; 3 => PlotDesign[c: c, to: requestFilename]; 4 => { TerminalIO.WriteRope["remote is not yet implemented\n"]; }; ENDCASE => TerminalIO.WriteRope["skipped\n"]; END; PlotDesignToLocalFile: ENTRY PROC [ c: CDSequencer.Command ] = BEGIN ENABLE UNWIND => NULL; PlotDesign[c: c, to: localFile]; END; PlotDesignToRemoteFile: ENTRY PROC [ c: CDSequencer.Command ] = BEGIN ENABLE UNWIND => NULL; PlotDesign[c: c, to: remoteFile]; END; PlotDesignToPlotter: ENTRY PROC [ c: CDSequencer.Command ] = BEGIN ENABLE UNWIND => NULL; PlotDesign[c: c, to: plotter]; END; signalFont: Graphics.FontRef _ NIL; viewer: ViewerClasses.Viewer _ NIL; plotter: Rope.ROPE _ "vice"; plotFileToSpool: Rope.ROPE _ "[vice]plot.bits"; plotFileOnPlotter: Rope.ROPE _ "plot.bits"; plotFileOnLocalMachine: Rope.ROPE _ "plot.bits"; plotFileOnServer: Rope.ROPE _ "[Luther.alpine]plot.bits"; latestPlotFile: Rope.ROPE _ NIL; spoolToPlotter: BOOL _ TRUE; abortPlot: BOOL _ FALSE; PlotDesign: INTERNAL PROC [ c: CDSequencer.Command, to: {localFile, remoteFile, plotter, requestFilename}] = BEGIN s: IO.STREAM _ NIL; strips: [1..100] _ TerminalIO.RequestInt["How many vertical strips in the plot? "]; BEGIN ENABLE -- for ERRORs BEGIN UNWIND => {s _ AbortFile[s]; TerminalIO.WriteRope[" ** plot aborted ** "]}; END; design: CD.Design = c.design; plotClip: CD.DesignRect = CDInline.ToRect[c.pos, c.sPos]; dr: CD.DrawRef = CD.NewNullDeviceDrawRef[design]; scale: REAL = MIN[32.0/CD.lambda, (REAL[scanLineWidth]+REAL[scanLineWidth-100]*(strips-1))/(plotClip.x2-plotClip.x1)]; patchHeight: CARDINAL = stippleRepeat*((MIN[maxPatchHeight, CARDINAL[Real.Fix[50*CD.lambda*scale]]]+stippleRepeat-1)/stippleRepeat); bitmap: GraphicsOps.BitmapRef = GraphicsOps.NewBitmap[width: scanLineWidth, height: patchHeight]; ps: PlotStateRef = NEW[ PlotState _ [ text: CornerStitching.NewTesselation[], scale: scale, totalPlotClip: plotClip, bitmap: bitmap, vPatch: GraphicsOps.NewContextFromBitmap[bitmap]] ]; usedLevels: REF PACKED ARRAY CD.Level OF BOOL _ NIL; abortPlot _ FALSE; TerminalIO.WriteRope["Starting Versatec plot "]; TRUSTED {Process.SetPriority[Process.priorityBackground]}; viewer _ ViewerOps.FindViewer["Versatec Stripe"]; IF viewer # NIL AND viewer.class.flavor # currentFlavor THEN {ViewerOps.DestroyViewer[viewer]; viewer _ NIL}; IF viewer=NIL THEN BEGIN viewer _ ViewerOps.CreateViewer[flavor: currentFlavor, info: [name: "Versatec Stripe", iconic: FALSE, openHeight: patchHeight+ViewerSpecs.menuHeight]]; END; viewer.data _ ps; dr.minimalSize _ 0; dr.drawRect _ dr.saveRect _ NoteLevel; dr.devicePrivate _ usedLevels; dr.worldClip _ CDInline.universe; dr.devicePrivate _ usedLevels _ NEW[PACKED ARRAY CD.Level OF BOOL _ ALL[FALSE]]; CDOps.DrawDesign[design, dr]; -- mark used levels { textureNo: CARDINAL _ 0; FOR l: CD.Level IN CD.Level DO -- assign textures to used levels IF usedLevels[l] THEN { textures[l] _ Texture[textureNo]; textureNo _ textureNo+1} ELSE textures[l] _ NIL; ENDLOOP; }; dr.drawRect _ dr.saveRect _ NoteRectangle; dr.devicePrivate _ ps; SELECT to FROM localFile => BEGIN TerminalIO.WriteRope["onto """]; s _ FS.StreamOpen[plotFileOnLocalMachine, create]; TerminalIO.WriteRope[plotFileOnLocalMachine]; TerminalIO.WriteRope[""""]; s.SetLength[0]; latestPlotFile _ plotFileOnLocalMachine; END; requestFilename => BEGIN r: Rope.ROPE _ CDExtras.AppendExt[TerminalIO.RequestRope["to file ? > "], "bits"]; TerminalIO.WriteRope["onto """]; s _ FS.StreamOpen[r, create]; TerminalIO.WriteRope[r]; TerminalIO.WriteRope[""""]; s.SetLength[0]; latestPlotFile _ r; END; remoteFile => BEGIN --???-- TerminalIO.WriteRope["onto remote file not yet converted to Cedar 5"]; ERROR; END; plotter => BEGIN TerminalIO.WriteRope["onto plotter "]; [self: s] _ STPStreams.OpenSTP[host: plotter, fileName: plotFileOnPlotter, accessOptions: create]; latestPlotFile _ NIL; END; ENDCASE => ERROR; TRUSTED { s.PutChar[LOOPHOLE[scanLineWidth/256, CHARACTER]]; s.PutChar[LOOPHOLE[scanLineWidth MOD 256]]; }; TerminalIO.WriteRope["\n.. found "]; TerminalIO.WriteInt[CDCallSpecific.CallForAll[design: design, whatElse: LookForSignalName, x: ps]]; TerminalIO.WriteRope[" top-level signal names "]; SendWhiteBar[s: s]; SendBlackBar[s: s]; FOR strip: INT IN [0..strips) DO clip: CD.DesignRect = [ x1: plotClip.x1+strip*((plotClip.x2-plotClip.x1)/strips), y1: plotClip.y1, x2: plotClip.x1+(strip+1)*((plotClip.x2-plotClip.x1)/strips)+Real.Fix[100./scale]+1, y2: plotClip.y2]; FOR topLine: INT _ 0, topLine+patchHeight WHILE topLine {s _ AbortFile[s]; TerminalIO.WriteRope[" ** plot aborted ** "]; abortPlot _ FALSE}; END; END; NoteLevel: PROC [ r: CD.DesignRect, l: CD.Level, pr: CD.DrawRef ] = BEGIN ps: REF PACKED ARRAY CD.Level OF BOOL = NARROW[pr.devicePrivate]; ps[l] _ TRUE; END; NoteRectangle: PROC [ r: CD.DesignRect, l: CD.Level, pr: CD.DrawRef ] = BEGIN ps: PlotStateRef = NARROW[pr.devicePrivate]; IF CDInline.NonEmpty[r] THEN BEGIN IF ps.tes[l]=NIL THEN ps.tes[l] _ CornerStitching.NewTesselation[]; ps.tes[l].ChangeRect[rect: r, newvalue: $covered, checkOldvalue: FALSE]; END; END; AnalyzeTesselations: PROC [ ps: PlotStateRef ] = BEGIN FOR l: CD.Level IN CD.Level DO IF ps.tes[l]#NIL THEN BEGIN ps.texture _ textures[l]^; [] _ ps.tes[l].EnumerateArea[rect: ps.bandClip, perTile: ProcessTile, data: ps, backgroundValue: $none]; END; ENDLOOP; END; ProcessTile: PROCEDURE [tile: CornerStitching.TilePtr, data: REF ANY] RETURNS [REF ANY] -- CornerStitching.PerTileProc -- = BEGIN -- only called on covered tiles t: CornerStitching.TilePtr; ps: PlotStateRef = NARROW[data]; tileValue: REF = tile.Value; IF tileValue = $covered THEN BEGIN r: CD.DesignRect = tile.Area; GraphicsOps.DrawTexturedBox[self: ps.context, box: [xmin: r.x1, ymin: r.y1, xmax: r.x2, ymax: r.y2], texture: ps.texture]; END; FOR t _ tile.NEastNeighbour, t.WSouthNeighbour WHILE tile.SouthEdge s _ Atom.GetPName[atom]; rope: Rope.ROPE => s _ rope; ENDCASE => s _ "?"; END; ps: PlotStateRef = NARROW[x]; r: CD.DesignRect = CDInline.Intersection[ps.totalPlotClip, CDApplications.ApplicationRect[aptr]]; signal: REF = CDProperties.GetProp[from: aptr, prop: $SignalName]; IF signal # NIL AND CDInline.NonEmpty[r] THEN BEGIN signalValue: SignalValueRef = NEW[SignalValue _ [s: GetSignalName[signal]]]; others: LIST OF REF CornerStitching.Region = NARROW[ps.text.EnumerateArea[rect: r]]; ps.text.ChangeRect[rect: r, newvalue: signalValue, checkOldvalue: FALSE]; FOR other: LIST OF REF CornerStitching.Region _ others, other.rest WHILE other#NIL DO ps.text.ChangeRect[rect: other.first.rect, newvalue: other.first.value, checkOldvalue: FALSE]; ENDLOOP; END ELSE done _ FALSE; END; PaintASignalName: PROC [tile: CornerStitching.TilePtr, data: REF ANY] RETURNS [REF ANY] -- CornerStitching.PerTileProc -- = BEGIN ps: PlotStateRef = NARROW[data]; textContext: Graphics.Context = ps.vPatch.CopyContext[]; signalValue: SignalValueRef = NARROW[tile.Value[]]; dx, dy, xmin, xmax, ymin, ymax: REAL; r: CD.DesignRect = CDInline.Intersection[tile.Area, ps.totalPlotClip]; ctr: CD.DesignPosition = Center[r]; [dx: dx, dy: dy] _ Graphics.Map[sc: ps.context, dc: ps.vPatch, sx: ctr.x, sy: ctr.y]; [xmin: xmin, ymin: ymin, xmax: xmax, ymax: ymax] _ Graphics.RopeBox[font: signalFont, rope: signalValue.s]; textContext.Translate[tx: dx-(xmax+xmin)/2, ty: dy-(ymax+ymin)/2]; -- centers the text in r IF ((xmax-xmin)>(ymax-ymin)) # ((r.x2-r.x1)>(r.y2-r.y1)) THEN textContext.Rotate[270]; textContext.SetColor[Graphics.white]; textContext.DrawBox[[xmin: -2, ymin: -2, xmax: xmax-xmin+2, ymax: ymax-ymin+2]]; textContext.SetColor[Graphics.black]; textContext.SetCP[x: 0, y: 0]; textContext.DrawRope[rope: signalValue.s, font: signalFont]; RETURN[data]; END; Center: PROC [ r: CD.Rect ] RETURNS [ CD.Position ] = {RETURN[[x: (r.x1+r.x2)/2, y: (r.y1+r.y2)/2]]}; SendWhiteBar: PROC [ s: IO.STREAM, lines: CARDINAL _ 40 ] = {SendBar[s, 0, lines]}; SendBlackBar: PROC [ s: IO.STREAM, lines: CARDINAL _ 20 ] = {SendBar[s, 15, lines]}; SendBar: PROC [ s: IO.STREAM, pattern: Nibble, lines: CARDINAL ] = BEGIN scanLineNibbles: CARDINAL = scanLineWidth/4; FOR j: CARDINAL IN [0..lines) DO FOR i: CARDINAL IN [0..(scanLineNibbles+15)/16) DO TRUSTED {s.PutChar[LOOPHOLE[CodeWord[repeats: MIN[16, scanLineNibbles-16*i], pattern: pattern]]]}; ENDLOOP; ENDLOOP; END; SendBitmap: PROC [ s: IO.STREAM, bitmap: GraphicsOps.BitmapRef ] = BEGIN csl: REF CodedScanLine = NEW[CodedScanLine _ [codeWords: NEW[CodeWords]]]; FOR i: CARDINAL IN [0..bitmap.height) DO -- send to the Versatec TRUSTED { EncodeScanLine[sl: LOOPHOLE[LOOPHOLE[bitmap.base, INT]+INT[bitmap.raster]*i, LONG POINTER TO ScanLine], bitWidth: bitmap.width, csl: csl]; s.UnsafePutBlock[[base: LOOPHOLE[csl.codeWords], startIndex: 0, count: csl.codeWordCount]]; } ENDLOOP; END; EncodeScanLine: PROC [ sl: LONG POINTER TO ScanLine, bitWidth: CARDINAL, csl: REF CodedScanLine ] = TRUSTED BEGIN size: CARDINAL _ 0; scanLineInNibbles: LONG POINTER TO ScanLineInNibbles = LOOPHOLE[sl]; scanLineNibbles: CARDINAL = (bitWidth+3)/4; i: CARDINAL _ 0; WHILE i Stipple[01H, 02H, 04H, 08H], 1 => Stipple[04H, 02H, 01H, 08H], 2 => Stipple[00H, 0AH, 00H, 0AH], 3 => Stipple[08H, 00H, 08H, 00H], 4 => Stipple[0AH, 00H, 00H, 00H], 5 => Stipple[08H, 00H, 02H, 00H], 6 => Stipple[00H, 01H, 00H, 04H], 7 => Stipple[04H, 04H, 00H, 00H], 8 => Stipple[00H, 00H, 00H, 03H], ENDCASE => Stipple[0FH, 0FH, 0FH, 0FH])[row]; ENDLOOP; RETURN[t]; END; PaintVersatecStripe: PROC [ self: ViewerClasses.Viewer, context: Graphics.Context, whatChanged: REF ANY, clear: BOOL ] -- ViewerClasses.PaintProc -- = BEGIN ps: PlotStateRef = NARROW[self.data]; x: INT = MAX[INT[0], (ps.bitmap.width-self.cw)/2]; y: INT = MAX[INT[0], (ps.bitmap.height-self.ch)/2]; context.SetCP[self.cw/2, self.ch/2]; GraphicsOps.DrawBitmap[self: context, bitmap: ps.bitmap, w: MIN[self.cw, ps.bitmap.width], h: MIN[self.ch, ps.bitmap.height], x: x, y: y, xorigin: ps.bitmap.width/2, yorigin: ps.bitmap.height/2]; END; AbortProc: Menus.MenuProc = {abortPlot _ TRUE}; AbortFile: PROC [s: IO.STREAM ] RETURNS [ IO.STREAM ] = {IF s#NIL THEN s.Close[abort: TRUE]; RETURN[NIL]}; SpoolToPlotter: ENTRY PROC = {SpoolFileToPlotter[latestPlotFile]}; SpoolFileToPlotter: PROC [name: Rope.ROPE] = BEGIN IF name # NIL THEN { TerminalIO.WriteRope["spool file """]; TerminalIO.WriteRope[name]; TerminalIO.WriteRope[""".."]; FS.Copy[from: name, to: plotFileToSpool ! FS.Error => IF error.group # bug THEN { TerminalIO.WriteRope[" not done: "]; TerminalIO.WriteRope[error.explanation]; TerminalIO.WriteLn[]; CONTINUE; } ]; TerminalIO.WriteRope[" spool finished\n"]; }; END; Init[]; END. -- of VersatecImpl VersatecImpl.mesa YOU'L FIND INTERESTING PLACES BY LOOKING FOR "???" A package to output a ChipnDale design for the Versatec plotter in Oliver format. That format is defined thus: Bytes 0, 1 (high-order first): The number of bits per Versatec scan line (probably must be divisible by 4). Byte j: Two four-bit nibbles. The high-order nibble tells how many times to repeat the low-order nibble in the output bit stream. A data byte may not carry from one scan line to the next. N. B. This is not a very economical format. You should be able at least to duplicate previous scan lines. written by E. McCreight, August 1, 1983 2:00 PM Last Edited by: Mccreight, November 23, 1983 4:58 pm Last Edited by: Jacobi, October 27, 1983 12:36 pm Last Edited by: Jacobi, January 12, 1984 4:54 pm rectangles in design space touching all geometry in the plot, or this band PlotDesign[c: c, to: remoteFile]; ???x.Error => BEGIN TerminalIO.WriteRope[]; GOTO AbortPlot; END; Center the x range of the selected area of the design on the plotter bed, with at most 32 pixels per lambda. If multiple strips are called for, overlap adjacent ones by 100 pixels. divisible by stippleRepeat, so that textures work out TerminalIO.WriteRope["onto remote file """]; s _ RemoteFiles.OpenAlpineForWrite[plotFileOnServer]; s.SetLength[0]; TerminalIO.WriteRope[plotFileOnServer]; TerminalIO.WriteRope[""""]; latestPlotFile _ plotFileOnServer; send the length of a scan line to the Versatec clear the bitmap clip to the user-specified design rectangle rectangle in design space that ChipNDale can use to clip its recursive drawing for debugging and to pacify the user Put lines at boundaries with regions of other color going south along east edge of tile going west along north edge of tile This area needs considerable improvement. The ultimate goal is to find a place to put the signal name where it will not be confused with any other geometry (than the named piece, or continuations on the same layer) or signal name. leave a two-scan-line white patch all around Module START code... Ê,˜JšœE™EJ˜šœo™ošœ™JšœL™L—šœ™Jšœµ™µ—J˜Jšœk™k—J˜Jšœ0™0J™4J™1J™0šÏk ˜ Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ ˜ J˜ Jšœ ˜ Jšœ˜Jšœ ˜ Jšœ ˜ Jšœ˜Jšœ˜Jšœ˜Jšœ ˜ Jšœ ˜ Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ ˜ Jšœ ˜ Jšœ˜Jšœ˜Jšœ ˜ Jšœ ˜ J˜—šÏb œœ˜JšœœœA˜ãJšœ˜ Jš˜J˜Jšœœ Ïc˜;Jšœœ˜+J˜JšœœŸ˜.J˜Jšœœ˜J˜Jšœœ ˜J˜Jš œ œœœœœ˜-Jš œœœœœ˜8J˜šœœœ˜Jšœœ˜Jšœ œ ˜—Jš œ œœœœ ˜Aš œ œœ œœ˜+J˜Jšœ˜J˜—Jš œ œœœœœœ˜?J˜Jšœœœ ˜#šœ œœ˜Jšœœœ˜,Jš œœœœœœœ˜BJšœ œ˜$Jšœ$œ˜(JšœœŸ˜0šœœ˜3JšœJ™J—Jšœœ˜%Jšœ˜J˜J˜—JšœC˜CJ˜šÏnœœœ˜Jšœ&˜&Jšœhœ˜oJ•StartOfExpansion![key: ATOM, name: ROPE _ NIL]šœ<œK˜ŠJšœE˜EJšœG˜GJšœE˜EJšœ:˜:Jšœ[œ˜bJšœ<˜Jšœœœœ˜Jšœ ˜ Jšœ˜J˜J˜—š œœœ˜?Jšœœœœ˜Jšœ!˜!Jšœ˜J˜J˜—š œœœ˜