//MesaX.bcpl - XM support for RunMesa - R. Levin
//last modified by Levin:  October 17, 1978  10:41 AM 

get "Mesa.d"

external	[ MoveBlock; Zero ]				// OS
external	[ DetermineConfiguration ]			//exported to Mesa.bcpl	

manifest	[
	WakeupsWaiting = #452
	Active = #453
	]

manifest	[ EmulatorBR = #177740 ]

structure BankRegister: [
		  unused bit 12
		  primary bit 2
		  alternate bit 2
		]

let DetermineConfiguration() be
[DetermineConfiguration
manifest bank0only = #10
let vers=table [
    #61014		//VERS
    #1401		//JMP 1 3
    ]
let engineeringNumber = vers() rshift 12
Zero(HardwareConfiguration,lHardwareInfo)
test engineeringNumber eq 0
    ifso HardwareConfiguration>>HardwareInfo.AltoType = 1
    ifnot HardwareConfiguration>>HardwareInfo.AltoType = engineeringNumber
HardwareConfiguration>>HardwareInfo.useXM = false
HardwareConfiguration>>HardwareInfo.banks = bank0only			// bank 0 only
HardwareConfiguration>>HardwareInfo.secondROM = false
HardwareConfiguration>>HardwareInfo.mesaMicrocodeVersion = 0
HardwareConfiguration>>HardwareInfo.XMMicrocodeVersion = 0
if (HardwareConfiguration>>HardwareInfo.AltoType < 2) %
   (HardwareConfiguration>>HardwareInfo.AltoType > 3) then return	// ignore pseudo-Altos
ROMVersion()
if HardwareConfiguration>>HardwareInfo.AltoType ne 3 then return
let banksAvailable = FindMemoryBanks()
HardwareConfiguration>>HardwareInfo.banks = banksAvailable
HardwareConfiguration>>HardwareInfo.useXM = (banksAvailable ne bank0only) &
	HardwareConfiguration>>HardwareInfo.secondROM &
	(HardwareConfiguration>>HardwareInfo.XMMicrocodeVersion ne 0)
]DetermineConfiguration


and let ROMVersion() be
[ROMVersion
manifest [ RealRAMloc = #300; PossibleRAMloc = #777-1 ]
manifest highword = #2000
let versionTable = table [ 34 ]
let saveRealRAM = vec 3
let savePossibleRAM = vec 3
let WriteOne=table [  // (high,address,low)
    #55001		//STA 3 1 2
    #35003		//LDA 3 3 2
    #61012		//WRTRAM
    #35001		//LDA 3 1 2
    #1401		//JMP 1 3
    ]
let ReadOne=table [  // (pointer,address)
    #55001		//STA 3 1 2
    #115000		//MOV 0 3
    #61011		//RDRAM
    #41400		//STA 0 0 3
    #35001		//LDA 3 1 2
    #1401		//JMP 1 3
    ]
let JmpRAM=table [
    #61010		//JMPRAM
    #1401		//JMP 1 3
    ]
let initCP = table [
    #100; #170301;	//     L←ALLONES, SWMODE, :x1;
    #60110; #102020;	// x1: cp←L, :START;
    ]
let getVersionCode = table [
    #60110; #102020;	// x2: cp←L,:START;
    #60; #170776;	//     L←-2, SWMODE,:x2;
    ]
let readCP = table [
    #60060; #100301;	//     L←cp, SWMODE, :x3;
    #14030; #102020;	// x3: AC0←L, :START;
    ]
ReadOne(saveRealRAM,highword+RealRAMloc);   ReadOne(saveRealRAM+1,RealRAMloc);
ReadOne(saveRealRAM+2,highword+RealRAMloc+1); ReadOne(saveRealRAM+3,RealRAMloc+1);
WriteOne(initCP!0,RealRAMloc,initCP!1);
WriteOne(initCP!2,RealRAMloc+1,initCP!3);
JmpRAM(0,RealRAMloc);				// cp ← -1

ReadOne(savePossibleRAM,highword+PossibleRAMloc);   ReadOne(savePossibleRAM+1,PossibleRAMloc);
ReadOne(savePossibleRAM+2,highword+PossibleRAMloc+1);
ReadOne(savePossibleRAM+3,PossibleRAMloc+1);
WriteOne(getVersionCode!0,PossibleRAMloc,getVersionCode!1);
WriteOne(getVersionCode!2,PossibleRAMloc+1,getVersionCode!3);
JmpRAM(0,PossibleRAMloc+1);
WriteOne(savePossibleRAM!0,PossibleRAMloc,savePossibleRAM!1);
WriteOne(savePossibleRAM!2,PossibleRAMloc+1,savePossibleRAM!3);

WriteOne(readCP!0,RealRAMloc,readCP!1);
WriteOne(readCP!2,RealRAMloc+1,readCP!3);
let valCP = JmpRAM(0,RealRAMloc);
WriteOne(saveRealRAM!0,RealRAMloc,saveRealRAM!1);
WriteOne(saveRealRAM!2,RealRAMloc+1,saveRealRAM!3);
switchon valCP into
  [VersionCases
  case -2:		// no ROM on machine
    [
    endcase
    ]
  case -1:		// Mesa 4.1 ROM on machine
    [
    HardwareConfiguration>>HardwareInfo.mesaMicrocodeVersion = versionTable!0
    HardwareConfiguration>>HardwareInfo.secondROM = true
    endcase
    ]
  default:		// some other ROM on machine
    [
    HardwareConfiguration>>HardwareInfo.secondROM = true
    if (valCP & #100000) ne 0 then
      [GetXM
      let version = 0
      let val = valCP
      while (val & #100000) ne 0 do
	[loop
	version = version+1
	val = val lshift 1
	]loop
      valCP = valCP & (#177777 rshift version)
      HardwareConfiguration>>HardwareInfo.XMMicrocodeVersion = version
      ]GetXM
    HardwareConfiguration>>HardwareInfo.mesaMicrocodeVersion = versionTable!valCP
    endcase
    ]
  ]VersionCases
]ROMVersion


and let FindMemoryBanks() = valof
[FindMemoryBanks
manifest testlocation = 0
let bitToSet = #4			// start with bank 1
let bankbits = #10			// bank 0 always present
let savedActive = @Active
let GetAlternateBank=table [
    #61025		//XMLDA
    #1401		//JMP 1 3
    ]
let SetAlternateBank=table [
    #61026		//XMSTA
    #1401		//JMP 1 3
    ]
@Active = 0
EmulatorBR>>BankRegister.alternate = 0
until bitToSet eq 0 do
    [
    EmulatorBR>>BankRegister.alternate = EmulatorBR>>BankRegister.alternate+1
    let oldval = GetAlternateBank(0,testlocation)
    SetAlternateBank(oldval+1,testlocation)
    if GetAlternateBank(testlocation) eq oldval+1 then
	[ bankbits = bankbits % bitToSet; ClearBank() ]
    bitToSet = bitToSet rshift 1
    ]
@WakeupsWaiting = 0
@Active = savedActive
resultis bankbits
]FindMemoryBanks

and let ClearBank() be			// will be unnecessary when Alto OS does it for us
[ClearBank
manifest BBTlength = 16
let BitBltTable = vec BBTlength				// extra word for even alignment
//	Clears pages [0..253]; pages 254-255 are I/O registers
let InitialBBT = table [
    #34			// dest in alternate bank, gray, replace
    #0			// unused
    #0			// dest address
    256*2		// length of scan line (words)
    #0			// dest block X-offset (bits)
    #0			// dest block Y-offset (scan lines)
    256*2*16		// dest block width (bits)  [2 pages wide]
    127			// dest block height (scan lines)
    #0; #0; #0; #0	// source info not relevant
    #0; #0; #0; #0	// gray
    ]
let DoBitBLT=table [
    #54411		//STA 3 savedAC3
    #50407		//STA 2 savedAC2
    #111000		//MOV 0 2
    #126400		//SUB 1 1
    #61024		//BITBLT
    #30403		//LDA 2 savedAC2
    #34403		//LDA 3 savedAC3
    #1401		//JMP 1 3
    #0			//savedAC2
    #0			//savedAC3
    ]
BitBltTable = BitBltTable + (BitBltTable & 1)		// ensure even word alignment
MoveBlock(BitBltTable,InitialBBT,BBTlength)
DoBitBLT(BitBltTable)
]ClearBank