LichenChecking.Mesa
Last tweaked by Mike Spreitzer on April 17, 1989 11:25:21 am PDT
DIRECTORY AbSets, BiRels, Histograms, HistogramsViewing, HistogramsViewingExtras, IntStuff, LichenDataOps, LichenDataStructure, LichenIntBasics, Process, Real, RealFns, Rope, SetBasics;
LichenChecking:
CEDAR
PROGRAM
IMPORTS AbSets, BiRels, Histograms, HistogramsViewing, HistogramsViewingExtras, IntStuff, LichenDataStructure, LichenIntBasics, Process, Real, RealFns, Rope, SetBasics
EXPORTS LichenDataOps
=
BEGIN OPEN IS:IntStuff, LichenIntBasics, LichenDataOps, LichenDataStructure, Sets:AbSets;
Histogram: TYPE ~ Histograms.Histogram;
Viewer: TYPE ~ HistogramsViewing.Viewer;
CheckDesign:
PUBLIC
PROC [d: Design] = {
CheckSubscript:
PROC [pair: BiRels.Pair]
RETURNS [
BOOL] ~ {
pw: PW ~ pair[left].VA;
class: PWClass ~ ClassOfPart[pw];
cct: CellType ~ NARROW[d.cct[class].ApplyA[pw].MA];
kids: Seq--of PW-- ~ BiRels.VB[pair[right]];
CheckKid:
PROC [pair: BiRels.Pair]
RETURNS [
BOOL] ~ {
index: INT ~ pair[left].VI;
kid: PW ~ pair[right].VA;
IF class # ClassOfPart[kid] THEN Error["Broken"];
IF d.cct[class].ApplyA[kid].MA # cct THEN Error["Broken"];
IF NOT d.parent.HasAA[kid, pw] THEN Error["Broken"];
RETURN [FALSE]};
IF kids.Scan[CheckKid].found THEN ERROR;
RETURN [FALSE]};
CheckParent:
PROC [pair: BiRels.Pair]
RETURNS [
BOOL] ~ {
kid: Sets.Value ~ pair[left];
parent: Sets.Value ~ pair[right];
kids: Seq--of PW-- ~ BiRels.VB[d.sub.Apply[parent].Val];
IF NOT kids.HasMapping[kid, rightToLeft] THEN Error["Broken"];
RETURN [FALSE]};
CheckCIType:
PROC [pair: BiRels.Pair]
RETURNS [
BOOL] ~ {
ci: CellInstance ~ NARROW[pair[left].VA];
ct: CellType ~ NARROW[pair[right].VA];
IF NOT (d.cellTypes.HasMemA[ct] AND d.partses[i].HasMemA[ci]) THEN ERROR Error["Broken"];
RETURN [FALSE]};
CheckCTName:
PROC [pair: BiRels.Pair]
RETURNS [
BOOL] ~ {
ct: CellType ~ NARROW[pair[left].VA];
name: ROPE ~ NARROW[pair[right].VA];
IF NOT d.cellTypes.HasMemA[ct] THEN ERROR Error["Broken"];
RETURN [FALSE]};
CheckArrayElt:
PROC [pair: BiRels.Pair]
RETURNS [
BOOL] ~ {
act: CellType ~ NARROW[pair[left].VA];
ect: CellType ~ NARROW[pair[left].VA];
IF NOT (d.cellTypes.HasMemA[act] AND d.cellTypes.HasMemA[ect]) THEN ERROR Error["Broken"];
IF act.asArray=NIL OR d.labelCellTypes.HasMemA[ect] THEN ERROR Error["Broken"];
RETURN [FALSE]};
CheckCIXfm:
PROC [pair: BiRels.Pair]
RETURNS [
BOOL] ~ {
ci: CellInstance ~ NARROW[pair[left].VA];
xfm: Transform ~ VXfm[pair[right]];
IF NOT d.partses[i].HasMemA[ci] THEN ERROR Error["Broken"];
RETURN [FALSE]};
PerCellType:
PROC [ctv: Sets.Value]
RETURNS [
BOOL] = {
ct: CellType ~ NARROW[ctv.VA];
IF ct.d # d THEN Error["Broken"];
CheckCellType[ct];
RETURN [FALSE]};
IF d.physd # (d.ciXfm#nilBiRel) OR d.physd # (d.scale#0.0) THEN ERROR Error["Broken"];
IF NOT d.labelCellTypes.Subset[d.cellTypes] THEN ERROR Error["Broken"];
IF NOT d.crossedCellTypes.Subset[d.cellTypes] THEN ERROR Error["Broken"];
IF d.sub.Scan[CheckSubscript].found THEN ERROR;
Process.CheckForAbort[];
IF d.parent.Scan[CheckParent].found THEN ERROR;
Process.CheckForAbort[];
FOR pc: PartClass
IN PartClass
DO
CheckCCT:
PROC [pair: BiRels.Pair]
RETURNS [
BOOL] ~ {
part: Part ~ NARROW[pair[left].VA];
cct: CellType ~ NARROW[pair[right].VA];
IF ClassOfPart[part]#pc OR NOT d.cellTypes.HasMemA[cct] THEN ERROR Error["Broken"];
IF pc=i
THEN {
IF NOT d.ciType.HasMapping[pair[left]] THEN ERROR Error["Broken"];
IF d.physd AND NOT d.ciXfm.HasMapping[pair[left]] THEN ERROR Error["Broken"]};
RETURN [FALSE]};
IF d.cct[pc].Scan[CheckCCT].found THEN ERROR;
Process.CheckForAbort[];
ENDLOOP;
IF d.ciType.Scan[CheckCIType].found THEN ERROR;
Process.CheckForAbort[];
IF d.ctName.Scan[CheckCTName].found THEN ERROR;
Process.CheckForAbort[];
IF d.arrayElt.Scan[CheckArrayElt].found THEN ERROR;
Process.CheckForAbort[];
IF d.physd AND d.ciXfm.Scan[CheckCIXfm].found THEN ERROR;
Process.CheckForAbort[];
IF d.cellTypes.Scan[PerCellType].found THEN ERROR;
Process.CheckForAbort[];
RETURN};
CheckCellType:
PROC [ct: CellType] = {
d: Design ~ ct.d;
unorg: BOOL ~ ct.asu # NIL;
isarray: BOOL ~ ct.asArray # NIL;
IF NOT d.cellTypes.HasMemA[ct] THEN Error["Broken"];
IF (ct.asArray#NIL) # d.arrayElt.HasMapA[ct] THEN Error["Broken"];
IF d.physd # (ct.bbox # fullRange2) THEN Error["Broken"];
FOR pc: PartClass
IN PartClass
DO
CheckFullName:
PROC [pair: BiRels.Pair]
RETURNS [
BOOL] ~ {
part: Part ~ pair[left].VA;
IF NOT d.cct[pc].HasAA[part, ct] THEN ERROR;
RETURN [FALSE]};
IF (ct.fullName[pc]#nilBiRel) # (pc=p OR unorg) THEN Error["Broken"];
IF ct.fullName[pc]#nilBiRel AND ct.fullName[pc].Scan[CheckFullName].found THEN ERROR;
Process.CheckForAbort[];
ENDLOOP;
IF unorg
THEN {
CheckConns:
PROC [c: Cell, conns: Fn
--port
b Wire--, ports: Set
--of Port--] ~ {
CheckCConn:
PROC [pair: BiRels.Pair]
RETURNS [
BOOL] ~ {
p: Port ~ NARROW[pair[left].VA];
w: Wire ~ NARROW[pair[right].VA];
IF NOT w.conns.HasAA[p, c] THEN ERROR;
RETURN [FALSE]};
IF ports.ScanIntersection[LIST[d.isAtomic, conns.SetOn[left].Negate]].found THEN Error["Broken"];
IF conns.Scan[CheckCConn].found THEN ERROR;
RETURN};
CheckSubcell:
PROC [ra:
REF
ANY] ~ {
ci: CellInstance ~ NARROW[ra];
ict: CellType ~ d.CiT[ci];
IF d.physd
THEN {
xfm: Transform ~ VXfm[d.ciXfm.ApplyA[ci].Val];
ibb: Range2 ~ TransOffRange2[xfm, ci.offset, ict.bbox];
IF NOT Range2Included[ibb, ct.bbox] THEN Error["Broken"]}
ELSE IF ci.offset # dullInt2 THEN Error["Broken"];
CheckConns[ci, ci.conns, ict.CTParts[p]];
RETURN};
CheckWire:
PROC [wv: Sets.Value]
RETURNS [
BOOL] ~ {
w: Wire ~ NARROW[wv.VA];
CheckWConn:
PROC [pair: BiRels.Pair]
RETURNS [
BOOL] ~ {
p: Port ~ NARROW[pair[left].VA];
WITH pair[right].
VA
SELECT
FROM
ci: CellInstance => IF NOT ci.conns.HasAA[p, w] THEN Error["Broken"];
t: CellType => {IF t#ct THEN Error["Broken"]; IF NOT ct.asu.exports.HasAA[p, w] THEN Error["Broken"]};
ENDCASE => ERROR;
RETURN [FALSE]};
IF w.conns.Scan[CheckWConn].found THEN ERROR;
RETURN [FALSE]};
ct.Subcells.EnumA[CheckSubcell];
Process.CheckForAbort[];
IF ct.CTParts[w].Scan[CheckWire].found THEN ERROR;
Process.CheckForAbort[];
CheckConns[ct, ct.asu.exports, ct.CTParts[p]];
Process.CheckForAbort[];
};
IF isarray
THEN {
a: Array ~ ct.asArray;
sr: StatRep ~ a.statrep;
dr: DumRep ~ a.dumrep;
ect: CellType ~ ct.EltType;
arrayPorts: Set ~ ct.CTParts[p];
eltPorts: Set ~ ect.CTParts[p];
phaseRange: Range2 ~ SizeRange[a.basePeriod];
aiRange: Range2 ~ SizeRange[a.size2];
CheckStatEdge:
PROC [sev: Sets.Value]
RETURNS [
BOOL] ~ {
se: StatEdge ~ NARROW[sev.VA];
svA: StatVertex ~ se.SeRSv[sr, FALSE];
svB: StatVertex ~ se.SeRSv[sr, TRUE];
IF NOT (sr.portEdge[FALSE].HasAA[svA.port, se] AND sr.portEdge[TRUE].HasAA[svB.port, se]) THEN Error["Broken"];
IF NOT InRange[svA.phase, phaseRange] THEN Error["Broken"];
IF svB.phase # AddMod[svA.phase, se.d, a.basePeriod] THEN Error["Broken"];
RETURN [FALSE]};
CheckExport:
PROC [pair: BiRels.Pair]
RETURNS [
BOOL] ~ {
ap: Port ~ NARROW[pair[left].VA];
pai: PortAtIndex ~ VPai[pair[right]];
IF NOT (arrayPorts.HasMemA[ap] AND eltPorts.HasMemA[pai.port]) THEN Error["Broken"];
IF NOT InRange[pai.ai, aiRange] THEN Error["Broken"];
RETURN [FALSE]};
CheckDumbWire:
PROC [dwv: Sets.Value]
RETURNS [
BOOL] ~ {
dw: DumbWire ~ NARROW[dwv.VA];
CheckEps:
PROC [pair: BiRels.Pair]
RETURNS [
BOOL] ~ {
ep: Port ~ NARROW[pair[left].VA];
cai: CompositeArrayIndex ~ pair[right].VI;
dws: Fn ~ BiRels.VB[dr.epToWire.ApplyA[ep].Val];
IF cai >= a.size THEN ERROR;
IF NOT dws.HasIA[cai, dw] THEN Error["Broken"];
RETURN [FALSE]};
IF dw.eps.Scan[CheckEps].found THEN ERROR;
RETURN [FALSE]};
CheckDWS:
PROC [pair: BiRels.Pair]
RETURNS [
BOOL] ~ {
ep: Port ~ NARROW[pair[left].VA];
dws: Fn ~ BiRels.VB[pair[right]];
CheckIndex:
PROC [pair: BiRels.Pair]
RETURNS [
BOOL] ~ {
cai: CompositeArrayIndex ~ pair[left].VI;
dw: DumbWire ~ NARROW[pair[right].VA];
IF NOT dw.eps.HasPair[[AV[ep], IV[cai]]] THEN Error["Broken"];
RETURN [FALSE]};
IF dws.SetOn[right].Difference[dr.wires].NonEmpty THEN Error["Broken"];
IF dws.Scan[CheckIndex].found THEN ERROR;
RETURN [FALSE]};
IF a.size # Area[a.size2] THEN Error["Broken"];
FOR dim: Dim2
IN Dim2
DO
IF a.basePeriod[dim] > a.size2[dim] THEN Error["Broken"];
ENDLOOP;
IF d.physd # (a.fXfm#nilBiRel) OR (a.fXfm#nilBiRel) # (a.offsets#NIL) THEN Error["Broken"];
IF a.buildPhase=statrepFixed AND a.dumrep=NIL THEN Error["Broken"];
IF sr.edges.Scan[CheckStatEdge].found THEN ERROR;
Process.CheckForAbort[];
FOR b:
BOOL
IN
BOOL
DO
IF sr.portEdge[b].SetOn[left].Difference[eltPorts].NonEmpty THEN Error["Broken"];
IF NOT sr.portEdge[b].SetOn[right].Equal[sr.edges] THEN Error["Broken"];
IF NOT sr.svEdge[b].SetOn[right].Equal[sr.edges] THEN Error["Broken"];
ENDLOOP;
IF sr.apToPAI.Scan[CheckExport].found THEN ERROR;
Process.CheckForAbort[];
IF a.buildPhase = statrepFixed
THEN {
IF dr.epToWire.SetOn[left].Difference[eltPorts].NonEmpty THEN Error["Broken"];
IF dr.apToWire.SetOn[left].Difference[arrayPorts].NonEmpty THEN Error["Broken"];
IF dr.apToWire.SetOn[right].Difference[dr.wires].NonEmpty THEN Error["Broken"];
IF dr.wires.Scan[CheckDumbWire].found THEN ERROR;
IF dr.epToWire.Scan[CheckDWS].found THEN ERROR;
};
};
RETURN};
base2: REAL ← RealFns.Power[base: 2.0, exponent: 0.25];
offset2: REAL ← RealFns.Power[base: base2, exponent: Real.Round[RealFns.Log[base: base2, arg: 0.1]]];
Status: TYPE ~ RECORD [i, n: INT ← 0, path, type: ROPE ← NIL];
status: REF Status ← NEW [Status ← []];
Hists: TYPE ~ RECORD [sizeCorr, combSize, wireSize, instSize: HV];
HV: TYPE ~ RECORD [h: Histogram, v: Viewer];
CountDesign:
PROC [d: Design, histPrefix:
ROPE, root: CellType ←
NIL]
RETURNS [cmpCellTypes, atmCellTypes, cellInstances, totWires, pubAtmWires, pvtAtmWires, pubCmpWires, pvtCmpWires, exblCmpWires, stuckWires, arrayFudge, atmPorts, cmpPorts, tNames, iNames, wNames, pNames:
INT ← 0, hists: Hists] ~ {
counted: Set ~ Sets.CreateHashSet[d.eSpace];
unorgUse: BiRel--parent CT child CT-- ~ d.cct[i].Invert.Compose[d.ciType, ALL[TRUE]];
CountCellType:
PROC [ctv: Sets.Value]
RETURNS [
BOOL] ~ {
IF NOT counted.AddElt[ctv] THEN RETURN [FALSE];
IF unorgUse.ScanMapping[ctv, CountCellType].found THEN ERROR;
IF d.arrayElt.ScanMapping[ctv, CountCellType].found THEN ERROR;
{ct: CellType ~ NARROW[ctv.VA];
ports: Set ~ ct.CTParts[p];
cmp: BOOL ~ ct.asu#NIL OR ct.asArray#NIL;
oldInsts: INT ~ cellInstances;
oldWires: INT ~ totWires;
IF cmp THEN cmpCellTypes ← cmpCellTypes + 1 ELSE atmCellTypes ← atmCellTypes + 1;
pNames ← pNames + ct.fullName[p].Size.EN;
IF ct.asu#
NIL
THEN {
wires: Set ~ ct.CTParts[w];
atmWires: Set ~ wires.Intersection[d.isAtomic];
cmpWires: Set ~ wires.Intersection[d.isComposite];
nonPubs: Set ~ ct.asu.notPublics;
pvts: Set ~ wires.Difference[d.ancest.Image[ct.asu.publics]].CreateHashCopy;
exCands: Set ~ nonPubs.Difference[pvts].CreateHashCopy;
pvtAtms: Set ~ nonPubs.Intersection[d.isAtomic];
pvtCmps: Set ~ pvts.Difference[atmWires];
troubled: Set ~ ct.asu.troubled.CreateHashCopy;
cellInstances ← cellInstances + ct.CTParts[i].Size.EN;
pubAtmWires ← pubAtmWires + atmWires.Intersection[ct.asu.publics].Size.EN;
pvtAtmWires ← pvtAtmWires + atmWires.Intersection[pvts].Size.EN;
pubCmpWires ← pubCmpWires + cmpWires.Intersection[ct.asu.publics].Size.EN;
pvtCmpWires ← pvtCmpWires + pvtCmps.Size.EN;
exblCmpWires ← exblCmpWires + exCands.Difference[troubled].Size.EN;
stuckWires ← stuckWires + exCands.Intersection[troubled].Size.EN;
totWires ← totWires + wires.Size.EN;
IF totWires # pubAtmWires + pvtAtmWires + pubCmpWires + pvtCmpWires + exblCmpWires + stuckWires THEN ERROR;
iNames ← iNames + ct.fullName[i].Size.EN;
wNames ← wNames + ct.fullName[w].Size.EN;
}
ELSE
IF ct.asArray#
NIL
THEN {
a: Array ~ ct.asArray;
ect: CellType ~ ct.EltType[];
epa: Set ~ ect.CTParts[p].Intersection[d.isAtomic];
dr: DumRep ~ a.dumrep;
cmpWires: Set ~ dr.dwParent.Image[dr.wires].CreateHashCopy;
someAtmWires: Set ~ dr.wires.Difference[cmpWires].CreateHashCopy;
pubWires: Set ~ dr.apToWire.SetOn[right];
somePvtAtmWires: Set ~ someAtmWires.Difference[pubWires];
pvtParents: Set ~ dr.dwParent.Image[somePvtAtmWires].CreateHashCopy;
pubParents: Set ~ dr.dwParent.Image[pubWires].CreateHashCopy;
ecTot: INT ~ epa.Size.EN * a.size;
ecSum: INT ← 0;
SumEC:
PROC [dwv: Sets.Value]
RETURNS [
BOOL] ~ {
dw: DumbWire ~ NARROW[dwv.VA];
IF dw.children=nilBiRel THEN ecSum ← ecSum + dw.eps.Size.EN;
RETURN [FALSE]};
IF dr.dwParent.ImageSize[cmpWires, leftToRight, IS.one]#IS.zero THEN ERROR;
IF pubParents.Difference[pubWires].NonEmpty THEN ERROR nyet--need to decide whether exportable or stuck--;
IF dr.wires.Scan[SumEC].found THEN ERROR;
IF ecSum > ecTot THEN ERROR;
{fudge: INT ~ ecTot - ecSum;
cellInstances ← cellInstances + a.size;
pubAtmWires ← pubAtmWires + someAtmWires.Intersection[pubWires].Size.EN;
pvtAtmWires ← pvtAtmWires + somePvtAtmWires.Size.EN + fudge;
pubCmpWires ← pubCmpWires + pubParents.Size.EN;
pvtCmpWires ← pvtCmpWires + pvtParents.Size.EN;
totWires ← totWires + dr.wires.Size.EN + fudge;
arrayFudge ← arrayFudge + fudge;
IF totWires # pubAtmWires + pvtAtmWires + pubCmpWires + pvtCmpWires + exblCmpWires + stuckWires THEN ERROR;
}}
atmPorts ← atmPorts + ports.Intersection[d.isAtomic].Size[].EN;
cmpPorts ← cmpPorts + ports.Intersection[d.isComposite].Size.EN;
status.i ← status.i + 1;
IF cmp
THEN {
di: INT ~ MAX[cellInstances - oldInsts, 1];
dw: INT ~ MAX[totWires - oldWires, 1];
hists.sizeCorr.h.ChangeTransformed[di, dw];
hists.combSize.h.ChangeTransformed[di+dw];
hists.wireSize.h.ChangeTransformed[dw];
hists.instSize.h.ChangeTransformed[di];
d ← d};
RETURN [FALSE]}};
tNames ← d.ctName.Size.EN;
status^ ← [n: d.cellTypes.Size.EN];
hists.sizeCorr.h ← Histograms.Create2D[iFactor: base2, jFactor: base2, iOffset: offset2, jOffset: offset2, logI: TRUE, logJ: TRUE];
hists.combSize.h ← Histograms.Create1D[factor: 5];
hists.wireSize.h ← Histograms.Create1D[factor: 5];
hists.instSize.h ← Histograms.Create1D[factor: 5];
hists.sizeCorr.v ← HistogramsViewing.Show[h: hists.sizeCorr.h, viewerInit: [name: Rope.Cat[histPrefix, "sizeCorr"]], base: 2.0, updatePeriod: 15];
hists.combSize.v ← HistogramsViewing.Show[h: hists.combSize.h, viewerInit: [name: Rope.Cat[histPrefix, "combSize"]], base: 2.0, updatePeriod: 15];
hists.wireSize.v ← HistogramsViewing.Show[h: hists.wireSize.h, viewerInit: [name: Rope.Cat[histPrefix, "wireSize"]], base: 2.0, updatePeriod: 15];
hists.instSize.v ← HistogramsViewing.Show[h: hists.instSize.h, viewerInit: [name: Rope.Cat[histPrefix, "instSize"]], base: 2.0, updatePeriod: 15];
IF CountCellType[AV[IF root=NIL THEN d.root ELSE root]] THEN ERROR;
WriteHV[hists.sizeCorr]; WriteHV[hists.combSize];
WriteHV[hists.wireSize]; WriteHV[hists.instSize];
RETURN};
WriteHV:
PROC [hv:
HV] ~ {
IF NOT hv.v.destroyed THEN HistogramsViewingExtras.ViewerWriteToFile[hv.v, hv.v.name.Cat[".hist"]];
RETURN};
anonymous: Sets.Value ~ SnV[OSn[R["?"]]];
FlatCount:
PROC [d: Design, start: CellType ←
NIL]
RETURNS [cmpCellTypes, atmCellTypes, cellInstances, atmWires, cmpWires:
INT ← 0] ~ {
cmpCTS: Set ~ d.cct[w].SetOn[right] .Union[d.cct[i].SetOn[right]] .Union[d.arrayElt.SetOn[left]] .CreateHashCopy;
atmCTS: Set ~ d.cellTypes.Difference[cmpCTS].CreateHashCopy[];
cmpInsts: Set ~ d.ciType.Image[cmpCTS, rightToLeft];
Work:
PROC [ct: CellType, n:
NATURAL, root:
BOOL, path:
ROPE] ~ {
status.path ← path;
status.type ← ct.ACtName[];
IF ct.asu#
NIL
THEN {
subcells: Set ~ ct.CTParts[i];
cmpSubs: Set ~ subcells.Intersection[cmpInsts];
defWires: Set ~ ct.CTParts[w];
intros: Set ~ IF NOT root THEN defWires.Difference[d.ancest.Image[ct.asu.publics]].CreateHashCopy ELSE defWires;
p1: ROPE ~ path.Concat["/"];
PerSub:
PROC [civ: Sets.Value]
RETURNS [
BOOL] ~ {
ci: CellInstance ~ NARROW[civ.VA];
ict: CellType ~ d.CiT[ci];
step: ROPE ~ UnparseSteppyName[VSn[ct.fullName[i].Lookup[goal: civ, side: left].DVal[anonymous]]];
Work[ict, n, FALSE, p1.Concat[step]];
RETURN [FALSE]};
cellInstances ← cellInstances + n*(subcells.Size.EN - cmpSubs.Size.EN);
atmWires ← atmWires + n*intros.Intersection[d.isAtomic].Size.EN;
cmpWires ← cmpWires + n*intros.Intersection[d.isComposite].Size.EN;
IF cmpSubs.Scan[PerSub].found THEN ERROR;
ct ← ct}
ELSE
IF ct.asArray#
NIL
THEN {
a: Array ~ ct.asArray;
ect: CellType ~ ct.EltType;
subn: NATURAL ~ INT[n]*a.size;
IF cmpCTS.HasMemA[ect] THEN Work[ect, subn, FALSE, path.Concat["/0"]] ELSE cellInstances ← cellInstances + subn;
ct ← ct}
ELSE ERROR;
};
IF start=NIL THEN start ← d.root;
IF NOT d.cellTypes.HasMemA[start] THEN ERROR;
cmpCellTypes ← cmpCTS.Size.EN;
atmCellTypes ← atmCTS.Size.EN;
Work[start, 1, TRUE, ""];
RETURN};
END.