// midas.bcpl

// midas main program

get "sysdefs.d"	//Needed for def of levDirectory
get "altofilesys.d"
get "streams.d"

external [
// OS
	CallSwat; Junta; MoveBlock; lvUserFinishProc; DoubleAdd
	Resets; OpenFile; Timer

// MASM
	ErrorProtect

// MDISP
	FinishDisplay; SetDisplay

// MRGN
	DriverLoop; UpdateDisplay

// MMPRGN
	DoubleNeg

// MMENU
	ExecuteTextCmdStream

// MTXTBUF
	TxtBNewChar

// STATE
	Storage; EndStorage
	GetStorage; StorageLeft; SaveState; RestoreState

// MINIT0
	Init0; mdsInitFP; StateStream

// MINIT1
	Init1

// MINIT2
	Init2; DInit0

// MINIT3
	Init3

// MCMD
	CmdDoRC; PrintComputeTime; CFOutStream

// MOVERLAY
	KillOverlays

// Machine dependent
	InitHardware; FinishHardware

// Defined here
	Nmidas; CopyTemplate; PutField; GetField; StartTimer; ElapsedTime
	MidasFinish; StateBlockSize; Restoring; lvFinishProc
	MidasCFA; FirstStatic; LastStatic; Switch; Initialized; HaveHardware

	TimeStart; TimeJunta; TimeLoadRam; TimeLookup; TimeOvScan
	TimeQFiles; TimeFont; TimeMRGN; TimeMAP; TimeMSYM; TimeMMPRGN
	TimeLoad; TimeInit3; TimeFinish
]

static 	[
	Initialized = false; HaveHardware = true; Restoring

	lvFinishProc
	MidasCFA	// To save CFA for Midas.run across Junta

	StateBlockSize = 140B	// Number of saved page zero statics * 2
	FirstStatic	// Address of first program static from Layout vector
	LastStatic	// Last static in program from Layout vector
	Switch		// Command line switch to program

// statistics
	TimeStart	// - Timer() at start
	TimeJunta	// Runtime after Junta
	TimeLoadRam	// Runtime after LoadRam
	TimeLookup	// Runtime after building FP's for Midas files
	TimeOvScan	// Runtime after OverlayScan
	TimeQFiles	// Runtime after building FP's for programs
	TimeFont	// Runtime after reading gacha10.al
	TimeMRGN	// Runtime after MRGN init
	TimeMAP		// Runtime after InitFmap
	TimeMSYM	// Runtime after MSYM init
	TimeMMPRGN	// Runtime after MMPRGN init
	TimeInit1	// Runtime after Display initialization
	TimeLoad	// Runtime after LOAD in command file
	TimeCFile	// Runtime after command file init
	TimeInit3	// Runtime after Init3
	TimeFinish	// Runtime at call to DriverLoop
]

let Nmidas(Layout,userParams,CFA) be
[	FirstStatic = Layout!26
	LastStatic = Layout!27
	Switch = userParams!1
	TimeStart = table [ 0; 0 ] ;	StartTimer()
//Since all statics are preserved by SaveState/RestoreState need to make
//some storage which is safe.  Restoring!0 is true if
//MidasFinish should boot regular Alto microcode, else false.
//Restoring!1 is a pointer to the command file name or 0 if Com.CM
//should be read.
	Restoring = table [ 0; 0; 0; 0 ]
//Save Midas.run CFA across Junta for OverlayScan
	MidasCFA = table [ 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0 ]
	MoveBlock(MidasCFA,CFA,lCFA)
	Junta(levDirectory,InitMidas)
]

and InitMidas() be
[
// Init0 returns true if full initialization should be done.  The
// stream for save or restore is left in StateStream
	test Init0(MidasCFA,Switch)
	ifso
	[ Storage = Init0	//Add Init0 code to free storage
	  Init1(); ElapsedTime(lv TimeInit1)
	  Storage = DInit0	//Add Init1 code to free storage
	  let EndSave = EndStorage
	  Init2()		//First display Init just to make OverlayZone
	  ErrorProtect(lv ExecuteTextCmdStream,
		OpenFile(0,ksTypeReadOnly,charItem,0,mdsInitFP))
	  TxtBNewChar(177B)
	  KillOverlays(); EndStorage = EndSave
	  ElapsedTime(lv TimeCFile)
	  SaveState(StateStream,Resume)
	]
	ifnot RestoreState(StateStream,false)
Resume:	InitHardware()
//It is safe to postpone display initialization because no screen
//painting occurs until SetDisplay turns on the display below
	Init2()		//Repeat display init (avoid saving all the bit
			//buffers by doing this twice)
	if Init3(Restoring!1) then
	[ KillOverlays(); CFOutStream = Restoring!3
	  ErrorProtect(lv CmdDoRC)
	]
	KillOverlays(); PrintComputeTime(); UpdateDisplay()
	if Restoring!2 ne 0 then ExecuteTextCmdStream(Restoring!2)
	SetDisplay(false); DriverLoop(); finish
]


and MidasFinish() be
[	FinishDisplay(); if Restoring!0 eq 0 then FinishHardware()
	@lvUserFinishProc = lvFinishProc; Restoring!0 = 0
]

and CopyTemplate() be return // needed by levStreams

and StartTimer() be [ Timer(TimeStart); DoubleNeg(TimeStart) ]

and ElapsedTime(lvStatic) = valof
[	let X = GetStorage(2); Timer(X); DoubleAdd(X,TimeStart)
	rv lvStatic = X; resultis X
]

and PutField(Bit1, NBits, DVec, Field) be
[	if (NBits le 0) % (NBits > 16) then CallSwat()
	let Wx = Bit1 rshift 4		// Bit1 starts at 0
	let LBx = (Bit1 & 17B) + NBits
	let Mask = #177777 rshift (16-NBits)
	let Shift = 16 - LBx
	if LBx le 16 then // fits in one word
	[ DVec!Wx = ( (DVec!Wx) & not(Mask lshift Shift)) logor
		  ((Field & Mask) lshift Shift) 
	  return
	]
	Shift = -Shift
	DVec!Wx = ((DVec!Wx) & not(Mask rshift Shift))
		    logor ((Field & Mask) rshift Shift)
	Shift = 32-LBx
	DVec!(Wx+1) = ((DVec!(Wx+1)) & not(Mask lshift Shift))
		     logor ((Field & Mask) lshift Shift)
]


and GetField(Bit1, NBits, DVec) = valof
[	if (NBits le 0) % (NBits > 16) then CallSwat()
	let Wx = Bit1 rshift 4
	let LBx = (Bit1 & 17B) + NBits
	if LBx le 16 then // field fits in one word
	  resultis ((DVec!Wx) rshift (16-LBx)) logand
		 ( #177777 rshift (16-NBits) )
	let Part1 = (DVec!Wx) & (#177777 rshift (LBx - NBits))
	let Part2 = ((DVec!(Wx+1)) rshift (32-LBx))
	resultis ( Part1 lshift (LBx-16)) logor Part2
]