OracleImpl.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
McCreight January 12, 1987 4:01:11 pm PST
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
EXPORTS Oracle
= BEGIN -- OPEN Oracle;
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.WRNIL;
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: ATOMNIL
];
LCS: TYPE = RECORD [ SEQUENCE size: NAT OF LONG CARDINAL ];
File: TYPE = RECORD [ name: IO.ROPENIL, stream: IO.STREAMNIL ];
OracleState: TYPE = REF OracleStateRec;
OracleStateRec: TYPE = RECORD [
clk, out, in: NATLAST[NAT],
prevClk: BOOLTRUE,
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<wire.size THEN {
portName ← IO.PutFR["%s[%d]", IO.rope[portName], IO.int[i]];
IF j<wire[i].size THEN
portName ← IO.PutFR["%s[%d]", IO.rope[portName], IO.int[j]];
};
reason ← IO.PutFR["At position %d in oracle file %s, port %s should have been %s, but was %s instead.",
IO.int[position], IO.atom[state.oracleProps.id], IO.rope[portName],
IO.char[levelName[shouldBe]], IO.char[levelName[is]]];
ShowPlaceInStream[s];
Rosemary.Stop[msg: reason];
};
SELECT wire.size FROM
0 => 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: BOOLTRUE;
{
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.