//D1PEScan.bcpl -- machine-dependent part of PE-scan overlay
//	9 May 1983

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

external [
// OS
	DoubleAdd

// MASM
	@OddParity; VUsc; @MADDRL

// MMPRGN
	UpdateMPDValues

// MPESCAN
	ReportPE

// D1ACTIONS
	@LongOne

// D1TABLES
	@MEMLEN; @MEMNAM

// D1MEM
	GetMemData; @SaveT; @SaveMCR; TurnOffRefresh

// D1ASM
	ReadDMux; GetErrs; @XctL16C; @Xct; @XctR16; @XctL16T
	@XctLFF; @SelectTask; @SetRSTK; LoadDAddr; LoadDMD; @D1In

// D1CONFIG
	NoCacheAParity; log2rows

// Defined here
	ScanForPE
]


let ScanForPE(MemX,WaitP,NPETab) be
[	let NPEX = NPETab!0
	let AVec,AVec1,DVec = vec 1,vec 1,vec 3
	AVec!0 = 0; AVec1!0 = 0
	NPETab!(NPEX+1) = " in "
	NPETab!(NPEX+2) = MEMNAM!MemX
	NPETab!0 = NPEX+3
	let Last = MEMLEN!(MemX+MemX+1)-1
	let RowMask = (1 lshift log2rows)-1	//For CACHEA/D scans
	switchon MemX into
	[
case IMXx:
	NPETab!(NPEX+1) = " "
	NPETab!(NPEX+2) = "breakpoints"
	NPETab!(NPEX+4) = " in "
	NPETab!(NPEX+5) = "IM[0:17]"
	NPETab!(NPEX+7) = " in "
	NPETab!(NPEX+8) = "IM[20:37]"
	NPETab!0 = NPEX+9
	for I = 0 to Last do
	[ AVec!1 = I
//To check IM parity errors, sequence analogous to the START sequence
//is used to get the addressed instruction into MIR
	  XctL16C(LLINK,I); Xct(STARTX)
	  switchon GetErrs() & (CIMlhPE+CIMrhPE) into
	  [
case CIMlhPE+CIMrhPE:	//Breakpoint--never wait
		ReportPE(NPETab,NPEX,DVec,MemX,AVec,0); loop
case CIMlhPE:		//PE in IM[0:17]
		GetMemData(IMXx,DVec,AVec)
		ReportPE(NPETab,NPEX+3,DVec,MemX,AVec,WaitP); loop
case CIMrhPE:		//PE in IM[20:37]
		GetMemData(IMXx,DVec,AVec)
		ReportPE(NPETab,NPEX+6,DVec,MemX,AVec,WaitP)
case 0:		loop
	  ]
	]
	endcase

case RMx:
	for I = 0 to Last do
	[ AVec!1 = I; GetMemData(MemX,DVec,AVec)
	  Xct(SetRSTK(RRM0,MADDRL))
	  if (GetErrs() & RAMPE) ne 0 then
		ReportPE(NPETab,NPEX,DVec,MemX,AVec,WaitP)
	]
	endcase

case STKx:
	for I = 0 to Last do
	[ AVec!1 = I; GetMemData(MemX,DVec,AVec); Xct(RSTACK)
	  if (GetErrs() & RAMPE) ne 0 then
		ReportPE(NPETab,NPEX,DVec,MemX,AVec,WaitP)
	]
	endcase

case MAPx:
	AVec!1 = 0
	AVec1 = MEMLEN+MemX+MemX
	while VUsc(AVec,AVec1,2) ne 0 do
	[ GetMemData(MemX,DVec,AVec)
	  if (DVec!0 & #10) ne 0 do
	    ReportPE(NPETab,NPEX,DVec,MemX,AVec,WaitP)
	  DoubleAdd(AVec,LongOne)
	]
	endcase

case IFUMx:
	for I = 0 to Last do
	[ AVec!1 = I; GetMemData(MemX,DVec,AVec)
	  if (DVec!1 & 70000B) ne 0 then
		ReportPE(NPETab,NPEX,DVec,MemX,AVec,WaitP)
	]
	endcase

case CACHEAx:
	if NoCacheAParity eq 0 do
	[ for I = 0 to Last do
	  [ AVec!1 = I; GetMemData(MemX,DVec,AVec)
	    if (DVec!0 & #50000) eq 0 do	//Not BeingLoaded % Vacant
	    [ XctL16T(NoWake+DisHold); Xct(MCRFT)
//Address word 0 of the munch with BR 36
//Arrange for BRLO+T = DVec!1+((AVec!1 & RowMask) lshift 4)
	      XctL16T(DVec!0); Xct(BRHIFT)
	      XctL16T((DVec!1+((AVec!1 & RowMask) lshift 4)) rshift 1)
	      Xct(BRLOFT)
//Similar to RdCACHEA in D1MEM.BCPL, but ensure Hit.
	      let CE = TurnOffRefresh()
	      Xct(DUMMYFT); Xct(NOOP)
	      LoadDAddr(#1072)	//HitColVA.Par
	      let Parity = (rv D1In) & #4000
//	      LoadDAddr(#1074)
//	      let Hit = rv D1In
	      LoadDMD(CE)
//	      if (Hit & #4000) eq 0 do
//		MidasSwat("Didn't get hit in CACHEA PEscan")
	      if OddParity(DVec!0 & #7777,DVec!1 xor Parity) do
		ReportPE(NPETab,NPEX,DVec,MemX,AVec,WaitP)
	    ]
	  ]
	]
	endcase

case CACHEDx:
	for I = 0 to MEMLEN!(CACHEAx+CACHEAx+1)-1 do
	[ AVec!1 = I; GetMemData(CACHEAx,DVec,AVec)
//Only if not Vacant or beingloaded
	  if (DVec!0 & #50000) eq 0 do
	  [ XctL16T(NoWake+DisHold); Xct(MCRFT)
//Address word 0 of the munch with BR 36
	    XctL16T(DVec!0); Xct(BRHIFT)
	    XctL16T(DVec!1+((AVec!1 & RowMask) lshift 4)); Xct(BRLOFT)
//Loop over words in munch
	    for J = 0 to 17B do
	    [ XctL16T(J); Xct(FETCHM); Xct(TFMD)
	      Xct(RT); XctR16(RT,DVec)
	      if (GetErrs() & MdPE) ne 0 then
	      [ AVec1!1 = (AVec!1 lshift 4)+J
		ReportPE(NPETab,NPEX,DVec,MemX,AVec1,WaitP)
	      ]
	    ]
	  ]
	]
	endcase

	]
	ReadDMux(); UpdateMPDValues()
]