//D1go.bcpl	stuff associated with stop and go of the microprocessor
//	11 May 1983

get "mcommon.d"
get "d1.d"
manifest [ get "d1pe.d" ]
manifest [ get "d1instrs.d" ]
manifest [ get "d1regmem.d" ]
//manifest [ get "d1dmux.d" ] "TOO MANY NAMES" so..
manifest [ dCJNK3=#16; dRTSB=#36; dFFK=#126; dESTAT=#164 ]

external [
// MINIT0
	MStatus

// MIDAS
	MidasSwat

// MASM
	ErrorProtect; ResetsCSS; PutsCSS; @WssCSS; WssCS1; GetField

// MDATA
	GoVec

// MRGN
	RemoveFromEveryTimeList

// MSYM
	SearchBlocks

// MCMD
	QuitCmdOverlay; DisplayError; ErrorAbort; WnsCSS
	CmdCommentStream; PassiveOnly

// MGO
	@CantContinue; @QuitF; CallAVec

// MPATTERN
	@PATTERN

// D1I0
	@DMuxTab; HWStatus

// D1I1
	@LDRMEM

// D1I2
	ConfigUnknown

// D1TABLES
	@MEMLEN; @MEMNAM

// D1ASM
	@DoStrobe; LoadMIR; @Xct; @XctL16C; @XctL16Q; @SelectTask
	Start; ContinueProgram; LoadDMD; LoadDWatch; stNotInVM; stNotIMA

// D1MEM
	MGetMemData; SaveTIOA; @SaveLINK; @SaveTPC; @SaveTask; @SaveQ

// D1RES
	RestoreD1Temps; ReadAllRegs; BreakTPC; BreakTask

// D1VM
	LookUpVA; LookUpAA; @VirtualP

// D1GOOVL
	PrintPEDetails; PrintCantContinue

// D1POKE
	PassivePending

// D1CONFIG
	FindConfiguration; ShowConnection; IMXmask

//Defined here
	OneStep; MStopped; SetupIMA; DefaultGoMemory
	PrCCV; PrintErrors; GetHMask; HaltFailed
]

//Setup for SS, Go, or Call.  GoP is true for Go or Call, false for SS.
//AVec and MemX are either IMx (virtual) or IMXx (absolute).
//NA eq 1 sets up for a continue from last breakpoint (ignoring AVec and
//MemX); NA eq 3 indicates that a new go or step is being issued for the
//current task.
//SetupIMA leaves its results in GoVec as described in the "Go"
//structure def in MCommon.D.
let SetupIMA(GoP,AVec,MemX,NA,Str,MB) be
[ //RunP gets the final value for the Step or Go
	GoVec>>Go.RunP = GoP ? Control+SetRun,Control+SetRun+SetSS
	test NA ge 3
	ifso			//New go for current task
	[ GoVec>>Go.Task = SaveTask
	  NA = AVec!1
	  switchon MemX into
	  [
case IMx:	NA = LookUpAA(NA)
		if NA < 0 then ErrorAbort(stNotInVM)
case IMXx:	GoVec>>Go.Addr = NA; endcase
default:	ErrorAbort(stNotIMA)
	  ]
	  GoVec>>Go.Proc = Start
//Following code is a subset of "ResetControl" in D1Reset.bcpl.
	  LoadMIR(LDRMEM+TON)
	  DoStrobe(Control+SetRun+SetSS)
	  Xct(NOOP)
	  if (MB & BottomButton) eq 0 do
	  [ let RunControl = RunEnable+HWStatus>>HWStatus.RunControl
	    LoadDMD(RunControl & not IOResetx)
//	    Xct(IFRES); Xct(NOSKED)
	    XctL16Q(#1400); Xct(TIOAFQ)
	    XctL16Q(#32); Xct(OUTPUTFQ)	//Reset interim dsp cont
	    XctL16Q(#1); Xct(TESTFQ)	//Reset junk wakeups
	    XctL16Q(SaveTIOA); Xct(TIOAFQ)	//Restore TIOA
	    Xct(RFINFO)			//Reset fault task
	    XctL16Q(SaveQ)
	    SelectTask(0)
	    SaveTPC = IMXmask
	    XctL16C(LLINK,SaveTPC); LoadMIR(LDRMEM+RETN)
	    DoStrobe(Control+SetRun+SetSS)
	    for I = 1 to #17 do
	    [ XctL16C(LLINK,SaveTPC); Xct(NOOP)
	      XctL16C(LTPC,I)
	    ]
	    DoStrobe(Clock+UseCPReg+ClrReady)
	    DoStrobe(Clock+UseCPReg)
	    XctL16C(LLINK,SaveLINK); Xct(NOOP)
	    LoadDMD(RunControl)	//Turn off IOReset
	  ]
	]
	ifnot			//Continue
	[ if CantContinue ne 0 do
	  [ ErrorProtect(lv PrintCantContinue)
	    DisplayError(0,"Try to continue",0,0)
	  ]
	  GoVec>>Go.Proc = ContinueProgram
	]
	CantContinue = 0
	RestoreD1Temps()
	LoadDWatch()
//The 3rd arg "GoVec" below should be (lv GoVec>>Go.Addr)-1 because
//GoVec is misdefined with an "Addr" argument rather than an "AVec" arg.
	ShowTaskandPC(Str,GoVec>>Go.Task,GoVec)
	(GoVec>>Go.Proc)(GoVec)
]

//Subroutine used by d1ti, d1simres, and mgo
and OneStep(ContArg) be
[	DoStrobe(Control); DoStrobe(Control+ClrStop); DoStrobe(ContArg)
]


//**Eventually maybe do something for microcomputer here and in
//**SetupIMA.
and DefaultGoMemory() = valof
[	resultis VirtualP ? MEMNAM!IMx,MEMNAM!IMXx
]


//Called from MStopped, ShowTaskandPC, PrintTLINK, PrintIFUM, and PrintDMXw
//For MemX eq IMx, AVec!1 is -1 if undefined, else valid.
//For MemX eq IMXx, AVec!1 may have garbage in high bits.
and PrCCV(AVec,MemX) be
[	let virt = AVec!1		//Correct if MemX eq IMx
	let absol = virt & IMXmask	//Correct if MemX eq IMXx
	switchon MemX into
	[
default:	MidasSwat(NotGoMemX)
case IMXx:	virt = LookUpVA(absol); endcase
case IMx:	if virt < 0 do
		[ WssCSS(stNotInVM); return
		]
		absol = LookUpAA(virt)
//If virt ge 0 then virt is valid IM address, so LookUpAA must always succeed
		if absol < 0 then MidasSwat(LookUpAAFail)
		endcase
	]
	if VirtualP do
	[ if virt ge 0 do
	  [ let AVec1 = vec 1; AVec1!0 = 0; AVec1!1 = virt
	    SearchBlocks(CmdCommentStream,IMx,AVec1); return
	  ]
	  WssCSS("abs ")	//Only get here for MemX eq IMXx
	]
	WnsCSS(absol)
]


and HaltFailed() be	//Called by MGO.BCPL when Stop() fails to halt machine
[	if ConfigUnknown do
	[ WssCSS("--assuming no Control section"); MStopped()
	]
]


//Called from SingleStepM, HaltWait, and HaltProc in MGO, from SimGo in
//D1SIMT, and from InitHardware in D1I2.  A message like "Go at 3:FOO"
//was printed on CmdCommentStream by SetupIMA; the caller may append other
//text to CmdCommentStream before calling MStopped.  MStopped appends a
//string to describe the BP location on CmdCommentStream, prints error
//information on CmdCS1, and cleans up after the SS, Go, or whatever.
//GoFlag is omitted for keyboard halts, true for BP or error halts,
//false for SS actions; MStopped returns when GoFlag is false, but does
//QuitCmdOverlay when it is omitted or true.
and MStopped(GoFlag; numargs NA) be
[	if QuitF ge 0 do RemoveFromEveryTimeList(QuitF)
	MStatus>>MStatus.MachRunning = false
	if PassivePending then PassiveOnly = true
//FindConfiguration clutters CmdCommentStream and CmdCS1, so do
//ShowConnection to print a simpler message that is followed by the
//MStopped printout.
	test ConfigUnknown
	ifso
	[ FindConfiguration(); ShowConnection(); ReadAllRegs(2)
	]
	ifnot ReadAllRegs(0)
	let HaltBits = DMuxTab!dESTAT
	if (HaltBits & MIRDebugena) ne 0 then
		CantContinue = CantContinue % MIRdebugon
	PrintErrors(HaltBits)	//Printout confined to CmdCS1
//Did last instruction do Fetch← and ←Md?
	if (DMuxTab!dCJNK3 & #10) eq 0 do	//If last inst not held
	[ let RTSB = DMuxTab!dRTSB & #66
	  let getsMd = (RTSB eq #20) % (RTSB eq #2) % (RTSB eq #22)
	  let didFetch = true	//False warnings & miss ←MDI if PassiveOnly
	  unless PassiveOnly do
	  [ let DVec,AVec = vec 3,vec 1
	    AVec!0,AVec!1 = 0,BreakTPC
	    MGetMemData(IMXx,DVec,AVec)
	    let oldASEL,oldBSEL = GetField(16B,3,DVec),GetField(10B,3,DVec)
//oldFFmem = (BSEL < 4) & (JCN < 20B) ? FF.01,3
	    let oldFFmem = (oldBSEL < 4) &
		(GetField(32B,4,DVec) ne 0) ? GetField(22B,2B,DVec),3
	    didFetch = (oldASEL eq 3) % ((oldASEL eq 1) & (oldFFmem eq 3))
	  ]
	  if getsMd & didFetch then CantContinue = CantContinue+didFetMD
	]

//**Should handle SS thru CallRetAddr and Abort happening after
//**CallRetAddr below also.
	if (NA > 0) then
	  test GoFlag
	  ifso test (BreakTPC eq CallRetAddr) & (CallAVec!0 ne -1)
	    ifso
	    [ CantContinue = CantContinue % didCall
	      WssCSS(", return from ")
	      PrCCV(CallAVec,CallAVec!2); CallAVec!0 = -1
	      QuitCmdOverlay()
	    ]
	    ifnot ShowTaskandPC(", halt after ",BreakTask,(lv BreakTPC)-1)
	  ifnot WssCSS(", halt")
	ShowTaskandPC(" at ",GoVec>>Go.Task,(lv GoVec>>Go.Addr)-1)
	if (NA < 1) % GoFlag then QuitCmdOverlay()
]


and ShowTaskandPC(str,task,AVec) be
[	WssCSS(str); WnsCSS(task); PutsCSS($:)
	PrCCV(AVec,IMXx)
]


and PrintErrors(ESTAT) be
[	PATTERN = ESTAT & (GetHMask())
	if (PATTERN & (IMlhPE+IMrhPE)) eq (IMlhPE+IMrhPE) do
	[ WssCS1("BrkP, "); PATTERN = PATTERN & not (IMlhPE+IMrhPE)
	]
	test PATTERN eq 0
	ifso WssCS1("No errors")
	ifnot ErrorProtect(lv PrintPEDetails)
]


and GetHMask() = valof
[	let D = DMuxTab!dESTAT
	let HMask = (D & IMrhPEena) ne 0 ? IMrhPE,0
	if (D & IMlhPEena) ne 0 then HMask = HMask+IMlhPE
	if (D & IOBPEena) ne 0 then HMask = HMask+IOBPE
	if (D & RAMPEena) ne 0 then HMask = HMask+RAMPE
	if (D & MemoryPEena) ne 0 then HMask = HMask+MemoryPE
	if (D & MdPEena) ne 0 then HMask = HMask+MdPE
	resultis HMask
]