//MXPAR.BCPL	parity error reporting and scanning overlay

get "mx.d"

manifest [ qeTimeout=#40; qeDIP=#20; qeAPE=#10; qePBF=4; qeDE=2; qeSE=1 ]

static [ NLMPEs ]

let ReportPE(Z) be
[	if (Z & 20B) ne 0 do WssCSS("Memory data bus PE ")
	test (Z & 40B) ne 0
	ifso
	[ WssCSS("LMPE "); let ARMvec = vec 2; GetRegData(11,ARMvec)
	  let E = ARMvec!0
	  if (E & 2000B) ne 0 do WssCSS("IM[0,17] ")
	  if (E & 1000B) ne 0 do WssCSS("IM[18,35] ")
	  if (E & 400B) ne 0 do WssCSS("IM[36,53] ")
	  if (E & 200B) ne 0 do WssCSS("IM[54,71] ")
	  if (E & 100B) ne 0 do WssCSS("SM[0,17] ")
	  if (E & 40B) ne 0 do WssCSS("SM[18,35] ")
	  if (E & 20B) ne 0 do WssCSS("MAP ")
	]
	ifnot if (Z & 100B) ne 0 do
	[ let Mask = qeTimeout+qeDIP+qeAPE+qeDE
	  let AnyErrors = (Z & 60B) ne 0
	  if ParityFatal ne 0 then Mask = Mask + qePBF
	  if SingleFatal ne 0 then Mask = Mask + qeSE
	  @ADREG = JKERRS
	  let MemErr = @INREG
	  ReportMemErrors("J",(MemErr rshift 8) & Mask,lv AnyErrors)
	  ReportMemErrors("K",MemErr & Mask,lv AnyErrors)
	  @ADREG = LMERRS; MemErr = @INREG
	  ReportMemErrors("L",(MemErr rshift 8) & Mask,lv AnyErrors)
	  ReportMemErrors("M",MemErr & Mask,lv AnyErrors)
	  test AnyErrors
	  ifso [ @ADREG = RESR; @OUTREG = 125B ]
	  ifnot WssCSS("mysteriously")
	]
]


and ReportMemErrors(Quad,Errors,lvPred) be
[	if Errors eq 0 then return
	rv lvPred = true
	for I = 0 to 5 do
	[ let Mask = 1 lshift I
	  if (Errors & Mask) ne 0 then WssCSS(
		selecton I into
	  [
case 0:	    "SE "
case 1:	    "DE "
case 2:	    "PBF "
case 3:	    "APE "
case 4:	    "DIP "
case 5:	    "NXM "
	  ] )
	]
	WssCSS("in "); WssCSS(Quad)
	Puts(CmdCommentStream,$ )
]

//Each bipolar memory, in cycles when it is not used, is implicitly
//read, so the MP and SM words pointed to by Y may potentially cause
//LMPE's, even when we aren't interested in them.
//The parity error hardware consists of one register for the IM PE
//indications and one for the SM/DM/DM1/DM2 and MP indications.  Each
//of these registers is clocked only when there are no parity errors
//currently in the register.  Hence, the code below has to cope with
//persistent MP or SM errors making it impossible to scan the memory
//of interest in that group and with a persistent IM error making
//it impossible to check the IM address of interest.

and ScanForLMPE() be
[	let AVec,DVec,ARMvec,ScanVec,PE = vec 1,vec 4,vec 2,vec 2,nil
	let ClearArm = table [ 0; 0; 0 ]
	AVec!0 = 0; NLMPEs = 0
//Preserve ARM across scan
	XctR36(RDARM,ARMvec); ARMvec!0 = (ARMvec!0 & 16B) lshift 3
	for I = 0 to MEMLEN!2 - 1 do	//Scan IM
	[ AVec!1 = I; ConvertAV(AVec,2)
	  XctL36(LDARM,ClearArm)	//Clear PE indications
	  XctMic(RDIMH)		//All four IM cards will be read
	  XctR36(RDARM,ScanVec)
	  if (ScanVec!0 & 3600B) ne 0 do
	  [ PE = ScanVec!0
	    if (PE & 2000B) ne 0 then ReportLMPE("IM[0,17]",I)
	    if (PE & 1000B) ne 0 then ReportLMPE("IM[18,35]",I)
	    if (PE & 400B) ne 0 then ReportLMPE("IM[36,53]",I)
	    if (PE & 200B) ne 0 then ReportLMPE("IM[54,71]",I)
	  ]
	]
//If subsequently ever use MP parity, have to change ConvertAV below to
//memory 5 and add RestoreMRegs(5) after RDARM.
	for I = 0 to 777B do		//Scan SM
	[ AVec!1 = I; ConvertAV(AVec,3) //Address SM
	  XctL36(LDARM,ClearArm)	//Clear and load parity
	  XctR36(RDARM,ScanVec)
	  test (ScanVec!0 & 160B) ne 0
	  ifso
	  [ PE = ScanVec!0
	    if (PE & 100B) ne 0 then ReportLMPE("SM[0,17]",I)
	    if (PE & 40B) ne 0 then ReportLMPE("SM[18,35]",I)
	    if (PE & 20B) ne 0 then ReportLMPE("MP",I)
	  ]
	  ifnot		//SM and MP errors in an address prevent check of
			//same address in DM, DM1, or DM2
	  [ XctMic(RDDM); XctR36(RDARM,ScanVec)
	    if (ScanVec!0 & 160B) ne 0 do
	    [ if (ScanVec!0 & 100B) ne 0 then ReportLMPE("DM[0,17]",I)
	      if (ScanVec!0 & 40B) ne 0 then ReportLMPE("DM[18,35]",I)
	      XctL36(LDARM,ClearArm)
	    ]
	    XctMic(RDDM1); XctR36(RDARM,ScanVec)
	    if (ScanVec!0 & 160B) ne 0 do
	    [ if (ScanVec!0 & 100B) ne 0 then ReportLMPE("DM1[0,17]",I)
	      if (ScanVec!0 & 40B) ne 0 then ReportLMPE("DM1[18,35]",I)
	      XctL36(LDARM,ClearArm)
	    ]
	    XctMic(RDDM2); XctR36(RDARM,ScanVec)
	    if (ScanVec!0 & 160B) ne 0 do
	    [ if (ScanVec!0 & 100B) ne 0 then ReportLMPE("DM2[0,17]",I)
	      if (ScanVec!0 & 40B) ne 0 then ReportLMPE("DM2[18,35]",I)
	    ]
	  ]
	]
//	for I = 1000B to 1777B do	//Scan MP high part
//	[ AVec!1 = I; ConvertAV(AVec,5)
//	  XctL36(LDARM,ClearArm)	//Clear and load parity
//	  XctR36(RDARM,ScanVec)
//	  if (ScanVec!0 & 20B) ne 0 do ReportLMPE("MP",I)
//	]
	RestoreAfterLoad()		//Restore address registers
	XctL36(LDARM,ARMvec)		//Restore ARM
	Resets(CmdCommentStream); Wns(CmdCommentStream,NLMPEs,0,10)
	WssCSS(" error"); if NLMPEs ne 1 then Puts(CmdCommentStream,$s)
]


and ReportLMPE(MemName,Addr) be
[	NLMPEs = NLMPEs+1
	Resets(CmdCommentStream); WssCSS("PE in ")
	WssCSS(MemName); Puts(CmdCommentStream,$ )
	Wns(CmdCommentStream,Addr,0,8)
	DisplayError(0,"Continue",0,0)
]