-- File: JaMSimMOS.mesa
-- Written by Martin Newell January 1980
-- Last edited: August 19, 1981 10:30 AM
-- JaM interface for running SimMOSFns.mesa

DIRECTORY
IODefs: FROM "IODefs" USING [GetOutputStream, SetOutputStream, WriteChar,
WriteString, WriteLine, CR],
SegmentDefs: FROM "SegmentDefs" USING [FileNameError, FileAccessError],
SimMOSDefs: FROM "SimMOSDefs" USING [SimReset, CircuitReset, ETrans, DTrans,
H, L, X, SH, SL, InitHi, InitLo, GetNodeValue,
SimSolve, MicroStep, SimNode, EnumerateETrans, EnumerateDTrans,
EnumerateNodes, RedefineETrans, RedefineDTrans,Node, Transistor,
NodeNames, NodeAttributes, SetStorage],
SimMOSUtilitiesDefs: FROM "SimMOSUtilitiesDefs" USING [SimMOSUtilities],
SimParserDefs: FROM "SimParserDefs" USING [SimRead, SimWrite],
StreamDefs: FROM "StreamDefs" USING [NewByteStream, StreamHandle, Read,
Write, Append],
StringDefs: FROM "StringDefs" USING [EquivalentString, AppendString],
JaMFnsDefs: FROM "JaMFnsDefs" USING [Register, PopString, PushString,
PopBoolean, PushInteger, PopInteger, GetJaMBreak];

JaMSimMOS: PROGRAM
IMPORTS IODefs, SegmentDefs, SimMOSDefs, SimMOSUtilitiesDefs, SimParserDefs, StreamDefs, StringDefs, JaMFnsDefs =
BEGIN
OPEN IODefs, SegmentDefs, SimMOSDefs, SimMOSUtilitiesDefs, SimParserDefs, StreamDefs, StringDefs, JaMFnsDefs;

CallSimReset: PROCEDURE =
BEGIN --expects nothing
SimReset[];
END;

CallCircuitReset: PROCEDURE =
BEGIN --expects (value) (STRING 0,1,X)
value: STRING ← [50];
PopString[value];
CircuitReset[value[0]];
END;

CallETrans: PROCEDURE =
BEGIN --expects <gate,source,drain> (STRINGs)
gate: STRING ← [50];
source: STRING ← [50];
drain: STRING ← [50];
PopString[drain];
PopString[source];
PopString[gate];
[] ← ETrans[gate,source,drain];
END;

CallDTrans: PROCEDURE =
BEGIN --expects <gate,source,drain> (STRINGs)
gate: STRING ← [50];
source: STRING ← [50];
drain: STRING ← [50];
PopString[drain];
PopString[source];
PopString[gate];
[] ← DTrans[gate,source,drain];
END;

CallH: PROCEDURE =
BEGIN --expects <nodename> (STRING)
nodename: STRING ← [50];
PopString[nodename];
H[nodename];
END;

CallL: PROCEDURE =
BEGIN --expects <nodename> (STRING)
nodename: STRING ← [50];
PopString[nodename];
L[nodename];
END;

CallX: PROCEDURE =
BEGIN --expects <nodename> (STRING)
nodename: STRING ← [50];
PopString[nodename];
X[nodename];
END;

CallSH: PROCEDURE =
BEGIN --expects <nodename> (STRING)
nodename: STRING ← [50];
PopString[nodename];
SH[nodename];
END;

CallSL: PROCEDURE =
BEGIN --expects <nodename> (STRING)
nodename: STRING ← [50];
PopString[nodename];
SL[nodename];
END;

CallInitHi: PROCEDURE =
BEGIN --expects <nodename> (STRING)
nodename: STRING ← [50];
PopString[nodename];
InitHi[nodename];
END;

CallInitLo: PROCEDURE =
BEGIN --expects <nodename> (STRING)
nodename: STRING ← [50];
PopString[nodename];
InitLo[nodename];
END;

CallGetNodeValue: PROCEDURE =
BEGIN --expects <nodename> (STRING) returns <value> (CHARACTER (1,0,X))
nodename: STRING ← [50];
value: STRING ← [1];
PopString[nodename];
value[0] ← GetNodeValue[nodename];
value.length ← 1;
PushString[value];
END;

CallSimSolve: PROCEDURE =
BEGIN --expects nothing, returns #iterations (0 = circuit already settled)
microSteps: CARDINAL ← 0;
AbortSimSolve: PROCEDURE RETURNS[BOOLEAN] =
BEGIN
microSteps ← microSteps+1;
IF microSteps >= MaxMicroSteps THEN
BEGIN
WriteLine["Max microSteps exhausted"];
RETURN[TRUE];
END;
IF GetJaMBreak[] THEN
BEGIN
WriteLine["SimSolve aborted"];
RETURN[TRUE];
END;
RETURN[FALSE];
END;
SimSolve[AbortSimSolve];
PushInteger[microSteps];
END;

MaxMicroSteps: CARDINAL ← 100;

SetMaxMicroSteps: PROCEDURE =
BEGIN --expects <maxmicrosteps> (INTEGER)
--applies only to SimSolve
MaxMicroSteps ← PopInteger[];
END;

CallMicroStep: PROCEDURE =
BEGIN --expects nothing, returns <changed> BOOLEAN
PushInteger[MicroStep[ReportChanges,ReportShorts].changed];
END;

ReportChanges: BOOLEAN ← FALSE;
ReportShorts: BOOLEAN ← TRUE;

SetReportChanges: PROCEDURE =
BEGIN --expects <whetherto> (BOOLEAN)
--applies only to MicroStep
ReportChanges ← PopBoolean[];
END;

SetReportShorts: PROCEDURE =
BEGIN --expects <whetherto> (BOOLEAN)
--applies only to MicroStep
ReportShorts ← PopBoolean[];
END;

CallSimNode: PROCEDURE =
BEGIN --expects <nodename> (STRING)
nodename: STRING ← [50];
PopString[nodename];
[] ← SimNode[nodename, FALSE];
END;

CallSimRead: PROCEDURE =
BEGIN --expects <filename> (STRING)
filename: STRING ← [50];
stream: StreamHandle;
BEGIN ENABLE
BEGIN
FileNameError =>
BEGIN
WriteString[filename];WriteLine[": invalid file name"];
CONTINUE;
END;
FileAccessError =>
BEGIN
WriteString[filename];WriteLine[": invalid file access"];
CONTINUE;
END;
END;
PopString[filename];
IF ~DotInName[filename] THEN AppendString[filename,".sim"];
stream ← NewByteStream[filename,Read];
[] ← SimRead[stream];
stream.destroy[stream];
END;
END;

CallSimWrite: PROCEDURE =
BEGIN --expects <filename> (STRING)
filename: STRING ← [50];
stream: StreamHandle;
PopString[filename];
IF ~DotInName[filename] THEN AppendString[filename,".sim"];
stream ← NewByteStream[filename,Write+Append];
SimWrite[stream];
stream.destroy[stream];
END;

CallWriteState: PROCEDURE =
--write state of entire circuit in JaM to enable restoring same
BEGIN --expects <filename> (STRING)
filename: STRING ← [50];
stream: StreamHandle;
savestream: StreamHandle ← GetOutputStream[];
WriteNode: PROCEDURE[n: Node] RETURNS[BOOLEAN] =
BEGIN
name: STRING ← [50];
value: CHARACTER;
input,storage: BOOLEAN;
[value, input, storage] ← NodeAttributes[n,name];
WriteString[" ("]; WriteString[name]; WriteChar[’)];
WriteLine[
IF value#’X
THENSELECT TRUE FROM
input=> (IF value = ’0 THEN "lo" ELSE "hi"),
storage=> (IF value = ’0 THEN "chlo" ELSE "chhi"),
ENDCASE=> (IF value = ’0 THEN "initlo" ELSE "inithi")
ELSE "x"];
RETURN[FALSE];
END;
PopString[filename];
IF ~DotInName[filename] THEN AppendString[filename,".state"];
stream ← NewByteStream[filename,Write+Append];
SetOutputStream[stream];
[] ← EnumerateNodes[WriteNode];
WriteChar[CR];
SetOutputStream[savestream];
stream.destroy[stream];
END;

DoListETrans: PROCEDURE =
-- List enhancement mode transistors that have given terminal nodes.
-- Wild card is null string
BEGIN --expects <gate,term1,term2> (STRINGs)
gate: STRING ← [50];
term1: STRING ← [50];
term2: STRING ← [50];
PopString[term2];
PopString[term1];
PopString[gate];
ListTrans1[gate,term1,term2,TRUE];
END;

DoListDTrans: PROCEDURE =
-- List enhancement mode transistors that have given terminal nodes.
-- Wild card is null string
BEGIN --expects <gate,term1,term2> (STRINGs)
gate: STRING ← [50];
term1: STRING ← [50];
term2: STRING ← [50];
PopString[term2];
PopString[term1];
PopString[gate];
ListTrans1[gate,term1,term2,FALSE];
END;

ListTrans1: PROCEDURE[gate,term1,term2: STRING, enh: BOOLEAN] =
-- List transistors that have given terminal nodes.
-- Wild card is null string
-- enh = (TRUE,FALSE) for (enhancement,depletion) mode transistors
BEGIN
type: STRING;
PrintTrans: PROCEDURE[t: Transistor] RETURNS[BOOLEAN] =
BEGIN
g: STRING ← [50];
s: STRING ← [50];
d: STRING ← [50];
NodeNames[t,g,s,d];
IFMatchTransistor[t, gate,term1,term2,g,s,d]
THENBEGIN
WriteString[" ("]; WriteString[g];
WriteString[")("]; WriteString[s];
WriteString[")("]; WriteString[d];
WriteString[")"]; WriteString[type];
END;
RETURN[FALSE];
END;
IF enh THEN
BEGIN
type ← "etrans";
[] ← EnumerateETrans[PrintTrans];
END
ELSE
BEGIN
type ← "dtrans";
[] ← EnumerateDTrans[PrintTrans];
END;
WriteChar[CR];
END;

CallRedefineTrans: PROCEDURE =
--Redefine the transistor having given terminal nodes. Wild card is null string
BEGIN --expects <gate,term1,term2, newgate,newsource,newdrain> (STRINGs)
newdrain: STRING ← [50];
newsource: STRING ← [50];
newgate: STRING ← [50];
term2: STRING ← [50];
term1: STRING ← [50];
gate: STRING ← [50];
type: STRING ← "etrans";
trans: Transistor ← NIL;
FindTrans: PROCEDURE[t: Transistor] RETURNS[BOOLEAN] =
BEGIN
g: STRING ← [50];
s: STRING ← [50];
d: STRING ← [50];
NodeNames[t,g,s,d];
IFMatchTransistor[t, gate,term1,term2,g,s,d]
THENBEGIN
IF trans=NIL
THENBEGIN
trans ← t;
RETURN[FALSE];
END
ELSEBEGIN
WriteChar[’(];
WriteString[gate];WriteString[")("];
WriteString[term1];WriteString[")("];
WriteString[term2];
WriteString[") is not unique - will redefine ("];
NodeNames[trans,g,s,d];
WriteString[g];WriteString[")("];
WriteString[s];WriteString[")("];
WriteString[d];WriteChar[’)];
WriteLine[type];
RETURN[TRUE];
END;
END;
RETURN[FALSE];
END;
PopString[newdrain];
PopString[newsource];
PopString[newgate];
PopString[term2];
PopString[term1];
PopString[gate];
[] ← EnumerateETrans[FindTrans];
IF trans#NIL THEN
BEGIN --matches at least one etrans - redefine first one found
[] ← EnumerateDTrans[FindTrans]; --to provoke reporting ambiguity with dtrans
RedefineETrans[trans, newgate,newsource,newdrain]; --do it
END
ELSE
BEGIN --no match with etrans
type ← "dtrans";
[] ← EnumerateDTrans[FindTrans]; --try dtrans
IF trans#NIL THEN RedefineDTrans[trans, newgate,newsource,newdrain];
END;
END;

MatchTransistor: PROCEDURE[trans: Transistor, gate,term1,term2,g,s,d: STRING]
RETURNS[BOOLEAN] =
BEGIN
RETURN[(gate.length=0 OR EquivalentString[g,gate]) AND
(((term1.length=0 OR EquivalentString[s,term1]) AND
(term2.length=0 OR EquivalentString[d,term2])) OR
((term1.length=0 OR EquivalentString[d,term1]) AND
(term2.length=0 OR EquivalentString[s,term2])))];
END;

CallSetStorage: PROCEDURE =
BEGIN --expects <gatesonly> (BOOLEAN)
SetStorage[PopBoolean[]];
END;

DotInName: PROCEDURE[name: STRING] RETURNS[BOOLEAN] =
BEGIN
FOR i:CARDINAL IN [0..name.length) DO
IF name[i]=’. THEN RETURN[TRUE];
ENDLOOP;
RETURN[FALSE];
END;

Register["simreset",CallSimReset];
Register["circuitreset",CallCircuitReset];
Register["etrans",CallETrans];
Register["dtrans",CallDTrans];
Register["hi",CallH];
Register["lo",CallL];
Register["x",CallX];
Register["chhi",CallSH];
Register["chlo",CallSL];
Register["inithi",CallInitHi];
Register["initlo",CallInitLo];
Register["getnodevalue",CallGetNodeValue];
Register["simsolve",CallSimSolve];
Register["maxmicrosteps",SetMaxMicroSteps];
Register["microstep",CallMicroStep];
Register["reportchanges",SetReportChanges];
Register["reportshorts",SetReportShorts];
Register["simnode",CallSimNode];
Register["simread",CallSimRead];
Register["simwrite",CallSimWrite];
Register["writestate",CallWriteState];
Register["listetrans",DoListETrans];
Register["listdtrans",DoListDTrans];
Register["redefinetrans",CallRedefineTrans];
Register["gatestorage",CallSetStorage];

START SimMOSUtilities; --to initialize globals - yuk
SimReset[]

END.