-- MDFakeBcdImpl.Mesa
-- last edit by Schmidt,  2-Mar-82 12:49:02
-- last edit by Satterthwaite, January 31, 1983 9:23 am
-- Mesa 7.0/ Pilot 6.0
-- procedures to load and start modules in a Model

-- can't use PilotLoaderOps since it is not exported by CoPilotDorado.Config
-- may use PilotLoadStateOps, however

-- links:
--	IF gfi > firstdummy, then gfi is index into Import table 
--		and ep is index into the export record pared with that import
--		binding is simply to copy control link in the export record
--		into this link
-- 	IF gfi < firstdummy, then gfi in this link is an index into the config's
--		moduletable.  Do not alter the ep

-- spaces:
--	assume there are n modules
--	there will be 
--	1 space in MDS for all the frames (and frame links)
--	1 space in VM for the Fake Config Bcd for the load state
--	n ReadOnly spaces for Code
--		n (up to n) subspaces for the code links
--		n subspaces for the code segments
--			(unless the bcd is Binder-output)
--	n spaces for the Bcd headers
--		(deleted on UnLoad)

DIRECTORY
  BcdDefs: TYPE USING [Base, BCD, CTIndex, CTNull, CTRecord, EXPIndex, EXPRecord, 
  	FTIndex, FTNull, FTRecord, FTSelf, GFTIndex, 
	Link, MTIndex, MTRecord, NameRecord, NullVersion, SGIndex, SGRecord, VersionID],
  BcdOps: TYPE USING [BcdBase, MTHandle, NameString, ProcessModules],
  CWF: TYPE USING [WF0, WF1, WF2, WF3, WF4],
  Dir: TYPE USING [FileInfo],
  Environment: TYPE USING [wordsPerPage],
  File: TYPE USING [Capability],
  Inline: TYPE USING [LowHalf],
  LowLoader: TYPE USING [CloseLinkSpace, DummyMapSeq, InterfaceSeq, LinkSegmentLength, 
  	LoadInfoSeq, OpenLinkSpace, ReadLink, Zero],
  MDLoad: TYPE USING [],
  MDModel: TYPE USING [APPLSymbol, LISTSymbol, LOCSymbol, MODELSymbol, 
  	NarrowToAPPL, NarrowToLIST, NarrowToLOC, 
	NarrowToPROC, PROCSymbol, Symbol, SymbolSeq, TraverseList, TraverseTree],
  PilotLoadStateOps: TYPE USING [ConfigIndex, EnterModule, ReleaseLoadState, UpdateLoadState],
  PrincOps: TYPE USING [ControlLink, GFTIndex, GlobalFrameHandle, NullLink, UnboundLink],
  Space: TYPE USING [Create, Delete, ForceOut, Handle, LongPointer, Map, 
  	nullHandle, virtualMemory],
  Subr: TYPE USING [NewFile, ReadWrite];
			
MDFakeBcdImpl: PROGRAM 
IMPORTS BcdOps, CWF, Inline, LowLoader, MDModel, PilotLoadStateOps, Space, Subr
EXPORTS MDLoad  = {

-- no MDS usage!


MTPAGE: CARDINAL = (SIZE[BcdDefs.BCD]/Environment.wordsPerPage) + 1;
nmtp: CARDINAL = 20;
FTPAGE: CARDINAL = MTPAGE + nmtp;
nftp: CARDINAL = 6;
SGPAGE: CARDINAL = FTPAGE + nftp;
nsgp: CARDINAL = 6;
CTPAGE: CARDINAL = SGPAGE + nsgp;
nctp: CARDINAL = 1;
SSPAGE: CARDINAL = CTPAGE + nctp;
nssp: CARDINAL = 16;
EXPAGE: CARDINAL = SSPAGE + nssp;
nexp: CARDINAL = 3;
BCDPAGES: CARDINAL = EXPAGE + nexp;

-- also updates the load state with the modules
BuildFakeBcd: PUBLIC PROC[spmodel: MDModel.MODELSymbol, symbolseq: MDModel.SymbolSeq] = {
bcdSpace: Space.Handle ← Space.nullHandle;
{
ENABLE UNWIND => 
	IF bcdSpace ~= Space.nullHandle THEN Space.Delete[bcdSpace];
Cbcdbase: BcdOps.BcdBase;
Cctb, Cmtb, Csgb, Cftb, Cetb: BcdDefs.Base;
Cmti: BcdDefs.MTIndex ← FIRST[BcdDefs.MTIndex];
Cfti: BcdDefs.FTIndex ← FIRST[BcdDefs.FTIndex];
Csgi: BcdDefs.SGIndex ← FIRST[BcdDefs.SGIndex];
Ceti: BcdDefs.EXPIndex ← FIRST[BcdDefs.EXPIndex];
Cnamei: CARDINAL;
Cnamestring: BcdOps.NameString;
Cngfi: CARDINAL ← 1;
cap: File.Capability;

	ProcAnalyze: PROC[sp: MDModel.Symbol, spmodel: MDModel.MODELSymbol] 
		RETURNS[proceed: BOOL ← TRUE] = {
	sgb, ftb: BcdDefs.Base;
	bcdbase: BcdOps.BcdBase;
	sploc: MDModel.LOCSymbol;
	namestring: BcdOps.NameString;
	
		ForEachModule: PROC[mth: BcdOps.MTHandle, mti: BcdDefs.MTIndex]
			RETURNS[stop: BOOL] = {
		rgfi: CARDINAL;
		stop ← FALSE;
		Check[Cmti + MTRecordLength[mth], Cbcdbase.mtLimit];
		Cmtb[Cmti] ← mth↑;
		Cmtb[Cmti].name ← NewName[namestring, mth.name];
		Cmtb[Cmti].gfi ← Cngfi;
		Cmtb[Cmti].extension ← direct[length: 0, frag:];
		IF mth.gfi >= sploc.fi.loadInfoSeq.dummymapseq.size THEN ERROR;
		rgfi ← sploc.fi.loadInfoSeq.dummymapseq[mth.gfi].ind;
		FOR i: CARDINAL IN [0 .. mth.ngfi) DO
			PilotLoadStateOps.EnterModule[rgfi+i, [resolved: TRUE, 
				config: spmodel.configindex, gfi: Cngfi+i]];
			ENDLOOP;
		Cngfi ← Cngfi + mth.ngfi;
		Check[Cfti + SIZE[BcdDefs.FTRecord], Cbcdbase.ftLimit];
		IF mth.file = BcdDefs.FTSelf THEN {
			-- get info from header
			Cftb[Cfti] ← [NewName[namestring, bcdbase.source], 
				bcdbase.version];
			Cmtb[Cmti].file ← Cfti;
			Cfti ← Cfti + SIZE[BcdDefs.FTRecord];
			}
		ELSE IF mth.file = BcdDefs.FTNull THEN {
			Cmtb[Cmti].file ← BcdDefs.FTNull;
			}
		ELSE {
			Cftb[Cfti] ← ftb[mth.file];
			Cftb[Cfti].name ← NewName[namestring, 
				ftb[mth.file].name];
			Cmtb[Cmti].file ← Cfti;
			Cfti ← Cfti + SIZE[BcdDefs.FTRecord];
			};
		Check[Csgi + SIZE[BcdDefs.SGRecord], Cbcdbase.sgLimit];
		Csgb[Csgi] ← sgb[mth.sseg];
		Cmtb[Cmti].sseg ← Csgi;
		Check[Cfti + SIZE[BcdDefs.FTRecord], Cbcdbase.ftLimit];
		IF Csgb[Csgi].file = BcdDefs.FTSelf THEN {
			-- if self then the symbols are in the config's file
			Cftb[Cfti] ← [NewString[sploc.fi.bcdFileName], 
				bcdbase.version];
			Csgb[Csgi].file ← Cfti;
			Cfti ← Cfti + SIZE[BcdDefs.FTRecord];
			}
		ELSE IF Csgb[Csgi].file = BcdDefs.FTNull THEN {
			Csgb[Csgi].file ← BcdDefs.FTNull;
			}
		ELSE {
			Cftb[Cfti] ← ftb[Csgb[Csgi].file];
			Cftb[Cfti].name ← NewName[namestring, 
				ftb[Csgb[Csgi].file].name];
			Csgb[Csgi].file ← Cfti;
			Cfti ← Cfti + SIZE[BcdDefs.FTRecord];
			};
		Csgi ← Csgi + SIZE[BcdDefs.SGRecord];
		Cmti ← Cmti + SIZE[BcdDefs.MTRecord[direct]];
		Cbcdbase.nModules ← Cbcdbase.nModules + 1;
		};
		
	IF sp.stype ~= typeLOC THEN RETURN;
	sploc ← MDModel.NarrowToLOC[sp];
	IF sploc.fi = NIL OR sploc.fi.loadInfoSeq = NIL THEN RETURN;
	bcdbase ← sploc.fi.loadInfoSeq.bcdbase;
	sgb ← LOOPHOLE[bcdbase + bcdbase.sgOffset, BcdDefs.Base];
	ftb ← LOOPHOLE[bcdbase + bcdbase.ftOffset, BcdDefs.Base];
	namestring ← LOOPHOLE[bcdbase + bcdbase.ssOffset];
	[] ← BcdOps.ProcessModules[bcdbase, ForEachModule];
	};
	
	NewName: PROC[namestring: BcdOps.NameString, oldname: BcdDefs.NameRecord]
		RETURNS[newname: BcdDefs.NameRecord] = {
	newname ← LOOPHOLE[Cnamei];
	Check[(Cnamei + namestring.size[oldname] + 1)/2 + 1, Cbcdbase.ssLimit];
	Cnamestring.size[newname] ← namestring.size[oldname];
	FOR i: CARDINAL IN [0 .. Cnamestring.size[newname]) DO
		Cnamestring.string.text[newname + i] ←
			namestring.string.text[oldname + i];
		ENDLOOP;
	Cnamei ← Cnamei + Cnamestring.size[newname] + 1;
	};
	
	NewString: PROC[oldstring: LONG STRING]
		RETURNS[newname: BcdDefs.NameRecord] = {
	newname ← LOOPHOLE[Cnamei];
	Check[(Cnamei + oldstring.length + 1)/2, Cbcdbase.ssLimit];
	Cnamestring.size[newname] ← oldstring.length;
	FOR i: CARDINAL IN [0 .. Cnamestring.size[newname]) DO
		Cnamestring.string.text[newname + i] ← oldstring[i];
		ENDLOOP;
	Cnamei ← Cnamei + Cnamestring.size[newname] + 1;
	};
	
	AddToExports: PROC[interfaceseq: LowLoader.InterfaceSeq] = {
	Check[Cfti + SIZE[BcdDefs.FTRecord], Cbcdbase.ftLimit];
	Check[Ceti + SIZE[BcdDefs.EXPRecord] + interfaceseq.size, Cbcdbase.expLimit];
	Cftb[Cfti] ← [name: NewString[interfaceseq.intname], version: interfaceseq.versstamp];
	Cetb[Ceti] ← [name: NewString[interfaceseq.intname], size: interfaceseq.size,
		port: interface, namedInstance: FALSE, typeExported: FALSE,
		file: Cfti, links: ];
	FOR i: CARDINAL IN [0 .. Cetb[Ceti].size) DO
		Cetb[Ceti].links[i] ← interfaceseq[i].blink;
		ENDLOOP;
	Cfti ← Cfti + SIZE[BcdDefs.FTRecord];
	Ceti ← Ceti + SIZE[BcdDefs.EXPRecord] + interfaceseq.size;
	Cbcdbase.nExports ← Cbcdbase.nExports + 1;
	};
	
bcdSpace ← Space.Create[size: BCDPAGES, parent: Space.virtualMemory];
cap ← Subr.NewFile["FakeConfig.Bcd"L, Subr.ReadWrite, BCDPAGES];
Space.Map[space: bcdSpace, window: [cap, 1]];
Cbcdbase ← Space.LongPointer[bcdSpace];
LowLoader.Zero[Cbcdbase, BCDPAGES * Environment.wordsPerPage];
Cbcdbase.versionIdent ← BcdDefs.VersionID;
Cbcdbase.nPages ← BCDPAGES;
Cbcdbase.version  ← BcdDefs.NullVersion;
Cbcdbase.nConfigs ← 1;
Cbcdbase.nModules ← 0;
Cbcdbase.extended ← TRUE;	-- to keep the RT happy
Cbcdbase.nImports ← Cbcdbase.nExports ← 0;
-- all the Limit vars are set to 0
Cbcdbase.impOffset ← Cbcdbase.evOffset ← 0;
Cbcdbase.spOffset ← Cbcdbase.ntOffset ← Cbcdbase.typOffset ← 0;
Cbcdbase.tmOffset ← Cbcdbase.fpOffset ← 0;
Cbcdbase.ctOffset ← CTPAGE * Environment.wordsPerPage;
Cbcdbase.mtOffset ← MTPAGE * Environment.wordsPerPage;
Cbcdbase.sgOffset ← SGPAGE * Environment.wordsPerPage;
Cbcdbase.ftOffset ← FTPAGE * Environment.wordsPerPage;
Cbcdbase.expOffset ← EXPAGE * Environment.wordsPerPage;
Cbcdbase.ssOffset ← SSPAGE * Environment.wordsPerPage;
Cnamei ← 0;
Cctb ← LOOPHOLE[Cbcdbase + Cbcdbase.ctOffset, BcdDefs.Base];
Cmtb ← LOOPHOLE[Cbcdbase + Cbcdbase.mtOffset, BcdDefs.Base];
Csgb ← LOOPHOLE[Cbcdbase + Cbcdbase.sgOffset, BcdDefs.Base];
Cftb ← LOOPHOLE[Cbcdbase + Cbcdbase.ftOffset, BcdDefs.Base];
Cetb ← LOOPHOLE[Cbcdbase + Cbcdbase.expOffset, BcdDefs.Base];
Cnamestring ← LOOPHOLE[Cbcdbase + Cbcdbase.ssOffset, BcdDefs.Base];
Cbcdbase.ctLimit ← FIRST[BcdDefs.CTIndex] + SIZE[BcdDefs.CTRecord];
Cbcdbase.mtLimit ← LOOPHOLE[nmtp * Environment.wordsPerPage];
Cbcdbase.ftLimit ← LOOPHOLE[nftp * Environment.wordsPerPage];
Cbcdbase.sgLimit ← LOOPHOLE[nsgp * Environment.wordsPerPage];
Cbcdbase.expLimit ← LOOPHOLE[nexp * Environment.wordsPerPage];
Cbcdbase.ssLimit ← LOOPHOLE[nssp * Environment.wordsPerPage];
LOOPHOLE[Cnamestring+1, LONG POINTER TO CARDINAL]↑ ← (Cbcdbase.ssLimit-2)*2;	-- the maxlength of namestring
Cnamestring.string.length ← Cnamestring.string.maxlength;
 
Cctb[FIRST[BcdDefs.CTIndex]] ← [name: NewString["FakeConfig"L], 
	namedInstance: FALSE, file: BcdDefs.FTNull, config: BcdDefs.CTNull, 
	nControls: 0, controls:];

-- that sets all the booleans to FALSE, etc.
MDModel.TraverseTree[spmodel, symbolseq, ProcAnalyze, TRUE];

-- now put exports in export table
{
splist: MDModel.LISTSymbol;
spproc: MDModel.PROCSymbol ← NIL;
splist ← spmodel.model;
WHILE splist ~= NIL AND splist.first.stype ~= typePROC DO
	splist ← splist.rest;
	ENDLOOP;
spproc ← MDModel.NarrowToPROC[splist.first];
splist ← spproc.procret;
WHILE splist ~= NIL DO
	IF splist.first.stype = typeAPPL THEN {
		spappl: MDModel.APPLSymbol ← MDModel.NarrowToAPPL[splist.first];
		IF spappl.interfaceseq ~= NIL THEN 
			AddToExports[spappl.interfaceseq];
		};
	splist ← splist.rest;
	ENDLOOP;
};

Cbcdbase.firstdummy ← Cngfi;	-- # gfi's needed for the modules in the config
Cbcdbase.mtLimit ← Cmti;
Cbcdbase.ftLimit ← Cfti;
Cbcdbase.sgLimit ← Csgi;
Cbcdbase.expLimit ← Ceti;
Cbcdbase.ssLimit ← (Cnamei/2)+1;

spmodel.fakebcdspace ← bcdSpace;
-- now insert the new bcdbase
-- newer version of BcdOps
PilotLoadStateOps.UpdateLoadState[spmodel.configindex, LOOPHOLE[Cbcdbase]];
PilotLoadStateOps.ReleaseLoadState[];
CWF.WF1["Total # of gfi's needed to load: %u.\n"L, @Cngfi];
Space.ForceOut[bcdSpace];
CWF.WF0["Fake bcd written out on FakeConfig.Bcd\n"L];
}};

Check: PROC[val, limit: UNSPECIFIED] = {
IF LOOPHOLE[val, CARDINAL] >= LOOPHOLE[limit, CARDINAL] THEN ERROR;
};

MTRecordLength: PROC[mth: BcdOps.MTHandle] RETURNS[len: CARDINAL] = {
RETURN[WITH m: mth SELECT FROM
	direct => SIZE[BcdDefs.MTRecord[direct]] + m.length*SIZE[BcdDefs.Link],
	indirect => SIZE[BcdDefs.MTRecord[indirect]],
	multiple => SIZE[BcdDefs.MTRecord[multiple]],
	ENDCASE => ERROR];
};

PrintFrameLinks: PROC[frame: PrincOps.GlobalFrameHandle, 
	bcdbase: BcdOps.BcdBase, mth: BcdOps.MTHandle] = {
links: LONG POINTER;
l, t: POINTER;
links ← LowLoader.OpenLinkSpace[frame, mth, bcdbase];
l ← Inline.LowHalf[links];
t ← l + LowLoader.LinkSegmentLength[mth, bcdbase];
CWF.WF3["Links from %bB to %bB, frame at %bB.\n"L, @l, @t, @frame];
FOR i: CARDINAL IN [0..LowLoader.LinkSegmentLength[mth, bcdbase]) DO
	PrintCLink[i, LowLoader.ReadLink[i]];
	ENDLOOP;
LowLoader.CloseLinkSpace[frame];
};

-- also in LowLoader, this one uses this CWF
PrintCLink: PROC[j: CARDINAL, link: PrincOps.ControlLink] = {
IF link = PrincOps.NullLink THEN 
	CWF.WF1["#%u: NullLink\n"L, @j]
ELSE IF link = PrincOps.UnboundLink THEN 
	CWF.WF1["#%u: UnboundLink\n"L, @j]
ELSE {
	gfi, ep: CARDINAL;
	gfi ← link.gfi;
	ep ← link.ep;
	CWF.WF4["#%u: gfi %bB ep %u, address %bB\n"L, @j, @gfi, @ep, @link];
	};
};

PrintFrames: PROC[spmodel: MDModel.MODELSymbol, 
	symbolseq: MDModel.SymbolSeq] = {

	ProcAnalyze: PROC[sptop: MDModel.Symbol, spmodel: MDModel.MODELSymbol] 
		RETURNS[proceed: BOOL ← TRUE] = {
	
		-- calls itself recursively
		-- spmodel, sptop is passed in
		ProcLoc: PROC[spl: MDModel.Symbol] = {
		IF spl = NIL THEN RETURN;
		IF spl.stype = typeLIST THEN 
			MDModel.TraverseList[MDModel.NarrowToLIST[spl], ProcLoc]
		ELSE IF spl.stype = typeLOC THEN {
			mti: BcdDefs.MTIndex ← FIRST[BcdDefs.MTIndex];
			mth: BcdOps.MTHandle;
			bcdbase: BcdOps.BcdBase;
			sploc: MDModel.LOCSymbol;
			sploc ← MDModel.NarrowToLOC[spl];
			IF sploc.fi = NIL OR sploc.fi.loadInfoSeq = NIL THEN RETURN;	-- defs file
			CWF.WF1["Frame of %s.Bcd:\n"L, sploc.tail];
			FOR m: CARDINAL IN [0 .. sploc.fi.loadInfoSeq.size) DO
				bcdbase ← sploc.fi.loadInfoSeq.bcdbase;
				mth ← @LOOPHOLE[bcdbase + bcdbase.mtOffset, 
					BcdDefs.Base][mti];
				PrintFrameLinks[sploc.fi.loadInfoSeq[m].frame, 
					bcdbase, mth];
				mti ← mti + MTRecordLength[mth];
				ENDLOOP;
			};
		};
		
	WITH spt: sptop SELECT FROM
	typeTYPE => ProcLoc[spt.typeval];
	typeAPPL => ProcLoc[spt.applval];
	typeLET => ProcLoc[spt.letval];
	ENDCASE => NULL;
	RETURN[TRUE];
	};


CWF.WF0["Print Frames:\n"L];
MDModel.TraverseTree[spmodel, symbolseq, ProcAnalyze, TRUE];
};

PrintInterfaceSeqs: PROC[spmodel: MDModel.MODELSymbol, 
	symbolseq: MDModel.SymbolSeq] = {

	ProcAnalyze: PROC[sptop: MDModel.Symbol, spmodel: MDModel.MODELSymbol] 
		RETURNS[proceed: BOOL ← TRUE] = {
	WITH spt: sptop SELECT FROM
	typeAPPL => {
		i: CARDINAL;
		interfaceseq: LowLoader.InterfaceSeq;
		interfaceseq ← spt.interfaceseq;
		IF interfaceseq = NIL THEN RETURN;
		CWF.WF2["%s: %u entries:\n"L, spt.applsym, @interfaceseq.size];
		FOR i IN [0 .. interfaceseq.size) DO
			PrintCLink[i, interfaceseq[i].clink];
			ENDLOOP;
		};
	ENDCASE => NULL;
	RETURN[TRUE];
	};


CWF.WF0["Print Interface Records:\n"L];
MDModel.TraverseTree[spmodel, symbolseq, ProcAnalyze, TRUE];
};


}.