SageImpl.mesa
Copyright Ó 1985, 1987 by Xerox Corporation. All rights reserved.
Barth, October 12, 1988 6:41:58 pm PDT
DIRECTORY Basics, CardTab, Convert, FS, GList, IO, Rope, Sage, SymTab;
SageImpl: CEDAR PROGRAM
IMPORTS Basics, CardTab, Convert, FS, GList, IO, Rope, SymTab
EXPORTS Sage =
BEGIN OPEN Sage;
Error: PUBLIC ERROR [msg: ROPENIL] = CODE;
Parse
ParseData: TYPE = REF ParseDataRec;
ParseDataRec: TYPE = RECORD [
streams: LIST OF IO.STREAM,
names: LIST OF ROPE,
noticeCR: BOOL,
token: ROPE,
char: CHAR,
kind: IO.TokenKind,
charsSkipped: INT];
ParseKeywordProc: TYPE = PROC [pd: ParseData, program: Programming, nextReserved: ROPE];
Parse: PUBLIC PROC [file: ROPE] RETURNS [program: Programming] = {
keywords: LIST OF ROPELIST ["TimingGroups", "NameDutPinTimingGroup", "DutPinFixturePin", "FixturePinChipChannel", "ColumnNames", "Vectors", "End"];
keywordProcs: LIST OF ParseKeywordProc ← LIST[TimingGroups, NameDutPinTimingGroup, DutPinFixturePin, FixturePinChipChannel, ColumnNames, Vectors];
pd: ParseData ← NEW[ParseDataRec];
pd.streams ← LIST[FS.StreamOpen[file]];
pd.names ← LIST[file];
pd.noticeCR ← FALSE;
program ← NEW[ProgrammingRec];
program.timingGroups ← SymTab.Create[];
program.nameDutPinTimingGroup ← SymTab.Create[];
program.dutPinFixturePin ← CardTab.Create[];
program.fixturePinChipChannel ← CardTab.Create[];
program.columnNames ← CardTab.Create[];
ParseToken[pd]; -- prime the pump
DO
IF pd.kind#tokenID THEN ERROR Error["Missing keyword"];
IF NOT Rope.Equal[pd.token, keywords.first, FALSE] THEN ERROR Error["Unknown keyword"];
keywordProcs.first[pd, program, keywords.rest.first];
keywords ← keywords.rest;
keywordProcs ← keywordProcs.rest;
IF keywordProcs=NIL THEN EXIT;
ENDLOOP;
};
TimingGroups: ParseKeywordProc = {
ParseToken[pd];
DO
name: ROPENIL;
group: TimingGroup ← NEW[TimingGroupRec];
IF (name ← ParseName[pd, nextReserved])=NIL THEN EXIT;
Format
IF pd.kind#tokenID THEN ERROR Error["Expecting timing group format"];
group.format ← SELECT TRUE FROM
Rope.Equal[pd.token, "NRZ", FALSE] => NRZ,
Rope.Equal[pd.token, "RZ", FALSE] => RZ,
Rope.Equal[pd.token, "RO", FALSE] => RO,
Rope.Equal[pd.token, "RC", FALSE] => RC,
Rope.Equal[pd.token, "RT", FALSE] => RT,
ENDCASE => ERROR Error["Unknown timing group format"];
ParseToken[pd];
group.delay ← ParseNs[pd];
group.width ← ParseNs[pd];
group.sample ← ParseNs[pd];
group.variableThreshold ← ParseBool[pd];
group.variableLevels ← ParseBool[pd];
ParseSeperator[pd];
IF NOT SymTab.Store[program.timingGroups, name, group] THEN ERROR Error["Multiply defined timing group"];
ENDLOOP;
};
NameDutPinTimingGroup: ParseKeywordProc = {
ParseToken[pd];
DO
name: ROPENIL;
group: DutPinTimingGroup ← NEW[DutPinTimingGroupRec];
groups: DutPinTimingGroups;
IF (name ← ParseName[pd, nextReserved])=NIL THEN EXIT;
IF pd.kind=tokenSINGLE THEN {
IF pd.char#'[ THEN ERROR Error["Bad bus index"];
ParseToken[pd];
group.index ← ParseNumber[pd];
IF pd.char#'] THEN ERROR Error["Bad bus index"];
ParseToken[pd];
}
ELSE group.index ← 0;
group.dutPin ← ParseNumber[pd];
group.timingGroup ← ParseName[pd];
ParseSeperator[pd];
groups ← NARROW[SymTab.Fetch[program.nameDutPinTimingGroup, name].val];
FOR s: DutPinTimingGroups ← groups, s.rest UNTIL s=NIL DO
IF s.first.index=group.index THEN ERROR Error["Multiply defined signal"];
ENDLOOP;
groups ← CONS[group, groups];
[] ← SymTab.Store[program.nameDutPinTimingGroup, name, groups];
ENDLOOP;
};
DutPinFixturePin: ParseKeywordProc = {
ParseToken[pd];
DO
dutPin: CARD ← 0;
fixturePin: REF CARDNEW[CARD];
IF pd.kind#tokenDECIMAL THEN EXIT;
dutPin ← ParseNumber[pd];
fixturePin^ ← ParseNumber[pd];
ParseSeperator[pd];
IF NOT CardTab.Store[program.dutPinFixturePin, dutPin, fixturePin] THEN ERROR Error["Multiply defined Dut Pin"];
ENDLOOP;
};
FixturePinChipChannel: ParseKeywordProc = {
ParseToken[pd];
DO
fixturePin: CARD ← 0;
chipChannel: ChannelAddress ← NEW[ChannelAddressRec];
IF pd.kind#tokenDECIMAL THEN EXIT;
fixturePin ← ParseNumber[pd];
chipChannel.chip ← ParseNumber[pd];
chipChannel.channel ← ParseNumber[pd];
ParseSeperator[pd];
IF NOT CardTab.Store[program.fixturePinChipChannel, fixturePin, chipChannel] THEN ERROR Error["Multiply defined Fixture Pin"];
ENDLOOP;
};
ColumnNames: ParseKeywordProc = {
position: CARD ← 0;
pd.noticeCR ← TRUE;
ParseToken[pd];
DO
SELECT pd.kind FROM
tokenSINGLE => {
IF pd.char#IO.CR THEN ERROR Error["Expecting carriage return in ColumnNames"];
position ← 0;
ParseToken[pd];
};
tokenID => {
name: ROPE;
IF Rope.Equal[pd.token, nextReserved, FALSE] THEN EXIT;
IF Rope.Length[pd.token]#1 THEN ERROR Error["Expecting only one character in ColumnNames"];
position ← position + pd.charsSkipped + 1;
name ← NARROW[CardTab.Fetch[program.columnNames, position].val];
name ← Rope.Concat[name, Rope.FromChar[pd.char]];
[] ← CardTab.Store[program.columnNames, position, name];
ParseToken[pd];
};
ENDCASE => ERROR Error["Expecting character in ColumnNames"];
ENDLOOP;
pd.noticeCR ← FALSE;
};
Vectors: ParseKeywordProc = {
ConsVector: PROC = {
IF triples#NIL THEN {
triplesLength: CARD ← GList.Length[triples];
vectors ← CONS[NEW[ParsedVectorRec[triplesLength]], vectors];
FOR index: CARD DECREASING IN [0..triplesLength) DO
vectors.first[index] ← triples.first;
triples ← triples.rest;
ENDLOOP;
};
};
vectors: LIST OF ParsedVector ← NIL;
triples: LIST OF ParsedVectorTriple ← NIL;
position: CARD ← 0;
vectorLength: CARD ← 0;
pd.noticeCR ← TRUE;
ParseToken[pd];
DO
SELECT pd.kind FROM
tokenSINGLE => {
IF pd.char#IO.CR THEN ERROR Error["Expecting carriage return in Vectors"];
position ← 1;
ParseToken[pd];
ConsVector[];
};
tokenDECIMAL, tokenID => {
triple: ParsedVectorTriple;
skip: CARD;
size: CARD;
IF Rope.Equal[pd.token, nextReserved, FALSE] THEN EXIT;
triple ← NEW[ParsedVectorTripleRec];
skip ← pd.charsSkipped + Rope.Length[pd.token];
size ← VectorColumnToBusSize[program, position + pd.charsSkipped];
triple.value ← ConvertBoolSequence[pd.token, size];
ParseToken[pd];
position ← position + skip;
[triple.inhibit, skip] ← ParseBoolSequence[pd, size];
position ← position + skip;
[triple.mask, skip] ← ParseBoolSequence[pd, size];
position ← position + skip;
triples ← CONS[triple, triples];
};
ENDCASE => ERROR Error["Unknown token type in Vectors"];
ENDLOOP;
pd.noticeCR ← FALSE;
ConsVector[];
vectorLength ← GList.Length[vectors];
program.vectors ← NEW[ParsedVectorsRec[vectorLength]];
FOR index: CARD DECREASING IN [0..vectorLength) DO
program.vectors[index] ← vectors.first;
vectors ← vectors.rest;
ENDLOOP;
};
VectorColumnToBusSize: PROC [program: Programming, column: CARD] RETURNS [size: CARD] = {
name: ROPENARROW[CardTab.Fetch[program.columnNames, column].val];
groups: DutPinTimingGroups;
max: CARD ← 0;
min: CARDLAST[CARD];
IF name=NIL THEN ERROR Error["Some column is not properly named"];
groups ← NARROW[SymTab.Fetch[program.nameDutPinTimingGroup, name].val];
IF groups=NIL THEN ERROR Error["Some signal has vectors but is not defined in NameDutPinTimingGroup"];
UNTIL groups=NIL DO
max ← MAX[groups.first.index, max];
min ← MIN[groups.first.index, min];
groups ← groups.rest;
ENDLOOP;
size ← max-min+1;
};
ParseBool: PROC [pd: ParseData] RETURNS [bool: BOOL] = {
IF pd.kind#tokenID THEN ERROR Error["Expecting boolean"];
IF Rope.Length[pd.token]#1 THEN ERROR Error["Expecting only T or F for boolean"];
bool ← SELECT pd.char FROM
'T, 't => TRUE,
'F, 'f => FALSE,
ENDCASE => ERROR Error["Expecting only T or F for boolean"];
ParseToken[pd];
};
ParseBoolSequence: PROC [pd: ParseData, size: CARD] RETURNS [bools: BoolSequence, skip: CARD] = {
IF NOT (pd.kind=tokenDECIMAL OR pd.kind=tokenID) THEN ERROR Error["Expecting hexadecimal number in Vectors"];
bools ← ConvertBoolSequence[pd.token, size];
ParseToken[pd];
skip ← pd.charsSkipped + Rope.Length[pd.token];
};
ConvertBoolSequence: PROC [token: ROPE, size: CARD] RETURNS [bools: BoolSequence] = {
boolIndex: CARD ← size;
bools ← NEW[BoolSequenceRec[size]];
FOR index: CARD DECREASING IN [0..LOOPHOLE[Rope.Length[token]]) DO
char: CHAR ← Rope.Fetch[token, index];
charValue: CARDSELECT TRUE FROM
char IN ['0..'9] => char-'0,
char IN ['a..'f] => char-'a+10,
char IN ['A..'F] => char-'A+10,
ENDCASE => ERROR Error["Bad hexadecimal digit in Vectors"];
THROUGH [1..4] DO
boolIndex ← boolIndex - 1;
bools[boolIndex] ← IF charValue MOD 2=1 THEN TRUE ELSE FALSE;
IF boolIndex=0 THEN EXIT;
charValue ← charValue / 2;
ENDLOOP;
IF boolIndex=0 AND index#0 THEN ERROR Error["Too many digits"];
ENDLOOP;
};
ParseName: PROC [pd: ParseData, nextReserved: ROPENIL] RETURNS [name: ROPENIL] = {
IF pd.kind#tokenID THEN ERROR Error["Expecting name or keyword"];
IF nextReserved#NIL AND Rope.Equal[pd.token, nextReserved, FALSE] THEN RETURN;
name ← pd.token;
ParseToken[pd];
};
ParseNumber, ParseNs: PROC [pd: ParseData] RETURNS [ns: Ns] = {
IF pd.kind#tokenDECIMAL THEN ERROR Error["Expecting number"];
ns ← Convert.CardFromRope[pd.token];
ParseToken[pd];
};
ParseSeperator: PROC [pd: ParseData] = {
IF pd.kind#tokenSINGLE THEN ERROR Error["Expecting seperator"];
IF pd.char#'; THEN ERROR Error["Bad seperator"];
ParseToken[pd];
};
ParseToken: PROC [pd: ParseData] = {
DO
{
ParseOneToken[pd ! IO.EndOfStream => GOTO PopFile];
EXIT;
EXITS PopFile => {
IO.Close[pd.streams.first];
pd.streams ← pd.streams.rest;
pd.names ← pd.names.rest;
IF pd.streams=NIL THEN ERROR; -- more pops than includes?
LOOP;
};
};
ENDLOOP;
};
ParseOneToken: PROC [pd: ParseData] = {
ParseOnlyOneToken[pd];
IF pd.kind=tokenID AND Rope.Equal[pd.token, "Include", FALSE] THEN {
file: ROPE;
[] ← IO.SkipWhitespace[pd.streams.first ! IO.EndOfStream => GOTO BadInclude];
file ← IO.GetLineRope[pd.streams.first ! IO.EndOfStream => GOTO BadInclude];
pd.streams ← CONS[FS.StreamOpen[file], pd.streams];
pd.names ← CONS[file, pd.names];
ParseOnlyOneToken[pd];
EXITS BadInclude => ERROR Error["No file name for include"];
};
};
ParseOnlyOneToken: PROC [pd: ParseData] = {
[pd.token, pd.charsSkipped] ← IO.GetTokenRope[pd.streams.first, IF pd.noticeCR THEN BreaksCR ELSE Breaks];
pd.char ← Rope.Fetch[pd.token];
pd.kind ← SELECT TRUE FROM
Rope.Length[pd.token]=1 AND (IF pd.noticeCR THEN BreaksCR ELSE Breaks)[pd.char]=break => tokenSINGLE,
pd.char IN ['0..'9] => tokenDECIMAL,
ENDCASE => tokenID;
};
BreaksCR: IO.BreakProc = {
RETURN[SELECT char FROM
IO.CR => break,
IN [IO.NUL .. IO.SP] => sepr,
'[, '], ';, '. => break,
IN ['0..'9], IN ['a..'z], IN ['A..'Z] => other,
ENDCASE => ERROR Error["Illegal character"]];
};
Breaks: IO.BreakProc = {
RETURN[SELECT char FROM
IN [IO.NUL .. IO.SP] => sepr,
'[, '], ';, '. => break,
IN ['0..'9], IN ['a..'z], IN ['A..'Z] => other,
ENDCASE => ERROR Error["Illegal character"]];
};
Transform
historyDepth: CARD = 64;
HistoryIndex: TYPE = [0..historyDepth);
DoubleByte: TYPE = RECORD [first, second: Byte10];
ColumnNameList: TYPE = LIST OF ColumnName;
ColumnName: TYPE = REF ColumnNameRec;
ColumnNameRec: TYPE = RECORD [
column: CARD,
name: ROPE];
TripleSequence: TYPE = REF TripleSequenceRec;
TripleSequenceRec: TYPE = RECORD [elements: SEQUENCE size: CARDINAL OF ChipTripleSequence]; -- chip
ChipTripleSequence: TYPE = ARRAY ChannelIndex OF TripleSequenceIndex;
TripleSequenceIndex: TYPE = RECORD [
assigned: BOOL,
triple: CARDINAL,
sequence: CARDINAL];
Transform: PUBLIC PROC [program: Programming] RETURNS [fixture: Fixture] = {
FindMaxChip: CardTab.EachPairAction = {
ca: ChannelAddress ← NARROW[val];
chips ← MAX[ca.chip+1, chips];
};
BuildColumnNames: CardTab.EachPairAction = {
columnNames ← CONS[NEW[ColumnNameRec], columnNames];
columnNames.first.column ← key;
columnNames.first.name ← NARROW[val];
};
CompareColumns: GList.CompareProc = {
first: ColumnName ← NARROW[ref1];
second: ColumnName ← NARROW[ref2];
RETURN[Basics.CompareCard[first.column, second.column]];
};
FillFormatTiming: SymTab.EachPairAction = {
FOR groups: DutPinTimingGroups ← NARROW[val], groups.rest UNTIL groups=NIL DO
group: DutPinTimingGroup ← groups.first;
fixturePin: REF CARDNARROW[CardTab.Fetch[program.dutPinFixturePin, group.dutPin].val];
chipChannel: ChannelAddress;
timingGroup: TimingGroup;
triplet: CARD ← 0;
IF fixturePin=NIL THEN ERROR Error["No fixture pin assigned for dut pin"];
chipChannel ← NARROW[CardTab.Fetch[program.fixturePinChipChannel, fixturePin^].val];
IF chipChannel=NIL THEN ERROR Error["No chip and channel assigned for fixture pin"];
timingGroup ← NARROW[SymTab.Fetch[program.timingGroups, group.timingGroup].val];
IF timingGroup=NIL THEN ERROR;
fixture[chipChannel.chip].formatTiming[chipChannel.channel] ← timingGroup;
FOR names: ColumnNameList ← columnNames, names.rest UNTIL names=NIL DO
IF Rope.Equal[names.first.name, key] THEN EXIT;
triplet ← triplet + 1;
REPEAT FINISHED => ERROR;
ENDLOOP;
map[chipChannel.chip][chipChannel.channel] ← [TRUE, triplet, group.index];
ENDLOOP;
};
chips: CARD ← 0;
map: TripleSequence;
columnNames: ColumnNameList ← NIL;
[] ← CardTab.Pairs[program.fixturePinChipChannel, FindMaxChip];
fixture ← AllocateFixture[chips];
map ← NEW[TripleSequenceRec[chips]];
FOR chipIndex: CARD IN [0..chips) DO
FOR channelIndex: CARD IN [0..channelsPerChip) DO
map[chipIndex][channelIndex] ← [FALSE, 0, 0];
ENDLOOP;
ENDLOOP;
[] ← CardTab.Pairs[program.columnNames, BuildColumnNames];
columnNames ← NARROW[GList.Sort[columnNames, CompareColumns]];
[] ← SymTab.Pairs[program.nameDutPinTimingGroup, FillFormatTiming];
FOR chipIndex: CARD IN [0..chips) DO
FillMaskInhibitVector[program, fixture[chipIndex], map[chipIndex]];
ENDLOOP;
};
AllocateFixture: PROC [chips: CARD] RETURNS [fixture: Fixture] = {
fixture ← NEW[FixtureRec[chips]];
FOR chipIndex: CARD IN [0..chips) DO
chip: Chip ← NEW[ChipRec[vectorAddressesPerChip]];
fixture[chipIndex] ← chip;
FOR channel: ChannelIndex IN ChannelIndex DO
FOR imIndex: InhibitMaskIndex IN InhibitMaskIndex DO
chip.inhibitMask[imIndex][channel].inhibit ← FALSE;
chip.inhibitMask[imIndex][channel].mask ← FALSE;
ENDLOOP;
ENDLOOP;
FOR vectorIndex: CARD IN [0..vectorAddressesPerChip) DO
FOR byteIndex: ByteIndex IN ByteIndex DO
chip.vectors[vectorIndex][byteIndex] ← 0;
ENDLOOP;
ENDLOOP;
ENDLOOP;
};
FillMaskInhibitVector: PROC [program: Programming, chip: Chip, map: ChipTripleSequence] = {
history: ARRAY HistoryIndex OF CARD32;
FOR historyIndex: HistoryIndex IN HistoryIndex DO
history[historyIndex] ← 0;
ENDLOOP;
FOR cycle: CARD IN [0..program.vectors.size) DO
current: CARD32 ← 0;
vector: ParsedVector ← program[cycle];
FOR channelIndex: ChannelIndex IN ChannelIndex DO
tsi: TripleSequenceIndex ← map[channelIndex];
current ← Basics.BITSHIFT[current, 1];
IF map[channelIndex].assigned THEN IF vector[tsi.triple][tsi.sequence] THEN current ← Basics.BITOR[current, 1];
ENDLOOP;
ENDLOOP;
};
Pickle
Pickle: PUBLIC PROC [fixture: Fixture, file: ROPE] = {
};
Unpickle: PUBLIC PROC [file: ROPE] RETURNS [fixture: Fixture] = {
};
END.