-- 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; }.