//D1goovl.bcpl -- Error print routine called from PrintErrors in D1go.
//	23 June 1983

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

external [
// MASM
	ResetsCSS; @WssCSS; WssCS1; PutsCS1; GetField

// MDATA
	GoVec; CallAVec

// MIOC
	DataToStream

// MMPRGN
	FixForm

// MCMD
	WnsCS1; CmdCS1

// MGO
	StartSetup; HaltWait; HaltWaitMenu; @CantContinue; PassiveOnly

// MPATTERN
	@PATTERN

// MPRINS
	NWss; NWss1

// MINIT0
	MStatus

// D1I0
	@DMuxTab; @SaveMIR

// D1TABLES
	@MEMWID; @MEMFORMS

// D1ASM
	@XctL16T; ReadDMux; @Xct; IMtoMIR

// D1RES
	BreakTPC

// D1MEM
	MGetRegData; MGetMemData; @SaveT; @SaveLINK

// D1GO
	SetupIMA; OneStep; MStopped; GetHMask

// Defined here
	OpcodeStep; CallM; PrintPEDetails; PrintCantContinue
]

//Keyboard "Call" action.  CallM is called from StartWithArgs in MGO.
//CallAVec!0 and CallAVec!1 are the collected address, CallAVec!2 is the
//MemX of the address, AV is a vector containing Count (up to 5) 32-bit
//argument vectors.
let CallM(MB,AV,Count) = valof
[	SaveLINK = CallRetAddr
	if Count > 0 then
	[ SaveT = AV!1; XctL16T(SaveT); Xct(NOOP)
	]
//"Start" will first load LINK with the subroutine address, and step
//the STARTX instruction (= RETURN, B←RWCPREG) with SaveLINK in CPReg.
//This causes CallRetAddr to wind up in LINK irrespective of whether
//the subroutine is on a call location.
	SetupIMA(true,CallAVec,CallAVec!2,3,"Call ",MB)
	OneStep(GoVec>>Go.RunP)
	resultis StartSetup(HaltWait)	//Displays "Abort" & "Dtach"
]


//"OS" action.  OpcodeStep is called from StartWithAddr in MGO.
//AVec and MemX args are supplied if starting at a new address,
//omitted if continuing from previous halt.  Single-step the
//microprocessor until a normal halt condition occurs or an
//IFUJump has been executed.
and OpcodeStep(MB,AVec,MemX; numargs NA) = valof
[	SetupIMA(false,AVec,MemX,NA,(NA ge 3 ? "Step opcode at ",
		"Next opcode at "),MB)
	StartSetup(OpcodeWait)
	ReadDMux(); MStatus>>MStatus.MachRunning = true
	resultis HaltWaitMenu	//Displays "Abort" action
]


and OpcodeWait(nil) be
[	let DVec = vec 4; IMtoMIR(SaveMIR,DVec)
	let JCN = GetField(32B,10B,DVec)
	OneStep(Control+SetRun+SetSS); ReadDMux()
//Halt after the IFUJump unless Hold occurred.
	if (JCN & 347B) eq 47B then
		unless (DMuxTab!dCJNK3 & 10B) ne 0 do MStopped(true)
	if (DMuxTab!dESTAT & GetHMask()) ne 0 then
		MStopped(true,true)
]


and PrintCantContinue() be
[	ResetsCSS(); WssCSS("Can't continue:")
	PATTERN = CantContinue
	NWss(" did-test",didTest)
	NWss(" did-Load")
	NWss(" did-PEscan")
	NWss(" after-Call")
	NWss(" did-SetClk")
	NWss(" did-Reset")
	NWss(" did-Tn")
	NWss(" IFUM-reset")
	NWss(" MIRdebug-on-at-break")
	NWss(" task 17 b.p. mem item displayed")
	NWss(" touched IMBD")
	NWss(" did-Fetch-and-←Md")
]

//DMuxTab!dESTAT & HaltConditions is in PATTERN
and PrintPEDetails() be
[	WssCS1("PE's from")
	NWss1(" IM[21:41]",IMrhPE)
	NWss1(" IM[0:20]")
//Analyze IM/MIR failures if MIRDebug feature enabled.  In this case
//SaveMIR contains what was in MIR; compare against direct IM output.
	if ((DMuxTab!dESTAT & MIRDebugena) ne 0) & (not PassiveOnly) &
		((PATTERN & (IMrhPE+IMlhPE)) ne 0) do
	[ let VMIR,VIM,AVec = vec 3,vec 3,vec 1
	  AVec!0 = 0; AVec!1 = BreakTPC
	  MGetRegData(MIRx,VMIR); MGetMemData(IMXx,VIM,AVec,0)
	  WssCS1(" (IMX["); WnsCS1(BreakTPC); WssCS1("]=")
	  DataToStream(CmdCS1,FixForm(MEMFORMS!IMXx,0),MEMWID!IMXx,VIM,8)
	  PutsCS1($))
	]
	let TaskBk = not DMuxTab!dRADDR
	let TaskInErr = TaskBk<<nib0	//Task2Bk
	let T = DMuxTab!dPERR
	if (PATTERN & MdPE) ne 0 do
	[ PrinProcErr(((T & 10000B) ne 0 ? "MD","MDI"),T rshift 2)
	  if (T & 10000B) ne 0 then TaskInErr = TaskBk<<nib1	//Task3Bk
	]
	if (PATTERN & IOBPE) ne 0 then
	  PrinProcErr(((T & 20000B) ne 0 ? "Output","Input"),T rshift 3)
	if (PATTERN & RAMPE) ne 0 do
	[ test (T & 1403B) eq 0
	  ifso WssCS1("RM-STK-T?")
	  ifnot
	  [ if (T & 1002B) ne 0 then
		PrinProcErr(((T & 100B) ne 0 ? "STK","RM"),T rshift 1)
	    if (T & 401B) ne 0 then PrinProcErr("T",T)
	  ]
	]
//Task unknown for memory errors
	if (PATTERN & (MdPE+IOBPE+RAMPE)) ne 0 do
	[ WssCS1(" (by task "); WnsCS1(TaskInErr); PutsCS1($))
	]
//STPerr, HitPerr, and ?MapPerr? (optional) on the mufflers remain
//at the values which cause MemPE until ←FaultInfo is done.  These
//errors are also reset and disabled by NoWake in Mcr.
	if (PATTERN & MemoryPE) ne 0 do
	[ PATTERN = DMuxTab!dRFSSRN
	  test (PATTERN & 160000B) ne 0
	  ifso
	  [ NWss1(" ST",#100000)
	    NWss1(" Map")
	    NWss1(" Cache")
	  ]
	  ifnot WssCS1(" Memory")
	]
]


and PrinProcErr(Str,Val) be
[	PutsCS1($ ); WssCS1(Str)
	WssCS1(selecton Val & 401B into
	  [ case 400B: "[0:7]"
	    case 1B: "[8:15]"
	    case 401B: ""
	    default: "?"
	  ] )
]