OracleImpl.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
McCreight January 20, 1987 5:43:42 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
WireFromRope: PROC [ r: IO.ROPE, name: IO.ROPE ] RETURNS [ w: Core.Wire ] =
{
s: IO.STREAM = IO.RIS[IO.PutFR["(%s)", IO.rope[r]]];
ref: REF ANY = s.GetRefAny[];
s.Close[];
w ← NARROW[WireFromRef[ref]];
IF name # NIL THEN [] ← CoreOps.SetShortWireName[w, name];
};
WireFromRef: PROC [ ref: REF ANY ] RETURNS [ w: CoreCreate.WR ] =
{
WITH ref SELECT FROM
size: REF INT =>
w ← CoreCreate.Seq[size: size^];
lora: LIST OF REF ANY => {
w ← CoreCreate.WireList[wrs: WireListFromRefList[lora]];
};
ENDCASE => ERROR;
};
WireListFromRefList: PROC [ lora: LIST OF REF ANY ] RETURNS [ wl: LIST OF CoreCreate.WR ] =
{
wl ← (IF lora=NIL THEN NIL ELSE CONS[WireFromRef[lora.first], WireListFromRefList[lora.rest]]);
};
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 [ wire: Core.Wire ] = {
SELECT wire.size FROM
0 => [] ← Ports.InitPort[wire, l, aggregate, none];
ENDCASE => {
FOR i: NAT IN [0..wire.size) DO
DoInitPort[wire[i]];
ENDLOOP;
};
};
ct ← CoreClasses.CreateUnspecified[name: OracleName,
public: CoreCreate.Wires["Vdd", "Gnd", "Clk",
WireFromRope[out, "Out"],
WireFromRope[in, "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[CoreOps.FindWire[ct.public, "Out"]];
DoInitPort[CoreOps.FindWire[ct.public, "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 ] = {
ScanLParen: PROC [ ] RETURNS [ found: BOOL ] = {
[] ← s.SkipWhitespace[];
found ← s.PeekChar[ ! IO.EndOfStream => { found ← FALSE; CONTINUE } ] = '(;
IF found THEN { [] ← s.GetChar[]; [] ← s.SkipWhitespace[] };
};
ScanRParen: PROC [ ] RETURNS [ found: BOOL ] = {
[] ← s.SkipWhitespace[];
found ← s.PeekChar[ ! IO.EndOfStream => { found ← FALSE; CONTINUE } ] = ');
IF found THEN { [] ← s.GetChar[]; [] ← s.SkipWhitespace[] };
};
ScanBar: PROC [ ] = {
[] ← s.SkipWhitespace[];
IF s.GetChar[ ! IO.EndOfStream => GOTO Failure ] # '|
THEN GOTO Failure;
[] ← s.SkipWhitespace[];
EXITS Failure => ERROR CantParse;
};
SkipToVisible: PROC [ ] = {
[] ← s.SkipWhitespace[];
[] ← s.PeekChar[]; -- force EndOfStream if no more characters
};
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 ], portName: IO.ROPENIL, depth: NAT ← 0 ] = {
Complain: PROC [ i, j: NAT, shouldBe, is: Ports.Level ] = {
levelName: ARRAY Ports.Level OF CHAR = [L: '0, H: '1, X: 'X];
reason: IO.ROPE;
position: INT = s.GetIndex[]-1;
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 => {
IF ScanLParen[] THEN parenDepth ← parenDepth+1;
FOR i: NAT IN [0..wire.size) DO
[] ← s.SkipWhitespace[];
DoWire[wire[i], port[i], proc, IO.PutFR["%s[%d]", IO.rope[portName], IO.int[i]], depth+1];
ENDLOOP;
IF ScanRParen[] THEN {
IF parenDepth>0 THEN parenDepth ← parenDepth-1 ELSE ERROR CantParse;
};
IF parenDepth>depth THEN ERROR CantParse;
};
};
parenDepth: NAT ← 0;
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, "Out"];
ScanBar[];
DoWire[state.oracleProps.ct.public[state.in], p[state.in], ScanIn, "In"];
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.