-- File: MemoryErrorInfo.mesa, Last Edit: HGM March 31, 1981 3:34 PM -- See page 40 of Alto Hardware Manual, and/or [Ivy]<IFS>Sources>IFSMemoryError.bcpl DIRECTORY Inline USING [BITAND, BITNOT, BITSHIFT, BITXOR], Menu USING [Handle, ItemObject, MCRType, Create, Instantiate], Process USING [Detach, SecondsToTicks, SetTimeout], Put USING [CR, Date, Line, LongDecimal, LongNumber, Number, Text], SegmentDefs USING [GetMemoryConfig, MemoryConfig], Storage USING [Node], String USING [AppendDecimal, AppendOctal, AppendString], Time USING [Current], UserInput USING [GetDefaultWindow], Window USING [Handle], GateDefs USING [typescript]; MemoryErrorInfo: MONITOR IMPORTS Inline, Menu, Process, Put, SegmentDefs, Storage, String, Time, UserInput, GateDefs = BEGIN first: ErrorInfo ← NIL; maxErrorBlocks: CARDINAL = 10; badSyndrome: LONG CARDINAL ← 0; otherErrors: LONG CARDINAL ← 0; Card: TYPE = [1..4]; Chip: TYPE = [11..90]; Syndrome: TYPE = [0..64); ErrorInfo: TYPE = POINTER TO ErrorInfoBlock; ErrorInfoBlock: TYPE = RECORD [ card: Card, chip: Chip, count: LONG CARDINAL, next: ErrorInfo]; maxErrors: LONG CARDINAL = LAST[LONG CARDINAL]; Address: TYPE = WORD; -- It's really a pointer, but we do arithametic on it mear: POINTER TO Address = LOOPHOLE[177024B]; mesr: POINTER TO UNSPECIFIED = LOOPHOLE[177025B]; -- Low TRUE MESR: TYPE = MACHINE DEPENDENT RECORD [ hamming: [0..64), parityError: BOOLEAN, parityBit: [0..1), syndrome: Syndrome, bank: [0..4) ]; WatchForMemoryErrors: ENTRY PROCEDURE = BEGIN sleep: CONDITION; info: MESR; first: BOOLEAN ← FALSE; Process.SetTimeout[@sleep,Process.SecondsToTicks[300]]; mesr↑ ← 0; -- reset error latches DO WAIT sleep; info ← Inline.BITNOT[mesr↑]; IF Inline.BITAND[info,1374B] = 0 THEN LOOP; IF ~first THEN BEGIN first ← TRUE; SetupMenu[]; END; RecordMemoryError[]; ENDLOOP; END; RecordMemoryError: PROCEDURE = BEGIN address: Address ← mear↑; info: MESR ← Inline.BITNOT[mesr↑]; PrintErrorInfo[address, info]; BEGIN card: Card; chip: Chip; [card: card, chip: chip] ← ConvertInfoToCardAndChip[address, info ! BadSyndrome => GOTO Bad]; PrintCardInfo[card: card, chip: chip]; AddToList[card: card, chip: chip]; EXITS Bad => badSyndrome ← badSyndrome+1; END; mesr↑ ← 0; -- reset error latches END; BadSyndrome: SIGNAL = CODE; ConvertInfoToCardAndChip: PROCEDURE [address: Address, info: MESR] RETURNS [card: Card, chip: Chip] = BEGIN -- The memory is 39 bits wide: 32 data bits, 6 hamming bits, and a parity bit BitNumber: TYPE = [0..39]; -- 39 is used to mark an invalid syndrome syndromeMapping: PACKED ARRAY Syndrome OF BitNumber = [ 38, 37, 36, 39, 35, 39, 18, 39, 34, 29, 14, 39, 07, 39, 22, 39, 33, 27, 12, 39, 05, 39, 20, 39, 02, 31, 16, 39, 09, 39, 24, 39, 32, 26, 11, 39, 04, 39, 19, 39, 01, 30, 15, 39, 08, 39, 23, 39, 00, 28, 13, 39, 06, 39, 21, 39, 03, 39, 17, 39, 10, 39, 25, 39 ]; bit: BitNumber ← syndromeMapping[info.syndrome]; IF bit=39 THEN SIGNAL BadSyndrome; IF TheSwitch[] THEN address ← Inline.BITXOR[address,100000B]; card ← (bit MOD 4)+1; -- This could be haired up to work with 4K chips chip ← bit/8 + 16 - (IF Odd[bit/4] THEN 5 ELSE 0) + 10*Inline.BITSHIFT[address,-15] + 20*info.bank; END; TheSwitch: PROCEDURE RETURNS [BOOLEAN] = INLINE BEGIN utlin: POINTER TO PACKED ARRAY [0..16) OF BOOLEAN = LOOPHOLE[177030B]; RETURN[utlin[6]]; END; Odd: PROCEDURE [x: UNSPECIFIED] RETURNS [BOOLEAN] = INLINE BEGIN RETURN[(x MOD 2)=1]; END; AddToList: PROCEDURE [card: Card, chip: Chip] = BEGIN length: CARDINAL ← 0; FOR e: ErrorInfo ← first, e.next UNTIL e=NIL DO IF chip=e.chip AND card=e.card THEN BEGIN IF e.count<maxErrors THEN e.count ← e.count+1; RETURN; END; length ← length+1; ENDLOOP; IF length < maxErrorBlocks THEN BEGIN e: ErrorInfo ← Storage.Node[SIZE[ErrorInfoBlock]]; e↑ ← [card: card, chip: chip, count: 1, next: first]; first ← e; END ELSE otherErrors ← otherErrors+1; END; PrintErrorInfo: PROCEDURE [address: Address, info: MESR] = BEGIN temp: STRING = [50]; PutHeader[NIL,"Main Memory Error "L, FALSE]; String.AppendString[temp, "MEAR: "L]; String.AppendOctal[temp, address]; String.AppendString[temp, ", MESR: "L]; String.AppendOctal[temp, info]; Put.Line[NIL,temp]; END; PrintCardInfo: PROCEDURE [card: Card, chip: Chip] = BEGIN temp: STRING = [50]; String.AppendString[temp, "card: "L]; String.AppendDecimal[temp, card]; String.AppendString[temp, ", chip: "L]; String.AppendDecimal[temp, chip]; Put.Line[NIL,temp]; END; PrintMemoryErrors: PUBLIC PROCEDURE [wh: Window.Handle] = BEGIN PutHeader[wh,"Main Memory Errors:"L]; IF first#NIL THEN BEGIN Put.Line[wh,"Card Chip Errors"L]; FOR e: ErrorInfo ← first, e.next UNTIL e=NIL DO Put.Number[wh, e.card, [10, FALSE, TRUE, 4]]; Put.Number[wh, e.chip, [10, FALSE, TRUE, 4]]; Put.LongNumber[wh, e.count, [10, FALSE, TRUE, 6]]; Put.CR[wh]; ENDLOOP; END; IF badSyndrome > 0 THEN BEGIN IF badSyndrome=1 THEN Put.Text[wh, "One main memory error"L]; IF badSyndrome>1 THEN BEGIN Put.LongDecimal[wh, badSyndrome]; Put.Text[wh, " main memory errors"L]; END; Put.Line[wh, " with bad symdrome."L]; END; IF otherErrors > 0 THEN BEGIN IF otherErrors=1 THEN Put.Text[wh, "One other main memory error"L]; IF otherErrors>1 THEN BEGIN Put.LongDecimal[wh, otherErrors]; Put.Text[wh, " other main memory errors"L]; END; Put.Line[wh, "."L]; END; END; PutHeader: PROCEDURE [wh: Window.Handle, s: STRING, cr: BOOLEAN ← TRUE] = BEGIN Put.Date[wh, Time.Current[], dateTime]; Put.Text[wh, " "L]; Put.Text[wh, s]; IF cr THEN Put.CR[wh]; END; items: ARRAY [0..1) OF Menu.ItemObject ← [["Errors", DoInfo]]; SetupMenu: PROCEDURE = BEGIN menu: Menu.Handle ← Menu.Create[DESCRIPTOR[items], "MemErr"]; Menu.Instantiate[menu, UserInput.GetDefaultWindow[]]; Menu.Instantiate[menu, GateDefs.typescript]; END; DoInfo: Menu.MCRType = BEGIN PrintMemoryErrors[NIL]; END; Init: PROCEDURE = BEGIN config: SegmentDefs.MemoryConfig ← SegmentDefs.GetMemoryConfig[]; IF config.AltoType#AltoIIXM THEN RETURN; Process.Detach[FORK WatchForMemoryErrors[]]; END; Init[]; END.