:TITLE[Initialize];
%
Tom Rich 15 October 1982: condition SCB handshake on ESSMode,
to exclude PathFinderMode. Zero low byte of CDC9730 DTab.
Tom Henning 20 September 1982: delete SCB handshake for Tor,
key it on WithCDC9730.
Ed Fiala 14 September 1982: Parameterize RefreshPeriod.
Tom Rich September 8, 1982: WithTor => WithUIB and WithEOM.
Ed Fiala 24 May 1982: Make SCB handshake work for Tor also.
Ed Fiala 17 May 1982: fix DTab comments.
Ed Fiala 14 May 1982: Fix DevFound bug for multitask devices.
Ed Fiala 6 May 1982: Absorb prTime, NWW, RS232Image init from Timer.Mc.
Ed Fiala 28 April 1982: Absorb ESS configuration edits from Tom Rich.
Ed Fiala 21 April 1982: add display of no. ’good’ pages from Initial, new 10
mb Ethernet DTab entries; delete old 10 mb Ethernet DTab entries, WithRDC,
WithUTVFC;
increase viewing delay; default init for vCrystal; conditionals on DTab
entries; device init changes from AMesa system; preserve refresh sequence
from Initial and use normal refresh during LoadRAM calls; eliminate
InitPage2, initpc, contemp, rlink0; speed up PNIP.
Ed Fiala 19 February 1982: delete unused MP code defs, removed ErrorCnt,
ErrorCountx, initr0-3; changed StartDeviceInit and NPages MP codes with
delay so they can be seen.
Ed Fiala 17 December 1981: change PilotMDS and xfMX init for new
Pilot.
%
RV[xCNT,20];*Used everywhere
RV[DevIndex,21];*Used in DeviceInit
RV[Assigned,23];*Used in DeviceInit
RV[rbuf0,24];*Used in DeviceInit
RV[rbuf1,25];*Used in DeviceInit
MC[NextDiskAddr,237];
RV[BootDiskAddr,37];
*Machine initialization begins here; start here from any task.
SoftStart:
xCNT ← HiA[Task0StartLoc], At[SoftStartLoc];
OnPage[InitPage];
xCNT ← (xCNT) or (LoA[Task0StartLoc]), GoTo[InitNotify];
Qtask:xCNT ← LoA[Qloc], At[Task0StartLoc];*Quiesce tasks 15b to 1
xCNT ← (xCNT) or (HiA[Qloc,15]);
DevIndex ← IP[DevIndex]C;
StkP ← DevIndex;
DevIndex ← LoA[QretLoc];
DevIndex ← (DevIndex) or (HiA[QretLoc]);
InitNotify:
Qloop:APCTask&APC ← xCNT;
initRET:
Return;*goes to Qx
*Notify comes here. Leave task’s TPC pointing at Qxy.
Qx:APCTask&APC ← Stack, Call[PFExit], At[Qloc];
*BadWakeup is on a non-overlaid page so that it will remain intact after
*initialization has completed. Wakeup from a device that isn’t reset
*properly comes here.
BadWakeup:
SetFault, GoTo[.];
Qret:LU ← LdF[xCNT,0,3], At[QretLoc]; *xCNT points to this location
xCNT ← (xCNT) - (10000C), GoTo[Qloop,ALU#0];
*Zap devices.
T ← RTemp1 ← 177400C;
RTemp ← 300C;
ZapDloop1:
Output[RTemp];*send 300 to register 0 of all devices
T ← RTemp1 ← (RTemp1) + (20C);
GoTo[ZapDloop1,ALU<0];
T ← RTemp1 ← 177400C;
RTemp ← 0C;
ZapDloop2:
Output[RTemp];*send 0 to register 0 of all devices
T ← RTemp1 ← (RTemp1) + (20C);
GoTo[ZapDloop2,ALU<0];
*During the Pilot1 LoadRAM, xfTemp1 was a state variable for inline refresh.
*Put xfTemp1 back into Refr for regular refresh. This avoids having some
*RAMs go unrefreshed for a longer than normal period.
T ← (xfTemp1) and not (17C);
xfTemp1 ← IP[Refr]C;
StkP ← xfTemp1;
Stack ← T;
xfTemp1 ← IP[NWW]C;
StkP ← xfTemp1;
T ← Stack ← 0C;
xfTemp1 ← IP[RSImage]C;
StkP ← xfTemp1;
Stack ← RS232 ← T;
xfTemp1 ← IP[prTime]C;
StkP ← xfTemp1;
Stack ← 3C;
*xfTemp1 odd for normal refresh on the LoadRAM calls during device init.
*Also need RTemp1 even (to believe starting address) and ZapDloop2 above
*leaves it even.
xfTemp1 ← 1C;
xCNT ← HiA[TimerInitLoc,16];
xCNT ← (xCNT) or (LoA[TimerInitLoc]), Call[InitNotify];
%Init location 7777b to be "PFetch4[PCB,IBuf,4], GoToExternal[MesaRefillLoc];"
= 0 164614 011004. LoadRAM can’t write 7777b. Unfortunately, the Boot
program from the EPROM leaves the machine number in location 7777b and the
software uses ReadRAM to obtain this number, so it can’t be used for code.
However, leave this code (which is untested) in as a comment in case we
can do it later.
%
%xBuf1 ← HiA[7777];
xBuf1 ← (xBuf1) or (LoA[7777]);
T ← 0C;*Data 2
xBuf ← HiA[164614];*Data 0
xBuf ← (xBuf) or (LoA[164614]);
LU ← xBuf;*This mi may be useless
APCTask&APC ← xBuf1;
WriteCS0&2;
xBuf ← HiA[011004];*Data 1
xBuf ← (xBuf) or (LoA[011004]);
LU ← xBuf;*This mi may be useless
APCTask&APC ← xBuf1;
WriteCS1;
%
*Before initializing and starting devices, set up the RM locations that
*must be valid.
RegInit1:
R400 ← 400C;
AllOnes ← (Zero) - 1;
RZero ← Zero;
LoadPage[PNIPPage];
T ← StartDeviceInit, CallP[PNIP];
*Wait ~0.4 seconds for user to view StartDeviceInit 0104. Outer loop
*repeats 32k times, so wait ~ 32k*123 cycles.
xBuf ← 0C, Call[MPWait];
xBuf ← (xBuf) + 1, GoTo[MPWait,R>=0];
*Default vCrystal to 120b (80d), appropriate with a 40 mHz processor crystal.
*If the Dolphin has a UTVFC, then DisplayInit.Mc will correct the value in
*vCrystal for 44.5 mHz or 50 mHz crystals.
xBuf ← IP[vCrystal]C;
StkP ← xBuf;
Stack ← 120C;
:IF[IFE[RefreshPeriod,5000,0,1]]; ********************
Set[RefPerShift,IFE[RefreshPeriod,2400,1,IFE[RefreshPeriod,1200,2]]];
Stack ← LSh[Stack,RefPerShift];
:ENDIF; **********************************************
*Get next disk address from reg 237 and save in reg 37.
xCNT ← NextDiskAddr;
StkP ← xCNT;
T ← Stack;
BootDiskAddr ← T, GoTo[DeviceInit];
*Delay subroutine executes 121d (=7+2*(56+1)) cycles before returning.
MPWaita:
xBuf1 ← 70C, Skip;
MPWait:xBuf1 ← 70C;
xBuf1 ← (xBuf1) - 1, GoTo[.,R>=0];
Return;
%Find and initialize all I/O devices:
The idea is to use RM 40-57 as a "slot table" with one entry per potential
I/O controller. First the table is filled with dummy controller addresses,
and these are clocked out to the controllers. Then, each controller is
interrogated for it’s Device ID, and these names are put in the table.
Then, for each slot, the device ID is looked up in a table (in IMX) of
potential devices, and if a match is found, the entry from the device table
is put into the slot table. A device table entry consists of the uPC value
of the device’s initialization routine (12 bits), and the task number for the
controller. When all slots have been looked up, the task numbers are clocked
out to the controllers, and the associated initialization routines are called
in turn.
To add a new controller to the system, simply add both a device table entry
here and its driver microcode. Note that each entry should be CONDITIONAL
upon having suitable microcode at the device’s starting address to avoid a
wild branch. A system with a DTAB entry but no driver microcode won’t run
on a Dolphin which has the device.
NOTE: ORDER OF BOARDS IN CHASIS IS IMPORTANT.
There are some problems:
1) The table is overlying RM 40-57 and DisplayInit.Mc may call LoadRAM.
When the old LoadRAM is called, xBuf-xBuf3 (RM 44-47) and RTemp (RM 52) will
be smashed and RTemp1 (RM 53) must be even. This means that the UTVFC must
be in chasis slots 0 to 3 or table entries not yet handled will be smashed.
For the new LoadRAM, yBuf-yBuf2 (50-52) will be smashed, so the UTVFC must be
in chasis slots 0 to 7. For both old and new LoadRAM, there must be fewer
than 13b controller mounted or RTemp1 might not be even (this could be fixed
easily).
2) The Ethernet software/StartIO microcode require that the "first board" be
assigned to the primary ethernet task (i.e., xoTask/xiTask or enxTask) and
that the "second board" be assigned to the second task (enxTask2) and the
third board to the third task (enxTask3), etc. This is necessary because
gateway software "knows" through a parameter file that board 1 is on
network X, board 2 on network Y, etc. To achieve this, the "first board"
must be mounted nearest the processor and must be assigned the highest
task number; second board next nearest and next highest task number; etc.
3) The two MIOC controllers want the task numbers assigned in the
opposite way from the Ethernet controllers.
%
*First, a macro to allow nice formatting of the device table entries...
Macro[DTab,IFE[#4,0,,IMData[LH[#1] RH[LShift[#2,4],#3] At[DTabLoc]]
Set[DTabLoc,Add[DTabLoc,1]]]];
Set[DTabBase,Add[InitBase,100]];
Set[DTabLoc,DTabBase];
*DTab[5400,FDinit,FDtask,1];*IFDC (floppy disk--not supported)
*Since DES and FP boards have no init microcode, assemble unconditionally.
DTab[12000,0,0,1];*DES board
DTab[127000,0,0,1];*FP board
DTab[127400,cdcInitLoc,cdcTask,WithCDC];*Color display
DTab[5000,uibInitLoc,uibTask,WithUIB];
DTab[7000,eomHiTaskInitLoc,eomHiTask,WithEOM];
DTab[7400,eomLoTaskInitLoc,eomLoTask,WithEOM];
DTab[4000,eimInitLoc,eimTask,WithEIM];
DTab[4400,vdInitLoc,vdTask,WithCDC9730];
DTab[10000,ioInitLoc,ioTask1,WithMIOC];*1st MIOC
DTab[10000,ioInitLoc,ioTask2,WithMIOC];*2nd MIOC
DTab[3400,xwInInitLoc,xiTask,With3MB];*1st 3mb Ethernet input
DTab[3000,xwOutInitLoc,xoTask,With3MB];*1st 3mb Ethernet output
DTab[3400,xwInInitLoc,xiTask2,With3MB];*2nd 3mb Ethernet input
DTab[3000,xwOutInitLoc2,xoTask2,With3MB];*2nd 3mb Ethernet output
DTab[12400,enxInitLoc,enxTask,With10MB];*1st 10mb Ethernet
DTab[12400,enxInitLoc2,enxTask2,With10MB];*2nd 10mb Ethernet
DTab[12400,enxInitLoc3,enxTask3,With10MB];*3rd 10mb Ethernet
DTab[1400,rdcInitLoc,rdcTask,WithRDC];*SA4000
DTab[2400,rdcInitLoc,rdcTask,WithRDC];*SA4000 kludge
DTab[1000,DisplayInitLoc,DisplayTask,WithUTVFC];*UTVFC ID = 1000b
DTab[0,0,0,1];*Final DTab entry must be Zero
OnPage[InitPage];
DeviceInit:
xCNT ← 57C;
xCNT ← T ← (StkP ← xCNT) + 1, Call[.+1];
*StkP = 57b, xCNT = T = 60b here; write 60-77 into RM 40-57 (StkP counts
*mod 20b, so StkP+1 when StkP .eq. 57b is 40b).
LU ← (xCNT) xor (77C);
Stack&+1 ← T, Skip[ALU=0];
xCNT ← T ← (xCNT) + 1, Return;
*Send dummy controller addresses to devices; wind up with (n lsh 14b) + 3 in
*RM (40b+n).
Assigned ← 0C;*Bit mask of assigned tasks
xCNT ← 57C, Call[ClockOutPattern];
*StkP = 57b here; read controller ID’s from register 0 of all devices.
xCNT ← T ← 177400C, Call[devRET];*Allow xCNT & T to be written
Input[Stack];
xCNT ← T ← (xCNT) + (20C), Skip[R>=0];*Advance to next device
devRET: Return;*Loop
*StkP is now back at 40b since it wraps around the last time it was bumped.
*Have 3000b, 3400b, 1055b, 1417b, etc. followed by 177777b for all undefined
*slots. Look up each slot table entry in the device table. Scan devices
*nearest the CPU first.
xCNT ← 17C;
DI4x:DevIndex ← HiA[DTabBase];*Base of device table in control store
DevIndex ← (DevIndex) or (LoA[DTabBase]);
DI4y:T ← 0C, Call[GetCon];*Get a device ID from the device table
*Compare with the slot table entry (high byte)
LU ← (LHMask[Stack]) xor T;
*Check for end of table (Zero entry)
LU ← T, GoTo[DevFound,ALU=0];
DevIndex ← (DevIndex) + 1, GoTo[DI4y,ALU#0];
*End of table reached without match--set slot’s task to 17 (unused)
Stack ← 17C;
DI4z:xCNT ← (xCNT) - 1;*check for all slots processed
Stack&+1, DblGoTo[DI4x,DI5,ALU>=0]; *set to next slot
DevFound:
T ← (SStkP&NStkP) xor (377C);
rbuf0 ← T;
T ← 1C, Call[GetCon];
rbuf1 ← T;*device table entry contains task assignment
rbuf1 ← LSh[rbuf1,4];*10:13b ← task number about to be assigned
CycleControl ← rbuf1;
T ← WFA[AllOnes];
LU ← (Assigned) and T;
Assigned ← (Assigned) or T, Skip[ALU=0];
*Keep looking, task already assigned
DevIndex ← (DevIndex) + 1, GoTo[DI4y];
T ← CSData;*Recover task assignment
Stack ← T;*Replace slot table entry with device table entry
*Write 177400 + 20b*task into RM 20b*task; this addresses the CSB for the
*device automatically.
StkP ← rbuf1;
T ← (rbuf1) or (177400C);
Stack ← T;
StkP ← rbuf0, GoTo[DI4z];
*Clock out new controller ID’s
DI5:xCNT ← 57C, Call[ClockOutPattern];
%Here the table has task and uPC for existing controllers and 170000b for
non-existent or undefined controllers. NOTE: StkP is 57b, so entries are
handled in the order 57, 56, ..., 41.
%
*Call all the Init routines
xCNT ← 17C;
*Come here from DisplayInit
DI5a:Call[devRET];*do Call to set up TPC for loop below
DI6:xCNT ← (xCNT) - 1, GoTo[BootEmulators,R<0];
LU ← LdF[Stack,4,14];*check for Init PC = 0 (no initialization required)
*Skip to call init routine for controller.
APCTask&APC ← Stack&-1, Skip[ALU#0];
Nop;
Return;
ClockOutPattern:
StkP ← xCNT;
xCNT ← 17C;*go through the slot table backwards
COP1:DevIndex ← 3C;*DevIndex used for loop count
COP2:T ← (Stack) xor (1C);*complement bit
DevIndex ← (DevIndex) - 1, GenSRClock;*send bit
Stack ← RCy[Stack,1], GoTo[COP2,ALU>=0];*get next bit
xCNT ← (xCNT) - 1;*all slot table entries done?
Stack&-1, GoTo[COP1,ALU>=0];*get next word
Return;
GetCon:APCTask&APC ← DevIndex;
ReadCS;
T ← CSData, Return, DispTable[1,1,0];*Force even placement
:IF[ESSMode]; ******************************************
*uib constants for communicating successful boot to SCB
Set[uibTASKL,LShift[uibTask,4]];
MC[BootOKLeft,LShift[25,10]];
MC[TurnOnVideoLeft,LShift[24,10]];
MC[BootDLeft,LShift[30,10]];
MC[RightAllOnes,377];*right side for above commands
MC[MESAregBusy,2000];*if this bit is on the Mesa Command Register is busy
MC[uibRegAddr,Add[uibTASKL,2]];
MC[uibMESAregAddrC,Add[uibTASKL,3]];
*RTemp and PrPsbIndexMask are available scratch registers
SendMessageToSCB:
PrPsbIndexMask ← (PrPsbIndexMask) or (RightAllOnes);
T ← uibRegAddr;*check Mesa register Status
Input[RTemp];
LU ← (RTemp) and (MESAregBusy);
T ← uibMESAregAddrC, GoTo[SendMessageToSCB,ALU#0];
Output[PrPsbIndexMask];*send command to Mesa register
PrPsbIndexMask ← PrPsbIndexMask, Return;*evade output gotcha
:ENDIF; ************************************************
%Initialize Mesa registers except StkP and FFault; LoadRAM will jump to
InitEndLoc (in MesaOP3.Mc) which will setup these two registers and jump to
Xfer which sets up CODE, GLOBAL, etc.
%
MC[PilotMDS,0];
BootEmulators:
prCurrentPsb ← 0C;
:IF[ESSMode]; ******************************************
PrPsbIndexMask ← BootOKLeft, Call[SendMessageToSCB]; *Assert boot is successful
PrPsbIndexMask ← TurnOnVideoLeft, Call[SendMessageToSCB]; *Turn on the UI
PrPsbIndexMask ← BootDLeft, Call[SendMessageToSCB]; *Until bootD in othello
:ENDIF; ************************************************
PrPsbIndexMask ← HiA[7774];
PrPsbIndexMask ← (PrPsbIndexMask) or (LoA[7774]), Task;
MemStat ← Normal;
xfMX ← 1000C;
xfMX ← (xfMX) or (2C), Task;
xfWDC ← 1C;
MDS ← 0C, Task;
xfGFIWord ← 0C;
xfXTSReg ← 0C;
xfBrkByte ← 40400C;*2001b rcy 2
*NWW, RSImage, and RS232 were zeroed by Timer.Mc initialization.
*Show count of ’good’ pages from Initial.
xBuf ← IP[xPageCount]C;
StkP ← xBuf;
LoadPage[PNIPPage];
T ← Stack, CallP[PNIP];
*Delay before overlaying control store because io microcode may not be
*finished initializing yet and will be overwritten.
xBuf ← 0C, Call[MPWaita];
xBuf ← (xBuf) + 1, GoTo[MPWaita,R>=0];
RTemp ← IP[FFault]C;
StkP ← RTemp;
T ← GLOBALhi ← PilotMDS;
T ← GLOBALhi ← (LSh[GLOBALhi,10]) or T;
LOCALhi ← T;
xfTemp1 ← 1C;*Odd (normal tasking)
RTemp1 ← 0C;*Even (believe starting address), .ge. 0 (resume Mesa)
MDShi ← T, LoadPageExternal[LRJPage];
LOCAL ← 0C, GoToExternal[LRJContinue];
%PNIP displays the number in T in the maintenance panel and returns, where T
is meaningfully in the range 0 to 9999d (0 to 23417b). Does not task unless
Called from task 0. Its registers, RTemp and RTemp1, should not conflict
with those for the Midas Kernel or with any used by tasks 14 to 17 because of
Calls from Fault.Mc, which might subsequently go to Midas; any io task that
Calls PNIP and expects to continue should be wary of the fact that PNIP’s
registers are defined for task 0 and might conflict.
The loop below must allow 800 ns after ClearMPanel and 400 ns after IncMPanel.
If necessary the high two bits of RTemp can be used to increase loop time.
ClearMPanel and IncMPanel may be illegal in the same mi with a true branch
condition. For large numbers, map/storage refresh may fail when Called by an
io task.
%
PNIP:RTemp ← T, ClearMPanel, At[PNIPStart];
UseCTask;
T ← APCTask&APC, UseCTask, Call[PFExit];
*14 cycles after ClearMPanel and 8 cycles after IncMPanel should be safe
*on the fastest machines.
PNIPl:RTemp ← (LdF[RTemp,2,16]) - 1;
RTemp1 ← T, Skip[ALU>=0];
APCTask&APC ← RTemp1, GoTo[PFExit];
LU ← LdF[RTemp1,0,4];
Skip[ALU=0];
IncMPanel, GoTo[PNIPl];
IncMPanel, Return;
*NotifyInterrupt ORs T into NWW and sets IntPending. Uses registers
*0 and 1 in whatever task Calls.
RV[IntTemp1,0];
RV[IntTemp2,1];
NotifyInterrupt:
IntTemp1 ← T, At[NotifyInterruptLoc];*Save interupt mask
IntTemp2 ← IP[NWW]C, Skip[ALU#0];*Point to NWW register
Return;*No change
T ← (SStkP&NStkP) xor (377C);*T ← StkP
StkP ← IntTemp2, IntTemp2 ← T, NoRegILockOK;
T ← IntTemp1;*T ← interrupt mask
Stack ← (Stack) or T;*set bits in NWW
Stack&-1;*Point StkP at RSImage
T ← Stack ← (Stack) or (IntPendingBit);
LU ← StkP ← IntTemp2, RS232 ← T, Return;
:END[Initialize];