// D1res.bcpl -- resident procedures
//	Last edited: 1 May 1980

get "mcommon.d"
get "d1.d"
manifest [ get "d1instrs.d" ]
manifest [ get "d1dmux.d" ]
manifest [ get "d1regmem.d" ]
manifest [ get "d1pe.d" ]

external [
// MIDAS
	MidasSwat

// MINIT0
	MStatus

// MMPRGN
	UpdateMPDValues

// MCMD
	ErrorAbort; PassiveOnly

// D1I0
	@SaveMIR; HWStatus; @DMuxTab; DChecked

// D1TABLES
	@REGCON

// D1ASM
	@MCXct; LoadMIR; LoadCPReg; @Xct; @XctR16; @XctR16C; @XctL16Q
	@XctL16T; @XctLFF; @DoStrobe; ReadDMux; LoadDMD; @SelectTask
	IMtoMIR; MIRtoIM; @D1Out; stReadOnly; stPassive; stRunning

// D1MEM
	GetMic2; FixClock; ClearIMBDAddr
	DMuxSelect; @OldTask; @SaveTask; @SaveQ; SaveSTKP
	@SaveT; @SaveSRN; @SaveMCR

// D1VM
	LookUpVA

// Defined here
	GetRegData; MGetChecks; MGetRegData
	PutRegData; MPutChecks; MPutRegData
]

static
[	SaveVA
]

//DMux items read out from the current, old, wrong, or checked versions
//of DMuxTab according to the last button action on DMux
let GetRegData(RegX,DVec) = valof
[	let T = nil
	switchon RegX into
	[
case CPREGx:	XctR16C(RLINK,DVec); endcase
case MIRx:	MIRtoIM(DVec,DMuxSelect+dSaveMIR); endcase
case IMOUTx:	MIRtoIM(DVec,DMuxSelect+dIMOUT); endcase
case Qx:	XctR16(RQ,DVec); endcase
case CNTx:	Xct(TFCNT); XctR16(RT,DVec); endcase
case SHCx:	Xct(TFSHC); XctR16(RT,DVec); endcase	
case MEMBXx:	Xct(TFPTRS); DVec!0 = (XctR16C(RT,DVec) lshift 1) & 140000B
		endcase
case STKPx:	Xct(TFTIOA); T = XctR16(RT,DVec) lshift 8
		Xct(TFPTRS); DVec!0 = T+(XctR16(RT,DVec) & 300B)
		endcase
case TASKx:	DVec!0 = SaveTask lshift 12; endcase

case MCRx:	DVec!0 = DMuxSelect!dMCR; endcase
case PROCSRNx:	DVec!0 = XctR16(RCONFG,DVec) & 170000B; endcase
case CONFIGx:	XctR16(RCONFG,DVec); endcase
case PCXx:	XctR16(RPCX,DVec); endcase
case INSSETx:	DVec!0 = #174000 & XctR16(RIFH,DVec); endcase
case TESTSYNx:
case STROBEx:
case D1OUTx:	resultis false	//write-only
case UPTIMEx:
case TGLITCHx:	T = RegX eq UPTIMEx ? 82,88
		MCXct(BCLdHi+BHoldInt+BInt); MCXct(BCLdLo+BHoldInt+BInt+T)
		GetMic2(DVec); GetMic2(DVec+1); GetMic2(DVec+2)
		MCXct(BInt+BCNoop); FixClock(); endcase
case EVCNTAx:	XctR16(REVA,DVec); endcase
case EVCNTBx:	XctR16(REVB,DVec); endcase
case AATOVAx:	DVec!0 = SaveVA; endcase
case ESTATx:	DVec!0 = DMuxSelect!dESTAT; endcase
default:	MidasSwat(UndefRegXRead)
	]
	resultis true
]


and MGetChecks(CON) = valof
[	let MachRunning = MStatus>>MStatus.MachRunning
	if MachRunning then
	  unless CON<<MRType.RunAccess ne 0 do resultis false
	if MachRunning % PassiveOnly then
	  unless CON<<MRType.Passive ne 0 do resultis false
	resultis true
]


and MGetRegData(RegX,DVec,nil,Extension) = valof
[	unless MGetChecks(REGCON!RegX) do resultis false
	let R = GetRegData(RegX,DVec)
	switchon RegX into
	[
case SHCx: case CNTx: case MEMBXx: case STKPx:
		XctL16T(SaveT); Xct(NOOP)
case Qx: case PCXx: case CPREGx: case CONFIGx: case PROCSRNx:
case INSSETx: case EVCNTAx: case EVCNTBx:
		LoadMIR(SaveMIR)
default:	endcase
	]
	resultis R
]

//Many Put's end with a NOOP, necessary if the final Xct is a load from
//CPReg at t3 because the next instruction might smash CPReg.
//For most registers, the minimal work necessary to load the register is
//done in PutRegData, and the cleanup is done in MPutRegData.  Things are
//divided this way so "Test" and "TestAll" will run quickly.  However,
//registers read via the DMux must do everything in PutRegData.

//Items whose read values are from the DMux are legal to write when
//DChecked signals are being shown; when DMuxTab signals are being shown
//the write is legal if there is some way to write the hardware item;
//otherwise (OldDMuxTab or DWrong being shown), the write is illegal.
//This includes MIR, IMOUT, and MCR.
and PutRegData(RegX,DVec) = valof
[	let D,T,U = DVec!0,nil,nil
	switchon RegX into
	[
case CPREGx:	LoadCPReg(D); resultis true
case MIRx:	test DMuxSelect eq DChecked
		ifso
		[ IMtoMIR(DMuxSelect+dSaveMIR,DVec); resultis true
		]
		ifnot test DMuxSelect eq DMuxTab
		  ifso
		  [ IMtoMIR(SaveMIR,DVec); endcase
		  ]
		  ifnot resultis false
case IMOUTx:	test DMuxSelect eq DChecked
		ifso
		[ IMtoMIR(DMuxSelect+dIMOUT,DVec); resultis true
		]
		ifnot resultis false
case Qx:	XctL16Q(D); SaveQ = D; Xct(NOOP); resultis true	
case CNTx:	XctL16Q(D); Xct(CNTFQ); resultis true
case SHCx:	XctL16Q(D); Xct(SHCFQ); resultis true
case MEMBXx:	XctLFF(LMBX0,D rshift 14); resultis true
case STKPx:	SaveSTKP = D<<lh; XctL16Q(SaveSTKP); Xct(STKPFQ)
		resultis true
case TASKx:	SelectTask(D rshift 12); endcase
case PROCSRNx:	SaveSRN = D rshift 12; XctL16Q(SaveSRN); Xct(SRNFQ)
		resultis true
case MCRx:	test DMuxSelect eq DMuxTab
		ifso
		[ SaveMCR = D; XctL16T(D); Xct(MCRFT)
		  XctL16T(SaveT); Xct(NOOP); endcase
		]
		ifnot test DMuxSelect eq DChecked
		  ifso
		  [ DMuxSelect!dMCR = D; resultis true
		  ]
		  ifnot resultis false
case INSSETx:	XctL16Q(((D & #14000) rshift 3)+#100000)
		Xct(ISEVFQ); endcase	//IdCnt not writeable
//**Leaves tags screwed up?? First reference held after writing this.**
case TESTSYNx:	OldTask = SelectTask(16B)
		XctL16T(FDMiss+DisHold+NoRef+NoWake)
		Xct(MCRFT); XctL16Q(D); Xct(NOOP)
		Xct(STORETQ); Xct(LTSYN); XctL16T(SaveMCR)
		Xct(MCRFT); XctL16T(SaveT); Xct(NOOP)
		XctL16Q(SaveQ); SelectTask(OldTask); endcase
case STROBEx:	DoStrobe(D); resultis true
case D1OUTx:	rv D1Out = D; resultis true
case EVCNTBx:	XctL16Q(D); Xct(EVBFQ); resultis true
case AATOVAx:	SaveVA = LookUpVA(D); resultis true
//Convert ESTAT format: Build LoadDMD controls in T and HaltConditions in U
case ESTATx:	test DMuxSelect eq DMuxTab
		ifso
		[ T = (D & IMlhPEena) ne 0 ?
			PEHaltEnable+IMlhPEen,PEHaltEnable
		  if (D & IMrhPEena) ne 0 do T = T+IMrhPEen
		  if (D & IOBPEena) ne 0 do T = T+IOPEen
		  if (D & RAMPEena) ne 0 do T = T+RAMPEen
		  if (D & MemoryPEena) ne 0 do T = T+MemPEen
		  if (D & MdPEena) ne 0 do T = T+MdPEen
		  LoadDMD(T)
		  HWStatus>>HWStatus.MIRdebugging =
			(D & MIRDebugena) ne 0 ? MIRdebug,0
		  ClearIMBDAddr()	//Enable/disable MIRdebug feature
		  ReadDMux(); resultis true
		]
		ifnot test DMuxSelect eq DChecked
		  ifso
		  [ DMuxSelect!dESTAT = D; resultis true
		  ]
		  ifnot resultis false
default:	MidasSwat(UndefRegXWrite)
	]
	LoadMIR(SaveMIR); ReadDMux(); resultis true
]


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,nil) be
[	MPutChecks(REGCON!RegX)
	test PutRegData(RegX,DVec)
	ifso
	[ switchon RegX into
	  [
case CNTx: case SHCx: case STKPx: case PCXx: case PROCSRNx:
case INSSETx: case EVCNTBx:
		XctL16Q(SaveQ); Xct(NOOP)
case MEMBXx: case Qx:
		LoadMIR(SaveMIR); ReadDMux()
//Mustn't do ReadDMux() after these two
case STROBEx: case D1OUTx:
default:	endcase
	  ]
	  UpdateMPDValues()
	]
	ifnot ErrorAbort(stReadOnly)	//Only the DMux items
]