// D1res.bcpl -- resident procedures	11 May 1983

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

external [
// OS
	DoubleAdd

// MIDAS
	MidasSwat

// MINIT0
	@MBlock; MStatus

// MASM
	WssCS1

// MDATA
	GoVec; VMBase

// MIOC
	DWns

// MMENU
	WssMark

// MMPRGN
	UpdateMPDValues

// MCMD
	ErrorAbort; WnsCS1; CmdCS1; PassiveOnly

// D1I0
	@SaveMIR; BreakMIR; OldGFrame; HWStatus
	@DMuxTab; @OldDMuxTab; DWrong; DChecked

// D1MICRES
	ChangeAltoControl

// D1ACTIONS
	AbsAct; VirtAct; DMuxAct; PassiveAct; ActiveAct

// D1ASM
	@MCXct; LoadMIR; @Xct; @XctR16; @XctR16C; @XctR16Link; @XctL16Q
	@XctL16T; @XctLFF; @DoStrobe; @SetALUF; ReadDMux; @SelectTask
	@CheckStopped

// D1MEM
	DMuxSelect; @SaveTPC; @SaveTask; @SaveLINK
	@SaveQ; SaveALUFM16; SaveALUFM0; SaveSTKP; SaveTIOA
	@SaveT; @SaveRBase; @SaveMBase; @SaveSRN; @SaveMCR; SaveR0

// D1VM
	@VirtualP

// D1POKE
	PassivePending

// D1CONFIG
	log2pgsize; log2rows; IMXmask

// Defined here
	FinishHardware; DetachHardware; FormHWMenu; HWShowAddr
	HWAlwaysUpdate; ReadAllRegs; RestoreD1Temps; DoNOPs
	BreakTPC; BreakTask; BR36Saved; UnBreakDefault
]

static
[	BreakTPC; BreakTask; BR36Saved; UnBreakDefault
]

//Form conditional parts of machine-dependent command menu
let FormHWMenu() be
[	test VirtualP	//Print current mode in menu, bound to opposite action
	ifso WssMark(VirtAct!0,AbsAct)
	ifnot WssMark(AbsAct!0,VirtAct)
//Active←Passive←PrePassive are in a ring such that the menu name printed
//is the current mode bound to the next state in the ring.
	test PassiveOnly
	ifso WssMark(PassiveAct!0,ActiveAct)
	ifnot test PassivePending
	  ifso WssMark("PrePassive",PassiveAct)
	  ifnot WssMark(ActiveAct!0,PassiveAct)
//For the DMux action, print current display mode as the action name,
//although command files will always have "DMux" as the name.
	WssMark((DMuxSelect eq DMuxTab ? DMuxAct!0,
		  (DMuxSelect eq OldDMuxTab ? "OldDMux",
		    (DMuxSelect eq DWrong ? "DWrong","DChk"))),DMuxAct)
]


//This is called prior to exit from Midas
and FinishHardware() be
[	DetachHardware(); rv #370 = OldGFrame
]


//Give baseboard control of the muffler/manifold system
//Restore hardware as though about to continue unless machine is running
//(and allow for possible boot).
and DetachHardware() be
[	unless (MStatus>>MStatus.MachRunning) % (CheckStopped() eq 0) do
	[ RestoreD1Temps(); DoStrobe(Clock)
	]
	ChangeAltoControl(BAltoControl+BCNoop)
	HWStatus>>HWStatus.ConnectedMachine = -1
]


//Called from ShowAddr in MMPRGN
and HWShowAddr(MemX,AVec) be
[	let AVec0,AVec1 = vec 1,vec 1
	if MemX eq VMx do
	[ MBlock(AVec0,AVec,2); DoubleAdd(AVec0,VMBase)
	  AVec1!0 = AVec0!0 rshift log2pgsize
	  AVec1!1 = (AVec0!0 lshift (16-log2pgsize))+
		(AVec0!1 rshift log2pgsize)
	  WssCS1("uses MAP "); DWns(CmdCS1,AVec1)
	  let Row = (AVec0!1 rshift 4) & (-1 rshift (16-log2rows))
	  WssCS1(", ROW "); WnsCS1(Row)
	]
]


//Return 1 if this item should be always updated, else 0; called from
//SetAddr in MMPRGN.  Returns 1 if AlwaysUpdate bit set in MEMCON/REGCON
//or for the COM-ERRS and MIR-PES items in MADDR, or for the OUTOFSPEC,
//BADSUPPLYSPEC, or PROBLEMS words in $ABSOLUTE.
and HWAlwaysUpdate(MorRCON,X,AVec) = valof
[	resultis MorRCON<<MRType.AlwaysUpdate ne 0 ? 1,
	  selecton X into
	  [
case MADDRx: ((AVec!1 eq 11B) % (AVec!1 eq 12B)) ? 1,0
case ABSOLx: ((AVec!1 eq #1) % (AVec!1 eq #147) % (AVec!1 eq #150)) ? 1,0
default:     0
	  ]
]

and RestoreD1Temps() be
[	SelectTask(GoVec>>Go.Task)
	unless PassiveOnly do
	[ XctL16Q(SaveALUFM0); Xct(LAF0)
	  XctL16Q(SaveALUFM16); Xct(SetALUF(LAF0,16B))
	  XctL16Q(SaveQ); Xct(NOOP)
	]
	LoadMIR(BreakMIR)
]


//Code ne 0 prevents ReadDMux
//Code eq 1 prevents changing Break and Continue info
and ReadAllRegs(Code) be
[	if Code eq 0 do ReadDMux()
	if Code ne 1 do		//Setup for possible Continue now
	[ GoVec>>Go.Addr,GoVec>>Go.Task = DMuxTab!dCIA,SaveTask
	  let ciainc = (DMuxTab!dCIAINC) & IMXmask
	  BreakTPC = (ciainc & 177700B)+((ciainc-1) & 77B)
	  DMuxTab!dOLDCIA = BreakTPC
	  UnBreakDefault = BreakTPC
	  BreakTask = DMuxTab!dCTD
	  MBlock(BreakMIR,SaveMIR,4)
	]
	SaveTPC,SaveMCR,BR36Saved = DMuxTab!dCIA,DMuxTab!dMCR,false
	unless PassiveOnly do
	[
//ReadDMux sets UseCPReg.  Have to undo that and do NOOP to finish
//possible read of LINK
	  XctR16Link(NOOP,lv SaveLINK)
//Propagate task stuff through levels on processor boards by doing two
//NOOP's; do many more NOOP's as a precaution against HOLD.
	  DoNOPs(30)
	  SaveLINK = not XctR16Link(RLINK,lv SaveLINK)
	  XctR16(RT,lv SaveT); XctR16(RQ,lv SaveQ)
	  Xct(TFMD)
	  Xct(TFTIOA); SaveSTKP = XctR16(RT,lv SaveTIOA)<<rh
//ALUFM[0]←"B" control
	  XctL16Q(25B); Xct(LAF0T); XctR16(RT,lv SaveALUFM0)
//ALUFM[16]←"not A" control
	  XctL16Q(1B); Xct(SetALUF(LAF0T,16B)); XctR16(RT,lv SaveALUFM16)
	  Xct(TFPTRS)
	  SaveMBase = (XctR16(RT,lv SaveRBase))<<Pointers.MemBase
	  SaveRBase = SaveRBase<<Pointers.RBase
	  SaveSRN = XctR16(RCONFG,lv SaveSRN) rshift 12
	  XctLFF(LRB0,0); XctR16(RRM0,lv SaveR0); XctLFF(LRB0,SaveRBase)
	  XctL16Q(SaveQ); Xct(NOOP)	//Restore
	  XctL16T(SaveT); Xct(NOOP); LoadMIR(SaveMIR)
	]
	UpdateMPDValues()
]


//Procedure to do Xct(NOOP) specified number of times
and DoNOPs(N) be for I = 1 to N do Xct(NOOP)