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];
[]Ops.IncludeObjectI[comm.design, icon, comm.pos]};
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];
[]𡤌oreOps.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]};
LayoutStructureAndDrcCheckOfSelectedIcons: PROC [comm: CDSequencer.Command] = {
count: INT ← 0;
drcErrors: INT ← 0;
errs: INT ← 0;
result: REF;
badguys: LIST OF ROPE;
objName: ROPE;
errorMsg: ROPE;
errorType: ATOM;
sourceCT: Core.CellType;
indirectOb: CD.Object;
directOb: CD.Object;
directCT: Core.CellType;
drcAtomDesign: ATOM ← DesignRules.FetchRulesID[comm.design];
drcAtom: ATOM ← IF drcAtomDesign#NIL THEN drcAtomDesign ELSE $VTI;
rules: DesignRules.Rules ← DesignRules.GetRuleSet[drcAtom];
tech: Drc.Tech ← DrcCMOSB.NewTechnology[DrcCMOSB.cMosBcompleteKey, rules];
IF comm.design.actual.rest#NIL THEN
{TerminalIO.PutF["Can't handle pushed in cell\n"]; RETURN};
TerminalIO.PutF["Using %g design rules\n", IO.atom[drcAtom]];
FOR w: CD.InstanceList ← CDOps.InstList[comm.design], w.rest WHILE w#NIL DO
IF NOT w.first.selected THEN LOOP;
objName ← CDDirectory.Name[w.first.ob, comm.design];
IF Rope.Find[objName, ".icon"]=-1 THEN
{TerminalIO.PutF["%g is not an icon.\n", IO.rope[objName]]; LOOP};
result ← SinixOps.ExtractCDInstance[w.first, comm.design, Sisyph.mode].result;
IF result=NIL OR NOT ISTYPE[result, Core.CellType] THEN
{TerminalIO.PutF["%g does not extract as a cell.\n", IO.rope[objName]]; LOOP};
sourceCT ← NARROW[result];
errorType ← NIL;
indirectOb ← PWCore.Layout[sourceCT !
PWCore.Error => {errorType ← type; errorMsg ← message; CONTINUE}];
IF errorType#NIL THEN {
TerminalIO.PutF["Cell for %g has Layout %g ERROR\n %g.\n",
IO.rope[objName], IO.atom[errorType], IO.rope[errorMsg]]; LOOP};
PWCoreLichen.Compare[sourceCT];
TerminalIO.PutF["Done extracting and comparing.\n"];
directOb ← CDDirectory.Expand1[indirectOb].new;
IF directOb=NIL THEN ERROR;
directCT ← NARROW[Sinix.Extract[directOb, PWCore.extractMode].result];
IF directCT=NIL THEN ERROR;
errs ← Drc.CheckDesignRules[directCT, CoreOps.CopyWire[directCT.public], tech, TRUE, NIL, PWCore.extractMode.decoration];
TerminalIO.PutF[" %2g errors in %g.\n", IO.int[errs],
IO.rope[CoreOps.GetCellTypeName[directCT]]];
IF errs#0 THEN {
[]ug.Draw[directOb, comm.design.technology, objName];
badguys ← CONS[objName, badguys]};
drcErrors ← drcErrors+errs;
count ← count+1;
ENDLOOP;
TerminalIO.PutF["%2g drc errors in %g cells.\n", IO.int[drcErrors], IO.int[count]];
FOR badguys ← badguys, badguys.rest WHILE badguys#NIL DO
TerminalIO.PutF[" %g\n", IO.rope[badguys.first]]; ENDLOOP};