-- ConnectorImpl.mesa
-- last edited by Suzuki: 5-Jan-82 15:24:38
DIRECTORY
Connector,
MOSSIMFunc,
Process,
Rope,
RandomCard,
SimTsim,
Storage,
TTY;
ConnectorImpl: MONITOR
IMPORTS RandomCard, SimTsim, Storage, Process, TTY
EXPORTS Connector, MOSSIMFunc = {
Node: PUBLIC TYPE = RECORD [
value: REF ANY,
cond: CONDITION,
waitingArrayLength: CARDINAL ← 0,
waiting: POINTER TO ARRAY OF LONG POINTER TO CONDITION ← NIL,
port: REF Port,
max: CARDINAL ← 0,
body: SEQUENCE size: [0..LAST[INTEGER]] OF RECORD [
choice: PrivateChoice,
response: CARDINAL,
direction: {Up, Down, Change}]
];
PrivateHandle: TYPE = REF Node;
Port: TYPE = RECORD [
body: SELECT size: {Single, Multiple} FROM
Single => [handle: SimTsim.nptr],
Multiple => [handle: REF PortSequence],
ENDCASE];
PortSequence: TYPE = RECORD[SEQUENCE size: [0..LAST[INTEGER]] OF SimTsim.nptr];
ChoiceNode: PUBLIC TYPE = RECORD [
response: CARDINAL,
cond: CONDITION];
PrivateChoice: TYPE = REF ChoiceNode;
TooManyWaiting: SIGNAL = CODE;
OutOfBounds: ERROR = CODE;
Assign: PUBLIC PROC [cond: LONG POINTER TO CONDITION, h:PrivateHandle]
RETURNS [CARDINAL] = {
IF h.waiting=NIL THEN {
h.waiting ← Storage.Node[20];
h.waitingArrayLength ← 10;
FOR i: NAT IN [0..10) DO
h.waiting[i] ← NIL ENDLOOP};
FOR i: NAT IN [0..10) DO
IF h.waiting[i]=NIL THEN {h.waiting[i] ← cond; RETURN[i]};
REPEAT
FINISHED => SIGNAL TooManyWaiting
ENDLOOP;
RETURN[0]};
CreateChoice: PUBLIC PROC RETURNS [PrivateChoice] = {
choice: PrivateChoice ← NEW[ChoiceNode];
Process.DisableTimeout[@choice.cond];
RETURN[choice]};
RegisterUp: PUBLIC PROC [choice: PrivateChoice, retValue: CARDINAL, port: PrivateHandle] = {
port.body[port.max] ← [choice, retValue, Up];
port.max ← port.max+1};
Remove: PUBLIC PROC [loc: CARDINAL, h: PrivateHandle] = {
IF loc>=h.waitingArrayLength THEN ERROR OutOfBounds;
h.waiting[loc] ← NIL};
GetChoice: PUBLIC PROC [choice: PrivateChoice] RETURNS [CARDINAL] = {
Wait[@choice.cond];
RETURN[choice.response]};
Create: PUBLIC PROC [size: CARDINAL] RETURNS [ret: PrivateHandle] = {
ret ← NEW[Node[size]];
Process.DisableTimeout[@ret.cond]};
Put: PUBLIC PROC [n: PrivateHandle, v: REF ANY] = {
-- WF.WF1["Put S:%u ", v];
CheckAbort[];
StuffIt[n, v];
WakeUp[n];
-- StandardDelay[];
Process.Yield[];
-- WF.WF0["Put F "]
};
Stuff: PROC [n: PrivateHandle, v: REF ANY] = {
-- WF.WF1[" Stuff S:%b ", v];
StuffIt[n, v];
WakeUp[n];
Process.Yield[];
-- WF.WF0[" Stuff F "]
};
StuffIt: ENTRY PROC [n: PrivateHandle, v: REF ANY] = {
n.value ← v};
Place: PUBLIC PROC [n: PrivateHandle, v: REF ANY] = {
CheckAbort[];
StuffIt[n, v];
};
Get: PUBLIC PROC [n: PrivateHandle] RETURNS [ret: REF ANY] = {
-- WF.WF0[" Get S "];
CheckAbort[];
ret ← GrabIt[n];
UNTIL ret#NIL DO
StandardDelay[];
ret ← GrabIt[n];
ENDLOOP;
Process.Yield[]
-- StandardDelay[];
-- WF.WF0[" Get F "]
};
Grab: PUBLIC ENTRY PROC [n: PrivateHandle] RETURNS [ret: REF ANY] = {
-- WF.WF0[" Grab S"];
CheckAbort[];
ret ← n.value;
-- WF.WF0[" Grab F "]
};
GrabIt: ENTRY PROC [n: PrivateHandle] RETURNS[REF ANY] = {
RETURN[n.value]};
GetNew: PUBLIC PROC [n: PrivateHandle, v: BOOLEAN] = {
-- WF.WF1[" GetNew S:%b ", v];
CheckAbort[];
StandardDelay[];
GetNewBody[n, v];
-- WF.WF0[" GetNew F"]
};
GetNewChange: PUBLIC PROC [n: PrivateHandle] = {
CheckAbort[];
Wait[@n.cond]
};
GetNewBody: ENTRY PROC[n: PrivateHandle, v: BOOLEAN] = {
DO
WaitInternal[@n.cond];
IF v=NARROW[n.value, REF BOOLEAN]↑ THEN EXIT;
ENDLOOP;
};
WakeUp: ENTRY PROC [h: PrivateHandle] = {
BROADCAST h.cond;
FOR i: NAT IN [0..h.waitingArrayLength) DO
IF h.waiting[i]#NIL THEN BROADCAST h.waiting[i]↑;
ENDLOOP;
FOR i: NAT IN [0..h.max) DO
IF (SELECT h.body[i].direction FROM
Change => TRUE,
Up => NARROW[h.value, REF BOOLEAN]↑,
Down => NOT NARROW[h.value, REF BOOLEAN]↑,
ENDCASE => FALSE) THEN {
h.body[i].choice.response ← h.body[i].response;
BROADCAST h.body[i].choice.cond};
ENDLOOP;
};
MOSSIMGet: PUBLIC PROC [node: PrivateHandle] = {
n: SimTsim.nptr;
CheckAbort[];
WITH s: node.port SELECT FROM
Single => {
n ← s.handle;
IF SimTsim.pchars[n.npot]='X THEN
SimTsim.error3String["Undefined value: ", "%s*n", n.nname]
ELSE {
val: REF BOOLEAN ← NEW[BOOLEAN ← SimTsim.boolvalue[n.npot]];
Stuff[node, val]}};
Multiple => IF s.handle.size<=16 THEN {
val: REF CARDINAL ← NEW[CARDINAL ← CARDPort[node]];
Stuff[node, val]}
ELSE IF s.handle.size<=32 THEN {
val: REF LONG CARDINAL ← NEW[LONG CARDINAL ← LongCARDPort[node]];
Stuff[node, val]}
ELSE SimTsim.error3String["Unimplemented port type for port: ",
"%s*n", n.nname];
ENDCASE
};
MOSSIMSet: PUBLIC PROC [node: PrivateHandle] = {
-- Assigns value from Sakura to MOSSIM through input ports
CheckAbort[];
IF node.value=NIL THEN { -- make nodes undefined
WITH p: node.port SELECT FROM
Single => SimTsim.setin[p.handle, 'x];
Multiple => FOR i: NAT IN [0..p.handle.size) DO
SimTsim.setin[p.handle[i], 'x] ENDLOOP;
ENDCASE;
RETURN};
WITH node.value SELECT FROM
n: REF BOOLEAN =>
WITH p: node.port SELECT FROM
Single => SimTsim.setin[p.handle, IF n↑ THEN 'h ELSE 'l];
ENDCASE => ERROR;
n: REF CARDINAL =>
WITH p: node.port SELECT FROM
Multiple => IF p.handle.size<=16 THEN {
val: CARDINAL ← n↑;
FOR i: NAT IN [p.handle.size..16) DO val ← val*2 ENDLOOP;
FOR i: NAT IN [0..p.handle.size) DO
SimTsim.setin[p.handle[i], IF val>=100000B THEN 'h ELSE 'l];
val ← val*2;
ENDLOOP}
ELSE ERROR;
ENDCASE => ERROR;
n: REF LONG CARDINAL =>
WITH p: node.port SELECT FROM
Multiple => IF p.handle.size<=32 THEN {
val: LONG CARDINAL ← n↑;
FOR i: NAT IN [p.handle.size..32) DO val ← val*2 ENDLOOP;
FOR i: NAT IN [0..32) DO
SimTsim.setin[p.handle[i], IF val>=20000000000B THEN 'h ELSE 'l];
val ← val*2;
ENDLOOP}
ELSE ERROR;
ENDCASE => ERROR;
ENDCASE => ERROR};
MOSSIMConnect: PUBLIC PROC [node: PrivateHandle, name: STRING] = {
n: SimTsim.nptr ← SimTsim.ufind[name];
CheckAbort[];
IF n=NIL THEN
SimTsim.error3String["Cannot find the name: ", "%s*n", name]
ELSE {
node.port ← NEW[Single Port];
node.port↑ ← [Single[n]]}};
MOSSIMMultiConnectInit, CharMultiConnectInit: PUBLIC PROC [node: PrivateHandle, size: CARDINAL] = {
node.port ← NEW[Multiple Port];
node.port↑ ← AllocatePorts[size]};
AllocatePorts: PROC [size: CARDINAL]
RETURNS [h: Multiple Port] = {
h.handle ← NEW[PortSequence[size]]};
MOSSIMMultiConnectAssign, CharMultiConnectAssign:
PUBLIC PROC [node: PrivateHandle, name: STRING,
loc: CARDINAL] = {
n: SimTsim.nptr ← SimTsim.ufind[name];
CheckAbort[];
IF n=NIL THEN
SimTsim.error3String["Cannot find the name: ", "%s*n", name]
ELSE WITH h: node.port SELECT FROM
Single => ERROR;
Multiple => h.handle[loc] ← n;
ENDCASE => ERROR};
CARDPort: PROC [node: PrivateHandle] RETURNS [ret: CARDINAL] = {
WITH n: node.port SELECT FROM
Single => ERROR;
Multiple =>
SELECT n.handle.size FROM
<= 16 => {
ret ← 0;
FOR i: CARDINAL IN [0..n.handle.size) DO
SELECT SimTsim.pchars[n.handle[i].npot] FROM
'1 => ret ← 2*ret+1;
'0 => ret ← 2*ret;
ENDCASE => SimTsim.error3String[
"This node returns undefined value: ", "%s*n",
n.handle[i].nname];
ENDLOOP};
ENDCASE => ERROR;
ENDCASE};
LongCARDPort: PROC [node: PrivateHandle] RETURNS [ret: LONG CARDINAL] = {
WITH n: node.port SELECT FROM
Single => ERROR;
Multiple =>
SELECT n.handle.size FROM
<= 32 => {
ret ← 0;
FOR i: CARDINAL IN [0..n.handle.size) DO
SELECT SimTsim.pchars[n.handle[i].npot] FROM
'1 => ret ← 2*ret+1;
'0 => ret ← 2*ret;
ENDCASE => SimTsim.error3String[
"This node returns undefined value: ", "%s*n",
n.handle[i].nname];
ENDLOOP};
ENDCASE => ERROR;
ENDCASE};
CharGet: PUBLIC PROC [node: PrivateHandle] = {
n: SimTsim.nptr;
ArrayPort: TYPE = RECORD[SEQUENCE size: [0..LAST[INTEGER]] OF CHARACTER];
CharPorts: PROC [handle: REF PortSequence, size: CARDINAL]
RETURNS [val: REF ArrayPort] = {
val ← NEW [ArrayPort[size]];
FOR i: NAT IN [0..size) DO
val[i] ← SimTsim.pchars[handle[i].npot];
ENDLOOP;
}; -- CharPorts
CheckAbort[];
WITH s: node.port SELECT FROM
Single => {
val: REF CHARACTER ← NEW[CHARACTER ← SimTsim.pchars[s.handle.npot]];
Stuff[node, val]};
Multiple => IF s.handle.size=16 THEN Stuff[node, CharPorts[s.handle, 16]]
ELSE IF s.handle.size=32 THEN Stuff[node, CharPorts[s.handle, 32]]
ELSE SimTsim.error3String["Unimplemented port type for port: ",
"%s*n", n.nname];
ENDCASE
};
Notify: PUBLIC PROC [node: PrivateHandle] = {
val: REF BOOLEAN;
CheckAbort[];
IF node=NIL THEN ERROR;
val ← NARROW[GrabIt[node], REF BOOLEAN];
IF val=NIL THEN
val ← NEW[BOOLEAN]
ELSE IF val↑ THEN
{val↑ ← FALSE;
StuffIt[node, val]};
val↑ ← TRUE;
Put[node, val]};
-- Scheduler
currentProcessSize: CARDINAL;
Pool: TYPE = RECORD [
cond: CONDITION, free: POINTER TO Pool];
MaxCond: CARDINAL = 100;
ConditionPool: ARRAY [0..MaxCond) OF Pool;
FreePool: POINTER TO Pool;
UniversalTime: LONG CARDINAL;
TimeQueue: TYPE = RECORD [
next: REF TimeQueue,
time: LONG CARDINAL,
size: CARDINAL,
events: POINTER TO Pool];
AllTime: REF TimeQueue ← NIL;
Fork: PUBLIC PROC[newProcess: PROC] RETURNS[PROCESS] = {
p: PROCESS;
CheckAbort[];
IncCurrentEntry[];
p ← FORK newProcess[];
Process.Yield[];
RETURN[p]
};
Join: PUBLIC PROC[process: PROCESS] = {
[] ← JOIN process;
};
NotifyAll: PUBLIC PROC[p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13,
p14, p15: PrivateHandle] = {
NotifyInternal[p1];
NotifyInternal[p2];
NotifyInternal[p3];
NotifyInternal[p4];
NotifyInternal[p5];
NotifyInternal[p6];
NotifyInternal[p7];
NotifyInternal[p8];
NotifyInternal[p9];
NotifyInternal[p10];
NotifyInternal[p11];
NotifyInternal[p12];
NotifyInternal[p13];
NotifyInternal[p14];
NotifyInternal[p15]};
NotifyInternal: ENTRY PROC [p: PrivateHandle] = {
IF p=NIL THEN RETURN;
NOTIFY p.cond;
FOR i: NAT IN [0..p.waitingArrayLength) DO
IF p.waiting[i]#NIL THEN NOTIFY p.waiting[i]↑
ENDLOOP;
FOR i: NAT IN [0..p.size) DO
IF p.body[i].choice#NIL THEN NOTIFY p.body[i].choice.cond;
ENDLOOP};
ProcessEnd: PUBLIC ENTRY PROC = {
DecCurrentInternal[];
IF AllTime = NIL THEN RETURN;
IF ~CurrentMore[] THEN NotifyEarliest[];
};
GetProcessSize: PUBLIC ENTRY PROC RETURNS[CARDINAL] = {
RETURN[currentProcessSize]};
Delay: PUBLIC PROC [max: CARDINAL] = {
CheckAbort[];
DelayInternal[max];
Process.Yield[];
};
RandomDelay: PUBLIC PROC [min, max: CARDINAL] = {
CheckAbort[];
DelayInternal[RandomCard.Choose[min, max]]
};
DelayInternal: ENTRY PROC [max: CARDINAL] = {
index: CARDINAL;
startTime: LONG CARDINAL ← UniversalTime+max;
DecCurrentInternal[];
IF currentProcessSize#0 THEN {
PutThisProcess[startTime];
RETURN};
IF startTime<Earliest[] THEN {
currentProcessSize ← currentProcessSize+1;
UniversalTime ← startTime; RETURN};
IF startTime>Earliest[] THEN {
NotifyEarliest[];
PutThisProcess[startTime];
RETURN};
index ← RandomCard.Choose[0,EarliestSize[]];
IF index=0 THEN {
currentProcessSize ← currentProcessSize+1;
UniversalTime ← startTime; RETURN};
NotifyEarliestAt[index-1];
PutThisProcess[startTime]
};
StandardDelay: PUBLIC PROC = {
CheckAbort[];
DelayInternal[RandomCard.Choose[1, 2]];
Process.Yield[];
};
Wait: PUBLIC ENTRY PROC [c: LONG POINTER TO CONDITION] = {
CheckAbort[];
IF currentProcessSize = 0 THEN ERROR;
currentProcessSize ← currentProcessSize-1;
IF AllTime#NIL AND currentProcessSize = 0 THEN NotifyEarliest[];
WAIT c↑;
currentProcessSize ← currentProcessSize+1};
WaitInternal: INTERNAL PROC [c: LONG POINTER TO CONDITION] = {
IF currentProcessSize = 0 THEN ERROR;
currentProcessSize ← currentProcessSize-1;
IF AllTime#NIL AND currentProcessSize = 0 THEN NotifyEarliest[];
WAIT c↑;
currentProcessSize ← currentProcessSize+1};
IncCurrent: PUBLIC PROC = {
CheckAbort[];
IncCurrentEntry[];
Process.Yield[]};
-- Current process size manipulation
CurrentMore: INTERNAL PROC RETURNS[BOOLEAN] = {
RETURN[currentProcessSize#0]
};
DecCurrentInternal: INTERNAL PROC = {
IF currentProcessSize = 0 THEN ERROR;
currentProcessSize ← currentProcessSize-1;
};
IncCurrentEntry: ENTRY PROC = {
currentProcessSize ← currentProcessSize+1;
};
-- Time queue manipulation
Earliest: INTERNAL PROC RETURNS[LONG CARDINAL] = {
IF AllTime=NIL THEN RETURN[LAST[LONG CARDINAL]];
RETURN[AllTime.time]};
EarliestSize: INTERNAL PROC RETURNS[CARDINAL] = {
RETURN[AllTime.size]};
NotifyEarliest: INTERNAL PROC = {
index: CARDINAL ← RandomCard.Choose[0,AllTime.size-1];
NotifyEarliestAt[index]
};
NotifyEarliestAt: INTERNAL PROC [index: CARDINAL] = {
eventQueue: POINTER TO Pool ← AllTime.events;
back: POINTER TO Pool;
currentProcessSize ← currentProcessSize+1;
UniversalTime ← AllTime.time;
IF index=0 THEN {
AllTime.events ← eventQueue.free;
NOTIFY eventQueue.cond;
eventQueue.free ← FreePool;
FreePool ← eventQueue;
IF AllTime.size=1 THEN {
time: REF TimeQueue ← AllTime;
AllTime ← AllTime.next}
ELSE AllTime.size ← AllTime.size-1;
RETURN};
THROUGH [0..index-1) DO
eventQueue ← eventQueue.free;
ENDLOOP;
back ← eventQueue;
eventQueue ← eventQueue.free;
NOTIFY eventQueue.cond;
back.free ← eventQueue.free;
eventQueue.free ← FreePool;
FreePool ← eventQueue;
AllTime.size ← AllTime.size-1;
};
PutToQueue: PROC[newProcess: PROC] = {
LockAndPutThisProcess[UniversalTime];
newProcess[]
};
LockAndPutThisProcess: ENTRY PROC[startTime: LONG CARDINAL] = {
PutThisProcess[startTime]
};
PutThisProcess: INTERNAL PROC[startTime: LONG CARDINAL] = {
timeQueue: REF TimeQueue;
{IF AllTime=NIL OR AllTime.time>startTime THEN GOTO PutFront;
timeQueue ← AllTime;
IF AllTime.time=startTime THEN GOTO PutHere;
FOR timeQueue← AllTime, timeQueue.next UNTIL timeQueue.next=NIL DO
IF timeQueue.time=startTime THEN GOTO PutHere;
IF timeQueue.next.time>startTime THEN GOTO PutAfter
REPEAT
FINISHED =>
IF timeQueue.time=startTime THEN GOTO PutHere
ELSE GOTO PutAfter
ENDLOOP;
EXITS
PutFront => {
time: REF TimeQueue ← NEW[TimeQueue];
event: POINTER TO Pool;
time.next ← AllTime;
AllTime ← time;
time.time ← startTime;
time.size ← 1;
time.events ← FreePool;
IF FreePool = NIL THEN ERROR;
FreePool ← FreePool.free;
time.events.free ← NIL;
event ← time.events;
WAIT event.cond};
PutHere => {
pool: POINTER TO Pool ← FreePool;
IF FreePool=NIL THEN ERROR;
FreePool ← FreePool.free;
pool.free ← timeQueue.events;
timeQueue.events ← pool;
timeQueue.size ← timeQueue.size+1;
WAIT pool.cond};
PutAfter => {
time: REF TimeQueue ← NEW[TimeQueue];
event: POINTER TO Pool;
time.next ← timeQueue.next;
timeQueue.next ← time;
time.time ← startTime;
time.size ← 1;
time.events ← FreePool;
IF FreePool = NIL THEN ERROR;
FreePool ← FreePool.free;
time.events.free ← NIL;
event ← time.events;
WAIT event.cond};
}};
-- Abort
CheckAbort: PROC = {
IF TTY.UserAbort[] THEN ERROR ABORTED};
-- Main part
[] ← RandomCard.InitRandom[seed: -1];
FreePool ← @ConditionPool[0];
{i: CARDINAL;
FOR i IN [0..MaxCond) DO
Process.DisableTimeout[@ConditionPool[i].cond];
ENDLOOP;
FOR i IN [0..MaxCond-1) DO
ConditionPool[i].free ← @ConditionPool[i+1]
ENDLOOP};
ConditionPool[MaxCond-1].free ← NIL;
UniversalTime ← 0;
currentProcessSize ← 0;
}.