File: PWPLABasicsImpl.mesa   
Copyright © 1985 by Xerox Corporation. All rights reserved.
Created by: Monier, March 14, 1985 9:54:02 pm PST
-- Low level stuff for PLA and CP generation.
DIRECTORY
Atom,
BasicTime,
CD,
CDDirectory,
CDExpr,
CDExtras,
Convert,
PW,
PWBasics,
PWPLABasics,
BoolOps, AMTypes, Rope, IO, FS, SymTab;
PWPLABasicsImpl: CEDAR PROGRAM    
IMPORTS Atom, BasicTime, BoolOps, CDDirectory, CDExpr, Convert, FS, PWBasics, Rope
EXPORTS PWPLABasics
SHARES CDDirectory = BEGIN
OPEN PWPLABasics;
Error: PUBLIC ERROR[ec: ErrorCode, msg: ROPE] ~ CODE;
-- Looks for name1, name2, then name3; if absent, return NIL and screams if required
GetTile: PROC[from, to: CD.Design, tilesPrefix: ROPE, tilesFetched: REF LIST OF ROPE, name1, name2, name3: PW.ObjName ← NIL, required: BOOL] RETURNS [newName: PW.ObjName] =
BEGIN
tile, oldTile: CD.ObPtr;
done, found: BOOL;
name: PW.ObjName ← SELECT TRUE FROM
IsPresent[from, name1] => name1,
IsPresent[from, name2] => name2,
IsPresent[from, name3] => name3,
ENDCASE => NIL;
IF name = NIL AND required THEN
BEGIN
PWBasics.Output["PWPLA could not find tile '", name1, "'"];
IF name2 # NIL THEN PWBasics.Output[" nor '", name2, "'"];
IF name3 # NIL THEN PWBasics.Output[" nor '", name3, "'"];
PWBasics.Output[".\n'"];
ERROR Error[MissingTile, NIL];
END;
IF name = NIL AND ~required THEN RETURN[NIL];
-- add the prefix to the cell name to form "tileset.tilename"
newName ← Rope.Cat[tilesPrefix, name];
IF ~AlreadyFetched[tilesFetched, name] THEN
BEGIN
tilesFetched^ ← CONS[name, tilesFetched^];
-- check if this tile is already in the design
[found, oldTile] ← CDDirectory.Fetch[to, newName];
-- if an old version of the tile is already in the design it gets renamed
-- we need a good gensym
IF found THEN
BEGIN
bogusName: ROPE ← Rope.Cat[newName, " renamed on ", Convert.RopeFromTime[BasicTime.Now[]]];
done ← CDDirectory.Rename[to, oldTile, bogusName];
IF ~done THEN ERROR;
END;
-- *** make a copy of the cell and include it: copy should be recursive ***
tile ← CDDirectory.Another[CDDirectory.Fetch[from, name].object, from, to];
-- rename the cell: there should be no conflict now
done ← CDDirectory.Rename[to, tile, newName];
-- If the name has changed, something is really wrong
IF ~done THEN ERROR;
END;
END;
IsPresent: PROC [whereTilesAre: CD.Design, name: ROPE] RETURNS [BOOL] =
{RETURN[CDDirectory.Fetch[whereTilesAre, name].found]};
-- Check if all names are non-NIL
AllPresent: PUBLIC PROC [list: LIST OF PW.ObjName] RETURNS [b: BOOLTRUE] =
{WHILE list#NIL DO b ← b AND list.first#NIL; list ← list.rest; ENDLOOP};
RequiredTile: PUBLIC PROC[from, to: CD.Design, tilesPrefix: ROPE, tilesFetched: REF LIST OF ROPE, name1, name2, name3: PW.ObjName ← NIL] RETURNS [PW.ObjName] =
{RETURN[GetTile[from, to, tilesPrefix, tilesFetched, name1, name2, name3, TRUE]]};
OptionalTile: PUBLIC PROC[from, to: CD.Design, tilesPrefix: ROPE, tilesFetched: REF LIST OF ROPE, name1, name2, name3: ROPENIL] RETURNS [PW.ObjName] =
{RETURN[GetTile[from, to, tilesPrefix, tilesFetched, name1, name2, name3, FALSE]]};
-- Check if a tile is present
AlreadyFetched: PROC[tilesFetched: REF LIST OF ROPE, name: ROPE] RETURNS [BOOL] =
BEGIN
list: LIST OF ROPE ← tilesFetched^;
WHILE list#NIL DO IF name=list.first THEN RETURN[TRUE]; list ← list.rest; ENDLOOP;
RETURN[FALSE];
END;
ListRefAnyToListRope: PUBLIC PROC [list: LIST OF REF] RETURNS [LIST OF ROPE] =
BEGIN
RETURN[IF list=NIL THEN NIL ELSE CONS[NARROW[list.first], ListRefAnyToListRope[list.rest]]];
END;
ListRefAnyToListOfListRope: PUBLIC PROC [list: LIST OF REF] RETURNS [llr: LIST OF LIST OF ROPE] =
BEGIN
IF list=NIL THEN RETURN[NIL];
llr CONS[
ListRefAnyToListRope[NARROW[list.first, LIST OF REF]],
ListRefAnyToListOfListRope[list.rest]];
END;
ReverseList: PUBLIC PROC [list: LIST OF PW.ObjName] RETURNS [newList: LIST OF PW.ObjName] =
BEGIN
newList ← NIL;
WHILE list#NIL DO newList ← CONS[list.first, newList]; list ← list.rest; ENDLOOP;
END;
Length: PUBLIC PROC [list: LIST OF ROPE] RETURNS [length: INT ← 0] =
BEGIN
WHILE list # NIL DO length ← length+1; list ← list.rest; ENDLOOP;
END;
LengthListOfList: PUBLIC PROC [list: LIST OF LIST OF ROPE] RETURNS [length: INT ← 0] =
BEGIN
WHILE list # NIL DO length ← length+Length[list.first]; list ← list.rest; ENDLOOP;
END;
EnsureSize: PUBLIC PROC [list: LIST OF ROPE, quantity: INT] =
{IF Length[list] # quantity THEN ERROR};
-- Read equations one at a time, converting to sum-of-products as we go
GetEQN: PUBLIC PROC[par: SymTab.Ref, inNames, outNames: LIST OF ROPE] RETURNS[BoolOps.TruthTable] =
BEGIN
tt: BoolOps.TruthTable;
inAtoms, reverseAtoms: LIST OF ATOMNIL;
eqnTrees, reversedEqnTrees: LIST OF BoolOps.Tree ← NIL;
message: ROPE;
allErrorMessages: ROPENIL;
IF inNames = NIL OR outNames = NIL THEN
ERROR Error[ParameterErrors, "Both 'Inputs' and 'Outputs' must be specified."];
-- read equations one at a time, converting to sum-of-products as we go
FOR outs: LIST OF ROPE ← outNames, outs.rest WHILE outs # NIL DO
eqn: ROPENIL;
t: BoolOps.Tree ← NIL;
eqn ← CDExpr.FetchRope[par, outs.first].val;
IF eqn = NIL THEN {
allErrorMessages ← Rope.Cat[allErrorMessages, "Equation for output '", outs.first, "' is missing.\n"];
};
FOR i: INT DECREASING IN [0 .. Rope.Length[eqn]) DO -- remove trailing semicolon
ch: CHAR ← Rope.Fetch[eqn, i];
IF ch # ' AND ch # '\t AND ch # '\n THEN {
IF ch = '; AND i > 0 THEN eqn ← Rope.Substr[eqn, 0, i];
EXIT;
};
ENDLOOP;
message ← NIL;
t ← BoolOps.RopeToTree[eqn ! BoolOps.Error => {message ← msg; CONTINUE}];
IF message # NIL THEN
allErrorMessages ← Rope.Cat[allErrorMessages, "Could not translate equation for output '", outs.first, "', error was: ", message, "\n"]
ELSE {
message ← NIL;
t ← BoolOps.TreeToSOP[t ! BoolOps.Error => {message ← msg; CONTINUE}];
IF message # NIL THEN
allErrorMessages ← Rope.Cat[allErrorMessages, "Could not translate output '", outs.first, "' to sum-of-products form, error was: ", message, "\n"]
ELSE {
reversedEqnTrees ← CONS[t, reversedEqnTrees];
};
};
ENDLOOP;
IF ~Rope.Equal[allErrorMessages, NIL] THEN ERROR Error[ParameterErrors, allErrorMessages];
-- reverse our list of equations since it is backwards
FOR trees: LIST OF BoolOps.Tree ← reversedEqnTrees, trees.rest WHILE trees # NIL DO
eqnTrees ← CONS[trees.first, eqnTrees];
ENDLOOP;
-- create a list of atoms from the input names
FOR ins: LIST OF ROPE ← inNames, ins.rest WHILE ins # NIL DO
reverseAtoms ← CONS[Atom.MakeAtom[ins.first], reverseAtoms];
ENDLOOP;
FOR ins: LIST OF ATOM ← reverseAtoms, ins.rest WHILE ins # NIL DO
inAtoms ← CONS[ins.first, inAtoms];
ENDLOOP;
-- make a truth table
message ← NIL;
tt ← BoolOps.SOPToTT[inAtoms, eqnTrees ! BoolOps.Error => {message ← msg; CONTINUE}];
IF message # NIL THEN
ERROR Error[ParameterErrors, Rope.Cat["Could not translate equations to truth table form, error was: ", message, "\n"]];
RETURN[tt];
END;
FetchTT: PUBLIC PROC [par: SymTab.Ref] RETURNS [truthTable: BoolOps.TruthTable] =
BEGIN
-- get the truth table from a file
GetTTFile: PROC[ttFile: ROPE] RETURNS[tt: BoolOps.TruthTable] =
BEGIN
ttStream: IO.STREAM;
explanation: ROPE;
IF ttFile = NIL THEN RETURN[NIL];
ttStream ← FS.StreamOpen[ttFile ! FS.Error => IF error.group = user THEN {ttStream ← NIL; CONTINUE}];
IF ttStream = NIL THEN
ERROR Error[ParameterErrors, Rope.Cat["Could not open truth table file '", ttFile, "'.\n"]];
tt ← BoolOps.StreamToTT[ttStream ! BoolOps.Error => {explanation ← msg; CONTINUE}];
IF explanation # NIL THEN
ERROR Error[ParameterErrors, Rope.Cat["Error in reading truth table: ", explanation, "\n"]];
END;
-- read the truth table directly from parameters file
GetTT: PROC[par: SymTab.Ref] RETURNS[BoolOps.TruthTable] = BEGIN
ref: REF ANY;
ref ← CDExpr.FetchRef[par, "TruthTable"].val;
IF ref = NIL THEN RETURN[NIL];
IF ~ISTYPE[ref, BoolOps.TruthTable] THEN ERROR Error[ParameterErrors, Rope.Cat["TruthTable option is not of type BoolOps.TruthTable!"]];
RETURN[NARROW[ref]];
END;
-- get a truth table
SELECT TRUE FROM
CDExpr.FetchRope[par, "TruthTableFile"].found =>
truthTable ← GetTTFile[CDExpr.FetchRope[par, "TruthTableFile"].val]; -- Read TruthTable from a file
CDExpr.FetchRef[par, "TruthTable"].found =>
truthTable ← GetTT[par]; -- Read TruthTable directly
ENDCASE => -- should be GetEQN[inputNames, outputNames]
truthTable ← NIL;
PWBasics.Output[". . . not tonight dearling, I have a headache !"];
END;
DumpTruthTable: PUBLIC PROC [tt: BoolOps.TruthTable, ttFile: ROPE] = BEGIN
-- dump truth table to file
ttStream: IO.STREAM;
message: ROPENIL;
ttStream ← FS.StreamOpen[ttFile, $create ! FS.Error => IF error.group = user THEN {ttStream ← NIL; CONTINUE}];
IF ttStream = NIL THEN ERROR Error[NoDump, Rope.Cat["Could not create truth table dump file '", ttFile, "'.\n"]];
BoolOps.TTToStream[tt, ttStream ! BoolOps.Error => {message ← msg; CONTINUE}];
IF message # NIL THEN ERROR Error[NoDump, Rope.Cat["Could not dump truth table to file '", ttFile, "', error was: ", message, "\n"]];
END;
END.