-- File: SimMOSCircuit.mesa
-- Adapted by Martin Newell, January 1980, from MIT’s MOSSIM
-- Last Updated: December 4, 1980 12:40 PM

--
For DStar compile using the /l switch

DIRECTORY
InlineDefs: FROM "InlineDefs" USING[BITAND, BITOR
],
IODefs: FROM "IODefs" USING[WriteLine],
SimMOSAccessDefs: FROM "SimMOSAccessDefs" USING[AllocateTransistor, DestroyNodes, DestroyTransistors, SetNodeFlags, GetNodeFlags, GetNodeName, GetNodeNext, SetTrans, SetTransNext, GetTransGate, GetTransSource, GetTransDrain, GetTransNext],
SimMOSDefs: FROM "SimMOSDefs" USING[Node, Transistor, TransistorRecord, L, H],
SimMOSUtilitiesDefs
: FROM "SimMOSUtilitiesDefs" USING[SimVddInputs, SimGndInputs, DestroyList, SimAtomsLength, SimAtoms, SimETrans, SimDTrans, sVDD, sGND, GateFlag, AllButGateFlag, SetDescriptor, AllButPullupFlag, GateStorage, SimIntern, PullupFlag, InputP, StorageP, OldGndFlag, OldVddFlag];

SimMOSCircuit: PROGRAM
IMPORTS InlineDefs, IODefs,
SimMOSAccessDefs, SimMOSDefs, SimMOSUtilitiesDefs
EXPORTS
SimMOSDefs =
BEGIN OPEN InlineDefs, IODefs,
SimMOSAccessDefs, SimMOSDefs, SimMOSUtilitiesDefs;

--**Circuit Definition**--

SimReset: PUBLIC PROCEDURE =
-- global simulator reset, zaps data base to initial state
BEGIN
i: CARDINAL;
SimVddInputs ← DestroyList[SimVddInputs];
SimGndInputs ← DestroyList[SimGndInputs];
FOR i IN [0..SimAtomsLength) DO
SimAtoms[i] ← DestroyNodes[SimAtoms[i]];
ENDLOOP;
SimETrans ← DestroyTransistors[SimETrans];
SimDTrans ← DestroyTransistors[SimDTrans];
sGND ← SimNode["GND", FALSE]; L["GND"];
sVDD ← SimNode["VDD", FALSE]; H["VDD"];
END;

ETrans: PUBLIC PROCEDURE[gate,source,drain: STRING] RETURNS[t: Transistor] =
-- (ETrans ’gate ’source ’drain) makes an enhancement mode transistor
-- with the specified connections
BEGIN
IF gate.length=0 OR source.length=0 OR drain.length=0 THEN
BEGIN
WriteLine["Null names not allowed in transistor definition"];
RETURN;
END;
RETURN[ETrans1[SimNode[gate,FALSE],SimNode[source,FALSE],SimNode[drain,FALSE]]];
END;

ETrans1: PROCEDURE[gate,source,drain: Node] RETURNS[trans: Transistor] =
BEGIN
gateFlags: WORD ← GetNodeFlags[gate];
trans ← AllocateTransistor[];
SetTrans[trans: trans,
transGate: gate,
transSource: source,
transDrain: drain,
transNext: SimETrans];
gateFlags ← BITOR[gateFlags,GateFlag];
gateFlags ← SetDescriptor[gateFlags];
SetNodeFlags[gate,gateFlags];
SimETrans ← trans;
END;

DTrans: PUBLIC PROCEDURE[gate,source,drain: STRING] RETURNS[t: Transistor] =
-- will either make an enhancement mode transistor with gate connected to VDD,
-- or will mark the relevant node pulled up, and return NIL
BEGIN
IF gate.length=0 OR source.length=0 OR drain.length=0 THEN
BEGIN
WriteLine["Null names not allowed in transistor definition"];
RETURN;
END;
RETURN[DTrans1[SimNode[gate,FALSE],SimNode[source,FALSE],SimNode[drain,FALSE]]];
END;

DTrans1: PROCEDURE[gate,source,drain: Node] RETURNS[trans: Transistor] =
BEGIN
IF source=sVDD OR drain=sVDD THEN
BEGIN -- a pullup - these are not explicitly represented
gateNodeFlags,sourceNodeFlags: WORD;
IF source=sVDD THEN
BEGIN --switch it around
temp: Node = source;
source ← drain;
drain ← temp;
END;
sourceNodeFlags ← GetNodeFlags[source];
sourceNodeFlags ← BITOR[sourceNodeFlags,PullupFlag];
sourceNodeFlags ← SetDescriptor[sourceNodeFlags];
SetNodeFlags[source,sourceNodeFlags];
gateNodeFlags ← GetNodeFlags[gate];
gateNodeFlags ← BITOR[gateNodeFlags,GateFlag];
gateNodeFlags ← SetDescriptor[gateNodeFlags];
SetNodeFlags[gate,gateNodeFlags];
RETURN[NIL];
END
ELSE -- a "yellow" transistor - put it on SimDTrans
BEGIN
gateFlags: WORD ← GetNodeFlags[gate];
trans ← AllocateTransistor[];
SetTrans[trans: trans,
transGate: gate,
transSource: source,
transDrain: drain,
transNext: SimDTrans];
gateFlags ← BITOR[gateFlags,GateFlag];
gateFlags ← SetDescriptor[gateFlags];
SetNodeFlags[gate,gateFlags];
SimDTrans ← trans;
END;
END;

SetStorage: PUBLIC PROCEDURE[gatesOnly: BOOLEAN] =
-- set mode of charge storage
BEGIN
GateStorage ← gatesOnly;
END;

SimNode: PUBLIC PROCEDURE[name: STRING, noCreate: BOOLEAN] RETURNS[n: Node] =
-- (SimNode name) makes a node with the appropriate name. if node
-- already exists, nothing is done (but it is returned). if node does
-- not exist and no-create=t then NIL is returned.
BEGIN
n ← SimIntern[name,noCreate];
END;

--**Circuit Interrogation**--

EnumerateNodes: PUBLIC PROCEDURE[apply: PROCEDURE[Node]RETURNS[abort: BOOLEAN]]
RETURNS[aborted: BOOLEAN] =
--Invoke apply for each node
BEGIN
i: CARDINAL;
nptr: Node;
FOR i IN [0..SimAtomsLength) DO
FOR nptr ← SimAtoms[i], GetNodeNext[nptr] UNTIL nptr=NIL DO
IF apply[nptr] THEN RETURN[TRUE];
ENDLOOP;
ENDLOOP;
RETURN[FALSE];
END;

EnumerateETrans: PUBLIC PROCEDURE[apply: PROCEDURE[Transistor]RETURNS[BOOLEAN]]
RETURNS[aborted: BOOLEAN] =
--Invoke apply for each enhancement mode transistor
--If apply returns TRUE then enumeration is aborted
BEGIN
tptr: Transistor;
FOR tptr ← SimETrans, GetTransNext[tptr] UNTIL tptr=NIL DO
IF apply[tptr] THEN RETURN[TRUE];
ENDLOOP;
RETURN[FALSE];
END;

EnumerateDTrans: PUBLIC PROCEDURE[apply: PROCEDURE[Transistor]RETURNS[BOOLEAN]]
RETURNS[aborted: BOOLEAN] =
--Invoke apply for each depletion mode transistor
-- However, pullup nodes are not explicitly sored
--If apply returns TRUE then enumeration is aborted
BEGIN
tptr: Transistor;
MakeDTrans: PROCEDURE[node: Node] RETURNS[BOOLEAN] =
BEGIN
nodeFlags: WORD ← GetNodeFlags[node];
--don’t use PullupP[node] in next line since gives FALSE if also InputP
IF BITAND[nodeFlags,PullupFlag]#0 THEN
BEGIN
trans: Transistor;
TransRec.transGate ← node;
TransRec.transSource ← node;
TransRec.transDrain ← sVDD;
TransRec.transNext ← NIL;
trans ← LONG[@TransRec];
RETURN[apply[trans]];
END
ELSE RETURN[FALSE];
END;
--enumerate yellow transistors
FOR tptr ← SimDTrans, GetTransNext[tptr] UNTIL tptr=NIL DO
IF apply[tptr] THEN RETURN[TRUE];
ENDLOOP;
--enumerate reconstituted transistors
RETURN[EnumerateNodes[MakeDTrans]];
END;

RedefineETrans: PUBLIC PROCEDURE[trans: Transistor, gate,source,drain: STRING] =
--Redefine terminals of given enhancement mode transistor
BEGIN
IF gate.length=0 OR source.length=0 OR drain.length=0 THEN
BEGIN
WriteLine["Null names not allowed in redefined transistor"];
RETURN;
END;
RedefineETrans1[trans, SimNode[gate,FALSE],SimNode[source,FALSE],SimNode[drain,FALSE]];
END;

RedefineETrans1: PROCEDURE[trans: Transistor, gate,source,drain: Node] =
--Redefine terminals of given transistor
BEGIN
oldGate: Node ← GetTransGate[trans];
oldGateFlags: WORD ← GetNodeFlags[oldGate];
oldTransNext: Transistor ← GetTransNext[trans];
gateFlags: WORD ← GetNodeFlags[gate];
FindGate: PROCEDURE[t: Transistor] RETURNS[BOOLEAN] =
BEGIN
RETURN[GetTransGate[t]=oldGate];
END;
SetTrans[trans: trans,
transGate: gate,
transSource: source,
transDrain: drain,
transNext: oldTransNext];
IF gate#oldGate THEN
BEGIN
gateFlags ← BITOR[gateFlags,GateFlag];
gateFlags ← SetDescriptor[gateFlags];
SetNodeFlags[gate,gateFlags];
IF ~EnumerateETrans[FindGate] THEN
BEGIN --not found - remove GateFlag
oldGateFlags ← AllButGateFlag[oldGateFlags];
oldGateFlags ← SetDescriptor[oldGateFlags];
SetNodeFlags[oldGate,oldGateFlags];
END;
END;
END;

RedefineDTrans: PUBLIC PROCEDURE[trans: Transistor, gate,source,drain: STRING] =
--Redefine terminals of given depletion mode transistor
BEGIN
IF gate.length=0 OR source.length=0 OR drain.length=0 THEN
BEGIN
WriteLine["Null names not allowed in redefined transistor"];
RETURN;
END;
RedefineDTrans1[trans, SimNode[gate,FALSE],SimNode[source,FALSE],SimNode[drain,FALSE]];
END;

RedefineDTrans1: PROCEDURE[trans: Transistor, gate,source,drain: Node] =
BEGIN
oldSource: Node ← GetTransSource[trans];
oldGate: Node ← GetTransGate[trans];
oldPullup: BOOLEAN ← TRUE;
tptr: Transistor;
prevD: Transistor;
FindGate: PROCEDURE[t: Transistor] RETURNS[BOOLEAN] =
BEGIN
RETURN[GetTransGate[t]=oldGate];
END;
--see if transistor is non-pullup, and establish pointer to previous
--cannot use EnumerateDTrans since do not want pullups
prevD ← NIL; --means head of SimDTrans
FOR tptr ← SimDTrans, GetTransNext[tptr] UNTIL tptr=NIL DO
IF tptr=trans THEN
BEGIN
oldPullup ← FALSE;
EXIT;
END;
prevD ← tptr;
ENDLOOP;
IF oldPullup THEN --remove PullupFlag from oldSource - no way of checking if valid!
BEGIN --will get reset if new is pullup
oldSourceFlags: WORD ← GetNodeFlags[oldSource];
oldSourceFlags ← AllButPullupFlag[oldSourceFlags];
oldSourceFlags ← SetDescriptor[oldSourceFlags];
SetNodeFlags[oldSource,oldSourceFlags];
END;
--establish type of new version
IF source=sVDD OR drain=sVDD THEN
BEGIN -- a pullup
IF source=sVDD THEN
BEGIN --switch it around
temp: Node = source;
source ← drain;
drain ← temp;
END;
IF ~oldPullup THEN --yellow becoming pullup - remove it from SimDTrans
BEGIN --previous transistor is prevD (notice lack of releasing space! - boo)
next: Transistor ← GetTransNext[trans];
IF prevD=NIL THEN SimDTrans ← next
ELSE SetTransNext[prevD,next];
END;
--reconnect new pullup
[] ← DTrans1[gate,source,drain];
END
ELSE --new transistor is yellow
BEGIN
IF oldPullup THEN
BEGIN --pullup becoming yellow
[] ← DTrans1[gate,source,drain];
END
ELSE
BEGIN --old and new are yellow
oldTransNext: Transistor ← GetTransNext[trans];
SetTrans[trans: trans,
transGate: gate,
transSource: source,
transDrain: drain,
transNext: oldTransNext];
END;
END;
--adjust gate bit if necessary
IF gate#oldGate THEN
BEGIN
gateFlags: WORD ← GetNodeFlags[gate];
gateFlags ← BITOR[gateFlags,GateFlag];
gateFlags ← SetDescriptor[gateFlags];
SetNodeFlags[gate,gateFlags];
IF ~EnumerateETrans[FindGate] AND ~EnumerateDTrans[FindGate] THEN
BEGIN --not found - remove GateFlag
oldGateFlags: WORD ← GetNodeFlags[oldGate];
oldGateFlags ← AllButGateFlag[oldGateFlags];
oldGateFlags ← SetDescriptor[oldGateFlags];
SetNodeFlags[oldGate,oldGateFlags];
END;
END;
END;

NodeNames: PUBLIC PROCEDURE[trans: Transistor, gate,source,drain: STRING] =
--Copy existing names of terminals of given transistor into strings provided
BEGIN
transGate: Node ← GetTransGate[trans];
transSource: Node ← GetTransSource[trans];
transDrain: Node ← GetTransDrain[trans];
[] ← GetNodeName[transGate,gate];
[] ← GetNodeName[transSource,source];
[] ← GetNodeName[transDrain,drain];
END;

NodeAttributes: PUBLIC PROCEDURE[node: Node, name: STRING]
RETURNS[value: CHARACTER, input,storage: BOOLEAN] =
--Copy existing name of node into string provided, and return other state
BEGIN
[] ← GetNodeName[node,name];
value ← SELECT TRUE FROM
BITAND[GetNodeFlags[node],OldGndFlag]#0 => ’0,
BITAND[GetNodeFlags[node],OldVddFlag]#0 => ’1,
ENDCASE => ’X;
input ← InputP[node];
storage ← StorageP[node];
END;

TransRec: PUBLIC TransistorRecord;
-- used as permanent storage in EnumerateDTrans

END.