IFUPWContStaticPLA:
CEDAR
PROGRAM
IMPORTS CD, CDFrame, CDPinObjects, IFUPWControl, IO, PLAOps, PW, PWPins, REFBit, Rope
EXPORTS IFUPWControl =
BEGIN
MakeStaticPLASection:
PUBLIC
PROC
[desc: IFUPWControl.PLADescription] = {
log.PutF["\n Make Static PLA Section %g", IO.rope[desc.drFrame.shell.name]];
GetOuts [desc];
GetBins [desc];
MakePla [desc];
MakeOutDrs [desc]};
SDesc: TYPE = RECORD[bins: REF Bins, outs: REF Outs];
Use: TYPE = RECORD[cols, wt: INT, seq: SEQUENCE size: CARDINAL OF BOOL];
SSInt: TYPE = RECORD[ seq: SEQUENCE size: CARDINAL OF REF SInt];
SInt: TYPE = RECORD[ seq: SEQUENCE size: CARDINAL OF INT];
Bins: TYPE = RECORD[ seq: SEQUENCE size: CARDINAL OF REF Use];
Outs: TYPE = RECORD[ttt: PLAOps.PLA, seq: SEQUENCE size: CARDINAL OF REF OUse];
OUse: TYPE = RECORD[lv: INT, seq: SEQUENCE size: CARDINAL OF REF TermUse];
TermUse: TYPE = RECORD[term: PLAOps.Term, bin: INT, use: REF Use];
NewUse:
PROC[size:
INT]
RETURNS [use:
REF Use] = {use ←
NEW[Use[size]];
use.cols ← 0; use.wt ← 0; FOR bit: INT IN [0..size) DO use[bit] ← FALSE ENDLOOP};
NewSInt:
PROC[size:
INT, init:
INT ← 0]
RETURNS [seq:
REF SInt] =
{seq ← NEW[SInt[size]]; FOR ii: INT IN [0..size) DO seq[ii] ← init ENDLOOP};
NewSSInt:
PROC[size0, size1:
INT]
RETURNS [seq:
REF SSInt] = {
seq ← NEW[SSInt[size0]];
FOR ii: INT IN [0..size0) DO seq[ii] ← NewSInt[size1] ENDLOOP};
NewBins:
PROC[size0, size1:
INT]
RETURNS [seq:
REF Bins] = {
seq ← NEW[Bins[size0]];
FOR ii: INT IN [0..size0) DO seq[ii] ← NewUse[size1] ENDLOOP};
GetOuts:
PROC[desc: IFUPWControl.PLADescription]= {
sd: REF SDesc ← NEW[SDesc];
TListSeq: TYPE = RECORD[SEQUENCE size: CARDINAL OF PLAOps.TermList];
nofBins: INT ← desc.nofTermCols;
nofTerms: INT ← 0;
iFormat: REFBit.Format ← REFBit.Desc[desc.ttt.data].bitForm;
oFormat: REFBit.Format ← REFBit.Desc[desc.ttt.out].bitForm;
tListSeq: REF TListSeq ← NEW[TListSeq[oFormat.size] ];
sd.outs ← NEW[Outs[oFormat.size] ];
sd.outs.ttt ← desc.ttt;
desc.data ← sd;
IF desc.plaType=decoder THEN desc.nofOrCols ← 0;
FOR out:
INT
IN [0..desc.smlToBigOut.size)
DO
bigOut: INT ← desc.smlToBigOut[out];
tListSeq[out] ← PLAOps.CopyTermListForField[desc.ttt.termList, oFormat[bigOut].firstBit, 1];
[ ] ← PLAOps.ConvertTermListToCompleteSum[tListSeq[out], TRUE, TRUE, log];
[ ] ← PLAOps.FindAMinimalCover[tListSeq[out], 10, log];
nofTerms ← MAX[nofTerms, tListSeq[out].length];
ENDLOOP;
IF desc.plaType=decoder THEN desc.nofTermCols ← nofBins ← nofTerms;
FOR out:
INT
IN [0..desc.smlToBigOut.size)
DO
term: PLAOps.Term;
level: INT;
level ←
IF desc.plaType=decoder
THEN 0 ELSE (tListSeq[out].length+nofBins-2)/nofBins;
nofTerms ← IF level=0 THEN nofBins ELSE level*nofBins+1;
sd.outs[out] ← NEW[OUse[nofTerms]];
sd.outs[out].lv ← level; -- = number of rows to be ORed with top row
term ← tListSeq[out].begin;
FOR termIdx:
INT
IN [0..nofTerms)
DO
use: REF Use ← NEW[Use[iFormat.size]];
sd.outs[out][termIdx] ← NEW[TermUse ← [term, -1, use]];
use.wt ← 0;
FOR bit:
INT
IN [0..use.size)
DO
use[bit] ← desc.fullWidthTerms
OR
(term#NIL AND PLAOps.GetInQrt[term, iFormat[bit].firstBit]#dontcare);
IF use[bit] THEN use.wt ← use.wt + 1;
ENDLOOP;
IF term#NIL THEN term ← term.next;
ENDLOOP;
ENDLOOP };
GetBins:
PROC[desc: IFUPWControl.PLADescription]={
sd: REF SDesc ← NARROW[desc.data];
useSize: INT ← sd.outs[0][0].use.size;
nofBins: INT ← desc.nofTermCols;
sd.bins ← NewBins[nofBins, useSize];
FOR out:
INT
IN [0..sd.outs.size)
DO
nofTerms: INT ← sd.outs[out].size;
minTBins: REF SInt ← NewSInt[nofTerms];
curTBins: REF SInt ← NewSInt[nofTerms, -1];
minTotalWt: INT ← useSize*nofTerms+1;
Enum:
PROC[left, wt:
INT, termBins:
REF SInt] = {
tempUse: REF Use;
bin: INT ← (nofTerms-left) MOD nofBins;
IF wt >= minTotalWt THEN RETURN;
IF left=0
THEN {
FOR tt: INT IN [0..nofTerms) DO minTBins[tt] ← termBins[tt]; ENDLOOP;
minTotalWt ← wt; RETURN};
tempUse ← NewUse[useSize];
FOR sel:
INT
DECREASING
IN [0..left)
DO
cnt, term: INT ← 0;
cnt ← sel;
FOR term ← 0, term+1
DO
IF termBins[term]>=0 THEN LOOP; IF cnt=0 THEN EXIT; cnt ← cnt-1 ENDLOOP;
UseOr[sd.bins[bin], sd.bins[bin], tempUse];
UseOr[sd.outs[out][term].use, sd.bins[bin], sd.bins[bin]];
termBins[term] ← bin;
Enum[left-1, wt + sd.bins[bin].wt - tempUse.wt, termBins];
UseOr[tempUse, tempUse, sd.bins[bin]];
termBins[term] ← -1;
ENDLOOP};
IF desc.fullWidthTerms
THEN {
FOR term:
INT
IN [0..nofTerms)
DO sd.outs[out][term].bin ← term MOD nofBins ENDLOOP;
LOOP};
Enum[nofTerms, 0, curTBins];
FOR term:
INT
IN [0..nofTerms)
DO
UseOr[sd.outs[out][term].use, sd.bins[minTBins[term]], sd.bins[minTBins[term]]];
sd.outs[out][term].bin ← minTBins[term] ENDLOOP;
ENDLOOP;
FOR out:
INT
IN [0..sd.outs.size)
DO
-- sd.bins[bin].cols used to determine OR columns/bin
FOR bin:
INT
IN [0..nofBins)
DO
binCnt: INT ← 0;
IF desc.fullWidthTerms
THEN {
FOR bit: INT IN [0..useSize) DO sd.bins[bin][bit] ← TRUE ENDLOOP;
sd.bins[bin].wt ← useSize};
FOR level:
INT
IN [1..sd.outs[out].lv]
DO
IF GetTerm[sd.outs, out, level, bin]#NIL THEN binCnt ← binCnt + 1 ENDLOOP;
sd.bins[bin].cols ← MAX[sd.bins[bin].cols, binCnt, desc.nofOrCols] ENDLOOP;
ENDLOOP};
MakePla:
PROC[desc: IFUPWControl.PLADescription] = {
sd: REF SDesc ← NARROW[desc.data];
rowType: IFUPWControl.RowType ← header;
out: INT ← 0;
tileRows: REF StaticTiles ← GetStaticPLATiles[];
useSize: INT ← sd.bins[0].size;
index: INT ← 0;
iForm: REFBit.Format ← REFBit.Desc[sd.outs.ttt.data].bitForm;
tiles: REF StaticTileRow;
levelRng: INT;
nofOrTerms: REF SInt;
v: Variety ← IF desc.plaType=static THEN s ELSE d;
seg, row, sec: CD.Object ← NIL;
segList, rowList, secList, colList: PW.ListOb ← NIL;
DO
rowType ←
IF out = sd.outs.size
THEN header
ELSE IF rowType=header THEN footer
ELSE IF rowType=footer THEN conn
ELSE IF (out MOD desc.termsPerHeader) = 0 THEN header ELSE conn;
levelRng ← IF rowType = conn THEN sd.outs[out].lv ELSE 0; -- OR sub rows
tiles ← tileRows[rowType];
nofOrTerms ← NewSInt[sd.bins.size];
IF rowType = conn
THEN
FOR tt:
INT
IN [0..sd.outs[out].size)
DO
IF sd.outs[out][tt].term=NIL THEN LOOP;
nofOrTerms[sd.outs[out][tt].bin]←MIN[sd.outs[out].lv,nofOrTerms[sd.outs[out][tt].bin]+1];
ENDLOOP;
FOR level:
INT
IN [0..levelRng]
DO
init: BOOL ← FALSE;
rowList ← CONS[tiles[v][leftSide], NIL];
FOR bin:
INT
IN [0..sd.bins.size)
DO
term: PLAOps.Term;
IF level#0 THEN init ← FALSE;
term ← IF rowType = conn THEN GetTerm[sd.outs, out, level, bin] ELSE NIL;
IF nofOrTerms[bin] > sd.bins[bin].cols THEN ERROR;
FOR index
IN[0..useSize)
DO
IF NOT sd.bins[bin][index] THEN LOOP;
segList ←
CONS[
IF term=
NIL
THEN IF ~init THEN tiles[v][andFalse] ELSE tiles[v][andPass]
ELSE
SELECT PLAOps.GetInQrt[term, iForm[index].firstBit]
FROM
zero => IF ~init THEN tiles[v][andIfNot] ELSE tiles[v][andNot],
one => IF ~init THEN tiles[v][andIf] ELSE tiles[v][and],
ENDCASE => IF ~init THEN tiles[v][andTrue] ELSE tiles[v][andPass], segList];
init ← TRUE;
ENDLOOP;
FOR index ← 0, index+1
WHILE index < nofOrTerms[bin]
DO
segList ←
CONS[ tiles[v][
SELECT index+1
FROM
< level => orBlank,
= level => orConn,
> level => IF level=0 THEN or ELSE orPass,
ENDCASE => ERROR], segList]; ENDLOOP;
THROUGH [nofOrTerms[bin]..sd.bins[bin].cols)
DO segList ← CONS[ tiles[v][orBlank] , segList] ENDLOOP;
segList ←
CONS[ tiles[v][
IF level#0
THEN innerRt
ELSE
IF bin+1 < sd.bins.size
THEN innerPass
ELSE outerRt ], segList];
seg ← PW.AbutListX[desc.design, PW.Reverse[segList]];
segList ← NIL;
rowList ← CONS[ seg, rowList];
ENDLOOP;
row ← PW.AbutListX[desc.design, PW.Reverse[rowList]];
rowList ← NIL;
secList ← CONS[ row, secList];
ENDLOOP;
sec ← PW.AbutListY[desc.design, PW.Reverse[secList]];
secList ← NIL;
colList ← CONS[ sec, colList];
IF rowType=conn THEN out ← out+1 ELSE IF out = sd.outs.size THEN EXIT;
ENDLOOP;
desc.cell ← PW.AbutListY[desc.design, PW.Reverse[colList]];
ReNameInputPins[desc]};
MakeOutDrs:
PROC [desc: IFUPWControl.PLADescription] = {
SetNewOfCnt:
PROC
[drRowType: IFUPWControl.RowType, driver: REF IFUPWControl.DriveRec] = {
new[cnt] ← CDFrame.NewObjectFrame[
IFUPWControl.DriverCell[desc.plaType, drRowType, driver, desc.design]];
cnt ← cnt+1};
sd: REF SDesc ← NARROW[desc.data];
new: CDFrame.Frame;
cnt: INT ← 2;
FOR out:
INT
IN [0..sd.outs.size)
DO
IF out IN [1..sd.outs.size-1) AND (out MOD desc.termsPerHeader)=0 THEN cnt ← cnt+2;
cnt ← cnt + sd.outs[out].lv+1 ENDLOOP;
new ← CDFrame.NewFrame[cnt, y, desc.name.Cat["-OutDr"]];
cnt ← 0;
SetNewOfCnt[footer, NIL];
FOR out:
INT
IN [0..sd.outs.size)
DO
IF out
IN [1..sd.outs.size-1)
AND (out
MOD desc.termsPerHeader)=0
THEN
{SetNewOfCnt[header, NIL]; SetNewOfCnt[footer, NIL]};
FOR term:
INT
IN [0..sd.outs[out].lv]
DO
SetNewOfCnt[IF term=0 THEN conn ELSE blank, desc.connSeq[out].dr] ENDLOOP;
ENDLOOP;
SetNewOfCnt[header, NIL];
desc.drFrame ← new};
DeleteUnusedStaticInDrs:
PUBLIC
PROC
[desc: IFUPWControl.PLADescription, drs: CDFrame.Frame] = {
enum: CDFrame.EnumProc = {
IF tempUse[oldIdx]
THEN
{new[newIdx] ← frame; new[newIdx].father ← new; newIdx ← newIdx +1};
oldIdx ← oldIdx+1};
sd: REF SDesc ← NARROW[desc.data];
oldIdx: INT ← 0;
newIdx: INT ← 0;
useSize: INT ← sd.bins[0].size;
tempUse: REF Use ← NewUse[useSize];
new: CDFrame.Frame;
FOR bin: INT IN [0..sd.bins.size) DO UseOr[sd.bins[bin], tempUse, tempUse] ENDLOOP;
IF tempUse.wt=useSize THEN RETURN;
new ← NEW[CDFrame.FrameSeq[tempUse.wt]];
new.shell ← drs[1].shell;
new.data ← drs[1].data;
new.father ← drs[1].father;
new.xory ← drs[1].xory;
new.unordered ← drs[1].unordered;
new.orient ← drs[1].orient;
CDFrame.EnumFrameBotOnly[drs[1], enum];
drs[1] ← new};
UseOr:
PROC[useArg0, useArg1, useOr:
REF Use] = {
IF useArg0.size#useArg1.size OR useArg1.size#useOr.size THEN ERROR;
useOr.wt ← 0;
FOR bit:
INT
IN [0..useArg0.size)
DO
useOr[bit] ← useArg0[bit] OR useArg1[bit];
IF useOr[bit] THEN useOr.wt ← useOr.wt + 1;
ENDLOOP };
GetTerm:
PROC[outs:
REF Outs, out, level, bin:
INT]
RETURNS[term: PLAOps.Term] = {
found: INT ← 0;
FOR tt:
INT
IN [0..outs[out].size)
DO
IF outs[out][tt].bin#bin THEN LOOP;
found ← found+1;
term ← outs[out][tt].term;
IF found = level THEN RETURN[term];
ENDLOOP;
IF found=0 THEN ERROR; -- Just checking, term can be NIL but bin must be represented
IF level#0 THEN ERROR; -- level 0 => last term
IF outs[out].lv#0 AND bin#0 THEN RETURN[NIL];
RETURN[term]}; -- last term for level 0 when outs[out].lv=0 OR bin=0
ReNameInputPins:
PROC[desc: IFUPWControl.PLADescription] = {
sd: REF SDesc ← NARROW[desc.data];
SSRope: TYPE = RECORD[SEQUENCE size: CARDINAL OF REF SRope];
SRope: TYPE = RECORD[SEQUENCE size: CARDINAL OF IO.ROPE];
tiles: REF StaticTiles ← GetStaticPLATiles[];
format: REFBit.Format ← REFBit.Desc[sd.outs.ttt.data].bitForm;
inName: REF SSRope ← NEW[SSRope[sd.bins.size]];
inNameInv: REF SSRope ← NEW[SSRope[sd.bins.size]];
v: Variety ← IF desc.plaType=static THEN s ELSE d;
leftSize: INT ← CD.InterestSize[tiles[header][v][leftSide]].x;
andWidth: INT ← CD.InterestSize[tiles[header][v][and]].x;
orWidth: INT ← CD.InterestSize[tiles[header][v][or]].x;
innerSize: INT ← CD.InterestSize[tiles[header][v][innerRt]].x;
changeProc: PWPins.ChangePinProc ~ {
pos: INT ← leftSize;
oldRope: Rope.ROPE ← CDPinObjects.GetName[oldPin];
in0: BOOL ← Rope.Equal[oldRope, "in0"];
in1: BOOL ← Rope.Equal[oldRope, "in1"];
IF NOT(in0 OR in1) THEN RETURN[oldPin];
FOR bin:
INT
IN [0..sd.bins.size)
DO
index: INT ← (oldPin.location.x-pos)/andWidth;
IF index < inName[bin].size
THEN {
CDPinObjects.SetName[oldPin,
IF in1 THEN inNameInv[bin][index] ELSE inName[bin][index]];
RETURN[oldPin]};
pos ← pos + inName[bin].size*andWidth + sd.bins[bin].cols*orWidth + innerSize;
REPEAT FINISHED => ERROR ENDLOOP};
FOR bin:
INT
IN [0..sd.bins.size)
DO
list: LIST OF IO.ROPE ← desc.plaInNames;
in: INT ← 0;
inName[bin] ← NEW[SRope[sd.bins[bin].wt]];
inNameInv[bin] ← NEW[SRope[sd.bins[bin].wt]];
FOR bit:
INT
IN [0..sd.bins[bin].size)
DO
IF sd.bins[bin][bit]
THEN {
inName [bin][in] ← list.first;
inNameInv [bin][in] ← list.rest.first;
in ← in+1};
list ← list.rest.rest;
ENDLOOP;
ENDLOOP;
desc.cell ← PWPins.ChangePins[desc.design, desc.cell, changeProc];
PW.RenameObject[desc.design, desc.cell, desc.name]};
staticTileDesign: CD.Design;
staticTiles: REF StaticTiles;
StaticTiles: TYPE = ARRAY IFUPWControl.RowType OF REF StaticTileRow;
StaticTileRow: TYPE = ARRAY Variety OF StaticTileVar;
StaticTileVar: TYPE = ARRAY StaticTileType OF CD.Object;
Variety: TYPE = {s, d}; -- static or decode
StaticTileType : TYPE = {leftSide, andTrue, andFalse, andIf, andIfNot, and, andNot, andPass, or, orNot, orPass, orBlank, orConn, innerPass, innerRt, outerRt};
GetStaticPLATiles:
PROC
RETURNS [tiles:
REF StaticTiles ] = {
tDesign: CD.Design;
IF staticTiles#NIL THEN RETURN[staticTiles];
log.PutRope["\n Initialize static pla tiles"];
tDesign ← staticTileDesign ← PW.OpenDesign["IFUPWControl.dale"];
IF tDesign=
NIL
THEN
ERROR PW.Error[MissingDesign, "TileSet design not found or empty"];
tiles ← staticTiles ← NEW[StaticTiles];
FOR row: IFUPWControl.RowType
IN IFUPWControl.RowType
DO
tiles[row] ←NEW[StaticTileRow] ENDLOOP;
tiles [header][s][leftSide] ← PW.Get[design: tDesign, name: "SPlaHLeftSide" ];
tiles [header][s][andTrue] ←
tiles [header][s][andFalse] ←
tiles [header][s][andIf] ←
tiles [header][s][andIfNot] ←
tiles [header][s][and] ←
tiles [header][s][andNot] ←
tiles [header][s][andPass] ← PW.Get[design: tDesign, name: "SPlaHAnd" ];
tiles [header][s][or] ←
tiles [header][s][orNot] ←
tiles [header][s][orPass] ←
tiles [header][s][orBlank] ←
tiles [header][s][orConn] ← PW.Get[design: tDesign, name: "SPlaHOr" ];
tiles [header][s][innerPass] ←
tiles [header][s][innerRt] ←
tiles [header][s][outerRt] ← PW.Get[design: tDesign, name: "SPlaHOuterRt" ];
tiles [footer][s][leftSide] ← PW.FlipY[tDesign, tiles [header][s][leftSide]];
tiles [footer][s][andTrue] ←
tiles [footer][s][andFalse] ←
tiles [footer][s][andIf] ←
tiles [footer][s][andIfNot] ←
tiles [footer][s][and] ←
tiles [footer][s][andNot] ←
tiles [footer][s][andPass] ← PW.FlipY[tDesign, tiles [header][s][andPass]];
tiles [footer][s][or] ←
tiles [footer][s][orNot] ←
tiles [footer][s][orPass] ←
tiles [footer][s][orBlank] ←
tiles [footer][s][orConn] ← PW.FlipY[tDesign, tiles [header][s][orConn]];
tiles [footer][s][innerPass] ←
tiles [footer][s][innerRt] ←
tiles [footer][s][outerRt] ← PW.FlipY[tDesign, tiles [header][s][outerRt]];
tiles [conn][s][leftSide] ← PW.Get[design: tDesign, name: "SPlaLeftSide" ];
tiles [conn][s][andTrue] ← PW.Get[design: tDesign, name: "SPlaAndTrue" ];
tiles [conn][s][andFalse] ← PW.Get[design: tDesign, name: "SPlaAndFalse" ];
tiles [conn][s][andIf] ← PW.Get[design: tDesign, name: "SPlaAndIf" ];
tiles [conn][s][andIfNot] ← PW.Get[design: tDesign, name: "SPlaAndIfNot" ];
tiles [conn][s][and] ← PW.Get[design: tDesign, name: "SPlaAnd" ];
tiles [conn][s][andNot] ← PW.Get[design: tDesign, name: "SPlaAndNot" ];
tiles [conn][s][andPass] ← PW.Get[design: tDesign, name: "SPlaAndPass" ];
tiles [conn][s][or] ← PW.Get[design: tDesign, name: "SPlaOr" ];
tiles [conn][s][orNot] ← PW.Get[design: tDesign, name: "SPlaOrNot" ];
tiles [conn][s][orPass] ← PW.Get[design: tDesign, name: "SPlaOrPass" ];
tiles [conn][s][orBlank] ← PW.Get[design: tDesign, name: "SPlaOrBlank" ];
tiles [conn][s][orConn] ← PW.Get[design: tDesign, name: "SPlaOrConn" ];
tiles [conn][s][innerPass] ← PW.Get[design: tDesign, name: "SPlaInnerPass" ];
tiles [conn][s][innerRt] ← PW.Get[design: tDesign, name: "SPlaInnerRt" ];
tiles [conn][s][outerRt] ← PW.Get[design: tDesign, name: "SPlaOuterRt" ];
FOR type: StaticTileType
IN StaticTileType
DO
tiles[header] [d][type] ← tiles[header] [s][type];
tiles[footer] [d][type] ← tiles[footer] [s][type] ENDLOOP;
tiles [header][d][innerPass] ←
tiles [header][d][innerRt] ←
tiles [header][d][outerRt] ← PW.Get[design: tDesign, name: "DPlaHRt" ];
tiles [footer][d][innerPass] ←
tiles [footer][d][innerRt] ←
tiles [footer][d][outerRt] ← PW.FlipY[tDesign, tiles [header][d][outerRt]];
tiles [conn][d][leftSide] ← PW.Get[design: tDesign, name: "DPlaLeftSide" ];
tiles [conn][d][andTrue] ← PW.Get[design: tDesign, name: "DPlaAndTrue" ];
tiles [conn][d][andFalse] ← PW.Get[design: tDesign, name: "DPlaAndFalse" ];
tiles [conn][d][andIf] ← PW.Get[design: tDesign, name: "DPlaAndIf" ];
tiles [conn][d][andIfNot] ← PW.Get[design: tDesign, name: "DPlaAndIfNot" ];
tiles [conn][d][and] ← PW.Get[design: tDesign, name: "DPlaAnd" ];
tiles [conn][d][andNot] ← PW.Get[design: tDesign, name: "DPlaAndNot" ];
tiles [conn][d][andPass] ← PW.Get[design: tDesign, name: "DPlaAndPass" ];
tiles [conn][d][or] ←
tiles [conn][d][orNot] ←
tiles [conn][d][orPass] ←
tiles [conn][d][orBlank] ←
tiles [conn][d][orConn] ← tiles[conn][s][or];
tiles [conn][d][innerPass] ←
tiles [conn][d][innerRt] ←
tiles [conn][d][outerRt] ← PW.Get[design: tDesign, name: "DPlaRt" ];
};
log: IO.STREAM ← CDFrame.GetLog[];
END.