;$PAGINATE
;$title(Arnold 5 test)
;$subtitle(Frame Flyback signal test)
;$copyright(Copyright (c) 1989, 1990, Amstrad plc.)
;$pagewidth=131
;
;
;        PUBLIC  FrameFlybackTest        ;called indirectly from TESTPACK
;                                        ; out of MainMenuTable
;
;
;        EXTERN  SetCursorPos
;        EXTERN  PrintStringHL           ;SUPPORT
;        EXTERN  DelayASeconds           ;SUPPORT
;        EXTERN  OfferRetest             ;SUPPORT
;
;        EXTERN  .FrameFlybackMess       ;MESSAGES
;;
;; This test routine is used to check that the 6845 is generating a proper
;; frame flyback signal when expected and that it lasts for the length of
;; time that one would expect.
;;
;
;        DEFSEG  TestCode, CLASS=CODE
;
;        SEG     TestCode

;================
FrameFlybackTest:
;================
;
; I am gonna assume that the machine must be 50Hz (indeed, I haven't
; allowed for anything else in the INITIALisation code). So I know exactly
; how far apart the leading edge of frame flyback must be (once every 1/50s
; unless I'm very much mistaken). The length the signal remains active high
; is also absolutely predicatble.
;
        ld      de,00A02h
        call    SetCursorPos

        ld      hl,.FrameFlybackMess    ;say what we're doing
        ld      b,1
        call    PrintStringHL

        ld      hl,0E00h                ;time we expect from one FF to another
        ld      d,h
        ld      e,l                     ;take a copy

        ld      bc,0F500h
        in      a,(c)                   ;read 8255 port B
        bit     0,a                     ;test the FF bit
        jr      nz,_FrameFFIsHigh       ;loop until FF is high
        dec     hl
        ld      a,h
        or      l
        jr      nz,FrameFlybackTest     ;only gonna keep looking for FF high
                                        ;as long as HL holds out.
        jp      _FrameStuckLow

_FrameFFIsHigh:
;
; At this point the FF signal is high - either we have just seen a low to
; high transition or we were already in FF at the start of the test. Now
; we wait for as long as we expect FF to last to see it go low (end). If it
; doesn't then it must be stuck high.
;
        ld      h,d
        ld      l,e                     ;get back longest time we expect

_FrameWaitFFLow:
        in      a,(c)
        bit     0,a
        jr      z,_FrameFFIsLow         ;we have just seen a high to low
        dec     hl
        ld      a,h
        or      l
        jr      nz,_FrameWaitFFLow
        jp      _FrameStuckHigh

_FrameFFIsLow:
;
; If we get here we have seen FF high and then, within a reasonable length
; of time it has gone low again. Now we wait a reasonable length of time
; to see it go back high again (almost sure to!). At that very moment we
; are synchronised with the leading edge of FF so the absolute timing test of
; both the high and the low bits can be started.
;
        ld      h,d
        ld      l,e                     ;a "reasonable" time to wait

_FrameWaitFFLeadingEdge:
        in      a,(c)
        bit     0,a
        jr      nz,_FrameFFGoneHighAgain
        dec     hl
        ld      a,h
        or      l
        jr      nz,_FrameWaitFFLeadingEdge
        jp      _FrameStuckLow
;
;now found a definite leading edge of the FF signal
;
_FrameFFGoneHighAgain:
        ld      hl,0                    ;use HL to time "high time"
_FrameTimeFFHigh:
        inc     hl
        in      a,(c)
        bit     0,a
        jr      nz,_FrameTimeFFHigh     ;keep counting up while in FF

        ld      de,0                    ;now use DE to time "low time"
_FrameTimeFFLow:
        inc     de
        in      a,(c)
        bit     0,a
        jr      z,_FrameTimeFFLow

;
; When we get here, HL holds a count of how long FF was high and DE has a
; count of how long it was low. There are magic values for both these that
; will now be subtracted from HL, then DE, in turn. As long as the results
; are within an acceptable range (1 or 2 either way ?) then we pass.
;
        ld      bc,5Ch                  ;how long we expect FF high to be
        sbc     hl,bc                   ;compare with value found
        ld      a,h                     ;expect 0FFh (if -ve) or 0
        cp      0FFh
        jr      z,_FrameHighPeriodOK
        cp      0
        jr      z,_FrameHighPeriodOK
        jr      _FrameHighPeriodWrong

_FrameHighPeriodOK:
        ld      a,l
        add     a,3                     ;gonna allow +/- 3
        cp      6
        jr      nc,_FrameHighPeriodWrong

        ld      h,d
        ld      l,e

        ld      bc,6BAh                 ;how long we expect FF low to be
        sbc     hl,bc                   ;compare with value found
        ld      a,h
        cp      0FFh
        jr      z,_FrameLowPeriodOK
        cp      0
        jr      z,_FrameLowPeriodOK
        jr      _FrameLowPeriodWrong

_FrameLowPeriodOK:
        ld      a,l
        add     a,3                     ;gonna allow +/- 3
        cp      6
        jr      nc,_FrameLowPeriodWrong

        xor     a                       ;Clear Carry cos everythings OK
        jp      _FrameEndTest
_FrameStuckLow:
        ld      b,1                     ;1 identifies to ERROR that it's LOW
        ld      a,4
        scf
        jr      _FrameEndTest

_FrameStuckHigh:
        ld      b,2                     ;2 identifies to ERROR that it's HIGH
        ld      a,4
        scf
        jr      _FrameEndTest

_FrameHighPeriodWrong:
        ld      b,3                     ;3 identifies to ERROR is high wrong
        ld      a,4
        scf
        jr      _FrameEndTest

_FrameLowPeriodWrong:
        ld      b,4                     ;4 identifies to ERROR is low wrong
        ld      a,4
        scf
        jr      _FrameEndTest

_FrameEndTest:
        jr      c,_FrameSkipReTest
        push    af                      ;save possible error flag
        ld      a,2
        call    DelayASeconds
        call    OfferRetest             ;rets C if we should re-do
        pop     bc                      ;so flags are in C !
        jp      c,FrameFlybackTest      ;yes, we must re-do the test
        push    bc
        pop     af                      ;flag result back into right register
_FrameSkipReTest:
        ret

