*-----------------------------------------------------------
Title[InitMem.mc...February 21, 1984 10:37 AM...Willie-Sue];
* Memory system initialization for all emulators.
*-----------------------------------------------------------

%
Entry points:

InitMapCold start: map and main storage initialization
(name is an historical artifact).

InitMapWarmWarm start: map initialization only; doesn’t disturb
main storage (Alto mode only).

After initialization, InitMap branches to the external label StartEmulator,
and InitMapWarm branches to ResumeEmulator.

InitMap code assumes that CacheA, CacheD, and the map automata have already
been put into a good state (by bootstrap initialization), but
assumes nothing about the contents of the map or main storage.
It zeroes all real storage in order to clear out any lurking bad parity.
It maps virtual addresses to real storage such that all real storage
is compacted in VM (usually at the bottom), and marks all other VM vacant.
As a side-effect, it computes VirtualBanks and RealPages, for the benefit of
emulators. If no real storage is present, it breaks at NoStorage.

InitMapWarm assumes that map and main storage are already in a reasonable
state for running the Alto emulator, and in particular that the first 64K
of REAL memory contains simulated Alto memory. It sets up the map as
appropriate for the new emulator (note that different emulators keep the
simulated Alto memory in different parts of VIRTUAL memory), so that
execution within the simulated Alto memory can continue.

For Alto mode only, this code depends on there being an external, emulator-specific
subroutine GetEmulatorMapParams, which returns the following in T:

T[0] = 1 to write-protect page 377, for XM Alto emulation;
0 to emulate a non-XM Alto.
T[4:15] = the VA[4:15] to be used to define the main "bank" (64K memory
region) for Alto emulation. Should be 0 in all emulators except Lisp.

This version of the code assumes 256-word pages,
but can cope with any map and main storage configuration.
%

Set[logWordsPerPage, 10];

TopLevel;
Set[XTask, IP[EMU]];

* Register usage -- bank shared with Ethernet output registers
SetRMRegion[EORegs];
*
Reserve[xx];* Registers defined in RegisterDefs.mc
*
RVN[VirtualBanks];
*
RVN[RealPages];
Reserve[Add[And[IP[RealPages], 17], 1]];

RVN[PgsPerMod];* Pages per storage module
RVN[ModMask];* Mask of modules present
RVN[ITemp0];* Temporaries
RVN[ITemp1];
RVN[ITemp2];

Reserve[1];* Ensure there is at least one register left
RVRel[ITemp17, 17];

:If[AltoMode];
********** Alto version **********
*-----------------------------------------------------------
* Warm start initialization.
*-----------------------------------------------------------

InitMapWarm:
RBase← RBase[ITemp0], Call[GetMemConfig];
RealPages← (RealPages)+1,* Set flag to note this is a warm start
Branch[CacheFlush];
:EndIf;
**********************************

*-----------------------------------------------------------
* Cold start initialization.
* Initially started here by "Initial" (second-stage bootstrap).
* Restarted here by Baseboard on 2-button boot.
*-----------------------------------------------------------

InitMap: At[InitMapLoc],
Call[TasksOff];* Do an I/O Reset

RBase← RBase[ITemp0];
B← FaultInfo’;* clear faults
T← mcr.noWake;* disable fault task wakeups
LoadMCR[T, T];
Call[WaitForMapBuf];

* Set TestSyndrome register to normal state (error correction on)
MemBase← IOBR, T← A0;
BrHi← T;
BrLo← T;
Fetch← T;* need to be sure store will hit
T← MD, Store← T, DBuf← tsyn.ecOn; * DBuf← data
LoadTestSyndrome;* TestSyn← DBuf
Call[WaitForMapBuf];
TaskingOn;

*-----------------------------------------------------------
* Map pre-initialization for cold start.
* Set the map one-to-one with real storage (without regard to the
* real storage configuration), in preparation for flushing the cache.
*-----------------------------------------------------------
Call[GetMemConfig];
ITemp1← T← A0, Call[BeginEnumerateMap];
Map1to1Loop:
ITemp0← A0, Call[IWriteMap];* Dirty=0, WP=0, RP = VPage mod 2↑16
SCall[NextMapEntry];
ITemp1← (ITemp1)+1, Branch[Map1to1Loop];

*-----------------------------------------------------------
* Cache flush and map clear.
* During a warm start, the data in the cache is flushed to wherever it
* belongs. During a cold start, it is flushed to memory arbitrarily.
* This may result in flushing into nonexistent storage, but no matter.
*-----------------------------------------------------------
CacheFlush:
ITemp1← T← A0, Call[BeginEnumerateMap];
CacheFlushLoop:
* Flush all munches in this page
ITemp0← A0, Cnt← 17S;
ITemp0← Flush← ITemp0, Carry20, Branch[., Cnt#0&-1];
* Set the map entry to vacant
Nop;
ITemp0← T-T-1, Call[IWriteMap];* Dirty = 1, WP = 1, RP = 0
SCall[NextMapEntry];
Branch[CacheFlushLoop];

*-----------------------------------------------------------
* Map and storage initialization.
* Map virtual addresses into real storage, starting with the virtual address
* defined by the BRHi value for MDS (emulator specific), and wrapping around
* the end of the virtual address space if necessary (Lisp requires this).
* Zero storage if cold start is in progress.
* Note: this code assumes that the virtual address space is at least as large as
* the real address space.
*-----------------------------------------------------------
:If[AltoMode];
********** Alto version **********
ITemp1← A0,* Init real page #
Call[GetEmulatorMapParams]; * Get emulator-specific information
:Else;
******** PrincOps version ********
ITemp1← T← A0;* Init real page #, virtual bank #
:EndIf;
**********************************
ITemp2← A0, Branch[BeginMapInit]; * No pages left in current module

* Register usage at top of loop:
* ITemp1 = real page number
* ITemp2 = -(remaining pages in current module)-1
MapInitLoop:
ITemp1← (ITemp1)+1,* Increment real page number
SCall[NextMapEntry];* Increment virtual page number
ITemp2← (ITemp2)+1,* +1 return; decrement (negative) page count
DblBranch[MapModuleCont, FindModule, R<0];

* Get here initially with T = bank for emulated Alto memory.
* If we go past the end of VM, we get here due to NextMapEntry returning to
* caller+2; T = 0 in this case, so we will wrap around to the beginning of VM.
BeginMapInit:
T← T AND (7777C), Call[BeginEnumerateMap];
ITemp2← (ITemp2)+1, DblBranch[MapModuleCont, FindModule, R<0];

* Current module exhausted, find the next one.
FindModule:
ModMask← (ModMask) LSH 1, Branch[MapModule, R<0];
T← PgsPerMod, Branch[EndOfStorage, ALU=0];
ITemp1← (ITemp1)+T, Branch[FindModule]; * Skip nonexistent real pages

MapModule:
T← (1S)-(PgsPerMod);* Init page count in module
ITemp2← T;

* Continue mapping virtual pages into the current module.
MapModuleCont:
ITemp0← A0, Call[IWriteMap];* Write map entry; WP and Dirty = 0
T← 377C, RealPages, Branch[MapInitLoop, R odd]; * Branch if warm start
T← ITemp0← A0, Cnt← T;* Zero out the page
ITemp0← (Store← ITemp0)+1, DBuf← T, Branch[., Cnt#0&-1];
Branch[MapInitLoop];

*-----------------------------------------------------------
* Finish setting up the high part of MDS.
* Then, if XM Alto emulation is desired, write-protect page 377 of
* the 64K space for Alto emulation (MDS).
*-----------------------------------------------------------
EndOfStorage: ;
:If[AltoMode];
********** Alto version **********
Call[GetEmulatorMapParams];
ITemp0← T;
T← T AND (7777C);
EmuXMBRHiReg← T;* For XM, start with alternate=normal
EmuBRHiReg← T;
BRHi← T, ITemp0, Branch[InitMemDone, R>=0]; * Test XM flag

* Make page 377B be write-protected.
* First, flush the page, then set WP in map entry.
T← 177400C;
ITemp0← A0, BRLo← T;
Cnt← 17S;
ITemp0← (Flush← ITemp0), Carry20, Branch[., Cnt#0&-1];
ITemp0← TIOAwProtect, Call[IWriteMapFlags];
:Else;
******** PrincOps version ********
* With current version of Cedar, there cannot be more than 4096 pages
* (1 megaword) of real storage; only 4096 pages of VIRTUAL MEMORY can
* be mapped to real memory
Pd← (RealPages) - (10000C);
branch[InitMemDone, alu<=0];* little enough real memory
* we’ll be kludgey, and only vacate as much of that map as we need to,
* that is, from 10000C to 37777C
ITemp0← 140000C;* hardware map = vacant
ITemp1← A0;
ITemp2← 10000C;
mlp:
T← RSH[ITemp2, 10];
BrHi← T;
T← LSH[ITemp2, 10];
BrLo← T;
Call[IWriteMap];
Pd← (ITemp2) - (40000C);
branch[mlp, alu >=0], ITemp2← (ITemp2) + 1;
nop;* placement

:EndIf;
**********************************

*-----------------------------------------------------------
* Now enable fault reporting and go run the emulator!
* For now, do not enable fault reporting of Single Errors.
*-----------------------------------------------------------
InitMemDone:
B← FaultInfo’;* Clear faults
T← mcr.noReportSE;* Normal MCR value
LoadMCR[T, T];
Call[WaitForMapBuf];
:If[AltoMode];
********** Alto version **********
RealPages← (RealPages) AND (177776C), Branch[.+2, R even];
Branch[ResumeEmulator];
:EndIf;
**********************************
Branch[StartEmulator];

*-----------------------------------------------------------
GetMemConfig: * Read the map and storage configuration, and set these registers:
*
VirtualBanks = size of virtual memory, in units of 64K words
*
RealPages = size of real memory, in pages
*
PgsPerMod = number of pages per module
*
ModMask = bit mask of modules present (B0=1 => module 0 present, etc.)
* Breakpoints at NoStorage if no storage modules are present.
* Clobbers T, ITemp0, ITemp1, ITemp17
*-----------------------------------------------------------
Subroutine;
ITemp0← Link;
TopLevel;
T← 1400C;
T← ITemp1← T OR (112C);
Call[SetDMuxAddress];* Read DMux[1512] = MapIs256K
ITemp17, Branch[MapIs256K, R<0];
VirtualBanks← 400C;
T← (ITemp1)-1, Call[SetDMuxAddress]; * Read DMux[1511] = MapIs64K
ITemp17, Branch[GotMapConfig, R<0];
VirtualBanks← 100C, Branch[GotMapConfig]; * Assume MapIs16K
MapIs256K:
VirtualBanks← 2000C;
GotMapConfig:
ModMask← NOT (Config’);
T← LDF[ModMask, 2, 2];* Storage chip size = 2↑(12 + 2*T)
T← DPF[T, 2, 11];* ShC count ← 2*T
RealPages← A0, ShC← T;
ModMask← LSH[ModMask, 10];* Left-justify the module-present bits
ModMask← T← (ModMask) AND (170000C);
ITemp1← T, Branch[NoStorage, ALU=0];
PgsPerMod← 400C;* 4K chips give 400B pages/module
PgsPerMod← T← ShiftNoMask[PgsPerMod]; * LCY[R, R, 2*n]
ITemp1← (ITemp1)+(ITemp1), Branch[.+2, R>=0]; * Count the modules
RealPages← (RealPages)+T, FreezeBC;
Link← ITemp0, Branch[.-2, ALU#0];
Subroutine;
PD← ModMask, Return;

*-----------------------------------------------------------
* No storage modules are present.
*-----------------------------------------------------------
NoStorage:
Branch[.], Breakpoint;

*-----------------------------------------------------------
* EnumerateMap:
Perform operation on every entry in the map
* Calling sequence:
*
*
T← <first virtual bank #, normally 0>, Call[BeginEnumerateMap];
* Loop:
<code to be executed for each entry>;
*
SCall[NextMapEntry];
*
Branch[Loop];
*
<code reached when map is exhausted>;
*
* Enter: MemBase = BR to use for enumeration
*
VirtualBanks set up
* Exit:
BR addresses word 0 of page corresponding to map entry
*
T = 0
* Clobbers T, ITemp17
*-----------------------------------------------------------
Subroutine;

BeginEnumerateMap:
ITemp17← A0, Branch[NextMap1];

NextMapEntry:
T← LShift[1, logWordsPerPage]C;* Let the memory system do the add!
DummyRef← T, T← MD;
ITemp17← VALo;
T← VAHi;
NextMap1:
BRLo← ITemp17;
PD← (BRHi← T)-(VirtualBanks);
T← A0, Return[ALU=0];


*-----------------------------------------------------------
IWriteMapFlags:
* Write map flags without disturbing real page
* Enter: ITemp0 = WP and Dirty bits
*
Current BR contains VA for map entry to be written
* Clobbers ITemp1, Q.
*-----------------------------------------------------------
Subroutine;
ITemp1← A0, Q← Link;
TopLevel;
RMap← ITemp1, Call[WaitForMapBuf]; * Read current map entry
ITemp1← NOT (Map’), Branch[IWriteMap1];


*-----------------------------------------------------------
IWriteMap:
* Write map entry
* Enter: ITemp0 = WP and Dirty bits
*
ITemp1 = real page number
*
Current BR contains VA for map entry to be written
* Clobbers Q.
*-----------------------------------------------------------
Subroutine;
Q← Link;
TopLevel;
IWriteMap1:
TIOA← ITemp0, Call[WaitForMapBuf];
Map← 0S, MapBuf← ITemp1;
Link← Q, Branch[WaitForMapBuf];

*-----------------------------------------------------------
WaitForMapBuf:
* Wait for map operation to complete
* Clobbers nothing
*-----------------------------------------------------------
Subroutine;
PD← T-T-1;
PD← PRef, Branch[., ALU<0];* MapBufBusy is sign bit
Return;