<> <> <> DIRECTORY CD, CDBasics, CDCells, CDCommandOps, CDDirectory, CDInstances, CDLayers, CDOps, CDPanelFonts, CDProperties, CDRects, CDSatellites, CDSequencer, CDTexts, CDViewer, Core, CoreCreate, CoreGeometry, CoreOps, CoreProperties, PopUpMenus, IO, PW, REFBit, Rope, SinixOps, Sisyph, TerminalIO, ViewerClasses, ViewerOps, WireIconExtras; WireIconExtrasImpl: CEDAR PROGRAM IMPORTS CD, CDBasics, CDCells, CDCommandOps, CDDirectory, CDInstances, CDLayers, CDOps, CDPanelFonts, CDProperties, CDRects, CDSatellites, CDTexts, CDViewer, CoreCreate, CoreGeometry, CoreProperties, CoreOps, IO, PW, REFBit, Rope, SinixOps, Sisyph, TerminalIO, ViewerOps EXPORTS WireIconExtras = BEGIN ROPE: TYPE = Rope.ROPE; Wire: TYPE = Core.Wire; ConstructIconCommand: PROC [comm: CDSequencer.Command] ~ { schFullName: ROPE; iconName: ROPE; icon: CD.Object; cell: Core.CellType; selected: CD.Instance; multiple: BOOL; cellRef: REF; sort: BOOL; [selected, multiple] _ CDOps.SelectedInstance[comm.design]; IF ~IsSingleSelectedAndCell[selected, multiple] THEN RETURN; schFullName _ CDDirectory.Name[selected.ob, comm.design]; IF schFullName=NIL THEN {TerminalIO.PutF["*** Selected schematic has no name.\n"]; RETURN}; IF NOT Rope.Match["*.sch", schFullName] THEN TerminalIO.PutF["*** Convention for schematics is to suffix them with '.sch'.\n"]; cellRef _ SinixOps.ExtractCDInstance[selected, comm.design, Sisyph.mode].result; IF ISTYPE [cellRef, Core.CellType] THEN cell _ NARROW [cellRef] ELSE {TerminalIO.PutF["*** Selected cell does not extract to Core CellType\n"]; RETURN}; iconName _ TerminalIO.RequestRope["Type icon short name: "]; IF Rope.IsEmpty[iconName] THEN iconName _ IF Rope.Match["*.sch", schFullName] THEN Rope.Substr[schFullName, 0, Rope.Length[schFullName]-4] ELSE schFullName; IF Rope.IsEmpty[schFullName] THEN {TerminalIO.PutF["No name provided, no default from schematic.\n"]; RETURN}; IF CDDirectory.Fetch[comm.design, Rope.Cat[iconName, ".icon"]]#NIL THEN { TerminalIO.PutF["*** The icon %g.icon already exists!\n", IO.rope[iconName]]; RETURN}; sort _ SELECT comm.key FROM $ConstructIconCommand => FALSE, $ConstructIconCommandSort => TRUE, ENDCASE => ERROR; icon _ IconFromSchematic[cell, schFullName, iconName, comm.design, sort]; IF icon=NIL THEN RETURN; CDCells.SetSimplificationTreshhold[cell: icon, val: 30, inPixels: TRUE]; []_CDOps.IncludeObjectI[comm.design, icon, comm.pos]}; ConstructRecWireIconCommand: PROC [comm: CDSequencer.Command] ~ { type: ROPE _ TerminalIO.RequestRope["Type (eg. Def.Record): "]; wire: Core.Wire _ RecWire[type]; name: ROPE _ type.Substr[type.Index[0,"."]+1]; icon: CD.Object _ ConstructWireIcon[comm, wire, name.Cat[".icon"]]; CDProperties.PutObjectProp[icon, $CodeFor, Rope.Cat["WireIconExtras.RecWire[\"", type, "\"]" ]]; CDProperties.PutObjectProp[icon, Sisyph.mode.extractProcProp, $SisyphExtractNamedWireIcon]}; ConstructDETWireIconCommand: PROC [comm: CDSequencer.Command] ~ { type: ROPE _ TerminalIO.RequestRope["Type (eg. Def.Enumerated): "]; pre: ROPE _ TerminalIO.RequestRope["Prefix:"]; suf: ROPE _ TerminalIO.RequestRope["Suffix:"]; wire: Core.Wire _ ETWire[pre, suf, type]; icon: CD.Object _ ConstructWireIcon[comm, wire, Rope.Cat[pre, suf, ".icon"]]; CDProperties.PutObjectProp [icon, $CodeFor, IO.PutFR["WireIconExtras.ETWire[\"%g\", \"%g\", \"%g\"]", IO.rope[pre], IO.rope[suf], IO.rope[type] ]]; CDProperties.PutObjectProp[icon, Sisyph.mode.extractProcProp, $SisyphExtractNamedWireIcon]}; ConstructWireIcon: PROC [comm: CDSequencer.Command, wire: Core.Wire, name: ROPE] RETURNS[icon: CD.Object] ~ { font: CDTexts.CDFont _ CDPanelFonts.CurrentFont[comm.design]; w: INT _ CDLayers.LayerWidth[comm.design, CD.commentLayer]; fw2: INT _ font.height/2 - w - font.origin.y; grid: CD.Number _ Grid[comm.design, font]; insts: CD.InstanceList _ NIL; pinObject: CD.Object _ CDRects.CreateRect[size: [grid/2, w], l: CD.commentLayer]; text: CD.Object; sat: CD.Instance; pin: CD.Instance; maxX: INT _ 0; FOR i: INT IN [0..wire.size) DO text _ CDTexts.Create[CoreOps.GetShortWireName[wire[i]], font]; maxX _ MAX[ maxX, CD.InterestSize[text].x]; sat _ CDInstances.NewInst[text, [[x: grid, y: grid*(i+2)-fw2 ]]]; pin _ CDInstances.NewInst[pinObject, [[x: 0, y: grid*(i+2) ]]]; insts _ CONS[sat, CONS[pin, insts]]; CDSatellites.Associate[master: pin, text: sat] ENDLOOP; text _ CDTexts.Create[CoreOps.GetShortWireName[wire], font]; maxX _ ((MAX[ maxX, CD.InterestSize[text].x] + 3*grid-1)/grid)*grid; sat _ CDInstances.NewInst[text, [[x: maxX-grid-CD.InterestSize[text].x, y: grid-fw2 ]]]; pin _ CDInstances.NewInst[pinObject, [[x: maxX-grid/2, y: grid ]]]; insts _ CONS[sat, CONS[pin, insts]]; CDSatellites.Associate[master: pin, text: sat]; icon _ PW.CreateCell[instances: insts, ir: [0, 0, maxX, grid*(wire.size+2)+w]]; IF NOT CDDirectory.Include[comm.design, icon, name] THEN {TerminalIO.PutF["*** Directory insertion of %g failed.\n", IO.rope[name]]; ERROR}; <> []_CDOps.IncludeObjectI[comm.design, icon, comm.pos]}; mark: ATOM _ CoreProperties.RegisterProperty[$TemporaryMark]; IconFromSchematic: PROC[ schCT: Core.CellType, schFullName: ROPE, iconName: ROPE, design: CD.Design, sort: BOOL ] RETURNS [iconObj: CD.Object] ~ { L16: PROC[in: INT] RETURNS[INT] = {XX: INT _ design.technology.lambda*16; RETURN[((in+XX-1)/XX)*XX]}; font: CDTexts.CDFont _ CDPanelFonts.CurrentFont[design]; grid: CD.Number _ Grid[design, font]; insts: CD.InstanceList _ NIL; schDeco: CoreGeometry.Decoration _ Sisyph.mode.decoration; schSize: CD.Position _ CD.InterestSize[CoreGeometry.GetObject[schDeco, schCT]]; iconSize: CD.Position; hChans: INT; vChans: INT; iNmOb: CD.Object _ CDTexts.Create[iconName, font]; pins: ARRAY CoreGeometry.Side OF CD.InstanceList _ ALL[NIL]; cnt: ARRAY CoreGeometry.Side OF NAT _ ALL[0]; smax: ARRAY CoreGeometry.Side OF INT _ ALL[16]; w: INT _ CDLayers.LayerWidth[design, CD.commentLayer]; fw2: INT _ font.height/2 - w - font.origin.y; iconFullName: ROPE _ iconName.Cat[".icon"]; pinObject: CD.Object; horWall: CD.Object; verWall: CD.Object; clearMark: CoreOps.EachWireProc = {CoreProperties.PutWireProp[wire, mark, NIL]}; FOR side: CoreGeometry.Side IN CoreGeometry.Side DO eachSortedPin: CoreGeometry.EachSortedPinProc = { IF CoreProperties.GetWireProp[wire, mark]=NIL THEN { text: CD.Object _ CDTexts.Create[CoreOps.GetShortWireName[wire], font]; inst: CD.Instance _ CDInstances.NewInst[text]; CoreProperties.PutWireProp[wire, mark, mark]; pins[side] _ CONS[inst, pins[side]]; cnt[side] _ cnt[side] + 1; smax[side] _ MAX[ smax[side], CD.InterestSize[text].x] }}; [] _ CoreGeometry.EnumerateSortedSides[schDeco, schCT, side, eachSortedPin]; []_CoreOps.VisitWire[schCT.public, clearMark]; ENDLOOP; IF sort THEN FOR side: CoreGeometry.Side IN CoreGeometry.Side DO DO ok: BOOL _ TRUE; FOR insts: CD.InstanceList _ pins[side], insts.rest WHILE insts#NIL AND insts.rest#NIL DO TwoObj: TYPE = RECORD[ob1, ob2: CD.Object]; r1: ROPE _ NARROW[insts.first.ob.specific, CDTexts.TextSpecific].text; r2: ROPE _ NARROW[insts.rest.first.ob.specific, CDTexts.TextSpecific].text; SELECT Rope.Compare[r1, r2] FROM less => LOOP; equal => ERROR; ENDCASE; [insts.first.ob, insts.rest.first.ob] _ TwoObj[insts.rest.first.ob, insts.first.ob]; ok_FALSE; ENDLOOP; IF ok THEN EXIT; ENDLOOP; ENDLOOP; hChans _ MAX[cnt[left], cnt[right]]; vChans _ MAX[cnt[top], cnt[bottom]]; iconSize.x_ L16[(vChans+4)*grid + 2*MAX[smax[left], smax[right],CD.InterestSize[iNmOb].x]]; iconSize.y_ L16[(hChans+4)*grid + 2*MAX[smax[top], smax[bottom]]]; IF schSize.x > schSize.y THEN iconSize.x _ L16[MAX[iconSize.x, (iconSize.y*schSize.x + schSize.y/2) /schSize.y]] ELSE iconSize.y _ L16[MAX[iconSize.y, (iconSize.x*schSize.y + schSize.x/2) /schSize.x]]; pinObject _ CDRects.CreateRect[size: [grid/2, w], l: CD.commentLayer]; horWall _ CDRects.CreateRect[size: [iconSize.x, w], l: CD.commentLayer]; verWall _ CDRects.CreateRect[size: [w, iconSize.y], l: CD.commentLayer]; FOR side: CoreGeometry.Side DECREASING IN CoreGeometry.Side DO tr: CD.Transformation _ SELECT side FROM top => [ [iconSize.x/2 - vChans*grid/2, iconSize.y], rotate270 ], bottom => [ [iconSize.x/2 - vChans*grid/2, 0], rotate90 ], left => [ [0, iconSize.y/2 - hChans*grid/2], original], right => [ [iconSize.x, iconSize.y/2 - hChans*grid/2], rotate180], ENDCASE => ERROR; index: INT _ (cnt[side]+(SELECT side FROM top,bottom=>vChans, ENDCASE => hChans)+1)/2; FOR temp: CD.InstanceList _ pins[side], temp.rest WHILE temp#NIL DO pin, sat: CD.Instance; index _ index-1; insts _ CONS[(sat _ temp.first), insts]; insts _ CONS[(pin _ CDInstances.NewInst[pinObject]), insts]; sat.trans.orient _ pin.trans.orient _ tr.orient; CDSatellites.Associate[master: pin, text: sat]; SELECT side FROM top => { pin.trans.off _ CDBasics.AddPoints[tr.off, [index*grid+0, 0 ]]; sat.trans.off _ CDBasics.AddPoints[tr.off, [index*grid+0-fw2, -grid ]]}; bottom => { pin.trans.off _ CDBasics.AddPoints[tr.off, [index*grid+w, 0 ]]; sat.trans.off _ CDBasics.AddPoints[tr.off, [index*grid+w+fw2, +grid ]]}; left => { pin.trans.off _ CDBasics.AddPoints[tr.off, [0, index*grid+0 ]]; sat.trans.off _ CDBasics.AddPoints[tr.off, [+grid, index*grid+0-fw2 ]]}; right => { pin.trans.off _ CDBasics.AddPoints[tr.off, [0, index*grid+w ]]; sat.trans.off _ CDBasics.AddPoints[tr.off, [-grid, index*grid+w+fw2 ]]}; ENDCASE => ERROR; ENDLOOP; ENDLOOP; insts _ CONS[CDInstances.NewInst[horWall, [off:[0, 0 ]]], insts]; CDProperties.PutInstanceProp[insts.first, Sisyph.mode.extractProcProp, $ExtractNull]; insts _ CONS[CDInstances.NewInst[horWall, [off:[0, iconSize.y-w ]]], insts]; CDProperties.PutInstanceProp[insts.first, Sisyph.mode.extractProcProp, $ExtractNull]; insts _ CONS[CDInstances.NewInst[verWall, [off:[0, 0 ]]], insts]; CDProperties.PutInstanceProp[insts.first, Sisyph.mode.extractProcProp, $ExtractNull]; insts _ CONS[CDInstances.NewInst[verWall, [off:[iconSize.x-w, 0 ]]], insts]; CDProperties.PutInstanceProp[insts.first, Sisyph.mode.extractProcProp, $ExtractNull]; insts _ CONS[CDInstances.NewInst[iNmOb, [off:[grid, iconSize.y-2*grid ]]], insts]; iconObj _ PW.CreateCell[instances: insts]; IF NOT CDDirectory.Include[design, iconObj, iconFullName] THEN {TerminalIO.PutF["*** Directory insertion of %g failed.\n", IO.rope[iconFullName]]; ERROR}; CDProperties.PutObjectProp[iconObj, Sisyph.mode.extractProcProp, $SisyphExtractCellIcon]; CDProperties.PutObjectProp[iconObj, $IconFor, schFullName]}; <<>> Grid: PROC[design: CD.Design, font: CDTexts.CDFont _ NIL] RETURNS[grid: NAT] = { viewers: CDViewer.ViewerList _ CDViewer.ViewersOf[design]; IF viewers#NIL THEN WITH ViewerOps.GetViewer[viewers.first, $Grid] SELECT FROM rgrid: REF CD.Number => grid _ rgrid^; ENDCASE => NULL ELSE grid _ design.technology.lambda*2; IF font#NIL THEN WHILE font.height > (grid*4)/3 DO grid _ grid*2 ENDLOOP}; <> <> <> <<[root: root, cell: cellType] _ SinixOps.SelectedCellType[comm.design, Sisyph.mode];>> <> <> <> <> <> <> <> <> <> <<>> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <<{TerminalIO.PutF["Can't handle pushed in cell\n"]; RETURN};>> <> <> <> <> <> <<{TerminalIO.PutF["%g is not an icon.\n", IO.rope[objName]]; LOOP};>> <> <> <<{TerminalIO.PutF["%g does not extract as a cell.\n", IO.rope[objName]]; LOOP};>> <> <> <> < {errorType _ type; errorMsg _ message; CONTINUE}];>> <> <> <> <> <> <> <> <> <> <> <> <> <> <<[]_CDDebug.Draw[directOb, comm.design.technology, objName];>> <> <> <> <> <> <> <> <<>> <> <> <<[selected, multiple] _ CDOps.SelectedInstance[comm.design];>> <> <> <<{TerminalIO.PutRope["*** Can't modify an immutable object\n"]; RETURN};>> <> << $AWireAddProp => $SisyphExtractUnNamedWireIcon,>> << $PWireAddProp => $SisyphExtractNamedWireIcon,>> < ERROR)]};>> <> <> <<[selected, multiple] _ CDOps.SelectedInstance[comm.design];>> <> <> <<{TerminalIO.PutRope["*** Can't modify an immutable object\n"]; RETURN};>> <> IsSingleSelected: PROC [selected: CD.Instance, multiple: BOOL] RETURNS [BOOL] = { IF selected=NIL THEN {TerminalIO.PutF["*** No current selection--can't do it.\n"]; RETURN[FALSE]}; IF multiple THEN {TerminalIO.PutF["*** Multiple instances selected--can't do it.\n"]; RETURN[FALSE]}; RETURN[TRUE]}; IsSingleSelectedAndCell: PROC [selected: CD.Instance, multiple: BOOL] RETURNS [BOOL] = { IF ~IsSingleSelected[selected, multiple] THEN RETURN [FALSE]; IF ~CDCells.IsCell[selected.ob] THEN {TerminalIO.PutF["*** Selected instance is not a cellcan't do it.\n"]; RETURN[FALSE]}; RETURN[TRUE]}; GridComposer: PW.GeneratorProc = { name: ROPE; grid: INT _ Grid[design]; n: INT _ TerminalIO.RequestInt["Size of the composer? "]; w: INT _ CDLayers.LayerWidth[design, CD.commentLayer]; IF n<1 THEN {TerminalIO.PutF["*** Invalid parameter.\n"]; RETURN}; name _ IO.PutFR["Grid%gW%gComposer[%g].icon", IO.int[grid], IO.int[w], IO.int[n]]; ob _ CDDirectory.Fetch[design, name].object; IF ob=NIL THEN { ob _ GridComposeObj[design, grid, n].obj; [] _ CDDirectory.Include[design, ob, name]}}; GridComposeWire: PUBLIC PROC[n: NAT] RETURNS [wire: Wire] ~ { wire _ CoreOps.CreateWires[n, "w"]; FOR ii: INT IN [0..n) DO wire[ii] _ CoreOps.CreateWires[0, IO.PutFR["w%g", IO.int[ii]]] ENDLOOP}; GridComposeObj: PROC [design: CD.Design, grid, n: INT] RETURNS [obj: CD.Object] = { Add: PROC[name: ROPE _ NIL, size, pos: CD.Position] = { list _ CONS[CDInstances.NewInst[CDRects.CreateRect[size, CD.commentLayer], [pos]], list]; IF name#NIL THEN { names: LIST OF ROPE _ LIST[name]; CDProperties.PutInstanceProp[list.first, Sisyph.expressionsProp, names]}}; list: CD.InstanceList _ NIL; w: INT _ CDLayers.LayerWidth[design, CD.commentLayer]; l: INT _ MAX[w, grid/4]; Add[size:[2*l, grid*2*n+w], pos:[l, 0]]; CDProperties.PutInstanceProp[list.first, Sisyph.mode.extractProcProp, $ExtractNull]; Add[name: "w", size:[l, w], pos:[0, grid]]; FOR ii: INT IN [0..n) DO Add[name: IO.PutFR["w%g", IO.int[ii]], size:[l, w], pos:[3*l, (2*ii+1)*grid]] ENDLOOP; obj _ PW.CreateCell[instances: list]; CDProperties.PutObjectProp [obj, $CodeFor, IO.PutFR["WireIconExtras.GridComposeWire[%g]", IO.int[n]]]; CDProperties.PutObjectProp[obj, Sisyph.mode.extractProcProp, $SisyphExtractUnNamedWireIcon]; CDCells.SetSimplificationTreshhold[obj, 20]}; RecWire: PUBLIC PROC[rec: ROPE, dual: BOOL _ FALSE] RETURNS[wire: Wire] = {RETURN[RefWire[REFBit.NEWFromName[rec], rec.Substr[rec.Index[0,"."]+1]]]}; RefWire: PUBLIC PROC[ref: REF, name: ROPE, dual: BOOL _ FALSE] RETURNS[wire: Wire] = { ZeroIfOne: PROC[s: INT] RETURNS[INT] = {RETURN[IF s=1 THEN 0 ELSE s]}; fieldForm: REFBit.Format _ REFBit.Desc[ref].fieldForm; wires: LIST OF Wire _ NIL; temp: LIST OF Wire _ NIL; FOR field: INT IN[0..fieldForm.size) DO fieldName: ROPE _ BitRopeToSigRope[fieldForm[field].name]; SELECT fieldForm[field].bitSize FROM 1 => {wires _ CONS[CoreCreate.Seq[fieldName, IF dual THEN 2 ELSE 0], wires]}; >1 => { fieldWire: Wire _ CoreOps.CreateWires[fieldForm[field].bitSize, fieldName]; wires _ CONS[fieldWire, wires]; FOR bit: INT IN[0..fieldWire.size) DO fieldWire[bit] _ CoreCreate.Seq[NIL, IF dual THEN 2 ELSE 0] ENDLOOP}; ENDCASE => ERROR; ENDLOOP; temp _ wires; wires _ NIL; FOR temp _ temp, temp.rest WHILE temp#NIL DO wires _ CONS[temp.first, wires] ENDLOOP; wire _ CoreOps.CreateWire[wires, name]}; <<>> ETWire: PUBLIC PROC[prefix, suffix, type: ROPE] RETURNS[wire: Wire] = { bitName, bitNameInv: ROPE; refREF: REF _ REFBit.NEWFromName[type]; format: REFBit.Format _ REFBit.Desc[refREF].bitForm; wire _ CoreOps.CreateWires[MAX[2, format.size], prefix.Cat[suffix]]; FOR i: INT IN[0..format.size) DO bitName _ BitRopeToSigRope[format[i].name]; bitNameInv _ BitRopeToSigRope[format[i].nameInv]; IF ((format.size#1) = (i+1=format.size)) = (bitName#NIL) THEN ERROR; IF ((format.size#1) = (bitNameInv#NIL)) = (bitName#NIL) THEN ERROR; IF bitName=NIL THEN bitName _ bitNameInv; wire[i] _ CoreOps.CreateWires[0, prefix.Cat[bitName, suffix]]; IF format.size=1 THEN wire[1] _ CoreOps.CreateWires[0, prefix.Cat[bitNameInv, suffix]]; ENDLOOP}; BitRopeToSigRope: PROC [name: ROPE] RETURNS [ROPE] ~ { Cap: PROC[rope: ROPE, idx: INT] RETURNS[ROPE] = { char: CHAR _ rope.Fetch[idx+1]; IF char IN ['a..'z] THEN char _ char + LOOPHOLE['A - 'a]; RETURN[IO.PutFR["%g", IO.char[char]]]}; IF name = NIL THEN RETURN[NIL]; name _ Rope.Cat[Cap[name, -1], name.Substr[1]]; DO -- remove peiods and Capitalize next letters until end or next char is number index: INT _ name.Index[0, "."]; IF index+1 >= name.Length[] OR name.Fetch[index+1] IN ['0..'9] THEN RETURN[name]; name _ Rope.Cat[name.Substr[0,index], Cap[name, index], name.Substr[index+2]]; ENDLOOP }; CDCommandOps.RegisterWithMenu[ menu: $SisyphIconMenu, entry: "Create Cell Icon from schematics - Grid 2", doc: "Pins on grid 2. Overall size in units of 16.", key: $ConstructIconCommand, proc: ConstructIconCommand ]; CDCommandOps.RegisterWithMenu[ menu: $SisyphIconMenu, entry: "Create Cell Icon from schematics - Grid 2 - Sorted", doc: "Pins on grid 2. Overall size in units of 16. Names sorted.", key: $ConstructIconCommandSort, proc: ConstructIconCommand ]; CDCommandOps.RegisterWithMenu[ menu: $SisyphIconMenu, entry: "Create Wire Icon from Cedar Record Type", doc: "RECORDs with field types such as: RECORD, INT, BOOL, enumerated, subranges", key: $ConstructRecWireIconCommand, proc: ConstructRecWireIconCommand ]; CDCommandOps.RegisterWithMenu[ menu: $SisyphIconMenu, entry: "Create Wire Icon from Cedar Enumerated Type", doc: "Decoded Enumerated types encoded as: 0, 3, 5, 9, 17 etc.", key: $ConstructDETWireIconCommand, proc: ConstructDETWireIconCommand ]; <> <> <> <> <<>> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <<>> <> <> <> <> <> <> <> <> <> <> <> <> PW.RegisterGenerator[GridComposer, "Composer - variable grid and width"]; END.