DIRECTORY Basics, BitOps, BrineIO, Convert, Core, CoreCreate, CoreIO, CoreOps, CoreProperties, RefTab, IO, RefText, Rope, Ports; PortsImpl: CEDAR PROGRAM IMPORTS Basics, BitOps, BrineIO, Convert, CoreIO, CoreOps, CoreProperties, RefTab, IO, RefText, Rope EXPORTS Ports = BEGIN OPEN Ports; levelTypeNames: PUBLIC ARRAY LevelType OF Core.ROPE _ [ "l", "ls", "b", "bs", "c", "lc", "q", "composite"]; levelNames: PUBLIC ARRAY Level OF Core.ROPE _ ["L", "H", "X"]; driveTypeNames: PUBLIC ARRAY DriveType OF Core.ROPE _ ["agg", "sep"]; driveNames: PUBLIC ARRAY Drive OF Core.ROPE _ [ "inspect", "e", "n", "cw", "cmw", "c", "cms", "cs", "f", "dw", "dmw", "d", "dms", "ds", "i"]; portTesterDriveAtom: ATOM _ CoreIO.RegisterProperty[prop: CoreProperties.RegisterProperty[prop: $PortTesterDrive, properties: CoreProperties.Props[[CoreProperties.propPrint, NEW[CoreProperties.PropPrintProc _ PortDataPrint]]]], write: PortDataWrite, read: PortDataRead]; portDataAtom: ATOM _ CoreIO.RegisterProperty[prop: CoreProperties.RegisterProperty[prop: $PortData, properties: CoreProperties.Props[[CoreProperties.propPrint, NEW[CoreProperties.PropPrintProc _ PortDataPrint]]]], write: PortDataWrite, read: PortDataRead]; PortDataPrint: CoreProperties.PropPrintProc = { portData: PortData _ NARROW[val]; CoreOps.PrintIndent[indent, to]; IO.PutF[to, "%g: ", IO.atom[prop]]; IF prop=portDataAtom THEN { IO.PutRope[to, levelTypeNames[portData.levelType]]; IO.PutRope[to, " "]; }; IO.PutRope[to, driveTypeNames[portData.driveType]]; SELECT portData.driveType FROM aggregate => { IO.PutRope[to, " "]; IO.PutRope[to, driveNames[portData.drive]]; }; separate => IF portData.drives#NIL THEN FOR i: NAT IN [0..portData.drives.size) DO IO.PutRope[to, " "]; IO.PutRope[to, driveNames[portData.drives[i]]]; ENDLOOP; ENDCASE => ERROR; }; PortDataWrite: CoreIO.PropWriteProc = { portData: PortData _ NARROW [value]; BrineIO.WriteID[stream, levelTypeNames[portData.levelType]]; BrineIO.WriteID[stream, driveTypeNames[portData.driveType]]; BrineIO.WriteID[stream, driveNames[portData.drive]]; IF portData.drives=NIL THEN BrineIO.WriteInt[stream, 0] ELSE { BrineIO.WriteInt[stream, portData.drives.size]; FOR i: NAT IN [0..portData.drives.size) DO BrineIO.WriteID[stream, driveNames[portData.drives[i]]]; ENDLOOP; }; }; PortDataRead: CoreIO.PropReadProc = { portData: PortData _ NEW[PortDataRec]; size: NAT; portData.levelType _ FindLevelType[BrineIO.ReadID[stream]]; portData.driveType _ FindDriveType[BrineIO.ReadID[stream]]; portData.drive _ FindDrive[BrineIO.ReadID[stream]]; size _ BrineIO.ReadInt[stream]; IF size>0 THEN { portData.drives _ NEW[DriveSequenceRec[size]]; FOR i: NAT IN [0..size) DO portData.drives[i] _ FindDrive[BrineIO.ReadID[stream]]; ENDLOOP; }; value _ portData; }; FindLevelType: PUBLIC PROC [levelTypeID: Core.ROPE] RETURNS [levelType: LevelType] = { FOR lev: LevelType IN LevelType DO IF Rope.Equal[levelTypeNames[lev], levelTypeID] THEN {levelType _ lev; EXIT}; REPEAT FINISHED => ERROR; ENDLOOP; }; FindLevel: PUBLIC PROC [levelID: Core.ROPE] RETURNS [level: Level] = { FOR lev: Level IN Level DO IF Rope.Equal[levelNames[lev], levelID] THEN {level _ lev; EXIT}; REPEAT FINISHED => ERROR; ENDLOOP; }; FindDriveType: PUBLIC PROC [driveTypeID: Core.ROPE] RETURNS [driveType: DriveType] = { FOR drv: DriveType IN DriveType DO IF Rope.Equal[driveTypeNames[drv], driveTypeID] THEN {driveType _ drv; EXIT}; REPEAT FINISHED => ERROR; ENDLOOP; }; FindDrive: PUBLIC PROC [driveID: Core.ROPE] RETURNS [drive: Drive] = { FOR drv: Drive IN Drive DO IF Rope.Equal[driveNames[drv], driveID] THEN {drive _ drv; EXIT}; REPEAT FINISHED => ERROR; ENDLOOP; }; CreatePort: PUBLIC PROC [cellType: Core.CellType, testerPort: BOOL _ FALSE] RETURNS [port: Port] = { wireTab: RefTab.Ref _ RefTab.Create[]; -- wire to port portAssignment: RefTab.Ref _ RefTab.Create[]; -- wire to port MakePort: PUBLIC PROC [wire: Core.Wire] RETURNS [port: Port] = { IF (port _ NARROW[RefTab.Fetch[x: wireTab, key: wire].val])=NIL THEN { data: PortData _ NARROW[CoreProperties.InheritPublicProp[cellType: cellType, from: wire, prop: portDataAtom]]; levelType: LevelType _ WirePortType[cellType, wire].levelType; IF levelType=composite THEN { port _ NEW[PortRec[wire.size]]; FOR sub: NAT IN [0..wire.size) DO port[sub] _ MakePort[wire: wire[sub]]; ENDLOOP; } ELSE { port _ NEW[PortRec[0]]; port.levelType _ levelType; SELECT levelType FROM ls => { port.ls _ NEW[LevelSequenceRec[CoreOps.WireBits[wire]]]; FOR bit: NAT IN [0..port.ls.size) DO port.ls[bit] _ L; ENDLOOP; }; bs => { port.bs _ NEW[BoolSequenceRec[CoreOps.WireBits[wire]]]; FOR bit: NAT IN [0..port.bs.size) DO port.bs[bit] _ FALSE; ENDLOOP; }; c => port.fieldStart _ 16 - CoreOps.WireBits[wire]; lc => port.fieldStart _ 32 - CoreOps.WireBits[wire]; q => port.fieldStart _ 64 - CoreOps.WireBits[wire]; ENDCASE; IF testerPort THEN data _ NARROW[CoreProperties.InheritPublicProp[cellType: cellType, from: wire, prop: portTesterDriveAtom]]; IF data#NIL THEN SELECT data.driveType FROM aggregate => port.d _ data.drive; separate => { port.driveType _ separate; IF data.drives=NIL THEN { port.ds _ NEW[DriveSequenceRec[CoreOps.WireBits[wire]]]; FOR i: NAT IN [0..port.ds.size) DO port.ds[i] _ data.drive; ENDLOOP; } ELSE port.ds _ CopyDrives[data.drives]; SELECT levelType FROM ls => IF port.ds.size#port.ls.size THEN ERROR; bs => IF port.ds.size#port.bs.size THEN ERROR; c => IF port.ds.size#16 - port.fieldStart THEN ERROR; lc => IF port.ds.size#32 - port.fieldStart THEN ERROR; q => IF port.ds.size#64 - port.fieldStart THEN ERROR; ENDCASE; } ENDCASE => ERROR; AssignPort[wire, port]; }; IF NOT RefTab.Insert[x: wireTab, key: wire, val: port] THEN ERROR; }; }; AssignPort: PROC [wire: Core.Wire, port: Port] = { assigned: Port _ NARROW[RefTab.Fetch[x: portAssignment, key: wire].val]; IF assigned=NIL THEN {IF NOT RefTab.Insert[x: portAssignment, key: wire, val: port] THEN ERROR} ELSE IF assigned#port THEN ERROR; -- multiple ports represent one wire FOR i: CARDINAL IN [0..wire.size) DO AssignPort[wire[i], port]; ENDLOOP; }; FixupNewToOld[cellType]; -- sb nop for old style specification port _ MakePort[cellType.public]; }; RenewPort: PUBLIC PROC [cellType: Core.CellType, port: Port, testerPort: BOOL _ FALSE] = { ResetPort: EachWirePortPairProc = { data: PortData _ NARROW[CoreProperties.InheritPublicProp[cellType: cellType, from: wire, prop: IF testerPort THEN portTesterDriveAtom ELSE portDataAtom]]; IF port=NIL THEN RETURN; port.d _ none; IF data#NIL THEN SELECT data.driveType FROM aggregate => port.d _ data.drive; separate => IF data.drives=NIL THEN FOR i: NAT IN [0..port.ds.size) DO port.ds[i] _ data.drive; ENDLOOP ELSE FOR i: NAT IN [0..port.ds.size) DO port.ds[i] _ data.drives[i]; ENDLOOP; ENDCASE => ERROR; port.l _ L; port.b _ FALSE; IF port.ls#NIL THEN FOR i: NAT IN [0..port.ls.size) DO port.ls[i] _ L; ENDLOOP; IF port.bs#NIL THEN FOR i: NAT IN [0..port.bs.size) DO port.bs[i] _ FALSE; ENDLOOP; port.c _ BitOps.BitWordZero; port.lc _ BitOps.BitDWordZero; port.q _ BitOps.BitQWordZero }; [] _ VisitBinding[cellType.public, port, ResetPort]; }; WirePortType: PUBLIC PROC [cellType: Core.CellType, wire: Core.Wire] RETURNS [levelType: LevelType, driveType: DriveType] = { data: PortData _ NIL; FixupNewToOld[cellType]; -- sb nop for old style specification data _ NARROW[CoreProperties.InheritPublicProp[cellType: cellType, from: wire, prop: portDataAtom]]; levelType _ IF data=NIL THEN IF wire.size=0 THEN b ELSE composite ELSE data.levelType; driveType _ IF data=NIL THEN aggregate ELSE data.driveType; }; PortLeaves: PUBLIC PROC [port: Port] RETURNS [leaves: CARDINAL] = { visited: RefTab.Ref _ RefTab.Create[]; CountLeaves: PROC [port: Port] RETURNS [leaves: CARDINAL _ 0] = { IF NOT RefTab.Fetch[x: visited, key: port].found THEN { IF NOT RefTab.Insert[x: visited, key: port, val: $Visited] THEN ERROR; IF port.size=0 THEN leaves _ 1 ELSE FOR sub: NAT IN [0..port.size) DO leaves _ leaves + CountLeaves[port[sub]]; ENDLOOP; }; }; leaves _ CountLeaves[port]; }; PortIndex: PUBLIC PROC [wire: Core.Wire, name: Core.ROPE] RETURNS [index: NAT] = { foo: INT _ CoreOps.GetWireIndex[wire, name]; IF foo=-1 THEN ERROR; -- not found index _ foo; }; PortIndexes: PUBLIC PROC [wire: Core.Wire, n0, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11: Core.ROPE _ NIL] RETURNS [i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11: NAT _ LAST[NAT]] ~ { IF n0#NIL THEN i0 _ PortIndex[wire, n0]; IF n1#NIL THEN i1 _ PortIndex[wire, n1]; IF n2#NIL THEN i2 _ PortIndex[wire, n2]; IF n3#NIL THEN i3 _ PortIndex[wire, n3]; IF n4#NIL THEN i4 _ PortIndex[wire, n4]; IF n5#NIL THEN i5 _ PortIndex[wire, n5]; IF n6#NIL THEN i6 _ PortIndex[wire, n6]; IF n7#NIL THEN i7 _ PortIndex[wire, n7]; IF n8#NIL THEN i8 _ PortIndex[wire, n8]; IF n9#NIL THEN i9 _ PortIndex[wire, n9]; IF n10#NIL THEN i10 _ PortIndex[wire, n10]; IF n11#NIL THEN i11 _ PortIndex[wire, n11]; }; CopyPortValue: PUBLIC PROC [from: Port, to: Port] = { CopyBits: EachPortPairProc = { IF onePort.levelType#anotherPort.levelType OR onePort.driveType#anotherPort.driveType THEN ERROR; IF onePort.levelType#composite THEN { anotherPort.d _ onePort.d; IF onePort.ds#NIL THEN FOR i: NAT IN [0..onePort.ds.size) DO anotherPort.ds[i] _ onePort.ds[i]; ENDLOOP; SELECT onePort.levelType FROM l => anotherPort.l _ onePort.l; ls => { IF anotherPort.ls.size#onePort.ls.size THEN ERROR; FOR bit: NAT IN [0..onePort.ls.size) DO anotherPort.ls[bit] _ onePort.ls[bit]; ENDLOOP; }; b => anotherPort.b _ onePort.b; bs => { IF anotherPort.bs.size#onePort.bs.size THEN ERROR; FOR bit: NAT IN [0..onePort.bs.size) DO anotherPort.bs[bit] _ onePort.bs[bit]; ENDLOOP; }; c => anotherPort.c _ onePort.c; lc => anotherPort.lc _ onePort.lc; q => anotherPort.q _ onePort.q; ENDCASE => ERROR; }; }; IF VisitPortPair[from, to, CopyBits] THEN ERROR; }; CheckPortValueEqual: PUBLIC PROC[root: Core.Wire, truth: Port, question: Port] = { Equal: EachPortPairProc = { Complain: PROC = { SetErrorMessage: EachWirePortPairProc = { IF onePort=port THEN { quit _ TRUE; msg _ IO.PutFR["Port %g expected %g but has %g", IO.rope[CoreOps.GetFullWireName[root, wire]], IO.rope[PortRope[onePort]], IO.rope[PortRope[anotherPort]]]; IF onePort.ds#NIL THEN { msg _ Rope.Cat[msg, " with expect mask ",]; FOR i: NAT IN [0..onePort.ds.size) DO msg _ Rope.Cat[msg, driveNames[onePort.ds[i]]]; ENDLOOP; }; }; }; msg: Core.ROPE; IF NOT VisitBinding[root, truth, SetErrorMessage] THEN ERROR; SIGNAL CheckError[msg]; }; IF onePort.levelType=composite THEN RETURN; IF onePort.d#anotherPort.d THEN SIGNAL CheckError["Port drives do not match"]; SELECT onePort.levelType FROM l => IF anotherPort.l#onePort.l THEN Complain[]; ls => FOR bit: NAT IN [0..onePort.ls.size) DO IF anotherPort.ls[bit]#onePort.ls[bit] THEN Complain[]; ENDLOOP; b => IF anotherPort.b#onePort.b THEN Complain[]; bs => FOR bit: NAT IN [0..onePort.bs.size) DO IF anotherPort.bs[bit]#onePort.bs[bit] THEN Complain[]; ENDLOOP; c => IF anotherPort.c#onePort.c THEN Complain[]; lc => IF anotherPort.lc#onePort.lc THEN Complain[]; q => IF anotherPort.q#onePort.q THEN Complain[]; ENDCASE => ERROR; }; [] _ VisitPortPair[truth, question, Equal]; }; CheckPortValue: PUBLIC PROC [root: Core.Wire, truth: Port, question: Port] = { CheckBits: EachPortPairProc = { Complain: PROC = { SetErrorMessage: EachWirePortPairProc = { IF onePort=port THEN { quit _ TRUE; msg _ IO.PutFR["Port %g expected %g but has %g", IO.rope[CoreOps.GetFullWireName[root, wire]], IO.rope[PortRope[onePort]], IO.rope[PortRope[anotherPort]]]; IF onePort.ds#NIL THEN { msg _ Rope.Cat[msg, " with expect mask ",]; FOR i: NAT IN [0..onePort.ds.size) DO msg _ Rope.Cat[msg, driveNames[onePort.ds[i]]]; ENDLOOP; }; }; }; msg: Core.ROPE; IF NOT VisitBinding[root, truth, SetErrorMessage] THEN ERROR; SIGNAL CheckError[msg]; }; IF onePort.levelType#composite THEN SELECT onePort.driveType FROM aggregate => SELECT onePort.d FROM expect, force => SELECT onePort.levelType FROM l => IF anotherPort.l#onePort.l THEN Complain[]; ls => FOR bit: NAT IN [0..onePort.ls.size) DO IF anotherPort.ls[bit]#onePort.ls[bit] THEN Complain[]; ENDLOOP; b => IF anotherPort.b#onePort.b THEN Complain[]; bs => FOR bit: NAT IN [0..onePort.bs.size) DO IF anotherPort.bs[bit]#onePort.bs[bit] THEN Complain[]; ENDLOOP; c => IF anotherPort.c#onePort.c THEN Complain[]; lc => IF anotherPort.lc#onePort.lc THEN Complain[]; q => IF anotherPort.q#onePort.q THEN Complain[]; ENDCASE => ERROR; inspect => SELECT onePort.levelType FROM l => onePort.l _ anotherPort.l; ls => FOR bit: NAT IN [0..onePort.ls.size) DO onePort.ls[bit] _ anotherPort.ls[bit]; ENDLOOP; b => onePort.b _ anotherPort.b; bs => FOR bit: NAT IN [0..onePort.bs.size) DO onePort.bs[bit] _ anotherPort.bs[bit]; ENDLOOP; c => onePort.c _ anotherPort.c; lc => onePort.lc _ anotherPort.lc; q => onePort.q _ anotherPort.q; ENDCASE => ERROR; ENDCASE; separate => FOR i: NAT IN [0..onePort.ds.size) DO SELECT onePort.ds[i] FROM expect, force => SELECT onePort.levelType FROM ls => IF anotherPort.ls[i]#onePort.ls[i] THEN {Complain[]; EXIT}; bs => IF anotherPort.bs[i]#onePort.bs[i] THEN {Complain[]; EXIT}; c => IF BitOps.EBFW[anotherPort.c, i, 16-anotherPort.fieldStart]#BitOps.EBFW[onePort.c, i, 16-onePort.fieldStart] THEN {Complain[]; EXIT}; lc => IF BitOps.EBFD[anotherPort.lc, i, 32-anotherPort.fieldStart]#BitOps.EBFD[onePort.lc, i, 32-onePort.fieldStart] THEN {Complain[]; EXIT}; q => IF BitOps.EBFQ[anotherPort.q, i, 64-anotherPort.fieldStart]#BitOps.EBFQ[onePort.q, i, 64-onePort.fieldStart] THEN {Complain[]; EXIT}; ENDCASE => ERROR; inspect => SELECT onePort.levelType FROM ls => onePort.ls[i] _ anotherPort.ls[i]; bs => onePort.bs[i] _ anotherPort.bs[i]; c => onePort.c _ BitOps.IBIW[BitOps.EBFW[anotherPort.c, i, 16-anotherPort.fieldStart], onePort.c, i, 16-anotherPort.fieldStart]; lc => onePort.lc _ BitOps.IBID[BitOps.EBFD[anotherPort.lc, i, 32-anotherPort.fieldStart], onePort.lc, i, 32-anotherPort.fieldStart]; q => onePort.q _ BitOps.IBIQ[BitOps.EBFQ[anotherPort.q, i, 64-anotherPort.fieldStart], onePort.q, i, 64-anotherPort.fieldStart]; ENDCASE => ERROR; ENDCASE; ENDLOOP; ENDCASE => ERROR; }; IF VisitPortPair[truth, question, CheckBits] THEN ERROR; }; PortRope: PROC [port: Port] RETURNS [value: Core.ROPE _ NIL] = { SELECT port.levelType FROM l => value _ SELECT port.l FROM L => "0", X => "X", H => "1" ENDCASE => ERROR; ls => value _ LevelSequenceToRope[container: port.ls, size: port.ls.size]; b => value _ IF port.b THEN "1" ELSE "0"; bs => { FOR bit: NAT IN [0..port.bs.size) DO value _ Rope.Concat[value, IF port.bs[bit] THEN "1" ELSE "0"]; ENDLOOP; }; c => value _ Convert.RopeFromCard[from: port.c, base: 16]; lc => value _ Convert.RopeFromCard[from: port.lc, base: 16]; q => { ls: LevelSequence _ NEW[LevelSequenceRec[64-port.fieldStart]]; FOR i: NAT IN [0..ls.size) DO ls[i] _ IF BitOps.EBFQ[port.q, i, ls.size] THEN H ELSE L; ENDLOOP; value _ LevelSequenceToRope[container: ls, size: ls.size]; }; ENDCASE => ERROR; }; CheckError: PUBLIC SIGNAL [msg: Core.ROPE] = CODE; CopyDrives: PROC [old: DriveSequence] RETURNS [new: DriveSequence _ NIL] = { IF old#NIL THEN { new _ NEW[DriveSequenceRec[old.size]]; FOR i: NAT IN [0..new.size) DO new[i] _ old[i]; ENDLOOP }; }; InitPort: PUBLIC PROC [wire: Core.Wire, levelType: LevelType _ b, driveType: DriveType _ aggregate, initDrive: Drive _ none, initDrives: DriveSequence _ NIL] RETURNS [sameWire: Core.Wire] = { PutPortData[prop: portDataAtom, wire: wire, levelType: levelType, driveType: driveType, initDrive: initDrive, initDrives: initDrives]; sameWire _ wire; }; InitPorts: PUBLIC PROC [ct: Core.CellType, initType: LevelType _ l, initDrive: Drive _ none, n0, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10: CoreCreate.WR _ NIL] = { ports: LIST OF CoreCreate.WR _ NIL; IF n0#NIL THEN ports _ CONS[n0, ports]; IF n1#NIL THEN ports _ CONS[n1, ports]; IF n2#NIL THEN ports _ CONS[n2, ports]; IF n3#NIL THEN ports _ CONS[n3, ports]; IF n4#NIL THEN ports _ CONS[n4, ports]; IF n5#NIL THEN ports _ CONS[n5, ports]; IF n6#NIL THEN ports _ CONS[n6, ports]; IF n7#NIL THEN ports _ CONS[n7, ports]; IF n8#NIL THEN ports _ CONS[n8, ports]; IF n9#NIL THEN ports _ CONS[n9, ports]; IF n10#NIL THEN ports _ CONS[n10, ports]; InitPortList[ct, initType, initDrive, ports]; }; InitPortList: PUBLIC PROC [ct: Core.CellType, initType: LevelType _ l, initDrive: Drive _ none, ports: LIST OF CoreCreate.WR] = { InitP: PROC [ref: REF] = { wire: Core.Wire _ FindWire[ct.public, ref]; [] _ InitPort[wire: wire, levelType: initType, initDrive: initDrive]; }; FOR p: LIST OF CoreCreate.WR _ ports, p.rest UNTIL p=NIL DO InitP[p.first]; ENDLOOP; }; InitTesterDrive: PUBLIC PROC [wire: Core.Wire, initDrive: Drive _ none, initDrives: DriveSequence _ NIL] = { PutPortData[prop: portTesterDriveAtom, wire: wire, driveType: IF initDrives=NIL THEN aggregate ELSE separate, initDrive: initDrive, initDrives: initDrives] }; InitTesterDrives: PUBLIC PROC [ct: Core.CellType, initDrive: Drive _ none, n0, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10: CoreCreate.WR _ NIL] = { ports: LIST OF CoreCreate.WR _ NIL; IF n0#NIL THEN ports _ CONS[n0, ports]; IF n1#NIL THEN ports _ CONS[n1, ports]; IF n2#NIL THEN ports _ CONS[n2, ports]; IF n3#NIL THEN ports _ CONS[n3, ports]; IF n4#NIL THEN ports _ CONS[n4, ports]; IF n5#NIL THEN ports _ CONS[n5, ports]; IF n6#NIL THEN ports _ CONS[n6, ports]; IF n7#NIL THEN ports _ CONS[n7, ports]; IF n8#NIL THEN ports _ CONS[n8, ports]; IF n9#NIL THEN ports _ CONS[n9, ports]; IF n10#NIL THEN ports _ CONS[n10, ports]; InitTesterDriveList[ct, initDrive, ports]; }; InitTesterDriveList: PUBLIC PROC [ct: Core.CellType, initDrive: Drive _ none, ports: LIST OF CoreCreate.WR] = { InitP: PROC [ref: REF] = { wire: Core.Wire _ FindWire[ct.public, ref]; [] _ InitTesterDrive[wire: wire, initDrive: initDrive]; }; FOR p: LIST OF CoreCreate.WR _ ports, p.rest UNTIL p=NIL DO InitP[p.first]; ENDLOOP; }; PutPortData: PUBLIC PROC [prop: ATOM, wire: Core.Wire, levelType: LevelType _ b, driveType: DriveType _ aggregate, initDrive: Drive _ none, initDrives: DriveSequence _ NIL] = { CoreProperties.PutWireProp[on: wire, prop: prop, value: NEW[PortDataRec _ [ levelType: levelType, driveType: driveType, drive: initDrive, drives: CopyDrives[initDrives]]]]; }; ITDList: PUBLIC PROC [public: Core.Wire, indicies: LIST OF NAT, initDrive: Drive] ~ { FOR l: LIST OF NAT _ indicies, l.rest WHILE l#NIL DO [] _ InitTesterDrive[wire: public[l.first], initDrive: initDrive]; ENDLOOP; }; IPList: PUBLIC PROC [public: Core.Wire, indicies: LIST OF NAT, levelType: LevelType, initDrive: Drive _ none] ~ { FOR l: LIST OF NAT _ indicies, l.rest WHILE l#NIL DO [] _ InitPort[wire: public[l.first], levelType: levelType, initDrive: initDrive]; ENDLOOP; }; FindWire: PROC [iconPublic: Core.Wire, name: CoreCreate.WR] RETURNS [iconWire: Core.Wire _ NIL] ~ { n: NAT; IF ISTYPE[name, Core.Wire] THEN iconWire _ NARROW[name] ELSE { n _ CoreOps.GetWireIndex[iconPublic, CoreOps.FixStupidRef[name]]; -- dies if -1 returned! iconWire _ iconPublic[n]; }; }; portLevelTypeAtom: ATOM _ CoreIO.RegisterProperty[prop: $PortLevelType, write: PortLevelTypeWrite, read: PortLevelTypeRead]; SetPortLevelType: PUBLIC PROC [wire: Core.Wire, levelType: LevelType _ b] RETURNS [sameWire: Core.Wire] = { CoreProperties.PutWireProp[wire, portLevelTypeAtom, NEW[LevelType _ levelType]]; sameWire _ wire; }; PortLevelTypeWrite: CoreIO.PropWriteProc ~ { levelType: REF LevelType = NARROW[value]; BrineIO.WriteID[stream, levelTypeNames[levelType^]]; }; PortLevelTypeRead: CoreIO.PropReadProc ~ { value _ NEW [LevelType _ FindLevelType[BrineIO.ReadID[stream]]]; }; portDriveTypeAtom: ATOM _ CoreIO.RegisterProperty[prop: $PortDriveType, write: PortDriveTypeWrite, read: PortDriveTypeRead]; portTesterDriveTypeAtom: ATOM _ CoreIO.RegisterProperty[prop: $PortTesterDriveType, write: PortDriveTypeWrite, read: PortDriveTypeRead]; SetPortDriveType: PUBLIC PROC [wire: Core.Wire, driveType: DriveType _ aggregate] RETURNS [sameWire: Core.Wire] = { CoreProperties.PutWireProp[wire, portDriveTypeAtom, NEW[DriveType _ driveType]]; sameWire _ wire; }; SetPortTesterDriveType: PUBLIC PROC [wire: Core.Wire, driveType: DriveType _ aggregate] RETURNS [sameWire: Core.Wire] = { CoreProperties.PutWireProp[wire, portTesterDriveTypeAtom, NEW[DriveType _ driveType]]; sameWire _ wire; }; PortDriveTypeWrite: CoreIO.PropWriteProc ~ { driveType: REF DriveType _ NARROW[value]; BrineIO.WriteID[stream, driveTypeNames[driveType^]]; }; PortDriveTypeRead: CoreIO.PropReadProc ~ { value _ NEW [DriveType _ FindDriveType[BrineIO.ReadID[stream]]]; }; portDriveAtom: ATOM _ CoreIO.RegisterProperty[prop: $PortDrive, write: PortDriveWrite, read: PortDriveRead]; portNewTesterDriveAtom: ATOM _ CoreIO.RegisterProperty[prop: $PortNewTesterDrive, write: PortDriveWrite, read: PortDriveRead]; SetInitialPortDrive: PUBLIC PROC [wire: Core.Wire, initDrive: Drive _ none, initDrives: DriveSequence _ NIL] RETURNS [sameWire: Core.Wire] = { CoreProperties.PutWireProp[wire, portDriveAtom, IF initDrives=NIL THEN NEW[Drive _ initDrive] ELSE CopyDrives[initDrives]]; sameWire _ wire; }; SetInitialPortTesterDrive: PUBLIC PROC [wire: Core.Wire, initDrive: Drive _ none, initDrives: DriveSequence _ NIL] RETURNS [sameWire: Core.Wire] = { CoreProperties.PutWireProp[wire, portNewTesterDriveAtom, IF initDrives=NIL THEN NEW[Drive _ initDrive] ELSE CopyDrives[initDrives]]; sameWire _ wire; }; PortDriveWrite: CoreIO.PropWriteProc ~ { WITH value SELECT FROM drive: REF Drive => { BrineIO.WriteInt[stream, -1]; -- to indicate not a sequence ... BrineIO.WriteID[stream, driveNames[drive^]]; }; drives: REF DriveSequence => { BrineIO.WriteInt[stream, drives.size]; FOR i: NAT IN [0..drives.size) DO BrineIO.WriteID[stream, driveNames[drives[i]]]; ENDLOOP; }; ENDCASE => ERROR; -- should never happen !!! }; PortDriveRead: CoreIO.PropReadProc ~ { size: NAT _ BrineIO.ReadInt[stream]; IF size<0 THEN value _ NEW [Drive _ FindDrive[BrineIO.ReadID[stream]]] ELSE { -- drive sequence drives: DriveSequence _ NEW[DriveSequenceRec[size]]; FOR i: NAT IN [0..size) DO drives[i] _ FindDrive[BrineIO.ReadID[stream]]; ENDLOOP; value _ drives }; }; SetPorts: PUBLIC PROC [r: Core.Wire, n: LIST OF Rope.ROPE, lt: LevelType _ b, cdt: DriveType _ aggregate, cd: Drive _ none, cds: DriveSequence _ NIL, tdt: DriveType _ aggregate, td: Drive _ none, tds: DriveSequence _ NIL] = { FOR nl: LIST OF Rope.ROPE _ n, nl.rest UNTIL nl=NIL DO w: Core.Wire _ CoreOps.FindWire[r, nl.first]; IF lt#b THEN [] _ SetPortLevelType[w, lt]; IF cdt#aggregate THEN [] _ SetPortDriveType[w, cdt]; IF cd#none THEN [] _ SetInitialPortDrive[w, cd]; IF cds#NIL THEN [] _ SetInitialPortDrive[wire: w, initDrives: cds]; IF tdt#aggregate THEN [] _ SetPortTesterDriveType[w, tdt]; IF td#none THEN [] _ SetInitialPortTesterDrive[w, td]; IF tds#NIL THEN [] _ SetInitialPortTesterDrive[wire: w, initDrives: tds]; ENDLOOP; }; CoerceNewToOld: PUBLIC PROC [rootWire: Core.WireSeq] = { CallInitPort: CoreOps.EachWireProc = { refLevelType: REF ANY _ CoreProperties.GetWireProp[wire, portLevelTypeAtom]; refDriveType: REF ANY _ CoreProperties.GetWireProp[wire, portDriveTypeAtom]; refInitDrive: REF ANY _ CoreProperties.GetWireProp[wire, portDriveAtom]; refTesterDriveType: REF ANY _ CoreProperties.GetWireProp[wire, portTesterDriveTypeAtom]; refInitTesterDrive: REF ANY _ CoreProperties.GetWireProp[wire, portNewTesterDriveAtom]; IF refLevelType#NIL OR refDriveType#NIL OR refInitDrive#NIL THEN { levelType: LevelType _ IF refLevelType=NIL THEN b ELSE NARROW[refLevelType, REF LevelType]^; driveType: DriveType _ IF refDriveType=NIL THEN aggregate ELSE NARROW[refDriveType, REF DriveType]^; initDrive: Drive _ none; initDrives: DriveSequence _ NIL; IF refInitDrive#NIL THEN WITH refInitDrive SELECT FROM rd: REF Drive => initDrive _ rd^; rds: DriveSequence => initDrives _ rds; ENDCASE => ERROR; [] _ InitPort[wire, levelType, driveType, initDrive, initDrives]; }; IF refTesterDriveType#NIL OR refInitTesterDrive#NIL THEN { initTesterDrive: Drive _ none; initTesterDrives: DriveSequence _ NIL; IF refInitTesterDrive#NIL THEN WITH refInitTesterDrive SELECT FROM rd: REF Drive => initTesterDrive _ rd^; rds: DriveSequence => initTesterDrives _ rds; ENDCASE => ERROR; PutPortData[prop: portTesterDriveAtom, wire: wire, driveType: IF refTesterDriveType=NIL THEN IF initTesterDrives=NIL THEN aggregate ELSE separate ELSE NARROW[refTesterDriveType, REF DriveType]^, initDrive: initTesterDrive, initDrives: initTesterDrives] }; }; [] _ CoreOps.VisitWireSeq[rootWire, CallInitPort]; }; FixupNewToOld: PROC [cell: Core.CellType] ~ { CoerceNewToOld[cell.public]; WHILE cell.class.layersProps AND cell.class.recast#NIL DO cell _ CoreOps.Recast[cell]; CoerceNewToOld[cell.public]; ENDLOOP; }; BindPort: PUBLIC PROC [rootWire: Core.WireSeq, rootPort: Port, name: Rope.ROPE] RETURNS [p: Port] = { FindMatchingPort: EachWirePortPairProc = { IF findWire=wire THEN {p _ port; quit _ TRUE}; }; findWire: Core.Wire _ CoreOps.FindWire[rootWire, name]; IF NOT VisitBinding[rootWire, rootPort, FindMatchingPort] THEN ERROR; }; BindPorts: PUBLIC PROC [rootWire: Core.WireSeq, rootPort: Port, n0, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11: Rope.ROPE _ NIL] RETURNS [p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11: Port _ NIL] = { IF n0#NIL THEN p0 _ BindPort[rootWire, rootPort, n0]; IF n1#NIL THEN p1 _ BindPort[rootWire, rootPort, n1]; IF n2#NIL THEN p2 _ BindPort[rootWire, rootPort, n2]; IF n3#NIL THEN p3 _ BindPort[rootWire, rootPort, n3]; IF n4#NIL THEN p4 _ BindPort[rootWire, rootPort, n4]; IF n5#NIL THEN p5 _ BindPort[rootWire, rootPort, n5]; IF n6#NIL THEN p6 _ BindPort[rootWire, rootPort, n6]; IF n7#NIL THEN p7 _ BindPort[rootWire, rootPort, n7]; IF n8#NIL THEN p8 _ BindPort[rootWire, rootPort, n8]; IF n9#NIL THEN p9 _ BindPort[rootWire, rootPort, n9]; IF n10#NIL THEN p10 _ BindPort[rootWire, rootPort, n10]; IF n11#NIL THEN p11 _ BindPort[rootWire, rootPort, n11]; }; GetDrive, GD: PUBLIC PROC [p: Port] RETURNS [v: Drive] = { IF (p.ds=NIL AND p.driveType#aggregate) OR (p.ds#NIL AND p.ds.size>1) THEN ERROR; v _ IF p.ds=NIL THEN p.d ELSE p.ds[0]; }; PutDrive, PD: PUBLIC PROC [p: Port, v: Drive] = { IF (p.ds=NIL AND p.driveType#aggregate) OR (p.ds#NIL AND p.ds.size>1) THEN ERROR; IF p.ds=NIL THEN p.d _ v ELSE p.ds[0] _ v; }; GetDriveSequence, GDS: PUBLIC PROC [p: Port, i: NAT] RETURNS [v: Drive] = { IF p.driveType#separate THEN ERROR; v _ p.ds[i]; }; PutDriveSequence, PDS: PUBLIC PROC [p: Port, i: NAT, v: Drive] = { IF p.driveType#separate THEN ERROR; p.ds[i] _ v; }; SetDrive: PROC [p: Port, d: Drive] = { IF p.ds=NIL THEN p.d _ d ELSE FOR i: NAT IN [0..p.ds.size) DO p.ds[i] _ d; ENDLOOP; }; GetLevel, GL: PUBLIC PROC [p: Port] RETURNS [v: Level] = { IF (p.ls=NIL AND p.levelType#l) OR (p.ls#NIL AND p.ls.size>1) THEN ERROR; v _ IF p.ls=NIL THEN p.l ELSE p.ls[0]; }; PutLevel, PL: PUBLIC PROC [p: Port, v: Level, d: Drive _ drive] = { IF (p.ls=NIL AND p.levelType#l) OR (p.ls#NIL AND p.ls.size>1) THEN ERROR; IF p.ls=NIL THEN p.l _ v ELSE p.ls[0] _ v; SetDrive[p, d]; }; GetLevelSequence, GLS: PUBLIC PROC [p: Port, i: NAT] RETURNS [v: Level] = { IF p.levelType#ls THEN ERROR; v _ p.ls[i]; }; PutLevelSequence, PLS: PUBLIC PROC [p: Port, i: NAT, v: Level, d: Drive _ drive] = { IF p.levelType#ls THEN ERROR; p.ls[i] _ v; IF p.ds=NIL THEN SetDrive[p, d] ELSE p.ds[i] _ d; }; GetBool, GB: PUBLIC PROC [p: Port] RETURNS [v: BOOL] = { IF (p.ls=NIL AND p.levelType#b) OR (p.ls#NIL AND p.ls.size>1) THEN ERROR; v _ IF p.ls=NIL THEN p.b ELSE ToBool[p.ls[0]]; }; PutBool, PB: PUBLIC PROC [p: Port, v: BOOL, d: Drive _ drive] = { IF (p.ls=NIL AND p.levelType#b) OR (p.ls#NIL AND p.ls.size>1) THEN ERROR; IF p.ls=NIL THEN p.b _ v ELSE p.ls[0] _ ToLevel[v]; SetDrive[p, d]; }; GetBoolSequence, GBS: PUBLIC PROC [p: Port, i: NAT] RETURNS [v: BOOL] = { IF p.ls=NIL AND p.levelType#bs THEN ERROR; v _ IF p.ls=NIL THEN p.bs[i] ELSE ToBool[p.ls[i]]; }; PutBoolSequence, PBS: PUBLIC PROC [p: Port, i: NAT, v: BOOL, d: Drive _ drive] = { IF p.ls=NIL AND p.levelType#bs THEN ERROR; IF p.ls=NIL THEN p.bs[i] _ v ELSE p.ls[i] _ ToLevel[v]; IF p.ds=NIL THEN SetDrive[p, d] ELSE p.ds[i] _ d; }; GetWord, GW: PUBLIC PROC [p: Port] RETURNS [v: BitOps.BitWord] = { IF p.ls=NIL AND p.levelType#c THEN ERROR; v _ IF p.ls=NIL THEN p.c ELSE LSToC[p.ls]; }; PutWord, PW: PUBLIC PROC [p: Port, v: BitOps.BitWord, d: Drive _ drive] = { IF p.ls=NIL AND p.levelType#c THEN ERROR; IF p.ls=NIL THEN p.c _ v ELSE LCToLS[v, p.ls]; SetDrive[p, d]; }; GetDWord, GDW: PUBLIC PROC [p: Port] RETURNS [v: BitOps.BitDWord] = { IF p.ls=NIL AND p.levelType#lc THEN ERROR; v _ IF p.ls=NIL THEN p.lc ELSE LSToLC[p.ls]; }; PutDWord, PDW: PUBLIC PROC [p: Port, v: BitOps.BitDWord, d: Drive _ drive] = { IF p.ls=NIL AND p.levelType#lc THEN ERROR; IF p.ls=NIL THEN p.lc _ v ELSE LCToLS[v, p.ls]; SetDrive[p, d]; }; GetQWord, GQW: PUBLIC PROC [p: Port] RETURNS [v: BitOps.BitQWord] = { IF p.ls=NIL AND p.levelType#q THEN ERROR; v _ IF p.ls=NIL THEN p.q ELSE LSToQ[p.ls]; }; PutQWord, PQW: PUBLIC PROC [p: Port, v: BitOps.BitQWord, d: Drive _ drive] = { IF p.ls=NIL AND p.levelType#q THEN ERROR; IF p.ls=NIL THEN p.q _ v ELSE QToLS[v, p.ls]; SetDrive[p, d]; }; Not: PUBLIC PROC [src, dst: Port] = { IF src.ls=NIL OR dst.ls=NIL THEN ERROR; NotLS[src.ls, dst.ls]; }; Copy: PUBLIC PROC [src, dst: Port] = { IF src.ls=NIL OR dst.ls=NIL THEN ERROR; CopyLS[src.ls, dst.ls]; }; Set: PUBLIC PROC [p: Port, v: Level] = { IF p.ls=NIL THEN ERROR; SetLS[p.ls, v]; }; AnyX: PUBLIC PROC [p: Port] RETURNS [BOOL] = { IF p.ls=NIL THEN ERROR; RETURN[HasX[p.ls]]; }; ToRope: PUBLIC PROC [p: Port, size: NAT _ 0, base: NAT _ 16] RETURNS [r: Rope.ROPE] = { IF p.ls=NIL THEN ERROR; r _ LSToRope[p.ls, size, base]; }; Size: PUBLIC PROC [p: Port] RETURNS [size: NAT] = { IF p.ls=NIL THEN ERROR; size _ p.ls.size; }; VisitPortPair: PUBLIC PROC [onePort: Port, anotherPort: Port, eachPortPair: EachPortPairProc] RETURNS [quit: BOOL] = { subElements: BOOL; IF onePort.size#anotherPort.size OR onePort.levelType#anotherPort.levelType OR (onePort.levelType=ls AND anotherPort.ls.size#onePort.ls.size) OR (onePort.levelType=bs AND anotherPort.bs.size#onePort.bs.size) THEN RETURN [TRUE]; -- ports do not conform [subElements, quit] _ eachPortPair[onePort, anotherPort]; IF quit OR ~subElements THEN RETURN; FOR i: NAT IN [0..onePort.size) DO IF VisitPortPair[onePort[i], anotherPort[i], eachPortPair] THEN RETURN [TRUE]; ENDLOOP; quit _ FALSE; }; VisitBinding: PUBLIC PROC [wire: Core.Wire, port: Port, eachWirePortPair: EachWirePortPairProc] RETURNS [quit: BOOL] = { subElements: BOOL; [subElements, quit] _ eachWirePortPair[wire, port]; IF quit OR ~subElements THEN RETURN; FOR i: NAT IN [0..wire.size) DO IF VisitBinding[ wire[i], IF port = NIL THEN NIL ELSE IF port.levelType#composite THEN NIL ELSE port[i], eachWirePortPair] THEN RETURN [TRUE]; ENDLOOP; quit _ FALSE; }; GetFullPortName: PUBLIC PROC [port: Port, rootPort: Port, rootWire: Core.Wire] RETURNS [name: Rope.ROPE _ NIL] ~ { EachWirePortPair: EachWirePortPairProc ~ { quit _ port=subPort; IF quit THEN name _ CoreOps.GetFullWireName[rootWire, wire]; }; subPort: Port = port; -- renaming IF NOT VisitBinding[rootWire, rootPort, EachWirePortPair] THEN name _ NIL; -- no such subport }; ConversionError: PUBLIC SIGNAL = CODE; ToBool: PUBLIC PROC [a: Level] RETURNS [b: BOOL] = { b _ SELECT a FROM L => FALSE, X => ERROR ConversionError, H => TRUE, ENDCASE => ERROR; }; ToLevel: PUBLIC PROC [a: BOOL] RETURNS [b: Level] = { b _ IF a THEN H ELSE L}; NotL: PUBLIC PROC [a: Level] RETURNS [b: Level] = { b _ SELECT a FROM L => H, H => L, ENDCASE => X}; AndL: PUBLIC PROC [a, b: Level] RETURNS [c: Level] = { tt: ARRAY Level OF ARRAY Level OF Level = [[L, L, L], [L, H, X], [L, X, X]]; c _ tt[a][b]; }; OrL: PUBLIC PROC [a, b: Level] RETURNS [c: Level] = { tt: ARRAY Level OF ARRAY Level OF Level = [[L, H, X], [H, H, X], [X, X, X]]; c _ tt[a][b]; }; XorL: PUBLIC PROC [a, b: Level] RETURNS [c: Level] = { tt: ARRAY Level OF ARRAY Level OF Level = [[L, H, X], [H, L, X], [X, X, X]]; c _ tt[a][b]; }; SumL: PUBLIC PROC [a, b, c: Ports.Level] RETURNS [carry, s: Ports.Level] ~ { v: ARRAY Ports.Level OF NAT _ [0, 1, 0]; -- value of the level d: ARRAY Ports.Level OF NAT _ [0, 0, 1]; -- possible delta lower, higher: NAT; cl, ch, sl, sh: Ports.Level; lower _ v[a]+v[b]+v[c]; -- lower sum higher _ lower+d[a]+d[b]+d[c]; -- higher sum [cl, sl] _ TwoBitsToLevels[lower]; [ch, sh] _ TwoBitsToLevels[higher]; carry _ MergeLevels[cl, ch]; s _ IF carry#X THEN MergeLevels[sl, sh] ELSE X; }; TwoBitsToLevels: PROC [n: NAT] RETURNS [c, s: Ports.Level] ~ { SELECT n FROM 0 => RETURN[L, L]; 1 => RETURN[L, H]; 2 => RETURN[H, L]; 3 => RETURN[H, H]; ENDCASE => ERROR; }; MergeLevels: PROC [b1, b2: Ports.Level] RETURNS [l: Ports.Level] ~ { l _ IF b1=b2 THEN b1 ELSE X}; NotLS: PUBLIC PROC [a, b: LevelSequence] = { FOR i: NAT IN [0..a.size) DO b[i] _ NotL[a[i]]; ENDLOOP; }; CopyLS: PUBLIC PROC [from, to: LevelSequence] = { FOR i: NAT IN [0..from.size) DO to[i] _ from[i]; ENDLOOP; }; SetLS: PUBLIC PROC [seq: LevelSequence, level: Level] = { FOR i: NAT IN [0..seq.size) DO seq[i] _ level; ENDLOOP; }; HasX: PUBLIC PROC [ls: Ports.LevelSequence] RETURNS [BOOL _ FALSE] ~ { FOR i: NAT IN [0..ls.size) DO IF ls[i]=X THEN RETURN[TRUE] ENDLOOP}; LSToRope, LevelSequenceToRope: PUBLIC PROC [container: LevelSequence, size: NAT _ 0, base: NAT _ 16] RETURNS [val: Core.ROPE _ NIL] = { bitsPerDigit: NAT _ BitOps.NBits[base]; scratch: REF TEXT; bitsInDigit: NAT; digitBitCount: NAT _ 0; allX: BOOL _ TRUE; someX: BOOL _ FALSE; digitVal: CARDINAL _ 0; IF size=0 THEN size _ container.size; scratch _ RefText.New[(size/bitsPerDigit)+1]; bitsInDigit _ IF size MOD bitsPerDigit = 0 THEN bitsPerDigit ELSE size MOD bitsPerDigit; FOR bit: NAT IN [0..size) DO bitVal: Level _ container[bit]; digitVal _ 2*digitVal; IF bitVal=X THEN someX _ TRUE ELSE { allX _ FALSE; IF bitVal=H THEN digitVal _ digitVal + 1; }; digitBitCount _ digitBitCount + 1; IF digitBitCount=bitsInDigit THEN { SELECT TRUE FROM allX => scratch _ RefText.InlineAppendChar[scratch, 'X]; someX => { scratch _ RefText.InlineAppendChar[scratch, '(]; FOR rescan: NAT DECREASING IN [0..bitsInDigit) DO scratch _ RefText.InlineAppendChar[scratch, SELECT container[bit-rescan] FROM L => '0, X => 'X, H => '1, ENDCASE => ERROR]; ENDLOOP; scratch _ RefText.InlineAppendChar[scratch, ')]; }; ENDCASE => scratch _ Convert.AppendCard[to: scratch, from: digitVal, base: base, showRadix: FALSE]; bitsInDigit _ bitsPerDigit; digitBitCount _ 0; allX _ TRUE; someX _ FALSE; digitVal _ 0; }; ENDLOOP; val _ Rope.FromRefText[scratch]; }; WordAsBits: TYPE = PACKED ARRAY [0..16) OF BOOL; DWordAsBits: TYPE = PACKED ARRAY [0..32) OF BOOL; LSToC: PUBLIC PROC [ls: LevelSequence] RETURNS [c: CARDINAL] = { asBits: WordAsBits _ ALL[FALSE]; FOR bit: INT IN [0..ls.size-16) DO IF ls[bit]#L THEN ERROR ConversionError; ENDLOOP; FOR bit: INT IN [MAX[ls.size-16, 0]..ls.size) DO asBits[bit+16-ls.size] _ ToBool[ls[bit]]; ENDLOOP; c _ LOOPHOLE[asBits]; }; CToLS: PUBLIC PROC [c: CARDINAL, ls: LevelSequence] = { asBits: WordAsBits _ LOOPHOLE[c]; FOR bit: INT IN [0..16-ls.size) DO IF asBits[bit] THEN ERROR ConversionError; ENDLOOP; FOR bit: INT IN [0..ls.size) DO ls[bit] _ IF bitKš œžœžœ žœžœ˜Eš œ žœžœžœžœ˜/Kšœ]˜]K˜—šœžœ•žœ]˜ŽK˜—šœžœŽžœ]˜€K˜šΟn œ"˜/Kšœžœ˜!Jšœ ˜ Kšžœžœ ˜#šžœžœ˜Kšžœ1˜3Kšžœ˜K˜—Kšžœ1˜3šžœž˜šœ˜Kšžœ˜Kšžœ)˜+K˜—šœ žœžœžœžœžœžœž˜RKšžœ˜Kšžœ-˜/Kšžœ˜—Kšžœžœ˜—K˜K˜—š  œ˜'Kšœžœ ˜$Kšœ<˜š œžœžœžœ˜@šžœ žœ+žœžœ˜FKšœžœW˜nKšœ>˜>šžœžœ˜Kšœžœ˜šžœžœžœž˜!Kšœ&˜&Kšžœ˜—K˜—šžœ˜Kšœžœ ˜Kšœ˜šžœ ž˜šœ˜Kšœ žœ+˜8šžœžœžœž˜$K˜Kšžœ˜—K˜—šœ˜Kšœ žœ*˜7šžœžœžœž˜$Kšœžœ˜Kšžœ˜—K˜—Kšœ3˜3Kšœ4˜4Kšœ3˜3Kšžœ˜—Kšžœ žœžœ^˜~š žœžœžœžœž˜+Kšœ!˜!šœ ˜ Kšœ˜šžœ žœžœ˜Kšœ žœ+˜8šžœžœžœž˜"Kšœ˜Kšžœ˜—Kšœ˜—Kšžœ#˜'šžœ ž˜Kšœžœžœžœ˜.Kšœžœžœžœ˜.Kšœžœ#žœžœ˜5Kšœžœ#žœžœ˜6Kšœžœ#žœžœ˜5Kšžœ˜—K˜—Kšžœžœ˜—K˜K˜—Kšžœžœ1žœžœ˜BK˜—Kšœ˜—š  œžœ"˜2Kšœžœ1˜HKšžœ žœžœžœžœ8žœžœ˜_Kš žœžœžœžœ‘$˜Gšžœžœžœž˜$K˜Kšžœ˜—K˜—Kšœ‘%˜>Kšœ!˜!˜K˜——š   œžœžœ3žœžœ˜ZK˜š  œ˜#Kš œžœHžœ žœžœ˜šKšžœžœžœžœ˜K˜š žœžœžœžœž˜+Kšœ!˜!šœ žœ žœž˜#šžœžœžœž˜"Kšœ˜Kšž˜—š žœžœžœžœž˜'Kšœ˜Kšžœ˜——Kšžœžœ˜—K˜ Kšœ žœ˜š žœ žœžœžœžœžœž˜6K˜Kšžœ˜—š žœ žœžœžœžœžœž˜6Kšœ žœ˜Kšžœ˜—Kšœ˜Kšœ˜Kšœ˜K˜K˜—Kšœ4˜4Kšœ˜K˜—š  œžœžœ,žœ1˜}Kšœžœ˜Kšœ‘%˜>KšœžœW˜dKšœ žœžœžœžœ žœžœ žœ˜VKš œ žœžœžœ žœ˜;Kšœ˜K˜—š   œžœžœžœ žœ˜CKšœ&˜&š  œžœžœ žœ ˜Ašžœžœ+žœ˜7Kšžœžœ5žœžœ˜FKšžœ žœ ˜š žœžœžœžœž˜&Kšœ)˜)Kšžœ˜—K˜—K˜—Kšœ˜Kšœ˜K˜—š   œžœžœžœžœ žœ˜RKšœžœ$˜,Kšžœžœžœ‘ ˜"Kšœ ˜ K˜K˜—š  œžœžœJžœžœžœ4žœžœžœ˜½Kšžœžœžœ˜(Kšžœžœžœ˜(Kšžœžœžœ˜(Kšžœžœžœ˜(Kšžœžœžœ˜(Kšžœžœžœ˜(Kšžœžœžœ˜(Kšžœžœžœ˜(Kšžœžœžœ˜(Kšžœžœžœ˜(Kšžœžœžœ˜+Kšžœžœžœ˜+K˜K˜—š  œžœžœ˜5K˜š œ˜Kšžœ)žœ)žœžœ˜ašžœžœ˜%Kšœ˜š žœ žœžœžœžœžœž˜Kšžœ˜—K˜—Kšœ:˜:Kšœ<˜<šœ˜Kšœžœ'˜>šžœžœžœž˜Kš œžœžœžœžœ˜9Kšžœ˜—Kšœ:˜:K˜—Kšžœžœ˜—Kšœ˜K˜—š   œžœžœ žœžœ˜2K˜—š  œžœžœžœ˜Lšžœžœžœ˜Kšœžœ˜&šžœžœžœž˜Kšœ˜Kšž˜—K˜—K˜K˜——™.š  œžœžœ„žœžœ˜ΏKšœ†˜†K˜Kš žœ žœžœžœžœ‘(™fKšœ˜K˜—š   œžœžœžœžœ˜’Kš œžœžœ žœžœ˜#Kšžœžœžœ žœ ˜'Kšžœžœžœ žœ ˜'Kšžœžœžœ žœ ˜'Kšžœžœžœ žœ ˜'Kšžœžœžœ žœ ˜'Kšžœžœžœ žœ ˜'Kšžœžœžœ žœ ˜'Kšžœžœžœ žœ ˜'Kšžœžœžœ žœ ˜'Kšžœžœžœ žœ ˜'Kšžœžœžœ žœ ˜)K˜-K˜K˜—š   œžœžœNžœžœ žœ˜š œžœžœ˜Kšœ+˜+KšœE˜EK˜—š žœžœžœ žœžœžœž˜;K˜Kšžœ˜—K˜K˜—š œžœžœHžœ˜lKš œ>žœ žœžœ žœ8˜›Kšœ˜K˜—š  œžœžœfžœžœ˜Kš œžœžœ žœžœ˜#Kšžœžœžœ žœ ˜'Kšžœžœžœ žœ ˜'Kšžœžœžœ žœ ˜'Kšžœžœžœ žœ ˜'Kšžœžœžœ žœ ˜'Kšžœžœžœ žœ ˜'Kšžœžœžœ žœ ˜'Kšžœžœžœ žœ ˜'Kšžœžœžœ žœ ˜'Kšžœžœžœ žœ ˜'Kšžœžœžœ žœ ˜)K˜*K˜K˜—š  œžœžœ5žœžœ žœ˜oš œžœžœ˜Kšœ+˜+Kšœ7˜7K˜—š žœžœžœ žœžœžœž˜;K˜Kšžœ˜—K˜K˜—š   œžœžœžœ„žœ˜°šœ7˜7šžœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ"˜"——Kšœ˜K˜—š Ÿœžœžœžœžœžœ˜Uš žœžœžœžœžœžœž˜4KšœB˜BKšžœ˜—K˜K˜—š Ÿœžœžœžœžœžœ4˜qš žœžœžœžœžœžœž˜4KšœQ˜QKšžœ˜—K˜K˜—š  œžœ*žœžœžœ˜cKšœžœ˜Kšžœžœžœ žœ˜7šžœ˜KšœC‘˜ZKšœ˜K˜—K˜K˜——™"šœΟt ™šœžœ"’ œ6˜|K˜—š œžœžœ-žœ˜kKšœ4žœ˜PKšœ˜K˜K˜—š œ˜,Kšœ žœ žœ˜)Kšœ4˜4K˜K˜—š œ˜*Kšœžœ5˜@K˜——šœ’œ™$šœžœe˜|K˜—šœžœk˜ˆK˜—š œžœžœ5žœ˜sKšœ4žœ˜PKšœ˜K˜K˜—š œžœžœ5žœ˜yKšœ:žœ˜VKšœ˜K˜K˜—š œ˜,Kšœ žœ žœ˜)Kšœ4˜4K˜K˜—š œ˜*Kšœžœ5˜@K˜K˜——šœ ’œ™šœžœY˜lK˜—šœžœb˜~K˜—š  œžœžœHžœžœ˜ŽKš œ0žœ žœžœžœžœ˜{Kšœ˜K˜K˜—š  œžœžœHžœžœ˜”Kš œ9žœ žœžœžœžœ˜„Kšœ˜K˜K˜—š œ˜(šžœžœž˜šœžœ ˜Kšœ‘!˜?Kšœ,˜,K˜—šœžœ˜Kšœ&˜&šžœžœžœž˜!Kšœ/˜/Kšžœ˜—Kšœ˜—Kšžœžœ‘˜,—K˜K˜—š  œ˜&Kšœžœ˜$Kšžœžœ žœ,˜Fšžœ‘˜Kšœžœ˜4šžœžœžœ ž˜Kšœ.˜.Kšžœ˜—Kšœ˜Kšœ˜—K˜K˜——š œžœžœžœžœžœXžœEžœ˜αš žœžœžœžœžœžœž˜6K˜-Kšžœžœ˜*Kšžœžœ˜4Kšžœ žœ!˜0Kšžœžœžœ4˜CKšžœžœ%˜:Kšžœ žœ'˜6Kšžœžœžœ:˜IKšžœ˜—K˜K˜—š œžœžœ˜8š  œ˜&Kšœžœžœ7˜LKšœžœžœ7˜LKšœžœžœ3˜HKšœžœžœ=˜XKšœžœžœ<˜Wšžœžœžœžœžœžœžœ˜BKš œžœžœžœžœžœžœ ˜\Kš œžœžœžœ žœžœžœ ˜dKšœ˜Kšœžœ˜ š žœžœžœžœžœž˜6Kšœžœ˜!Kšœ'˜'Kšžœžœ˜—KšœA˜AK˜—š žœžœžœžœžœ˜:Kšœ˜Kšœ"žœ˜&š žœžœžœžœžœž˜BKšœžœ ˜'Kšœ-˜-Kšžœžœ˜—Kšœ>žœžœžœžœžœžœ žœ žœžœžœG˜όK˜—K˜—K˜2K˜K˜—š  œžœ˜-Kšœ5™5Kšœ˜šžœžœžœž˜9K˜Kšœ˜Kšžœ˜—K˜K˜——™š Ÿœžœžœ5žœžœ˜eš œ˜*Kšžœžœžœ˜.K˜—Kšœ7˜7Kšžœžœ4žœžœ˜EK˜K˜—šŸ œžœžœažœžœžœ;žœ˜ΝKšžœžœžœ'˜5Kšžœžœžœ'˜5Kšžœžœžœ'˜5Kšžœžœžœ'˜5Kšžœžœžœ'˜5Kšžœžœžœ'˜5Kšžœžœžœ'˜5Kšžœžœžœ'˜5Kšžœžœžœ'˜5Kšžœžœžœ'˜5Kšžœžœžœ)˜8Kšžœžœžœ)˜8K˜K˜——™™š Οb Πbkœžœžœ žœ˜:Kšžœžœžœžœžœžœžœžœ˜QKš œžœžœžœžœ ˜&K˜K˜—š£ €œžœžœ˜1Kšžœžœžœžœžœžœžœžœ˜QKšžœžœžœ žœ ˜*K˜K˜—š £€œžœžœžœžœ˜KKšžœžœžœ˜#K˜ K˜K˜—š £€œžœžœžœ˜BKšžœžœžœ˜#K˜ K˜K˜—š œžœ˜&Kšžœžœžœ˜š žœžœžœžœž˜$K˜ Kšžœ˜—K˜K˜——š£™š £ €œžœžœ žœ˜:Kšžœžœžœžœžœžœžœžœ˜IKš œžœžœžœžœ ˜&K˜K˜—š£ €œžœžœ*˜CKšžœžœžœžœžœžœžœžœ˜IKšžœžœžœ žœ ˜*K˜K˜K˜—š £€œžœžœžœžœ˜KKšžœžœžœ˜K˜ K˜K˜—š £€œžœžœžœ!˜TKšžœžœžœ˜K˜ Kšžœžœžœžœ ˜1K˜K˜—š £ €œžœžœ žœžœ˜8Kšžœžœžœžœžœžœžœžœ˜IKš œžœžœžœžœ˜.K˜K˜—š £ €œžœžœžœ˜AKšžœžœžœžœžœžœžœžœ˜IKšžœžœžœ žœ˜3K˜K˜K˜—š £€œžœžœžœžœžœ˜IKš žœžœžœžœžœ˜*Kš œžœžœžœ žœ˜2K˜K˜—š £€œžœžœžœžœ˜RKš žœžœžœžœžœ˜*Kšžœžœžœ žœ˜7Kšžœžœžœžœ ˜1K˜K˜—š £ €œžœžœ žœ˜BKš žœžœžœžœžœ˜)Kš œžœžœžœžœ ˜*K˜K˜—š£ €œžœžœ3˜KKš žœžœžœžœžœ˜)Kšžœžœžœ žœ˜.K˜K˜K˜—š £ €œžœžœ žœ˜EKš žœžœžœžœžœ˜*Kš œžœžœžœžœ˜,K˜K˜—š£ €œžœžœ4˜NKš žœžœžœžœžœ˜*Kšžœžœžœ žœ˜/K˜K˜K˜—š £ €œžœžœ žœ˜EKš žœžœžœžœžœ˜)Kš œžœžœžœžœ ˜*K˜K˜—š£ €œžœžœ4˜NKš žœžœžœžœžœ˜)Kšžœžœžœ žœ˜-K˜K˜——š£ ™ šŸœžœžœ˜%Kš žœžœžœžœžœžœ˜'K˜K˜K˜—šŸœžœžœ˜&Kš žœžœžœžœžœžœ˜'Kšœ˜K˜K˜—š œžœžœ˜(Kšžœžœžœžœ˜K˜K˜K˜—š  œžœžœ žœžœ˜.Kšžœžœžœžœ˜Kšžœ ˜K˜K˜—š œžœžœžœ žœžœ žœ˜WKšžœžœžœžœ˜Kšœ˜K˜K˜—š  œžœžœ žœžœ˜3Kšžœžœžœžœ˜K˜K˜K˜———™š   œžœžœDžœžœ˜vJšœ žœ˜Jšžœžœ)žœžœ&žœžœ&žœžœžœ‘˜ϋJšœ9˜9Jšžœžœžœžœ˜$šžœžœžœž˜"Jšžœ9žœžœžœ˜NJšžœ˜—Jšœžœ˜ K˜K˜—š   œžœžœGžœžœ˜xJšœ žœ˜Jšœ3˜3Jšžœžœžœžœ˜$šžœžœžœž˜šžœ˜Jšœ ˜ Jšžœžœžœžœžœžœžœžœžœ ˜OJšœžœžœžœ˜%—Jšžœ˜—Jšœžœ˜ K˜K˜—š  œžœžœ3žœ žœžœ˜rK™ š œ˜*Kšœ˜Kšžœžœ0˜Kšœžœ žœžœ‘˜:Kšœžœ˜Kšœ˜Kšœ‘ ˜$Kšœ‘ ˜,Kšœ"˜"Kšœ#˜#Kšœ˜Kšœžœ žœžœ˜/K˜—šŸœžœžœžœ˜>šžœž˜ Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšžœžœ˜—K˜—š  œžœžœ˜DKšœžœžœžœ˜K™—š œžœžœ˜,Kš žœžœžœ žœžœ˜8K˜K˜—š œžœžœ˜1Kš žœžœžœžœžœ˜9K˜K˜—š œžœžœ'˜9Kš žœžœžœžœžœ˜7K˜K˜—š  œžœžœžœžœžœ˜FKšžœžœžœžœžœ žœžœžœžœ˜DK˜—šœ  œžœžœ"žœ žœžœ žœžœ˜‡Kšœžœ˜'Kšœ žœžœ˜Kšœ žœ˜Kšœžœ˜Kšœžœžœ˜Kšœžœžœ˜Kšœ žœ˜Kšžœžœ˜%Kšœ-˜-Kš œžœžœžœžœžœ˜Xšžœžœžœ ž˜Kšœ˜Kšœ˜Kšžœ žœ ž˜šžœ˜Kšœžœ˜ Kšžœ žœ˜)K˜—Kšœ"˜"šžœžœ˜#šžœžœž˜Kšœ8˜8˜ Kšœ0˜0š žœ žœž œžœž˜1šœ,žœž˜MKšœ˜Kšœ˜Kšœ˜Kšžœžœ˜—Kšžœ˜—Kšœ0˜0K˜—KšžœUžœ˜c—Kšœ˜Kšœ˜Kšœžœ˜ Kšœžœ˜Kšœ ˜ K˜—Kšžœ˜—Kšœ ˜ K˜K˜—Kš œ žœžœžœ žœžœ˜0š œ žœžœžœ žœžœ˜1K˜—š  œžœžœžœžœ˜@Kšœžœžœ˜ šžœžœžœž˜"Kšžœ žœžœ˜(Kšžœ˜—š žœžœžœžœž˜0Kšœ)˜)Kšžœ˜—Kšœžœ ˜Kšœ˜K™—š œžœžœžœ˜7Kšœžœ˜!šžœžœžœž˜"Kšžœ žœžœ˜*Kšžœ˜—šžœžœžœž˜Kšœ žœžœžœ!˜IKšžœ˜—K˜K˜—š  œžœžœžœžœžœ˜GKšœžœžœ˜!šžœžœžœž˜"Kšžœ žœžœ˜(Kšžœ˜—š žœžœžœžœž˜0Kšœ)˜)Kšžœ˜—Kšœžœžœ ˜3Kšœ˜K™—š  œžœžœžœžœ˜>Kšœžœžœ˜@šžœžœžœž˜"Kšžœ žœžœ˜*Kšžœ˜—šžœžœžœž˜Kšœ žœžœžœ!˜IKšžœ˜—Kšœ˜K™—š œžœžœžœ/˜]šžœžœžœž˜"Kšžœ žœžœ˜(Kšžœ˜—š žœžœžœžœž˜.Kšœ žœ˜.Kšžœ˜—Kšœ˜K™—š œžœžœ,˜>šžœžœžœž˜"Kšžœžœ žœžœ˜2Kšžœ˜—šžœžœžœž˜Kš œ žœžœžœžœ˜QKšžœ˜—Kšœ˜K™——Kšžœ˜K˜—…—ŽτΔι