// SwatParityErrors.bcpl - Parity error diagnosis code.
// Copyright Xerox Corporation 1979, 1982
// Last modified April 22, 1982  3:39 PM by Boggs

get "Swat.decl"
get "AltoDefs.d"

external
[
// outgoing procedures
ParityError

// incoming procedures from Swat
VMStore; VMFetch; EventReport
Ws; PutTemplate; SetFailPt; UnSetFailPt

// incoming procedures from OS
Zero; MyFrame; Usc; FrameSize
DisableInterrupts; EnableInterrupts

// incoming statics
dsp
]

static errorBits

manifest
[
AltoIIMemEnable = 177773b
SingleInterruptNoCorrect = 177765b
DoubleInterrupt = 177773b
]

structure ESR:		//Alto II Error Status Register
[			//All signals low true
hamming bit 6
parityError bit
memParity bit
syndrome bit 6
spare bit
switch bit		//Not really here, but we put it there...
]

structure SERParity:	// Parity error report = type 1
[
@SERHead
errLoc word		// Location in error
errCon word		// Contents
status word		// AltoII status + (bit 15) switch position
DCBR word
KNMAR word
DWA word
CBA word
PC word
SAD word
PCcontents word
bangResults word 3 =	// Results of banging on the location
   [
   spare bit 10
   moreErrors bit
   which bit 5
   error1 byte
   error0 byte
   tried1 byte
   tried0 byte
   ]
]
manifest lenSERParity = size SERParity/16

//----------------------------------------------------------------------------
let ParityError(p, fetch) be
//----------------------------------------------------------------------------
// Parity error diagnosis code.  This is complicated a bit by the
// differences between Alto I and Alto II.  In addition, the "bug"
// in the Alto II memory interface that loses parity error information
// requires some special treatment.
//
// Interrupts are disabled
// p!0 = 77401b
// p!1 = JMP ...
// 2 = Address of bad word or 0
// 3 = PC at time of interrupt
// 4 = AC0 at time of interrupt
// 5 = carry at time of interrupt
// 6 = Display list at time of interrupt
// 7 = Active interrupts at time of interrupt
// 10b-15b (OsVersion 8 or greater) are DCBR,KNMAR, etc.
// fetch may use virtual memory
[
let errv = vec size SERParity/16
errv>>SERHead.type = serTypeParity
errv>>SERHead.AltoVersion = (table [ 61014B; 1401B ])()
errv>>SERHead.OsVersion = VMFetch(VMFetch(176777B)+23B)  // 23rd top OS static

let AltoII = (table [ 61014B; 1401B ])()<<VERS.eng gr 1

// Gather status
let memEAR = @MEAR
let stat = AltoII? @MESR, 0	//May reset the memory interface
stat<<ESR.switch = @utilIn rshift 9
errv>>SERParity.status = stat

// Following boolean is true if the Alto II memory interface
//  "saw" the error and retained the memory of it.
let AltoIIMemSaw = stat<<ESR.syndrome ne 77b % stat<<ESR.parityError eq 0

// Error location and contents
let errLoc = 0
let printLoc = true
test AltoII
   ifnot
      [
      errLoc = fetch(p+2)	//Get sweep error address
      printLoc = errLoc ne 0	//Indication sweep found an error
      ]
   ifso
      [
      errLoc = memEAR		//Error address register
      unless AltoIIMemSaw then [ errLoc = 0; printLoc = false ]
      ]
errv>>SERParity.errLoc = errLoc
let errCon = fetch(errLoc)
errv>>SERParity.errCon = errCon

errv>>SERParity.DCBR = fetch(p+10)	//DCBR
errv>>SERParity.KNMAR = fetch(p+11)	//KNMAR
errv>>SERParity.DWA = fetch(p+12)	//DWA
errv>>SERParity.CBA = fetch(p+13)	//CBA
errv>>SERParity.PC = fetch(p+14)	//PC
errv>>SERParity.SAD = fetch(p+15)	//SAD
errv>>SERParity.PCcontents = fetch(errv>>SERParity.PC)

// DiagnoseParityError (cont'd)

// Now try to decide if an error really happened.
// 0 = probably not; 1 = for sure; 2 = suggestive

let happened = 2
// On OS 11 and greater, we set the parity task locations (614 to 621)
// to a magic number (52525b) every time a subsystem is run.
// If these locations have been changed, this is evidence that the
// parity task has indeed run.
for i = 0 to 5 do if fetch(p+10b+i) ne 52525b then happened = 1

// On Alto II, memory interface is positive indication.
if AltoII ne 0 & AltoIIMemSaw ne 0 then happened = 1

// On Alto I, if sweep found an error, that is positive.
if errLoc ne 0 then happened = 1

Ws(selecton happened into
   [
   case 0: "A parity interrupt has occurred, but there is no evidence of*nbad parity in the memory.*n"
   case 1: "A parity error has occurred.*n"
   case 2: "A parity interrupt has occurred, but there is only suggestive*nevidence that a parity error actually occurred.*n"
   ])

if AltoII ne 0 & AltoIIMemSaw eq 0 then
   Ws("The memory interface has lost the exact error information.*n")

// If we really believe there is a bad location, print it out.
// If we don't, it makes sense to tell Alto I users about
// the phantom.  But there is no way a scan of Alto II memory
// means much, because the parity task turned off the parity
// error detection logic when the first error occurred.
test printLoc
   ifso PutTemplate(dsp, "Location $UO exhibits bad parity. Contents=$UO*N",
    errLoc, errCon)
   ifnot unless AltoII do Ws("A scan of memory found no bad locations.*n")

PutTemplate(dsp, "DCBR=$UO KNMAR=$UO DWA=$UO CBA=$UO PC=$UO SAD=$UO*N",
 errv>>SERParity.DCBR, errv>>SERParity.KNMAR, errv>>SERParity.DWA,
 errv>>SERParity.CBA, errv>>SERParity.PC, errv>>SERParity.SAD)
if AltoII then PutTemplate(dsp, "Alto II: status=$UO*N", stat)

// Now go bang on the bad location
let br = lv errv>>SERParity.bangResults
Zero(br, size SERParity.bangResults/16)
br!0 = 31
if printLoc then
   [
   BangOn(errLoc, fetch, AltoII, br)
   if br!1 ne 0 then
      PutTemplate(dsp, "Results of testing bad location: $UO $UO $UO*N",
       br!0, br!1, br!2)
   ]

// Now try to log the error:
let ok = false
Ws("Logging error...")
SetFailPt(notLogged)
ok = EventReport(errv, lenSERParity)
UnSetFailPt()
notLogged: Ws(ok? "OK.*N", "failed.*N")

// Re-enable the various interfaces, and reset parity task posting
// locations to magic number.
@MECR = AltoIIMemEnable
@MESR = 0
for i = 614b to 621b do [ @i = 52525B; VMStore(i, 52525B) ]
]

//----------------------------------------------------------------------------
and BangOn(loc, fetch, AltoII, resultVec) be
//----------------------------------------------------------------------------
// Routine to bang on a memory location suspected of being bad,
// and return some results.
// ResultVec is structure
//	[
//	spare bit 10
//	more bit	-- on if more than 1 bit seems bad
//	which bit 5 --
//		0-15 number the data bits in the word
//		16 is the parity bit
//		17-22 number the Hamming code bits (Alto II only)
//		30 means queer results from memory interface (Alto II)
//		31 means no error was detected
//	error1 byte -- number of times a 1 bit was returned as 0
//	error0 byte -- number of times a 0 bit was returned as 1
//	tried1 byte -- number of times 1 value was tried
//	tried0 byte -- number of times 0 value was tried
//	]
[
Zero(resultVec, 3)
let f = MyFrame()
if Usc(loc, f) ge 0 & Usc(loc, f+FrameSize(BangOn)) le 0 then return
if Usc(loc, BangOn) ge 0 & Usc(loc, BangOnEnd+100) le 0 then return
if Usc(loc, 400b) ge 0 & Usc(loc, 777b) le 0 then return
let queer = 0
let v1 = vec 60
Zero(v1, 60)
errorBits = v1
let oldContents = fetch(loc)
let otherLoc = loc xor 1
let otherContents = fetch(otherLoc)

for j = 0 to 4 do
   [
   let m = 100000b
   for i = 0 to 15 do
      [
      let val = m
      val = val xor selecton j into
         [
         case 0: 0
         case 1: 1
         case 2: -1
         case 3: -2
         case 4: oldContents
         ]
      DisableInterrupts()
      let old = @loc
      let oldOther = @otherLoc
      let newval = nil
      let wws = nil
      @wakeupsWaiting = 0; @MESR = 0; @MECR = SingleInterruptNoCorrect

      // Here begins the window during which we have changed memory:
      for cnt = 0 to 500 do
         [
         @otherLoc = otherContents
         @loc = val
         newval = @loc
         wws = @wakeupsWaiting
         if (wws&1) ne 0 break		//Error
         ]
      let mems = @MESR; let memEAR = @MEAR
      @loc = old
      @otherLoc = oldOther
      // Here ends the window
      @wakeupsWaiting = 0; @MECR = DoubleInterrupt; @MESR = 0
      EnableInterrupts()

      // Compute parity -- a la Alto I
      let parity = 0
      for i = 0 to 15 do
         if ((val rshift i)&1) ne 0 then
            parity = parity xor -1

      // Record what we tried, and what failed
      let error = (wws & 1) ne 0
      for i = 0 to 15 do RecordE(val, newval, i, 15-i)
      test AltoII
         ifso
            [
            // Here compute goodMems, the "good" status in the syndrome
            //  and parity bits. -- Dummy computation for now:
            let hc = 0; let m = 100000b
            let evenW = ((loc & 1) eq 0)? val,otherContents
            let oddW = evenW xor val xor otherContents
            for i = 0 to 15 do
               [
               if (evenW & m) ne 0 then hc = hc xor (table [
                60b; 50b; 30b; 70b; 44b; 24b; 64b; 14b;
                54b; 34b; 74b; 42b; 22b; 62b; 02b; 52b ])!i
               if (oddW & m) ne 0 then hc = hc xor (table [
                32b; 72b; 06b; 46b; 26b; 66b; 16b; 56b;
                36b; 76b; 41b; 21b; 61b; 11b; 51b; 31b ])!i
		m = m rshift 1
               ]
            let t = otherContents xor hc
            for i = 0 to 15 do
               if ((t rshift i)&1) ne 0 then
                  parity = parity xor -1
            let goodMems = (hc lshift 10)
            goodMems<<ESR.memParity = parity	//Odd parity, but 0 true

            if mems<<ESR.syndrome eq 77b % memEAR ne loc then
               [
               if error then queer = true
               mems = goodMems		//No way to tell, assume good
               ]
            for i = 17 to 22 do RecordE(goodMems, mems, i, 32-i)
            RecordE(goodMems, mems, 16, 8)
            ]
         ifnot RecordE(parity, parity xor (error&(val eq newval)), 16)
      m = m rshift 1
      ]
   ]

// Now look for the best error to report.
let best = 31
let bdiff = 0
let tot = 0
for i = 0 to 22 do if errorBits!i then
   [
   let d = errorBits!i
   tot = tot+1
   d = (d rshift 8)+(d&377b)
   if d gr bdiff then [ best = i; bdiff = d ]
   ]
if best eq 31 & queer ne 0 then best = 30
resultVec!0 = best+((tot gr 1)? 40b, 0)
if best le 22 then
   [
   resultVec!1 = errorBits!best
   resultVec!2 = errorBits!(30+best)
   ]
]

//----------------------------------------------------------------------------
and RecordE(goodVal, badVal, i, shamt; numargs na) be
//----------------------------------------------------------------------------
[
if na eq 4 then
   [
   goodVal = goodVal rshift shamt
   badVal = badVal rshift shamt
   ]
let goodBit = goodVal&1
if ((goodVal xor badVal) & 1) ne 0 then
   errorBits!i = errorBits!i+(goodBit? 400B, 1)
i = i+30
errorBits!i = errorBits!i+(goodBit? 400B, 1)
]

//----------------------------------------------------------------------------
and BangOnEnd() be [ ]
//----------------------------------------------------------------------------