GenRichards.mesa
Copyright © 1984, 1985, 1986 by Xerox Corporation. All rights reserved.
Russ Atkinson (RRA) September 15, 1986 11:37:35 pm PDT
This program was hand-converted from Richards.mesa, which started out life as Martin Richards' simple operating system benchmark program (written in BCPL).
DIRECTORY
DragOpsCross,
DragOpsCrossUtils,
HandCoding,
HandCodingPseudos,
HandCodingSupport;
GenRichards: CEDAR PROGRAM
IMPORTS DragOpsCrossUtils, HandCoding, HandCodingPseudos, HandCodingSupport
= BEGIN OPEN DragOpsCross, DragOpsCrossUtils, HandCoding, HandCodingPseudos;
Area: TYPE = HandCodingSupport.Area;
This program takes
2.56 seconds on a Dorado
Total instructions: 693, Bytes: 1094
Offsets in the global frame
gZ: NAT = 0;
gQueuePacketCount: NAT = 1;
gHoldCount: NAT = 2;
gTaskTable: NAT = 3;
gTaskTableSize: NAT = 7;
gTaskList: NAT = 10;
gCurrentTask: NAT = 11;
gCurrentTaskIdentity: NAT = 12;
gAllocObjects: NAT = 13;
gAllocWords: NAT = 14;
gAllocBase: NAT = 15;
gAllocPtr: NAT = 16;
gAllocPtrPtr: NAT = 17;
Reserve space in the global frame for procedure variables
gIdleFunction: NAT = 18;
gDeviceFunction: NAT = 19;
gHandlerFunction: NAT = 20;
gWorkFunction: NAT = 21;
gSIZE: NAT = 22;
Global Labels and stuff
globalFrameCard: LONG CARDINAL; -- global frame base
globalFrame: Word; -- global frame base as word
externalAlloc: Label ← NIL;
externalMove: Label ← NIL;
enterInit: Label ← NIL;
enterAlloc: Label ← NIL;
enterInitScheduler: Label ← NIL;
enterCreateTask: Label ← NIL;
enterCreatePacket: Label ← NIL;
enterQueuePacket: Label ← NIL;
enterAppend: Label ← NIL;
enterSchedule: Label ← NIL;
enterWait: Label ← NIL;
enterHoldSelf: Label ← NIL;
enterRelease: Label ← NIL;
enterFindTask: Label ← NIL;
enterCreateIdler: Label ← NIL;
enterIdleFunction: Label ← NIL;
enterCreateDevice: Label ← NIL;
enterDeviceFunction: Label ← NIL;
enterCreateHandler: Label ← NIL;
enterHandlerFunction: Label ← NIL;
enterCreateWorker: Label ← NIL;
enterWorkFunction: Label ← NIL;
enterMain: Label ← NIL;
TaskControlBlock: TYPE = RECORD [
link: Task,
identity: TaskIdentity,
priority: TaskPriority,
input: WorkQueue,
state: TaskState,
function: TaskOperation,
handle: LONG POINTER];
tcbLink: NAT = 0;
tcbIdentity: NAT = 1;
tcbPriority: NAT = 2;
tcbInput: NAT = 3;
tcbState: NAT = 4;
tcbFunction: NAT = 5;
tcbHandle: NAT = 6;
tcbSIZE: NAT = 7;
WorkQueue: TYPE = LONG POINTER TO Packet;
Packet: TYPE = RECORD [
link: WorkQueue,
identity: TaskIdentity,
kind: PacketKind,
datum: CARDINAL,
data: ARRAY [0..packetBufferSize] OF CARDINAL];
pktLink: NAT = 0;
pktIdentity: NAT = 1;
pktKind: NAT = 2;
pktDatum: NAT = 3;
pktData: NAT = 4;
pktBufferSize: NAT = 3;
pktSIZE: NAT = pktData+pktBufferSize+1;
pktKdevicePacketKind: NAT = 0;
pktKworkPacketKind: NAT = 1;
waiting: Word = CardToWord[10000000000B];
waitingWithPacket: Word = CardToWord[30000000000B];
TaskState: TYPE = RECORD [packetPending, taskWaiting, taskHolding: BOOLFALSE];
packetPending: NAT = 31;
taskWaiting: NAT = 30;
taskHolding: NAT = 29;
All: PROC = {
This procedure generates all of the code for the bench mark. It basically handles housekeeping pertinent to the code generation, but not to the code execution.
area: Area = HandCodingSupport.GetCurrentArea[];
externalAlloc ← HandCodingPseudos.GetGlobalLabel["Basics.AllocVector"];
externalMove ← HandCodingPseudos.GetGlobalLabel["Basics.MoveVector"];
enterInit ← GenLabel[];
enterInitScheduler ← GenLabel[];
enterCreateTask ← GenLabel[];
enterCreatePacket ← GenLabel[];
enterQueuePacket ← GenLabel[];
enterAppend ← GenLabel[];
enterSchedule ← GenLabel[];
enterWait ← GenLabel[];
enterHoldSelf ← GenLabel[];
enterRelease ← GenLabel[];
enterFindTask ← GenLabel[];
enterCreateIdler ← GenLabel[];
enterIdleFunction ← GenLabel[];
enterCreateDevice ← GenLabel[];
enterDeviceFunction ← GenLabel[];
enterCreateHandler ← GenLabel[];
enterHandlerFunction ← GenLabel[];
enterCreateWorker ← GenLabel[];
enterWorkFunction ← GenLabel[];
enterMain ← GenLabel[];
enterAlloc ← GenLabel[];
GenInit[]; -- global frame initialization comes first
GenAlloc[]; -- our pet simple allocator
GenInitScheduler[];
GenCreateTask[];
GenCreatePacket[];
GenQueuePacket[];
GenAppend[];
GenSchedule[];
GenWait[];
GenHoldSelf[];
GenRelease[];
GenFindTask[];
GenCreateIdler[];
GenIdleFunction[];
GenCreateDevice[];
GenDeviceFunction[];
GenCreateHandler[];
GenHandlerFunction[];
GenCreateWorker[];
GenWorkFunction[];
GenMain[];
Reserve the static storage (last to avoid overwriting code)
Reserve the global frame (a page is quite sufficient)
HandCodingSupport.SetOutputPC[globalFrameCard * bytesPerWord];
HandCodingSupport.OutputWord[area, ZerosWord];
};
GenInit: PROC = {
This procedure generates the initialzation code for Puzzle.
area: Area = HandCodingSupport.GetCurrentArea[];
startLabel: Label = GenLabelHere[];
HandCodingPseudos.MakeLabelGlobal["Richards.Init", startLabel];
reserve data statically
globalFrameCard ← HandCodingSupport.ReserveData[1*wordsPerPage] / bytesPerWord;
globalFrame ← CardToWord[globalFrameCard];
{
Initialialize the global variables.
G: RegSpec = reg0;
top: RegSpec = reg1;
drASL[255]; -- ensure that stack is empty, regardless of where it was
drLIQB[globalFrame];
drLC0[];
Initialize the procedure variables (we need one level of indirection for SFCI)
drLIQB[UseLabel32[enterIdleFunction]]; drSRIn[G, gIdleFunction];
drLIQB[UseLabel32[enterDeviceFunction]]; drSRIn[G, gDeviceFunction];
drLIQB[UseLabel32[enterHandlerFunction]]; drSRIn[G, gHandlerFunction];
drLIQB[UseLabel32[enterWorkFunction]]; drSRIn[G, gWorkFunction];
drLIDB[256+1]; drLFC[UseLabel16[externalAlloc]]; drSRIn[G, gAllocBase];
Allocate enough memory to hold the objects we will allocate
drLRIn[G, gAllocBase]; drLIDB[256]; drWSB[0];
init the words field of the sequence
drLIQB[UseLabel32[enterAlloc]]; drSRIn[G, gAllocPtr];
allocPtr: PROC ANY RETURNS ANY ← Alloc
drLRn[G]; drADDB[gAllocPtr]; drSRIn[G, gAllocPtrPtr];
allocPtrPtr: LONG POINTERLOOPHOLE[LONG[@allocPtr]]
drLRn[G]; drADDB[gAllocPtrPtr]; drSRIn[G, gZ];
z ← LOOPHOLE[LONG[@allocPtrPtr]]
drLFC[UseLabel16[enterMain]];
Enter the main program
};
};
GenAlloc: PROC = {
Alloc: PROC [z: UNCOUNTED ZONE, words: CARDINAL] RETURNS [LONG POINTER]
returnLabel: Label = GenLabel[];
rZ: RegSpec = reg0;
rWords: RegSpec = reg1;
G: RegSpec = reg2;
rIndex: RegSpec = reg3;
ProcedureEntry[enterAlloc, 2];
HandCodingPseudos.MakeLabelGlobal["Richards.Alloc", enterAlloc];
drLIQB[globalFrame];
drLRIn[G, gAllocWords];
index: CARDINAL ← allocWords
drLRIn[G, gAllocObjects]; drADDB[1]; drSRIn[G, gAllocObjects];
allocObjects ← allocObjects + 1
drLRIn[G, gAllocWords]; drQADD[topAtop, rWords]; drSRIn[G, gAllocWords];
allocWords ← allocWords + words
drLRn[rIndex];
drLRIn[G, gAllocBase]; drRB[0]; drBC[];
drLRIn[G, gAllocBase]; drADDB[1]; drADD[];
RETURN [@allocBase[index]]
drSRn[rZ];
ProcedureExit[1];
};
GenInitScheduler: PROC = {
InitScheduler: PROC []
G: RegSpec = reg0;
rZero: RegSpec = reg1;
ProcedureEntry[enterInitScheduler, 0];
HandCodingPseudos.MakeLabelGlobal["Richards.InitScheduler", enterInitScheduler];
drLIQB[globalFrame];
drLC0[];
drWRI[rZero, G, gQueuePacketCount]; drWRI[rZero, G, gHoldCount];
queuePacketCount ← holdCount ← 0
drWRI[rZero, G, gAllocWords]; drWRI[rZero, G, gAllocObjects];
allocWords ← allocObjects ← 0
drWRI[rZero, G, gTaskTable]; drWRI[rZero, G, gTaskTable+1];
drWRI[rZero, G, gTaskTable+2]; drWRI[rZero, G, gTaskTable+3];
drWRI[rZero, G, gTaskTable+4]; drWRI[rZero, G, gTaskTable+5];
drWRI[rZero, G, gTaskTable+6];
taskTable ← ALL[noTask]
drWRI[rZero, G, gTaskList];
taskList ← noTask
ProcedureExit[0];
};
GenCreateTask: PROC = {
CreateTask: PROC [identity: TaskIdentity, priority: TaskPriority, initialWorkQueue: WorkQueue, initialState: TaskState, function: TaskOperation, privateData: LONG POINTER]
rIdentity: RegSpec = reg0;
rPriority: RegSpec = reg1;
rInitialWorkQueue: RegSpec = reg2;
rInitialState: RegSpec = reg3;
rFunction: RegSpec = reg4;
rPrivateData: RegSpec = reg5;
G: RegSpec = reg6;
rT: RegSpec = reg7;
ProcedureEntry[enterCreateTask, 6];
HandCodingPseudos.MakeLabelGlobal["Richards.CreateTask", enterCreateTask];
drLIQB[globalFrame];
drLC0[];
{
t: Task ← z.NEW[TaskControlBlock ← [
link: taskList,
identity: identity,
priority: priority,
input: initialWorkQueue,
state: initialState,
function: function,
handle: privateData]];
drLRIn[G, gZ]; drLIB[tcbSIZE];
drLRIn[G, gZ]; drRB[0]; drRB[0]; drSFC[]; drSRn[rT];
t: Task ← z.NEW[TaskControlBlock ...
drLRIn[G, gTaskList]; drSRIn[rT, tcbLink];
link: taskList,
drWRI[rIdentity, rT, tcbIdentity];
identity: identity,
drWRI[rPriority, rT, tcbPriority];
priority: priority,
drWRI[rInitialWorkQueue, rT, tcbInput];
input: initialWorkQueue,
drWRI[rInitialState, rT, tcbState];
state: initialState,
drWRI[rFunction, rT, tcbFunction];
function: function,
drWRI[rPrivateData, rT, tcbHandle];
handle: privateData,
};
drLRn[rT]; drSRIn[G, gTaskList];
taskList ← t
drLRn[rT]; drRADD[pushDst, G, rIdentity]; drWB[gTaskTable];
taskTable[identity] ← t
ProcedureExit[0];
};
GenCreatePacket: PROC = {
CreatePacket: PROC [link: WorkQueue, identity: TaskIdentity, kind: PacketKind]
RETURNS [workQueue: WorkQueue]
rLink: RegSpec = reg0;
rIdentity: RegSpec = reg1;
rKind: RegSpec = reg2;
rWorkQueue: RegSpec = reg3;
G: RegSpec = reg4;
rZero: RegSpec = reg5;
ProcedureEntry[enterCreatePacket, 3];
HandCodingPseudos.MakeLabelGlobal["Richards.CreatePacket", enterCreatePacket];
drLC0[];
drLIQB[globalFrame];
drLC0[];
{
workQueue ← z.NEW[Packet ← [
link: link,
identity: identity,
kind: kind,
datum: 0,
data: ALL[0]]];
drLRIn[G, gZ]; drLIB[pktSIZE];
drLRIn[G, gZ]; drRB[0]; drRB[0]; drSFC[]; drSRn[rWorkQueue];
workQueue ← z.NEW[Packet ...
drWRI[rLink, rWorkQueue, pktLink];
link: link,
drWRI[rIdentity, rWorkQueue, pktIdentity];
identity: identity,
drWRI[rKind, rWorkQueue, pktKind];
kind: kind,
drWRI[rZero, rWorkQueue, pktDatum];
datum: 0,
drWRI[rZero, rWorkQueue, pktData]; drWRI[rZero, rWorkQueue, pktData+1];
drWRI[rZero, rWorkQueue, pktData+2]; drWRI[rZero, rWorkQueue, pktData+3];
data: ALL[0]]]
};
drROR[reg0, const0, rWorkQueue];
RETURN [workQueue]
ProcedureExit[1];
};
GenQueuePacket: PROC = {
QueuePacket: PROC [packet: WorkQueue] RETURNS [task: Task]
rPacket: RegSpec = reg0;
rTask: RegSpec = reg1;
G: RegSpec = reg2;
rT: RegSpec = reg3;
returnLabel: Label = GenLabel[];
ProcedureEntry[enterQueuePacket, 1];
HandCodingPseudos.MakeLabelGlobal["Richards.QueuePacket", enterQueuePacket];
drLC0[];
drLIQB[globalFrame];
drLRIn[rPacket, pktIdentity]; drLFC[UseLabel16[enterFindTask]];
t: Task ← FindTask[packet.identity]
{fiLabel: Label = GenLabel[];
drLRn[rT]; drJNEBBJ[0, UseLabel8B[fiLabel]];
drLC0[]; drJB[UseLabel8A[returnLabel]];
IF t = noTask THEN RETURN [noTask];
SetLabel[fiLabel];
};
drLRIn[G, gQueuePacketCount]; drLIDB[23246];
drRJGEBJ[left: popSrc, right: belowSrcPop, dist: 6];
Halt[201B]; -- bomb out here if the queuePacketCount gets too large
drLRIn[G, gQueuePacketCount]; drADDB[1]; drSRIn[G, gQueuePacketCount];
queuePacketCount ← queuePacketCount+1;
drLC0[]; drSRIn[rPacket, pktLink];
packet.link ← noWork;
drLRIn[G, gCurrentTaskIdentity]; drSRIn[rPacket, pktIdentity];
packet.identity ← currentTaskIdentity;
{
elseLabel: Label = GenLabel[];
fiLabel: Label = GenLabel[];
drLRIn[rT, tcbInput]; drJNEBB[0, UseLabel8B[elseLabel]];
IF t.input = noWork ...
drWRI[rPacket, rT, tcbInput];
t.input ← packet
drLRIn[rT, tcbState];
drLC1[];
drSHDR[FieldDescriptorToCard[[insert: TRUE, mask: packetPending+1, shift: packetPending]]];
drSRIn[rT, tcbState];
t.state.packetPending ← TRUE
drLRIn[rT, tcbPriority]; drLRIn[G, gCurrentTask]; drRB[tcbPriority];
drRJGEBJ[left: popSrc, right: belowSrcPop, dist: UseLabel8B[fiLabel]];
IF t.priority > currentTask.priority THEN ...
drLRn[rT]; drJB[UseLabel8A[returnLabel]];
... RETURN [t]
SetLabel[elseLabel];
drLRn[rPacket]; drRADD[pushDst, rT, const3]; drLFC[UseLabel16[enterAppend]];
ELSE
Append[packet, @t.input];
SetLabel[fiLabel];
};
drLRIn[G, gCurrentTask];
SetLabel[returnLabel];
drSRn[reg0];
RETURN [currentTask]
ProcedureExit[1];
};
GenAppend: PROC = {
Append: PROC [packet: WorkQueue, head: LONG POINTER TO WorkQueue]
rPacket: RegSpec = reg0;
rHead: RegSpec = reg1;
G: RegSpec = reg2;
rZero: RegSpec = reg3;
returnLabel: Label = GenLabel[];
ProcedureEntry[enterAppend, 2];
HandCodingPseudos.MakeLabelGlobal["Richards.Append", enterAppend];
drLIQB[globalFrame];
drLC0[];
drWRI[rZero, rPacket, pktLink];
packet.link ← noWork
{fiLabel: Label = GenLabel[];
drLRIn[rHead, 0]; drJNEBBJ[0, UseLabel8B[fiLabel]];
drWRI[rPacket, rHead, 0]; ProcedureExit[0];
IF head^ = noWork THEN {head^ ← packet; RETURN};
SetLabel[fiLabel];
};
{
FOR mouse: WorkQueue ← head^, mouse.link UNTIL mouse.link = noWork DO
REPEAT
FINISHED => mouse.link ← packet
ENDLOOP;
rMouse: RegSpec = reg4;
loopLabel: Label = GenLabel[];
testLabel: Label = GenLabel[];
drLRIn[rHead, 0];
mouse: WorkQueue ← head^
drJB[UseLabel8A[testLabel]];
HandCodingSupport.WordAlign[];
SetLabel[loopLabel];
drLRIn[rMouse, 0];
drSRn[rMouse];
, mouse.link
SetLabel[testLabel];
drLRIn[rMouse, 0];
drJNEBBJ[0, UseLabel8B[loopLabel]];
UNTIL mouse.link = noWork DO REPEAT
drWRI[rPacket, rMouse, pktLink];
FINISHED => mouse.link ← packet
drDIS[];
ENDLOOP
};
SetLabel[returnLabel];
ProcedureExit[0];
};
GenSchedule: PROC = {
Schedule: PROC []
G: RegSpec = reg0;
rZero: RegSpec = reg1;
rMessage: RegSpec = reg2;
returnLabel: Label = GenLabel[];
ProcedureEntry[enterSchedule, 0];
HandCodingPseudos.MakeLabelGlobal["Richards.Schedule", enterSchedule];
drLIQB[globalFrame];
drLC0[];
drLC0[];
drLRIn[G, gTaskList]; drSRIn[G, gCurrentTask];
currentTask ← taskList
{
testLabel: Label = GenLabel[];
loopLabel: Label = GenLabel[];
drJB[UseLabel8A[testLabel]];
WHILE currentTask # noTask DO
HandCodingSupport.WordAlign[];
SetLabel[loopLabel];
drROR[rMessage, const0, const0];
message ← noWork
{
thenLabel: Label = GenLabel[];
elseLabel: Label = GenLabel[];
fiLabel: Label = GenLabel[];
drLRIn[G, gCurrentTask]; drRB[tcbState]; ExtractField[2, 1];
drJEBB[1, UseLabel8B[thenLabel]];
drLRIn[G, gCurrentTask]; drRB[tcbState]; drLIQB[waiting];
drRJNEB[left: popSrc, right: belowSrcPop, dist: UseLabel8B[elseLabel]];
IF currentTask.state.taskHolding OR currentTask.state = waiting
SetLabel[thenLabel];
drLRIn[G, gCurrentTask]; drRB[tcbLink]; drSRIn[G, gCurrentTask];
drJB[UseLabel8A[fiLabel]];
THEN currentTask ← currentTask.link
SetLabel[elseLabel];
ELSE
{
innerElseLabel: Label = GenLabel[];
IF currentTask.state = waitingWithPacket THEN {
message ← currentTask.input;
currentTask.input ← message.link;
...
};
drLRIn[G, gCurrentTask]; drRB[tcbState]; drLIQB[waitingWithPacket];
drRJNEB[left: popSrc, right: belowSrcPop, dist: UseLabel8B[innerElseLabel]];
IF currentTask.state = waitingWithPacket THEN {
drLRIn[G, gCurrentTask]; drRB[tcbInput]; drSRn[rMessage];
message ← currentTask.input
drLRIn[rMessage, tcbLink]; drLRIn[G, gCurrentTask]; drWB[tcbInput];
currentTask.input ← message.link
{
innerInnerElseLabel: Label = GenLabel[];
innerInnerFiLabel: Label = GenLabel[];
drLRIn[G, gCurrentTask]; drRB[tcbInput];
drJNEBB[0, UseLabel8B[innerInnerElseLabel]];
IF currentTask.input = noWork
drLC0[]; drLRIn[G, gCurrentTask]; drWB[tcbState];
drJB[UseLabel8A[innerInnerFiLabel]];
THEN currentTask.state ← running
SetLabel[innerInnerElseLabel];
LReg[constNI]; drLRIn[G, gCurrentTask]; drWB[tcbState];
ELSE currentTask.state ← [packetPending: TRUE]
SetLabel[innerInnerFiLabel];
};
SetLabel[innerElseLabel];
drLRIn[G, gCurrentTask]; drRB[tcbIdentity]; drSRIn[G, gCurrentTaskIdentity];
currentTaskIdentity ← currentTask.identity;
drLRn[rMessage]; drLRIn[G, gCurrentTask]; drRB[tcbHandle];
drLRIn[G, gCurrentTask]; drRB[tcbFunction]; drSFCI[];
drSRIn[G, gCurrentTask];
currentTask ← currentTask.function[message, currentTask.handle];
};
SetLabel[fiLabel];
};
SetLabel[testLabel];
drLRIn[G, gCurrentTask];
drJNEBBJ[0, UseLabel8B[loopLabel]];
};
SetLabel[returnLabel];
ProcedureExit[0];
};
GenWait: PROC = {
Wait: PROC [] RETURNS [task: Task]
rTask: RegSpec = reg0;
G: RegSpec = reg1;
ProcedureEntry[enterWait, 0];
HandCodingPseudos.MakeLabelGlobal["Richards.Wait", enterWait];
drLC0[];
drLIQB[globalFrame];
drLRIn[G, gCurrentTask]; drRB[tcbState];
drLC1[];
drSHDR[FieldDescriptorToCard[[insert: TRUE, mask: taskWaiting+1, shift: taskWaiting]]];
drLRIn[G, gCurrentTask]; drWB[tcbState];
currentTask.state.taskWaiting ← TRUE
drLRIn[G, gCurrentTask]; drSRn[rTask];
RETURN [currentTask]
ProcedureExit[1];
};
GenHoldSelf: PROC = {
HoldSelf: PROC [] RETURNS [task: Task]
rTask: RegSpec = reg0;
G: RegSpec = reg1;
ProcedureEntry[enterHoldSelf, 0];
HandCodingPseudos.MakeLabelGlobal["Richards.HoldSelf", enterHoldSelf];
drLC0[];
drLIQB[globalFrame];
drLRIn[G, gHoldCount]; drADDB[1]; drSRIn[G, gHoldCount];
holdCount ← holdCount+1
drLRIn[G, gCurrentTask]; drRB[tcbState];
drLC1[];
drSHDR[FieldDescriptorToCard[[insert: TRUE, mask: taskHolding+1, shift: taskHolding]]];
drLRIn[G, gCurrentTask]; drWB[tcbState];
currentTask.state.taskHolding ← TRUE
drLRIn[G, gCurrentTask]; drRB[tcbLink]; drSRn[rTask];
RETURN [currentTask.link]
ProcedureExit[1];
};
GenRelease: PROC = {
Release: PROC [identity: TaskIdentity] RETURNS [task: Task]
rIdentity: RegSpec = reg0;
rTask: RegSpec = reg1;
G: RegSpec = reg2;
rT: RegSpec = reg3;
ProcedureEntry[enterRelease, 1];
HandCodingPseudos.MakeLabelGlobal["Richards.Release", enterRelease];
drLC0[];
drLIQB[globalFrame];
drLRn[rIdentity]; drLFC[UseLabel16[enterFindTask]];
t: Task ← FindTask[identity]
{elseLabel: Label = GenLabel[];
drLRn[rT]; drJNEBBJ[0, UseLabel8B[elseLabel]];
drROR[reg0, const0, const0]; ProcedureExit[1];
IF t = noTask THEN RETURN [noTask];
SetLabel[elseLabel];
};
drLRIn[rT, tcbState];
drLC0[];
drSHDR[FieldDescriptorToCard[[insert: TRUE, mask: taskHolding+1, shift: taskHolding]]];
drSRIn[rT, tcbState];
t.state.taskHolding ← FALSE
{
elseLabel: Label = GenLabel[];
drLRIn[rT, tcbPriority]; drLRIn[G, gCurrentTask]; drRB[tcbPriority];
drRJGEB[left: popSrc, right: belowSrcPop, dist: UseLabel8B[elseLabel]];
IF t.priority > currentTask.priority
drROR[reg0, const0, rT]; ProcedureExit[1];
THEN RETURN [t]
SetLabel[elseLabel];
drRRI[reg0, G, gCurrentTask]; ProcedureExit[1];
ELSE RETURN [currentTask]
};
};
GenFindTask: PROC = {
FindTask: PROC [identity: TaskIdentity] RETURNS [task: Task]
rIdentity: RegSpec = reg0;
rTask: RegSpec = reg1;
G: RegSpec = reg2;
rT: RegSpec = reg3;
returnLabel: Label = GenLabel[];
ProcedureEntry[enterFindTask, 1];
HandCodingPseudos.MakeLabelGlobal["Richards.FindTask", enterFindTask];
drLC0[];
drLIQB[globalFrame];
drRVADD[pushDst, G, rIdentity]; drRB[gTaskTable];
t: Task ← taskTable[identity]
{
drLRn[rT]; drJNEBBJ[0, UseLabel8B[returnLabel]];
IF t = noTask THEN ERROR
Halt[377B];
};
SetLabel[returnLabel];
drROR[reg0, const0, rT];
ProcedureExit[1];
};
GenCreateIdler: PROC = {
CreateIdler: PROC
[identity: TaskIdentity, priority: TaskPriority, work: WorkQueue, state: TaskState]
rIdentity: RegSpec = reg0;
rPriority: RegSpec = reg1;
rWork: RegSpec = reg2;
rState: RegSpec = reg3;
G: RegSpec = reg4;
rData: RegSpec = reg5;
ProcedureEntry[enterCreateIdler, 4];
HandCodingPseudos.MakeLabelGlobal["Richards.CreateIdler", enterCreateIdler];
drLIQB[globalFrame];
drLC0[];
{
data: IdleTaskData ← z.NEW[IdleTaskDataRecord ← [initialControl, 10000]];
drLRIn[G, gZ]; drLIB[2];
drLRIn[G, gZ]; drRB[0]; drRB[0]; drSFC[]; drSRn[rData];
drLIB[1]; drSRIn[rData, 0];
drLIDB[10000]; drSRIn[rData, 1];
};
{
CreateTask[identity, priority, work, state, IdleFunction, data];
drLRn[rIdentity]; drLRn[rPriority]; drLRn[rWork]; drLRn[rState];
drLRn[G]; drADDB[gIdleFunction]; drLRn[rData];
drLFC[UseLabel16[enterCreateTask]];
};
ProcedureExit[0];
};
GenIdleFunction: PROC = {
IdleFunction: TaskOperation
== [work: WorkQueue, word: LONG POINTER] RETURNS [t: Task]
rWork: RegSpec = reg0;
rWord: RegSpec = reg1;
G: RegSpec = reg2;
rT: RegSpec = reg3;
rData: RegSpec = reg4;
returnLabel: Label = GenLabel[];
ProcedureEntry[enterIdleFunction, 2+1];
HandCodingPseudos.MakeLabelGlobal["Richards.IdleFunction", enterIdleFunction];
drSUBB[gIdleFunction]; -- a pointer into the global frame is an implcit argument
drLC0[];
{
elseLabel: Label = GenLabel[];
drLRn[rWord];
data: IdleTaskData ← word
drLRIn[rData, 1]; drRVSUB[topDst, topSrc, const1]; drSRIn[rData, 1];
data.count ← data.count-1
drLRIn[rData, 1]; drJNEBBJ[0, UseLabel8B[elseLabel]];
drLFC[UseLabel16[enterHoldSelf]];
drJB[UseLabel8A[returnLabel]];
IF data.count = 0 THEN RETURN [HoldSelf[]];
SetLabel[elseLabel];
};
{
elseLabel: Label = GenLabel[];
drLRIn[rData, 0]; drQAND[topAtop, const1];
drJNEBB[0, UseLabel8B[elseLabel]];
drLRIn[rData, 0]; ExtractField[0, 31]; drSRIn[rData, 0];
data.control ← data.control/2;
drLIB[5]; drLFC[UseLabel16[enterRelease]]; drJB[UseLabel8A[returnLabel]];
RETURN [Release[deviceA]];
SetLabel[elseLabel];
drLRIn[rData, 0]; ExtractField[0, 31];
drLIDB[0D008H]; drRXOR[belowDst, belowSrc, popSrc]; drSRIn[rData, 0];
data.control ← PrincOpsUtils.BITXOR[data.control/2, hashValue]
drLIB[6]; drLFC[UseLabel16[enterRelease]];
RETURN [Release[deviceB]];
};
SetLabel[returnLabel];
drSRn[reg0];
ProcedureExit[1];
};
GenCreateDevice: PROC = {
CreateDevice: PROC
[identity: TaskIdentity, priority: TaskPriority, work: WorkQueue, state: TaskState]
rIdentity: RegSpec = reg0;
rPriority: RegSpec = reg1;
rWork: RegSpec = reg2;
rState: RegSpec = reg3;
G: RegSpec = reg4;
rData: RegSpec = reg5;
ProcedureEntry[enterCreateDevice, 4];
HandCodingPseudos.MakeLabelGlobal["Richards.CreateDevice", enterCreateDevice];
drLIQB[globalFrame];
drLC0[];
{
data: DeviceTaskData ← z.NEW[DeviceTaskDataRecord ← [noWork]];
drLRIn[G, gZ]; drLIB[2];
drLRIn[G, gZ]; drRB[0]; drRB[0]; drSFC[]; drSRn[rData];
drLC0[]; drSRIn[rData, 0];
};
{
CreateTask[identity, priority, work, state, DeviceFunction, data];
drLRn[rIdentity]; drLRn[rPriority]; drLRn[rWork]; drLRn[rState];
drLRn[G]; drADDB[gDeviceFunction]; drLRn[rData];
drLFC[UseLabel16[enterCreateTask]];
};
ProcedureExit[0];
};
GenDeviceFunction: PROC = {
DeviceFunction: TaskOperation
== [work: WorkQueue, word: LONG POINTER] RETURNS [t: Task]
rWork: RegSpec = reg0;
rWord: RegSpec = reg1;
G: RegSpec = reg2;
rT: RegSpec = reg3;
rData: RegSpec = reg4;
returnLabel: Label = GenLabel[];
ProcedureEntry[enterDeviceFunction, 2+1];
HandCodingPseudos.MakeLabelGlobal["Richards.DeviceFunction", enterDeviceFunction];
drSUBB[gDeviceFunction]; -- a pointer into the global frame is an implcit argument
drLC0[];
{
elseLabel: Label = GenLabel[];
drLRn[rWord];
data: IdleTaskData ← word
drLRn[rWork]; drJNEBB[0, UseLabel8B[elseLabel]];
IF work = noWork THEN
{
innerElseLabel: Label = GenLabel[];
drLRIn[rData, 0]; drJNEBB[0, UseLabel8B[innerElseLabel]];
drLFC[UseLabel16[enterWait]];
drJB[UseLabel8A[returnLabel]];
IF data.pending = noWork THEN RETURN [Wait[]]
SetLabel[innerElseLabel];
};
drRRI[rWork, rData, 0];
work ← data.pending
drLC0[]; drSRIn[rData, 0];
data.pending ← noWork
drLRn[rWork]; drLFC[UseLabel16[enterQueuePacket]];
drJB[UseLabel8A[returnLabel]];
RETURN [QueuePacket[work]]
SetLabel[elseLabel];
ELSE
drWRI[rWork, rData, 0];
data.pending ← work
drLFC[UseLabel16[enterHoldSelf]];
RETURN [HoldSelf[]]
};
SetLabel[returnLabel];
drSRn[reg0];
ProcedureExit[1];
};
GenCreateHandler: PROC = {
CreateHandler: PROC
[identity: TaskIdentity, priority: TaskPriority, work: WorkQueue, state: TaskState]
rIdentity: RegSpec = reg0;
rPriority: RegSpec = reg1;
rWork: RegSpec = reg2;
rState: RegSpec = reg3;
G: RegSpec = reg4;
rData: RegSpec = reg5;
ProcedureEntry[enterCreateHandler, 4];
HandCodingPseudos.MakeLabelGlobal["Richards.CreateHandler", enterCreateHandler];
drLIQB[globalFrame];
drLC0[];
{
data: HandlerTaskData ← z.NEW[HandlerTaskDataRecord ← [noWork, noWork]];
drLRIn[G, gZ]; drLIB[2];
drLRIn[G, gZ]; drRB[0]; drRB[0]; drSFC[]; drSRn[rData];
drLC0[]; drSRIn[rData, 0];
drLC0[]; drSRIn[rData, 1];
};
{
CreateTask[identity, priority, work, state, HandlerFunction, data];
drLRn[rIdentity]; drLRn[rPriority]; drLRn[rWork]; drLRn[rState];
drLRn[G]; drADDB[gHandlerFunction]; drLRn[rData];
drLFC[UseLabel16[enterCreateTask]];
};
ProcedureExit[0];
};
GenHandlerFunction: PROC = {
HandlerFunction: TaskOperation
== [work: WorkQueue, word: LONG POINTER] RETURNS [t: Task]
rWork: RegSpec = reg0;
rWord: RegSpec = reg1;
G: RegSpec = reg2;
rT: RegSpec = reg3;
rData: RegSpec = reg4;
rWorkPacket: RegSpec = reg5;
rDevicePacket: RegSpec = reg6;
rCount: RegSpec = reg7;
returnLabel: Label = GenLabel[];
ProcedureEntry[enterHandlerFunction, 2+1];
HandCodingPseudos.MakeLabelGlobal["Richards.HandlerFunction", enterHandlerFunction];
drSUBB[gHandlerFunction]; -- a pointer into the global frame is an implcit argument
drLC0[];
drLRn[rWord];
data: IdleTaskData ← word
drLC0[]; drLC0[];
workPacket, devicePacket: WorkQueue
drLC0[];
count: INTEGER
{elseLabel: Label = GenLabel[];
drLRn[rWork]; drJEBB[0, UseLabel8B[elseLabel]];
IF work # noWork THEN
{
innerElseLabel: Label = GenLabel[];
innerFiLabel: Label = GenLabel[];
drLRIn[rWork, pktKind]; drJNEBB[1, UseLabel8B[innerElseLabel]];
IF work.kind = workPacketKind
drLRn[rWork]; drLRn[rData]; drLFC[UseLabel16[enterAppend]];
THEN Append[work, @data.workIn]
drJB[UseLabel8A[innerFiLabel]];
SetLabel[innerElseLabel];
drLRn[rWork]; drQADD[pushA1, rData]; drLFC[UseLabel16[enterAppend]];
ELSE Append[work, @data.deviceIn]
SetLabel[innerFiLabel];
};
SetLabel[elseLabel];
};
{elseLabel: Label = GenLabel[];
drLRIn[rData, 0]; drJEBB[0, UseLabel8B[elseLabel]];
IF data.workIn # noWork THEN
drRRI[rWorkPacket, rData, 0];
workPacket ← data.workIn
drLRIn[rWorkPacket, pktDatum];
drRBC[rCount, topSrc, constNI]; -- (check for negative while assigning)
count ← workPacket.datum
{
innerElseLabel: Label = GenLabel[];
drLRn[rCount];
drRJLEBJ[left: popSrc, right: const3, dist: UseLabel8B[innerElseLabel]];
IF count > packetBufferSize THEN
drLRIn[rData, 0]; drRB[pktLink]; drSRIn[rData, 0];
data.workIn ← data.workIn.link
drLRn[rWorkPacket]; drLFC[UseLabel16[enterQueuePacket]];
drJB[UseLabel8A[returnLabel]];
RETURN [QueuePacket[workPacket]]
SetLabel[innerElseLabel];
};
{
drLRIn[rData, 1]; drJEBB[0, UseLabel8B[elseLabel]];
IF data.deviceIn # noWork THEN
drRRI[rDevicePacket, rData, 1];
devicePacket ← data.deviceIn
drLRIn[rData, 1]; drRB[pktLink]; drSRIn[rData, 1];
data.deviceIn ← data.deviceIn.link
drRBC[pushDst, rCount, const4];
drQADD[topAtop, rWorkPacket]; drRB[pktData];
drSRIn[rDevicePacket, pktDatum];
devicePacket.datum ← workPacket.data[count]
drQADD[pushA1, rCount];
drQBC[topAtop, constNI]; -- INT => CARDINAL coercion
drSRIn[rWorkPacket, pktDatum];
workPacket.datum ← count+1
drLRn[rDevicePacket]; drLFC[UseLabel16[enterQueuePacket]];
drJB[UseLabel8A[returnLabel]];
RETURN [QueuePacket[devicePacket]]
};
SetLabel[elseLabel];
};
drLFC[UseLabel16[enterWait]];
RETURN [Wait[]]
SetLabel[returnLabel];
drSRn[reg0];
ProcedureExit[1];
};
GenCreateWorker: PROC = {
CreateWorker: PROC
[identity: TaskIdentity, priority: TaskPriority, work: WorkQueue, state: TaskState]
rIdentity: RegSpec = reg0;
rPriority: RegSpec = reg1;
rWork: RegSpec = reg2;
rState: RegSpec = reg3;
G: RegSpec = reg4;
rData: RegSpec = reg5;
ProcedureEntry[enterCreateWorker, 4];
HandCodingPseudos.MakeLabelGlobal["Richards.CreateWorker", enterCreateWorker];
drLIQB[globalFrame];
drLC0[];
{
data: WorkerTaskData ← z.NEW[WorkerTaskDataRecord ← [handlerA, 0]];
drLRIn[G, gZ]; drLIB[2];
drLRIn[G, gZ]; drRB[0]; drRB[0]; drSFC[]; drSRn[rData];
drLC3[]; drSRIn[rData, 0];
drLC0[]; drSRIn[rData, 1];
};
{
CreateTask[identity, priority, work, state, WorkFunction, data];
drLRn[rIdentity]; drLRn[rPriority]; drLRn[rWork]; drLRn[rState];
drLRn[G]; drADDB[gWorkFunction]; drLRn[rData];
drLFC[UseLabel16[enterCreateTask]];
};
ProcedureExit[0];
};
GenWorkFunction: PROC = {
WorkFunction: TaskOperation
== [work: WorkQueue, word: LONG POINTER] RETURNS [t: Task]
rWork: RegSpec = reg0;
rWord: RegSpec = reg1;
G: RegSpec = reg2;
rT: RegSpec = reg3;
rData: RegSpec = reg4;
returnLabel: Label = GenLabel[];
ProcedureEntry[enterWorkFunction, 2+1];
HandCodingPseudos.MakeLabelGlobal["Richards.WorkFunction", enterWorkFunction];
drSUBB[gWorkFunction]; -- a pointer into the global frame is an implcit argument
drLC0[];
drLRn[rWord];
data: IdleTaskData ← word
{elseLabel: Label = GenLabel[];
drLRn[rWork]; drJNEBB[0, UseLabel8B[elseLabel]];
IF work = noWork THEN
drLFC[UseLabel16[enterWait]]; drJB[UseLabel8A[returnLabel]];
RETURN [Wait[]]
SetLabel[elseLabel];
{
data.destination ←
(IF data.destination = handlerA THEN handlerB ELSE handlerA);
drLC3[];
drLRIn[rData, 0]; drJNEBB[3, 6];
drROR[topDst, const0, const4];
drSRIn[rData, 0];
};
drLRIn[rData, 0]; drSRIn[rWork, pktIdentity];
work.identity ← data.destination
drLC0[]; drSRIn[rWork, pktDatum];
work.datum ← 0
{
rI: RegSpec = reg5;
rLimit: RegSpec = reg6;
testLabel: Label = GenLabel[];
loopLabel: Label = GenLabel[];
drLC0[];
drLC3[];
drJB[UseLabel8A[testLabel]];
HandCodingSupport.WordAlign[];
SetLabel[loopLabel];
drLRIn[rData, 1]; drRVADD[topDst, topSrc, const1]; drSRIn[rData, 1];
data.count ← data.count+1;
{elseLabel: Label = GenLabel[];
IF data.count > 26 THEN data.count ← 1;
drLRIn[rData, 1]; drRXOR[topDst, topSrc, constNI];
drLIB[26]; drRXOR[topDst, topSrc, constNI];
drRJGEBJ[left: popSrc, right: belowSrcPop, dist: UseLabel8B[elseLabel]];
drLC1[]; drSRIn[rData, 1];
SetLabel[elseLabel];
};
drLRIn[rData, 1]; drADDB[100B];
drRBC[pushDst, rI, const4];
drQADD[topAtop, rWork]; drWB[pktData];
work.data[i] ← ('A-0C)+data.count-1;
drRADD[rI, rI, const1];
SetLabel[testLabel];
drRJGEBJ[left: topSrc, right: rI, dist: UseLabel8B[loopLabel]];
drAS[256-2];
ENDLOOP
};
drLRn[rWork]; drLFC[UseLabel16[enterQueuePacket]];
RETURN [QueuePacket[work]]
};
SetLabel[returnLabel];
drSRn[reg0];
ProcedureExit[1];
};
GenMain: PROC = {
Main: PROC RETURNS [time: REAL]
rTime: RegSpec = reg0;
G: RegSpec = reg1;
rWorkQ: RegSpec = reg2;
rPulses: RegSpec = reg3;
ProcedureEntry[enterMain, 0];
HandCodingPseudos.MakeLabelGlobal["Richards.Main", enterMain];
workQ: WorkQueue;
pulses: BasicTime.Pulses = BasicTime.GetClockPulses[];
drLC0[]; drLIQB[globalFrame];
drLC0[]; drLC0[];
init rTime, G, rWorkQ, rPulses
drLFC[UseLabel16[enterInitScheduler]];
InitScheduler[]
drLC1[]; drLC0[]; drLC0[]; drLC0[];
drLFC[UseLabel16[enterCreateIdler]];
CreateIdler[idler, 0, noWork, running]
drLC0[]; drLC2[]; drLC1[]; drLFC[UseLabel16[enterCreatePacket]]; drSRn[rWorkQ];
workQ ← CreatePacket[noWork, worker, workPacketKind];
drLRn[rWorkQ]; drLC2[]; drLC1[]; drLFC[UseLabel16[enterCreatePacket]]; drSRn[rWorkQ];
workQ ← CreatePacket[workQ, worker, workPacketKind];
drLC2[]; drLIDB[1000]; drLRn[rWorkQ]; drLIQB[waitingWithPacket];
drLFC[UseLabel16[enterCreateWorker]];
CreateWorker[worker, 1000, workQ, waitingWithPacket];
drLC0[]; drLIB[5]; drLC0[]; drLFC[UseLabel16[enterCreatePacket]]; drSRn[rWorkQ];
workQ ← CreatePacket[noWork, deviceA, devicePacketKind];
drLRn[rWorkQ]; drLIB[5]; drLC0[]; drLFC[UseLabel16[enterCreatePacket]]; drSRn[rWorkQ];
workQ ← CreatePacket[workQ, deviceA, devicePacketKind];
drLRn[rWorkQ]; drLIB[5]; drLC0[]; drLFC[UseLabel16[enterCreatePacket]]; drSRn[rWorkQ];
workQ ← CreatePacket[workQ, deviceA, devicePacketKind];
drLC3[]; drLIDB[2000]; drLRn[rWorkQ]; drLIQB[waitingWithPacket];
drLFC[UseLabel16[enterCreateHandler]];
CreateHandler[handlerA, 2000, workQ, waitingWithPacket];
drLC0[]; drLIB[6]; drLC0[]; drLFC[UseLabel16[enterCreatePacket]]; drSRn[rWorkQ];
workQ ← CreatePacket[noWork, deviceB, devicePacketKind];
drLRn[rWorkQ]; drLIB[6]; drLC0[]; drLFC[UseLabel16[enterCreatePacket]]; drSRn[rWorkQ];
workQ ← CreatePacket[workQ, deviceB, devicePacketKind]
drLRn[rWorkQ]; drLIB[6]; drLC0[]; drLFC[UseLabel16[enterCreatePacket]]; drSRn[rWorkQ];
workQ ← CreatePacket[workQ, deviceB, devicePacketKind]
drLC4[]; drLIDB[2000]; drLRn[rWorkQ]; drLIQB[waitingWithPacket];
drLFC[UseLabel16[enterCreateHandler]];
CreateHandler[handlerB, 2000, workQ, waitingWithPacket]
drLIB[5]; drLIDB[4000]; drLC0[]; drLIQB[waiting];
drLFC[UseLabel16[enterCreateDevice]];
CreateDevice[deviceA, 4000, noWork, waiting]
drLIB[6]; drLIDB[5000]; drLC0[]; drLIQB[waiting];
drLFC[UseLabel16[enterCreateDevice]];
CreateDevice[deviceB, 5000, noWork, waiting];
drLFC[UseLabel16[enterSchedule]];
Schedule[]
drLRIn[G, gQueuePacketCount]; drLIDB[23246];
drRJEBJ[left: popSrc, right: belowSrcPop, dist: 6];
Halt[100B];
IF queuePacketCount # 23246 THEN ERROR Bogus
drLRIn[G, gHoldCount]; drLIDB[9297];
drRJEBJ[left: popSrc, right: belowSrcPop, dist: 6];
Halt[101B];
IF holdCount # 9297 THEN ERROR Bogus
drLRIn[G, gAllocObjects]; drLIDB[20];
drRJEBJ[left: popSrc, right: belowSrcPop, dist: 6];
Halt[102B];
IF allocObjects # 20 THEN ERROR Bogus
Halt[0];
ProcedureExit[1];
The following were not generated, since they are not really applicable in Dragon
IF allocWords # 140 THEN ERROR Bogus;
time ← BasicTime.PulsesToSeconds[BasicTime.GetClockPulses[] - pulses];
};
END.