//d0reg.bcpl	hardware interface procedures for register read/write
//	Last edited: 9 June 1980

get "mcommon.d"
get "d0.d"
manifest [ get "d0regmem.d" ]

external [
// MINIT0
	MStatus

// MIDAS
	MidasSwat

// MMPRGN
	UpdateMPDValues

// MASM
	GetField; PutField

// MCMD
	ErrorAbort; @WssCSS; WnsCSSD; PassiveOnly

// D0I0
	DVx

// D0I1
	d0rnvr; d0wnvr

// D0TABLES
	@REGCON

// D0ASM
	stReadOnly; stRunning; stPassive; stNotInVM; sendbyte

// D0MRW
	sovlcurr; sovlput; readrr; wrtrr; readt; readtpc

// D0VM
	LookUpAA; LookUpVA; @VirtualP

//Defined here for use by machine-independent code
	GetRegData; MGetRegData; PutRegData; MPutRegData

// Defined here for use by D0go, D0asm, etc.
	ReadAllRegs; PutAllRegs; ReadRegisters; MGetChecks; MPutChecks
	MakeVA; MakeAA
]

static [ SaveVA ]

let ReadRegisters() be
[	readrr(RXALU,lv DVx!0) //read the volatile registers first
	readrr(RXSTK,lv DVx!1)
	readrr(RXAPC,lv DVx!6)
	readrr(RXCTASK,lv DVx!7)
	readrr(RXPPB,lv DVx!8)
	DVx!8 = DVx!8 xor #77 //BootReason is read inverted
	sendbyte(sovlput(d0rnvr)) //send and execute overlay to get the others

	readrr(stack0,lv DVx!2) //MemSyndrome
	readrr(stack1,lv DVx!3) //CycleControl, PCX, PCF
	readrr(stack2,lv DVx!4) //DB,SB
	readrr(stack3,lv DVx!5) //MNBR
]


and ReadAllRegs() be
[	ReadRegisters(); UpdateMPDValues()
]


and PutAllRegs() be
[	wrtrr(RXALU,lv DVx!0) //volatile first.. CTASK is written in StartD0
	wrtrr(RXSTK,lv DVx!1)
	wrtrr(RXAPC,lv DVx!6)
	wrtrr(RXPPB,lv DVx!8)
//now the non-volatile registers
//NOTE:  must be very careful about overlays, as they smash Stack2-stack5.
	sovlput(d0wnvr) //send overlay to get them written.  Dont execute it yet.
	wrtrr(stack0,lv DVx!3) //PCF
	wrtrr(stack1,lv DVx!4) //DB,SB
	wrtrr(stack2,lv DVx!5) //MNBR
	sendbyte(EXOVLcode) //execute the overlay
]


//Called from GetRegData, GetMemData
and MakeVA(Addr) = VirtualP ? LookUpVA(Addr),Addr


//Called from PutRegData, PutMemData (but VirtualP should only be true
//when these are called from MPutRegData and MPutMemData).
and MakeAA(Addr) = valof
[	if VirtualP do
	[ Addr = LookUpAA(Addr)
	  if Addr < 0 then ErrorAbort(stNotInVM)
	]
	resultis Addr
]

and GetRegData(RegX,DVec) = valof
[	let T = nil
	switchon RegX into
	[
case APCTASKx:
	DVec!0 = DVx>>srbus.apctask lshift (16-size srbus.apctask); endcase
case APCx:
	DVec!0 = MakeVA(DVx>>srbus.apc) lshift 4; endcase
case CTASKx:
	DVec!0 = DVx>>srbus.ctask lshift (16-size srbus.ctask); endcase
case CIAx:
	DVec!0 = MakeVA(#7777 xor DVx>>srbus.ncia) lshift 4; endcase
case CYCLECONTROLx:
	DVec!0 = DVx>>srbus.cyclecontrol lshift (16-size srbus.cyclecontrol); endcase
case PAGEx:
	DVec!0 = DVx>>srbus.page lshift (16-size srbus.page); endcase
case PARITYx:
	DVec!0 = DVx>>srbus.parity lshift (16-size srbus.parity); endcase
case BOOTREASONx:
	DVec!0 = DVx>>srbus.bootreason lshift (16-size srbus.bootreason)
	endcase
case PCXREGx:
	DVec!0 = DVx>>srbus.pcxreg lshift (16-size srbus.pcxreg); endcase
case PCFREGx:
	DVec!0 = DVx>>srbus.pcfreg lshift (16-size srbus.pcfreg); endcase
case DBREGx:
	DVec!0 = DVx>>srbus.dbreg lshift (16-size srbus.dbreg); endcase
case SBREGx:
	DVec!0 = DVx>>srbus.sbreg lshift (16-size srbus.sbreg); endcase
case MNBRx:
	DVec!0 = DVx>>srbus.mnbr lshift (16-size srbus.mnbr); endcase	
case ALURESULTx:
	DVec!0 = DVx>>srbus.aluresult lshift (16-size srbus.aluresult)
	endcase	
case SALUFx:
	DVec!0 = DVx>>srbus.saluf lshift (16-size srbus.saluf); endcase
case SSTKPx:
	DVec!0 = DVx>>srbus.sstkp lshift (16-size srbus.sstkp); endcase
case STKPx:
	DVec!0 = DVx>>srbus.stkp lshift (16-size srbus.stkp); endcase
case MEMSYNDROMEx:
	DVec!0 = DVx>>srbus.memsyndrome lshift (16-size srbus.memsyndrome)
	endcase
case CALLERx:
	readtpc(DVx>>srbus.ctask,DVec)
	DVec!0 = MakeVA((DVec!0 & #7760)+((DVec!0-1) & #17)) lshift 4
	endcase
case AATOVAx:
	DVec!0 = SaveVA; endcase
default:
	MidasSwat(UndGRegX)
	]
	resultis true
]


//Called by MGetRegData and MGetMemData--resultis false if not ok to
//read, else true.
and MGetChecks(CON) = valof
[	let MachRunning = MStatus>>MStatus.MachRunning
	if MachRunning then
	  if CON<<MRType.RunAccess eq 0 do resultis false
	if MachRunning % PassiveOnly then
	  if CON<<MRType.Passive eq 0 do resultis false
	resultis true
]


and MGetRegData(RegX,DataVec,nil,Extension) =
	MGetChecks(REGCON!RegX) ? GetRegData(RegX,DataVec),false

and PutRegData(RegX,DVec) = valof
[	let T = DVec!0
	switchon RegX into
	[
case APCTASKx:
	DVx>>srbus.apctask = T rshift (16-size srbus.apctask); endcase
case APCx:
	DVx>>srbus.apc = MakeAA(T rshift (16-size srbus.apc)); endcase
case CTASKx:
	DVx>>srbus.ctask = T rshift (16-size srbus.ctask); endcase
case CIAx:
	DVx>>srbus.ncia = #7777 xor MakeAA(T rshift (16-size srbus.ncia))
	endcase
case CYCLECONTROLx:
	DVx>>srbus.cyclecontrol = T rshift (16-size srbus.cyclecontrol); endcase
//case PAGEx:
//	DVx>>srbus.page = T rshift (16-size srbus.page); endcase
//case PCXREGx:
//	DVx>>srbus.pcxreg = T rshift (16-size srbus.pcxreg); endcase	
//case PCFREGx:
//	DVx>>srbus.pcfreg = T rshift (16-size srbus.pcfreg); endcase
case DBREGx:
	DVx>>srbus.dbreg = T rshift (16-size srbus.dbreg); endcase
case SBREGx:
	DVx>>srbus.sbreg = T rshift (16-size srbus.sbreg); endcase
case MNBRx:
	DVx>>srbus.mnbr = T rshift (16-size srbus.mnbr); endcase	
case ALURESULTx:
	DVx>>srbus.aluresult = T rshift (16-size srbus.aluresult); endcase
case SALUFx:
	DVx>>srbus.saluf = T rshift (16-size srbus.saluf); endcase
//case SSTKPx:
//	DVx>>srbus.sstkp = T rshift (16-size srbus.sstkp); endcase
case STKPx:
	DVx>>srbus.stkp = T rshift (16-size srbus.stkp); endcase
case AATOVAx:
	SaveVA = LookUpVA(T); endcase
default:
	MidasSwat(UndPRegX)
	]
//***The hardware should be written here***
	resultis true
]


//Called by MPutRegData and MPutMemData--ErrorAbort if illegal to write
and MPutChecks(CON) be
[	if CON<<MRType.ReadOnly ne 0 do ErrorAbort(stReadOnly)
	let MachRunning = MStatus>>MStatus.MachRunning
	let PassiveWrite = CON<<MRType.PassiveWrite
	if MachRunning then
	  unless (CON<<MRType.RunAccess ne 0) &
		(PassiveWrite ne 0) do ErrorAbort(stRunning)
	if PassiveOnly then
	  if PassiveWrite eq 0 do ErrorAbort(stPassive)
]


and MPutRegData(RegX,DVec,nil,Extension) be
[	MPutChecks(REGCON!RegX)
	test PutRegData(RegX,DVec)
	ifso UpdateMPDValues()
	ifnot ErrorAbort()
]