-- SakuraRTImpl.mesa -- last edited by Suzuki: 19-Apr-82 10:06:27 DIRECTORY MOSSIMFns USING [assignArg, initializationResult, readFileString, setInputH, setInputL, setInputX, targc], SakuraRT, Process, Rope, RandomCard, SimStep, SimTsim USING [boolvalue, nptr, pchars, pnode, ufind], stdio, Storage, TTY; SakuraRTImpl: MONITOR IMPORTS MOSSIMFns, RandomCard, SimStep, SimTsim, stdio, Storage, Process, TTY EXPORTS SakuraRT = { 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.EnableAborts[@choice.cond]; 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.EnableAborts[@ret.cond]; 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] = { ENABLE UNWIND => NULL; 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 "] }; GetCard: PUBLIC PROC [tree: PrivateHandle] RETURNS [CARDINAL] = { RETURN[NARROW[Get[tree], REF CARDINAL]↑]}; GetBool: PUBLIC PROC [tree: PrivateHandle] RETURNS [BOOLEAN] = { RETURN[NARROW[Get[tree], REF BOOLEAN]↑]}; Grab: PUBLIC ENTRY PROC [n: PrivateHandle] RETURNS [ret: REF ANY] = { ENABLE UNWIND => NULL; -- WF.WF0[" Grab S"]; CheckAbort[]; ret ← n.value; -- WF.WF0[" Grab F "] }; GrabIt: ENTRY PROC [n: PrivateHandle] RETURNS[ret: REF ANY] = { ENABLE UNWIND => NULL; ret ← 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] = { ENABLE UNWIND => NULL; DO WaitInternal[@n.cond]; IF v=NARROW[n.value, REF BOOLEAN]↑ THEN EXIT; ENDLOOP; }; WakeUp: ENTRY PROC [h: PrivateHandle] = { ENABLE UNWIND => NULL; 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; }; SIMGet: 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 PrintStringLine["Undefined value: ", SimTsim.pnode[n]] 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 PrintStringLine["Unimplemented port type for port: ", SimTsim.pnode[s.handle[0]]]; ENDCASE }; SIMSet: 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 => { MOSSIMFns.assignArg[1, SimTsim.pnode[p.handle]]; MOSSIMFns.targc ← 2; MOSSIMFns.setInputX[]}; Multiple => { FOR i: NAT IN [0..p.handle.size) DO MOSSIMFns.assignArg[i+1, SimTsim.pnode[p.handle[i]]]; ENDLOOP; MOSSIMFns.targc ← p.handle.size+1; MOSSIMFns.setInputX[]}; ENDCASE; RETURN}; WITH node.value SELECT FROM n: REF BOOLEAN => WITH p: node.port SELECT FROM Single => { MOSSIMFns.assignArg[1, SimTsim.pnode[p.handle]]; MOSSIMFns.targc ← 2; IF n↑ THEN MOSSIMFns.setInputH[] ELSE MOSSIMFns.setInputL[]}; 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 MOSSIMFns.assignArg[i+1, SimTsim.pnode[p.handle[i]]]; val ← val*2; ENDLOOP; MOSSIMFns.targc ← p.handle.size+1; IF val>=100000B THEN MOSSIMFns.setInputH[] ELSE MOSSIMFns.setInputL[]} 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 MOSSIMFns.assignArg[i+1, SimTsim.pnode[p.handle[i]]]; val ← val*2; ENDLOOP; MOSSIMFns.targc ← 33; IF val>=20000000000B THEN MOSSIMFns.setInputH[] ELSE MOSSIMFns.setInputL[]} ELSE ERROR; ENDCASE => ERROR; ENDCASE => ERROR}; SIMConnect: PUBLIC PROC [node: PrivateHandle, name: STRING] = { n: SimTsim.nptr ← SimTsim.ufind[name]; CheckAbort[]; IF n=NIL THEN PrintStringLine["Cannot find the name: ", name] ELSE { node.port ← NEW[Single Port]; node.port↑ ← [Single[n]]}}; SIMMultiConnectInit, 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]]}; SIMMultiConnectAssign, CharMultiConnectAssign: PUBLIC PROC [node: PrivateHandle, name: STRING, loc: CARDINAL] = { n: SimTsim.nptr ← SimTsim.ufind[name]; CheckAbort[]; IF n=NIL THEN PrintStringLine["Cannot find the name: ", 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 => PrintStringLine[ "This node returns undefined value: ", SimTsim.pnode[n.handle[i]]]; 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 => PrintStringLine[ "This node returns undefined value: ", SimTsim.pnode[n.handle[i]]]; ENDLOOP}; ENDCASE => ERROR; ENDCASE}; CharGet: PUBLIC PROC [node: PrivateHandle] = { 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 PrintStringLine["Unimplemented port type for port: ", SimTsim.pnode[s.handle[0]]]; 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] = { ENABLE UNWIND => NULL; 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 = { ENABLE UNWIND => NULL; DecCurrentInternal[]; IF AllTime = NIL THEN RETURN; IF ~CurrentMore[] THEN NotifyEarliest[]; }; Abort: PUBLIC PROC = { }; ProcessHolder: TYPE = REF ProcessHolderRec; ProcessHolderRec: TYPE = RECORD [ name: PROCESS, next: ProcessHolder]; ProcessHolderList: ProcessHolder ← NIL; CatalogProcId: PUBLIC ENTRY PROC [process: PROCESS] = { ENABLE UNWIND => NULL; processHolder: ProcessHolder ← NEW[ProcessHolderRec]; processHolder.name ← process; processHolder.next ← ProcessHolderList; ProcessHolderList ← processHolder}; AbortAll: PUBLIC ENTRY PROC = { ENABLE UNWIND => NULL; UNTIL ProcessHolderList=NIL DO Process.Abort[ProcessHolderList.name]; ProcessHolderList ← ProcessHolderList.next; ENDLOOP}; GetProcessSize: PUBLIC ENTRY PROC RETURNS[ret: CARDINAL] = { ENABLE UNWIND => NULL; ret ← 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] = { ENABLE UNWIND => NULL; 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] = { ENABLE UNWIND => NULL; 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] = { currentProcessSize ← currentProcessSize-1; IF AllTime#NIL AND currentProcessSize = 0 THEN NotifyEarliest[]; WAIT c↑; currentProcessSize ← currentProcessSize+1}; IncCurrent: PUBLIC PROC = { CheckAbort[]; IncCurrentEntry[]; Process.Yield[]}; DecCurrent: PUBLIC PROC = { CheckAbort[]; DecCurrentEntry[]; 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 = { ENABLE UNWIND => NULL; currentProcessSize ← currentProcessSize+1; }; DecCurrentEntry: ENTRY PROC = { ENABLE UNWIND => NULL; IF currentProcessSize = 0 THEN ERROR; currentProcessSize ← currentProcessSize-1; IF AllTime#NIL AND currentProcessSize = 0 THEN NotifyEarliest[]; }; -- 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; }; 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 }; Unimplementd: SIGNAL = CODE; Alarm: PROC = { SIGNAL Unimplementd}; SIMRead: PUBLIC PROC [file: STRING] = { PrintStringLine["File read started: ", file]; MOSSIMFns.assignArg[1, file]; MOSSIMFns.targc ← 2; MOSSIMFns.readFileString[]; PrintStringLine["", "File read finished"]; PrintStringLine["Initialization started", ""]; UNTIL MOSSIMFns.initializationResult[]=0 DO ENDLOOP; PrintStringLine["Initialization finished", ""]}; PrintStringLine: PROC [s1, s2: stdio.SimString] = { stdio.foutstring[stdio.stdout, s1]; stdio.foutstring[stdio.stdout, s2]; stdio.putc[stdio.CR, stdio.stdout]}; SIMStep: PUBLIC PROC = { [] ← SimStep.step[]; StandardDelay[]}; SakuraWatchProc: PROC = { DO Process.Pause[1]; IF TTY.UserAbort[] THEN { AbortAll[]; EXIT} ENDLOOP}; -- Main part watch: PROCESS; [] ← RandomCard.InitRandom[seed: -1]; FreePool ← @ConditionPool[0]; {i: CARDINAL; FOR i IN [0..MaxCond) DO Process.EnableAborts[@ConditionPool[i].cond]; 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 ← 1; watch ← FORK SakuraWatchProc[]; Process.Detach[watch]; }.