//RunMesa.bcpl - BCPL setup for Mesa Emulator - R. Johnsson
//last modified by Johnsson:  September 30, 1980  12:22 PM 

//Bldr RunMesa/S RunMesa Run Template MBoot Mesa-Nova1 Mesa-Nova2 MesaImage XMesaImage XMesaOverflow Configuration ReadPram GP TimeConvA TimeConvB TimeIO

//files MesaImage and later may not be used after FindSpace() [in Run]

//incompatible microcode with version 15a; February 3, 1977
//ROM compatible microcode with version 16a; February 18, 1977
//incompatible microcode with version 18a; May 18, 1977
//incompatible microcode with version 19a; May 27, 1977
//new version numbering at 23.3
//check file format at version 29; March 1978
//support Alto XM; July 27, 1978
//major reorganization at 32.0; November 1978
//merge Mesa and XMesa microcode; support 3K RAM; November 1979

manifest [ MajorVersion = 35; MinorVersion = 9 ]
manifest [ ImageVersionID = 01040 ]
manifest [ printversion = true ]

get "SysDefs.d"
get "Streams.d"
get "AltoFileSys.d"
get "RunMesa.d"

external	[ SetupReadParam; ReadParam ]		//gp
external	[ ReadPackedRAM; LoadPackedRAM ]	//readpram
external	[ PutTemplate ]				//template
external	[ UNPACKDT; WRITEUDT ]			//ctime

let RunMesa(layout,up,cfa) be
[Mesa
let imageStream = 0
until up!0 eq 0 do
  [
  if up>>UPE.type eq openStreams then imageStream = up!1
  if up>>UPE.type eq mesaMemoryMask then memoryBanks = up!1
  up = up + up>>UPE.length
  ]

DetermineConfiguration()

if printversion then WriteVersion()

let giveImageVersion = false
if imageStream eq 0 then
    imageStream = SetupParams(lv giveImageVersion)

let header = vec lImagePrefix-1
ReadBlock(imageStream,header,lImagePrefix)

if giveImageVersion then
	[
	WriteStamp(lv header>>ImagePrefix.version)
	Ws(", creator ")
	WriteStamp(lv header>>ImagePrefix.creator)
	KeyboardWait()
	]

if header>>ImagePrefix.versionident ne ImageVersionID then
	AbortMsg("*NIncorrect image file format.")

let imageCfa = vec lCFA-1
GetCompleteFa(imageStream, imageCfa)

if header>>ImagePrefix.type eq checkfile &
   header>>ImagePrefix.leaderDA ne imageCfa>>CFA.fp.leaderVirtualDa then
	AbortMsg("*NThis CheckPoint file has been tampered with.")

LoadInternalMicrocode()
Run(imageStream,header)
]Mesa



and SetupParams(lvVersionSwitch) = valof
[
let iFileName = vec 20; iFileName!0 = 0
//Get switches from command line
let argument=vec 100
let switches=vec 100
let bootfile = false
let comcm = OpenFile("Com.Cm", ksTypeReadOnly, charItem, verLatest, fpComCm);
SetupReadParam(argument,switches,comcm,switches)

let done = false

let usename = false

test ImageFile(argument)
  ifso usename=true
  ifnot
    if (switches!0 ne 0) then for I=1 to switches!0 do
	[GlobalSwitchLoop
	switchon (switches!I) & #137 into
		[SwitchCases
		case $V:	// print version info
			[V
			if not printversion then WriteVersion()
			@lvVersionSwitch = true
			endcase
			]V
		case $M:	// load microcode only
			[M
			test LoadInternalMicrocode()
			  ifso [ Ws( "*NMicrocode loaded"); finish ]
			  ifnot AbortMsg("*NCan't load microcode")
			endcase
			]M
		case $S:	// go into Swat before starting image
			[S
			@SwatFlag=#77400
			endcase
			]S
		case $Q: case $G:	// end of commands
			[C
			done=true
			endcase
			]C
		case $B:
			[B
			bootfile=true
			endcase
			]B
		default:
			[Huh
			Ws("*NBad switch encountered. ")
			endcase
			]Huh
		]SwitchCases
	]GlobalSwitchLoop

let rewritecomcm = not usename

// read the parameters
test usename
  ifso AppendString(iFileName,argument)
  ifnot
    until done do
    [paramloop
    let p = ReadParam($P,0,0,0,true)
    if (p eq 0)%(p eq -1) then break
    test switches!0 eq 0
        ifso if iFileName!0 eq 0 then [ AppendString(iFileName,p); break ]
        ifnot
        [localswitches
        for I=1 to switches!0 do
            switchon (switches!I) & #137 into
            [
            case $C:	// end of commands
                [ if iFileName!0 eq 0 then AppendString(iFileName,p);
                  done = true;
                  endcase
                ]
            case $I:	// image file name
                [ AppendString(iFileName,p); endcase ]
            case $M:	// microcode (pram) file
                [
		let c = nil
		test I ls switches!0
		  ifso [ c = switches!(I+1); I=I+1 ]
		  ifnot c = $0
		if c ge $0 & c le $2 then LoadRamBank(p, c-$0)
		endcase
		]
            case $B:	// restrict banks (bit mask)
                [ RestrictMemoryBanks(Octal(p)); endcase ]
            case $X:	// restrict banks (bank numbers)
                [ RestrictMemoryBanks(BankMask(p)); endcase ]
            default:
                [
                PutTemplate(dsp, "*NBad switch '$C', item will be ignored.", switches!I)
                KeyboardWait()
                ]
            ]
        ]localswitches
    ]paramloop

if bootfile then
	[
	DefaultName(iFileName,"MESA","SV")
	LoadInternalMicrocode()
	let message = vec lInLdMessage
	let fp = vec lFP
	let cfa = vec lCFA
	let file = OpenFile(iFileName,ksTypeReadOnly,wordItem)
	if file eq 0 then
		[
		PutTemplate(dsp,"*NFile '$S' not found.",iFileName)
		AbortMsg()
		]
	GetCompleteFa(file,cfa);
	MoveBlock(fp, lv cfa>>CFA.fp, lFP)
	let realda = 0
	RealDiskDA(sysDisk, cfa>>CFA.fa.da, lv realda)
	fp>>FP.leaderVirtualDa = realda
	message!1 = #377  // level = -1, reason = proceed
	InLd(fp,message)
	]

DefaultName(iFileName,"Mesa","image")

// maybe rewrite comcm here
test rewritecomcm
    ifso
    [   let newcomcm = OpenFile("Com.Cm", ksTypeWriteOnly, charItem, verLatest, fpComCm)
        for i=1 to iFileName>>STRING.length do
            Puts(newcomcm,iFileName>>STRING.char↑i)
	test Endofs(comcm)
	  ifso Puts(newcomcm,$*N)
	  ifnot Puts(newcomcm,$*S)
        until Endofs(comcm) do
            Puts(newcomcm,Gets(comcm));
        Closes(comcm); Closes(newcomcm);
    ]
    ifnot Closes(comcm)

let image=OpenFile(iFileName,ksTypeReadOnly)
if image eq 0 then
	[
	PutTemplate(dsp,"*NImage file '$S' not found.",iFileName)
	AbortMsg()
	]
resultis image
] // end SetupParams


and ImageFile(name) = valof
[
	let cap(c) = ((c ge $a) & (c le $z)) ? c+$A-$a, c
	let s = vec 40
	s>>STRING.length = name!0
	for i = 1 to s>>STRING.length do
	  s>>STRING.char↑i = name!i
	MoveBlock(name,s,name!0)
	s=".IMAGE"
	let ofs = name>>STRING.length-s>>STRING.length
	if ofs ls 0 then resultis false
	for i = 1 to s>>STRING.length do
	  if cap(name>>STRING.char↑(ofs+i)) ne s>>STRING.char↑i then resultis false
	resultis true
]


and Octal(s) = valof
[Octal // s is octal bit mask of banks to be ignored
let n = 0
for i = 1 to s>>STRING.length do
  n = 8*n + (s>>STRING.char↑i-$0)
resultis n
]Octal

and BankMask(s) = valof
[BankMask // s is string of bank numbers (sep by ,) to be ignored
let n = 0
let mask = 0
for i = 1 to s>>STRING.length do
  [
  let c = s>>STRING.char↑i
  test c ge $0 & c le $9
    ifso n = n*10 + c-$0
    ifnot [ mask = mask % (100000b rshift n); n = 0 ]
  ]
mask = mask % (100000b rshift n)
resultis (not mask)
]BankMask

and RestrictMemoryBanks(mask) be
[RestrictMemoryBanks
HardwareConfiguration>>HardwareInfo.banks =
  HardwareConfiguration>>HardwareInfo.banks & mask
if HardwareConfiguration>>HardwareInfo.banks eq 100000b then
  HardwareConfiguration>>HardwareInfo.useXM = false
]RestrictMemoryBanks

and LoadRamBank(name, bank) be
[LoadRamBank
DefaultName(name, "Mesa", "pram")
let mFile=OpenFile(name,ksTypeReadOnly,wordItem)
if mFile eq 0 then
	[
	PutTemplate(dsp,"*N$S not found.",name)
	AbortMsg()
	]
let ramver = 0
let trouble=ReadPackedRAM(mFile, lv ramver, bank)
PutTemplate(dsp,"$S loaded in bank $D; version = $D*N",
	name, bank, ramver)
if trouble ne 0 then KeyboardWait()
microcodeLoaded = microcodeLoaded % (1 lshift bank)
]LoadRamBank

and DefaultName(name,defname,defext) be
[DefaultName
if name!0 eq 0 then
    [
    AppendString(name,defname,".",defext)
    return
    ]
for I=1 to name>>STRING.length do
    [
    if name>>STRING.char↑I eq $. then return
    ]
AppendString(name,".",defext)
]DefaultName


and AppendString(s,s1,s2,s3,s4,s5,s6,s7,s8,s9; numargs na) be
[AppendString
let p = lv s1
for i = 0 to na-2 do
  [
  let t = p!i
  for k = 1 to t>>STRING.length do
    [ let l = s>>STRING.length+1
    s>>STRING.length = l
    s>>STRING.char↑l = t>>STRING.char↑k
    ]
  ]
]AppendString

and WriteVersion() be
[WriteVersion
PutTemplate(dsp,"*NRunMesa $D.$D, ", MajorVersion, MinorVersion)
GiveMicrocodeVersion()
if HardwareConfiguration>>HardwareInfo.ControlStore eq RAMandROM then
    PutTemplate(dsp,"; ROM1 microcode $D",
	HardwareConfiguration>>HardwareInfo.mesaMicrocodeVersion)
if HardwareConfiguration>>HardwareInfo.ControlStore eq RAM3K then
    Ws("; 3K RAM")
if HardwareConfiguration>>HardwareInfo.useXM then
    [
    let m = 0
    let b = memoryBanks
    until b eq 0 do [ if b ls 0 then m = m + 64; b = b lshift 1 ]
    PutTemplate(dsp,"; $DK memory", m)
    ]
Puts(dsp,$*N)
]WriteVersion

and WriteStamp(v) be
[WriteStamp
  let uv = vec 6
  let dv = vec 1
  dv!0, dv!1 = v>>VersionStamp.time.high, v>>VersionStamp.time.low // reverse
  UNPACKDT(dv, uv)
  WRITEUDT(dsp,uv)
  PutTemplate(dsp," $O#$O#",v>>VersionStamp.net,v>>VersionStamp.host)
]WriteStamp