$PAGINATE
$title(Arnold 5 test)
$subtitle(When an error is detected control comes here to print report)
$copyright(Copyright (c) 1989, 1990, Amstrad plc.)
$pagewidth=131

        PUBLIC  ErrorHandler


        EXTERN  ?TempSPStore            ;defined in TESTVARS
        EXTERN  ?ErrorRegisters         ;defined in TESTVARS
        EXTERN  .CrLfMess               ;defined in MESSAGES
        EXTERN  .ErrorMessageTable      ;defined in MESSAGES
        EXTERN  .LowMess                ;defined in MESSAGES
        EXTERN  .HighMess               ;defined in MESSAGES
        EXTERN  .RAMFillMess            ;defined in MESSAGES
        EXTERN  .RAMWaveUpStoredMess    ;defined in MESSAGES
        EXTERN  .RAMWaveUpInverseMess   ;defined in MESSAGES
        EXTERN  .RAMWaveDnInverseMess   ;defined in MESSAGES
        EXTERN  .RAMWaveDnStoredMess    ;defined in MESSAGES
        EXTERN  .RAMBlockMess           ;defined in MESSAGES
        EXTERN  .RAMOffsetMess          ;defined in MESSAGES
        EXTERN  .RAMBitMess             ;defined in MESSAGES
        EXTERN  .FlybackLowMess         ;defined in MESSAGES
        EXTERN  .FlybackHighMess        ;defined in MESSAGES
        EXTERN  .FlybackActiveMess      ;defined in MESSAGES
        EXTERN  .FlybackInactiveMess    ;defined in MESSAGES
        EXTERN  .IntPeriodMess          ;defined in MESSAGES
        EXTERN  .IntNotThereMess        ;defined in MESSAGES
        EXTERN  ScreenSetMode           ;defined in SUPPORT
        EXTERN  ScreenResetPalette      ;defined in SUPPORT
        EXTERN  SetCursorPos            ;defined in SUPPORT
        EXTERN  PrintStringHL           ;defined in SUPPORT
        EXTERN  PrintAHex               ;defined in SUPPORT
        EXTERN  LPrintAHex              ;defined in SUPPORT
        EXTERN  KeyboardRead            ;defined in SUPPORT


        DEFSEG  TestCode, CLASS=CODE

        SEG     TestCode

;============
ErrorHandler:
;============
;
; When an error occurs control passes to this routine with the A register
; holding a value that identifies the error (they are listed in MESSAGES)
;
; With errors such as RAM faults, other values are passed to identify the
; location of the fault in BC, DE or HL. The following code identifies which
; registers hold important values for each of the various errors.
;
        ld      (?TempSPStore),sp
        ld      sp,?ErrorRegisters + 20
        push    af                      ;2
        push    bc                      ;4
        push    de                      ;6
        push    hl                      ;8
        exx
        push    bc                      ;10
        push    de                      ;12
        push    hl                      ;14
        exx
        push    ix                      ;16
        push    iy                      ;18 bytes of register info.
        ld      sp,(?TempSPStore)

        add     a,a                     ;double error code so we wont touch
                                        ;l':0
        ld      b,a
        exx
        ld      a,l                     ;get current L'
        exx
        and     1                       ;clear all but bit 0
        or      b                       ;add in err code * 2
        exx
        ld      l,a
        exx

        ld      a,1
        call    ScreenSetMode           ;corrupts AF BC DE HL

        call    ScreenResetPalette      ;get the colors we know and love

        ld      bc,7F10h
        out     (c),c                   ;point at border palette register

        ld      bc,7F47h
        out     (c),c                   ;make border bright PINK

        ld      de,00A02h
        call    SetCursorPos

        exx
        ld      a,l                     ;get error code + printer state
        exx
        srl     a                       ;move error code back to norm posn

        ld      b,a                     ;put counter (error code) in right reg
        push    bc

        ld      hl,.ErrorMessageTable
_ErrScanMessages:
        dec     b                       ;count down error number
        jr      z,_ErrFoundMessage
_ErrWasteTilDollar:
        ld      a,(hl)                  ;get message char
        inc     hl                      ;step on
        cp      '$'                     ;looking for terminating "$"s
        jr      z,_ErrScanMessages      ;found end of a message
        jr      _ErrWasteTilDollar      ;keep looping along message

_ErrFoundMessage:
;
; here with HL pointing to first char of relevant message for error number
; A' still has a copy of the error number.
;
        ld      b,011b                  ;both screen and printer
        call    PrintStringHL           ;print first part of error

        pop     bc
        ld      a,b
        dec     a                       ;make it 0 based
        ld      h,0
        ld      l,a                     ;using hl for 16 bit sum and indirection
        add     hl,hl                   ;make a word offset
        ld      bc,._ErrRoutineTable    ;defined in this file
        add     hl,bc                   ;index into the table
        ld      a,(hl)
        inc     hl
        ld      h,(hl)
        ld      l,a                     ;get entry for routine to run

        ld      (?TempSPStore),sp
        ld      sp,?ErrorRegisters + 2
        pop     iy
        pop     ix
        exx
        pop     hl
;        pop     de
        pop     bc                      ;don't want to corrupt DE' (cursor)
        pop     bc
        exx
        pop     de                      ;waste saved HL
        pop     de
        pop     bc
        pop     af
        jp      (hl)                    ;continue printing error with approp.
                                        ;routine

._ErrRoutineTable:
;
; This runs sub-routines that go on to print extra bits on the end of the
; root message. If there is no more to print (i.e. just a single piece of
; text that has already been printed) then the entry is just to go straight
; to _ErrWaitKey
;
        defw    _ErrWaitKey             ;ERROR 1 (processor) no more to print
        defw    _ErrRAMFailure          ;ERROR 2 (ram)
        defw    _ErrWaitKey             ;ERROR 3 (ram switch)
        defw    _ErrFlybackFailure      ;ERROR 4 (frame flyback)
        defw    _ErrInterruptFailure    ;ERROR 5 (timer interrupt)
        defw    _ErrBUSYFailure         ;ERROR 6 (printer BUSY signal)

;--------------
_ErrRAMFailure:
;--------------
;
; We get here with B:7..4 holding the bit that failed (1..8), B:3..0 holds
; 1..5 to identify the actual error (Fill, WaveUpCheckingPat, WaveUpCheckingInv,
; WaveDownCheckingInv, WaveDownCheckingPat).
; C Holds the block number that failed (0..7)
; DE holds the offset within the 16K block where the error occured
;
        push    de
        ld      a,b
        and     7                       ;get error code
        ld      hl,.RAMFillMess
        cp      1                       ;is it on Fill ?
        jr      z,_ErrRAMDirection
        ld      hl,.RAMWaveUpStoredMess
        cp      2                       ;is it on Wave up checking stored
        jr      z,_ErrRAMDirection
        ld      hl,.RAMWaveUpInverseMess
        cp      3                       ;is it on Wave up checking inverse
        jr      z,_ErrRAMDirection
        ld      hl,.RAMWaveDnInverseMess
        cp      4                       ;is it on Wave down checking Inverse
        jr      z,_ErrRAMDirection
        ld      hl,.RAMWaveDnStoredMess
;        cp      5               ;is it on Wave down checking pattern - MUST BE

_ErrRAMDirection:
        push    bc                      ;save B and C with err bits etc. in
        ld      b,3                     ;screen and printer
        call    PrintStringHL           ;print test that failed

        ld      hl,.CrLfMess
        ld      b,3
        call    PrintStringHL

        ld      hl,.RAMBlockMess
        ld      b,3
        call    PrintStringHL
        pop     bc
        push    bc
        ld      a,c
        call    PrintAHex
        call    LPrintAHex

        ld      hl,.RAMOffsetMess
        ld      b,3
        call    PrintStringHL

        pop     bc
        pop     de                      ;get back offset
        push    bc                      ;just put B (with err bit) back on stack

        ld      a,d
        push    de
        call    PrintAHex
        call    LPrintAHex
        pop     de
        ld      a,e
        call    PrintAHex
        call    LPrintAHex

        ld      hl,.RAMBitMess
        ld      b,3
        call    PrintStringHL
        pop     bc
        ld      a,b
        sra     a
        sra     a
        sra     a
        sra     a                       ;move top nybble to lower half
        and     7                       ;mask into range
        call    PrintAHex
        call    LPrintAHex
        jp      _ErrWaitKey


;------------------
_ErrFlybackFailure:
;------------------
;
; There are 4 possible errors here. B contains the ID to decide from
;       1 = Signal Permenantly low
;       2 = Signal Permenantly high
;       3 = Active Period is wrong
;       4 = Inactive Period is wrong
;
        ld      a,b
        ld      hl,.FlybackLowMess
        cp      1
        jr      z,_ErrFlyPrintIt
        ld      hl,.FlybackHighMess
        cp      2
        jr      z,_ErrFlyPrintIt
        ld      hl,.FlybackActiveMess
        cp      3
        jr      z,_ErrFlyPrintIt
        ld      hl,.FlybackInactiveMess
_ErrFlyPrintIt:
        ld      b,3
        call    PrintStringHL
        jp      _ErrWaitKey

;--------------------
_ErrInterruptFailure:
;--------------------
;
; B=1 No INT signal detected
; B=2 INT Period incorrect
;
        ld      a,b
        cp      2
        ld      hl,.IntPeriodMess
        jr      _ErrIntPeriod
        ld      hl,.IntNotThereMess
_ErrIntPeriod:
        ld      b,3
        call    PrintStringHL
        jp      _ErrWaitKey

;---------------
_ErrBUSYFailure:
;---------------
;
; Now just have to print "high" or "low" depending on B=0 or 1
;
        ld      a,b
        ld      hl,.LowMess
        cp      0
        jr      z,_ErrBUSYPrintState
        ld      hl,.HighMess
_ErrBUSYPrintState:
        ld      b,3
        call    PrintStringHL
        jp      _ErrWaitKey

;-----------
_ErrWaitKey:
;-----------
;
; Now we've reported the error we just sit and wait for a key press then
; restart the test software which will look to the user like a return to
; the main menu (except that the sign-on is printed again).
;
        call     KeyboardRead        ;wait for a key press
        cp      0FFh
        jr      z,_ErrWaitKey

        jp      0                       ;Restart the test pack software

        END
