<> <> <> DIRECTORY -- Oracle, -- Atom, BitOps, Core, CoreClasses, CoreCreate, CoreFlat, CoreOps, CoreProperties, FileViewerOps, FS, IO, Logic, Ports, Rosemary; OracleImpl: CEDAR PROGRAM IMPORTS Atom, CoreCreate, CoreClasses, CoreFlat, CoreOps, CoreProperties, FileViewerOps, FS, IO, Logic, Ports, Rosemary <> = BEGIN -- OPEN Oracle; <> NatSeq: TYPE = REF NatSeqRec _ NIL; NatSeqRec: TYPE = RECORD [ SEQUENCE size: NAT OF NAT ]; SizesFromRope: PROC [ sRope: IO.ROPE ] RETURNS [ sizes: NatSeq ] = { s: IO.STREAM = IO.RIS[sRope]; len: NAT; FOR len _ 0, len+1 DO [] _ s.GetCard[ ! IO.EndOfStream => GOTO Done ]; REPEAT Done => NULL; ENDLOOP; s.SetIndex[0]; sizes _ NEW[NatSeqRec[len]]; FOR len _ 0, len+1 DO sizes[len] _ s.GetCard[ ! IO.EndOfStream => GOTO Done ]; REPEAT Done => NULL; ENDLOOP; s.Close[]; }; WireFromSizes: PROC [ sizes: NatSeq, wireName: IO.ROPE ] RETURNS [ w: CoreCreate.WR ] = { SELECT sizes.size FROM 0 => ERROR; 1 => w _ CoreCreate.Seq[wireName, sizes[0]]; ENDCASE => { wrs: LIST OF CoreCreate.WR _ NIL; FOR i: NAT DECREASING IN [0..sizes.size) DO fieldName: IO.ROPE = IO.PutFR["x%d", IO.int[i]]; wrs _ CONS[CoreCreate.Seq[fieldName, sizes[i]], wrs]; ENDLOOP; w _ CoreCreate.WireList[wrs, wireName]; }; }; OracleName: IO.ROPE = Rosemary.Register[roseClassName: "Oracle", init: OracleInit, evalSimple: OracleSimple]; Oracle: PUBLIC PROC [out, in, c: IO.ROPE, id: INT] RETURNS [ct: Core.CellType] = { DoInitPort: PROC [ name: IO.ROPE ] = { wire: Core.Wire = CoreOps.FindWire[ct.public, name]; SELECT wire.size FROM 0 => [] _ Ports.InitPort[wire, l, aggregate, none]; ENDCASE => { FOR i: NAT IN [0..wire.size) DO wi: Core.Wire = wire[i]; SELECT wi.size FROM 0 => [] _ Ports.InitPort[wi, l, aggregate, none]; ENDCASE => { FOR j: NAT IN [0..wi.size) DO [] _ Ports.InitPort[wi[j], l, aggregate, none]; ENDLOOP; }; ENDLOOP; }; }; outSizes: NatSeq = SizesFromRope[out]; inSizes: NatSeq = SizesFromRope[in]; ct _ CoreClasses.CreateUnspecified[name: OracleName, public: CoreCreate.Wires["Vdd", "Gnd", "Clk", WireFromSizes[outSizes, "Out"], WireFromSizes[inSizes, "In"] ]]; CoreProperties.PutCellTypeProp[ct, $oracle, NEW[OraclePropRec _ [ ct: ct, id: Atom.MakeAtom[IO.PutFR["%s-%xx", IO.rope[c], IO.int[id]]] ]]]; [] _ Rosemary.BindCellType[cellType: ct, roseClassName: OracleName]; [] _ CoreFlat.CellTypeCutLabels[ct, Logic.logicCutSet]; Ports.InitPorts[ct, l, none, "Vdd", "Gnd"]; Ports.InitPorts[ct, b, none, "Clk"]; DoInitPort["Out"]; DoInitPort["In"]; }; OracleProp: TYPE = REF OraclePropRec _ NIL; OraclePropRec: TYPE = RECORD [ ct: Core.CellType _ NIL, id: ATOM _ NIL ]; LCS: TYPE = RECORD [ SEQUENCE size: NAT OF LONG CARDINAL ]; File: TYPE = RECORD [ name: IO.ROPE _ NIL, stream: IO.STREAM _ NIL ]; OracleState: TYPE = REF OracleStateRec; OracleStateRec: TYPE = RECORD [ clk, out, in: NAT _ LAST[NAT], prevClk: BOOL _ TRUE, cycle: INT _ 0, oracleProps: OracleProp ]; OracleInit: Rosemary.InitProc = { clk: NAT = Ports.PortIndex[cellType.public, "Clk"]; in: NAT = Ports.PortIndex[cellType.public, "In"]; out: NAT = Ports.PortIndex[cellType.public, "Out"]; state: OracleState = NEW[OracleStateRec]; oracleProps: REF OraclePropRec _ NARROW[CoreProperties.GetCellTypeProp[cellType, $oracle], REF OraclePropRec]; source: REF ANY = Atom.GetProp[$RosemaryOracle, oracleProps.id]; WITH source SELECT FROM s: IO.STREAM => s.SetIndex[0]; r: IO.ROPE => Atom.PutProp[$RosemaryOracle, oracleProps.id, IO.RIS[r]]; f: REF File => { IF f.stream # NIL THEN { f.stream.Close[]; f.stream _ NIL }; f.stream _ FS.StreamOpen[f.name]; }; ENDCASE => { <<-- no oracle definition -->> ERROR; }; state^ _ [ clk: clk, in: in, out: out, oracleProps: oracleProps ]; stateAny _ state; }; Disagreement: SIGNAL [ shouldBe, is: Ports.Level ] = CODE; CantParse: ERROR = CODE; OracleSimple: Rosemary.EvalProc = { DoValues: PROC [ s: IO.STREAM ] = { ScanBar: PROC [ ] = { [] _ s.SkipWhitespace[]; IF s.GetChar[] # '| THEN ERROR CantParse; [] _ s.SkipWhitespace[]; }; SkipToVisible: PROC [ ] = { [] _ s.SkipWhitespace[]; [] _ s.PeekChar[]; }; SendOut: PROC [ port: Ports.Port ] = { c: CHAR _ s.GetChar[]; SELECT c FROM '0, 'F, 'f, 'L, 'l => {port.l _ L; port.d _ drive}; '1, 'T, 't, 'H, 'h => {port.l _ H; port.d _ drive}; '-, '., 'x, 'X => {port.d _ none}; ENDCASE => ERROR CantParse; }; ScanIn: PROC [ port: Ports.Port ] = { c: CHAR _ s.GetChar[]; SELECT c FROM '0, 'F, 'f, 'L, 'l => IF port.l # L THEN SIGNAL Disagreement[L, port.l]; '1, 'T, 't, 'H, 'h => IF port.l # H THEN SIGNAL Disagreement[H, port.l]; '-, '., 'x, 'X => NULL; ENDCASE => ERROR CantParse; }; DoWire: PROC [ wire: Core.Wire, port: Ports.Port, proc: PROC [ Ports.Port ] ] = { Complain: PROC [ i, j: NAT, shouldBe, is: Ports.Level ] = { levelName: ARRAY Ports.Level OF CHAR = [L: '0, H: '1, X: 'X]; portName: IO.ROPE _ "In"; reason: IO.ROPE; position: INT = s.GetIndex[]-1; IF i proc[port ! Disagreement => {Complain[0, 0, shouldBe, is]; RESUME}]; ENDCASE => { FOR i: NAT IN [0..wire.size) DO wi: Core.Wire = wire[i]; [] _ s.SkipWhitespace[]; SELECT wi.size FROM 0 => proc[port[i] ! Disagreement => {Complain[i, 0, shouldBe, is]; RESUME}]; ENDCASE => { FOR j: NAT IN [0..wi.size) DO proc[port[i][j] ! Disagreement => {Complain[i, j, shouldBe, is]; RESUME}]; ENDLOOP; }; ENDLOOP; }; }; firstTry: BOOL _ TRUE; { ENABLE CantParse => GOTO FormatError; [] _ SkipToVisible[ ! IO.EndOfStream => IF firstTry THEN { firstTry _ FALSE; s.SetIndex[0]; -- return to beginning of test RETRY; } ELSE GOTO FormatError ]; DoWire[state.oracleProps.ct.public[state.out], p[state.out], SendOut]; ScanBar[]; DoWire[state.oracleProps.ct.public[state.in], p[state.in], ScanIn]; EXITS FormatError => { position: INT = s.GetIndex[]-1; reason: IO.ROPE = IO.PutFR["At position %d in oracle file %s, couldn't parse it.", IO.int[position], IO.atom[state.oracleProps.id]]; ShowPlaceInStream[s]; Rosemary.Stop[msg: reason]; }; }; }; state: OracleState _ NARROW[stateAny]; curClk: BOOL = p[state.clk].b; IF curClk AND NOT state.prevClk THEN { ref: REF ANY = Atom.GetProp[$RosemaryOracle, state.oracleProps.id]; WITH ref SELECT FROM s: IO.STREAM => DoValues[s]; f: REF File => DoValues[f.stream]; ENDCASE => ERROR; state.cycle _ state.cycle+1; }; state.prevClk _ curClk; }; ShowPlaceInStream: PROC [ s: IO.STREAM, index: INT _ -1 ] = { file: FS.OpenFile = FS.OpenFileFromStream[s ! IO.Error => GOTO DoesntWork]; IF index < 0 THEN index _ s.GetIndex[]+index; FileViewerOps.OpenSource[fileName: FS.GetName[file].fullFName, index: index, chars: 1]; EXITS DoesntWork => NULL; }; END.