; > TestSrc.VIDC

        TTL RISC OS 2+ POST video controller
;
; The video outputs cannot be tested directly, and VIDC permits only
; write operations on its registers. 
; This module performs two tests to verify VIDC's operation 
;
;       - measure mode 0 FLBK period against IOC timer 
;       - check that sound DMA occurs (MEMC reports DMA complete)
;
; This code contains timing loops affected by gross changes in processor 
; speed, and will re-initialise MEMC with 4K pages and continous refresh.  
;
;------------------------------------------------------------------------
; History
;
; Date          Name            Comment
; ----          ----            -------
; 18-Dec-89     ArtG            Initial version
; 04-Apr-90     ArtG            Use saved MEMC control register setting
; 20-Jun-93     ArtG            Medusa VIDC20 / IOMD changes
;
;
;------------------------------------------------------------------------


VIDC_CLOCK_CONTROL      *       ts_S5_base :OR: &0048  ; Fox VIDC clock control
VIDC_CLOCK_NORMAL       *       &0

VIDC_VFLYWAIT           *       72000           ; 200mS timeout loop
VIDC_SOUNDWAIT          *       40000           ; 100mS  timeout loop

MEMC_Sstart             *       MEMCADR   :OR: &80000
MEMC_SendN              *       MEMCADR   :OR: &A0000
MEMC_Sptr               *       MEMCADR   :OR: &C0000
MEMC_Son                *                      &00800

ts_Soundbuf             *       &200            ; relative to PhysRam
ts_Soundbuf_length      *       &400

        [ VIDC_Type = "VIDC20"
VIDSTIM0                *       &A0000000       ; base VIDC20 register values
VIDSTIM1                *       &A1000000
VIDSFR                  *       &B0000000
VIDSCR                  *       &B1000005
VIDDMAoff               *       &94000024
VIDVCOWAIT              *       &5
VIDVCOFREQ              *       &D0000404
        |
VIDSTIM0                *       &60000000       ; base VIDC register values
VIDSTIM1                *       &64000000
VIDSFR                  *       &C0000100
        ]

        SUBT    FLBK period test
;
; This test attempts to validate the video timing system by checking for
; the proper period from the vertical flyback pulse. To make life easier, 
; the test is performed only in mode 0 - i.e a 20mS period.
;
; This test contains a processor-clock timed loop as an outer limit :
; it assumes that the processor will never run more than a factor of ten
; faster than an 8Mhz ARM2.
; This is valid provided that this code isn't run with an ARM3 cache enabled.
; 

; Initialise video clock control (for FOX)
; Initialise VIDC
; Clear IR interrupt request in IOC
; Poll IOC until IR appears (if ever)
; Set IOC timer 0 to 32 mS
; Clear IR interrupt request in IOC
; Poll IOC until IR appears (if ever)
; Check timer 0 has counted down 20 mS (19.8 - 20.2 mS)
; Return zero flag set on OK, clear on test failure.


ts_VIDC_period ROUT

        ; Initialise VIDC clock and VIDC

        [ VIDC_Type = "VIDC1a"
        LDR     r3, =VIDC_CLOCK_CONTROL         ; 
        MOV     r1, #VIDC_CLOCK_NORMAL
        STRB    r1, [r3]
        ]

        MOV     r7, #0
        MOV     r1, #ts_VIDCPhys
        ADRL    r6, TestVIDCTAB
00      LDR     r0, [r6],#4                     ; setup using main table
        CMP     r0, #-1
        STRNE   r0, [r1]
        BNE     %BT00
01      LDR     r0, [r6],#4                     ; enable DMA using 2nd table 
        CMP     r0, #-1
        STRNE   r0, [r1]
        BNE     %BT01
        
        ; Wait for the start of a flyback period

04
        LDR     r3, =IOC
        [ MEMC_Type = "IOMD"
        LDR     r1, [r6]                        ; get FSIZE value from end of TestVIDCTAB
        STR     r1, [r3, #IOMD_FSIZE]
        ]
        MOV     r1, #vsync_bit
        STRB    r1, [r3, #IOCIRQCLRA]
        LDR     r2, =VIDC_VFLYWAIT              ; long timeout loop - C 200mS

05      LDRB    r1, [r3, #IOCIRQSTAA] 
        ANDS    r1, r1,  #vsync_bit    
        BNE     %06                    
        SUBS    r2, r2,#1               
        BNE     %05                   

        LDR     r0,=&fffff
        ORRS    r0, r0,r7, LSL #20              ; Failed : clear 0 flag
        MOV     pc, r14                         ; ... and quit

        ; Set up IOC timer 0
06
        LDR     r1, =(32 * 1000 * 2)            ; 32mS upper limit
        STRB    r1, [r3, #Timer0LL]
        MOV     r0, r1, LSR #8
        STRB    r0, [r3, #Timer0LH]
        MOV     r0, #0
        STRB    r0, [r3, #Timer0GO]             ; start the timer

        ; clear the IR and T0 bits

        MOV     r0, #(vsync_bit :OR: timer0_bit)
        STRB    r0, [r3,#IOCIRQCLRA]

        ; wait for what should be a complete vflyback period

10      LDR     r2, =VIDC_VFLYWAIT              ; timeout loop -  C 200 msec
11      LDRB    r0, [r3,#IOCIRQSTAA]
        TSTS    r0, #vsync_bit
        BNE     %14                             ; wait for end of vsync

        TSTS    r0, #timer0_bit                 ; or timer underflow
        BNE     %13

12      SUBS    r2, r2, #1                      ; or last-ditch timeout 
        BNE     %11

13      ORRS    r0, r0,#1                       ; Failed : clear 0 flag
        MOV     r0, #0                          ; but return a zero
        MOV     pc, r14                         ; ... and quit

        ; finished in reasonable time : check against margins.

14      STRB    r0, [r3, #Timer0LR]             ; latch the current count
        LDRB    r2, [r3, #Timer0CL]
        LDRB    r0, [r3, #Timer0CH]
        ADD     r2, r2, r0, LSL #8

        SUB     r2, r1, r2
        MOV     r0, r2, LSR #1                  ; Vertical flyback time in uS

        LDR     r1, =19800                      ; inside limits ?
        SUBS    r2, r0, r1
        BLE     %F20

        LDR     r1, =400                        ; 19.8 -> 20.2 mS
        CMPS    r2, r1
        BGE     %F20
        MOV     r1,#0                           ; OK -  0 indicates pass

        ; After success using the 24MHz reference clock, select the
        ; VCO clock (also at 24MHz) and ensure the test is passed after
        ; a few cycles to allow the VCO to settle.

20
        [ VIDC_Type = "VIDC20"

        TEQ     r7,#0                           ; if this is the first loop ..
        BNE     %FT21
        TEQ     r1,#0                           ; and it passed OK ..
        BNE     %FT25
        MOV     r2,#ts_VIDCPhys
        LDR     r3,=VIDVCOFREQ                  ; set the vco to 24MHz
        LDR     r4,=&E0000400                   ; and use the vco clock
        STMIA   r2,{r3,r4}
        MOV     r7,#VIDVCOWAIT                  ; set the vco test loop count
        B       %BT04                           ; and run around again

21      ORR     r0,r0,r7,LSL #20
        SUBS    r7,r7,#1                        ; if all attempts now made
        BEQ     %FT25                           ; return final result
        TEQ     r1,#0                           ; else repeat until passed
        BNE     %BT04
        ]

        ; return with zero flag set if timers were OK
        ; measured time (in uS) in r0 if flyback was wrong,
        ; bits 20+ show fail loop - 0 for refclk, 1 for vcoclk.

25
        ORRS    r1,r1,r1
        MOV     pc, r14


        SUBT    Sound DMA test
;
; This test runs the sound DMA system to prove the operation of VIDC and 
; MEMC's sound DMA control and the operation of the SIRQ sound DMA complete
; interrupt.
; To avoid making a noise, set the sound muting bit on.
;
; Initialise MEMC sound DMA
; Initialise VIDC sound channel
; Initialise timer 0 and timer 1 to guard-band 10mS sound duration
; Poll IOC until IL1 (SIRQ interrupt) becomes active
; Check timer 0 has completed and timer 1 has not
;

ts_SIRQ_period  ROUT

        ; set up MEMC to point to a buffer near the start of physical RAM,
        ; labelled in r9_fiq by the early memory size tests (not MemSize) 
        ; Registers are set as (address / 16)
        ; Register bits are (register * 4) in VIDC address mask
        ; Hence values written to MEMC + register offset + (pointer / 4)    


        [ MEMC_Type = "IOMD"
        MOV     r3,#IOMD_Base
        MOV     r0,#(IOMD_DMA_C_Bit :OR: IOMD_DMA_E_Bit :OR: 16)
        STR     r0,[r3,#IOMD_SD0CR]
        MOV_fiq r0,r9                   ; zero the DMA buffer
        ADD     r1,r0,#ts_Soundbuf_length
        MOV     r2,#0
02      STR     r2,[r0],#4
        CMPS    r0,r1
        BNE     %BT02
        |
        MOV_fiq r0,r11_fiq
        BIC     r0, r0, #MEMC_Son        ; ensure sound DMA disabled

        STR     r0, [r0]
        LDR     r1, =(MEMC_SendN :OR: ((ts_Soundbuf + ts_Soundbuf_length) / 4))
        STR     r1, [r1]
        LDR     r2, =(MEMC_Sstart :OR: (ts_Soundbuf / 4))
        STR     r2, [r2]
        LDR     r0, =MEMC_Sptr          ; initialise Sptr and set up again ..
        STR     r0, [r0]
        STR     r1, [r1]
        STR     r2, [r2]
        ]

        ; Set up VIDC for 8 channels, 10uS (/8) per sample

        LDR     r0, =ts_VIDCPhys
        [ VIDC_Type = "VIDC20"
        LDR     r1, =VIDSCR             ; VIDC10 mode, 24Mhz clock
        STR     r1, [r0]
        LDR     r1, =VIDDMAoff
        STR     r1, [r0]
        ]
        LDR     r1, =(VIDSTIM0 + 1)     ; channel 0 at 100% left
        LDR     r2, =((VIDSTIM1 - VIDSTIM0) + 1)
        MOV     r3, #7
05      STR     r1, [r0]                ; .. up to 6 at 100% right
        ADD     r1, r1, r2
        SUBS    r3, r3, #1
        BNE     %05
        SUB     r1, r1, #4              ; finally ch7 at centre again
        STR     r1, [r0]

        LDR     r1, =(VIDSFR + 8)       ; 10uS/byte
        STR     r1, [r0]

        ; Set up the timer to limit at 20 us (10uS/sample, 1024-16 bytes => 10.08 mS)

        LDR     r3, =IOC
        LDR     r1, =(20 * 1000 * 2)        ; 20 mS upper limit
        STRB    r1, [r3, #Timer1LL]
        MOV     r0, r1, LSR #8
        STRB    r0, [r3, #Timer1LH]

        MOV     r0, #-1
        STRB    r0, [r3, #IOCControl]           ; mute sound (on IOC system)
        STRB    r0, [r3, #Timer1GO]             ; start the timer

        [ MEMC_Type = "IOMD"
        MOV     r0, #(IOMD_DMA_E_Bit :OR: 16)   ; enable the IOMD DMA
        STR     r0, [r3,#IOMD_SD0CR]
        MOV_fiq r0,r9                           ; set the buffer pointers
        MOV     r4,#((ts_Soundbuf_length/2) - 16)
        STR     r0,[r3,#IOMD_SD0CURA]
        STR     r4,[r3,#IOMD_SD0ENDA]
        LDR     r2,[r3,#IOMD_SD0ST]
        ORR     r4,r4,#IOMD_DMA_S_Bit
        STR     r0,[r3,#IOMD_SD0CURB]
        STR     r4,[r3,#IOMD_SD0ENDB]
        |
        MOV_fiq r0, r11_fiq
        ORR     r0, r0, #MEMC_Son
        STR     r0, [r0]                        ; enable the MEMC1a DMA
        ]

        ; set long timeout, clear the IL1, T0 and T1 bits

        LDR     r2, =VIDC_SOUNDWAIT             ; lastditch timeout loop
        LDR     r0, =(timer0_bit :OR: timer1_bit) 
        STRB    r0, [r3,#IOCIRQCLRA]


        ; Wait until sound DMA completes (or up to about 100 mS), 
        ; then check timers.

10
        [ MEMC_Type = "IOMD"
        LDRB    r0,[r3, #IOMD_SD0ST]
        AND     r0, r0, #(IOMD_DMA_O_Bit :OR: IOMD_DMA_I_Bit)
        CMPS    r0, #(IOMD_DMA_O_Bit :OR: IOMD_DMA_I_Bit)
        BEQ     %12
        |
        LDRB    r0, [r3,#IOCIRQSTAB]
        ANDS    r0, r0, #sound_IRQ_bit
        BNE     %12
        ]
        LDR     r0, [r3, #IOCIRQSTAA]
        ANDS    r0, r0,#timer1_bit              ; timeout if timer 1 expires
        BNE     %11

        SUBS    r2, r2, #1                      ; or counter reaches zero
        BNE     %10

11      ORRS    r0, r0, #1                      ; Failed : clear 0 flag
        MOV     r2, #0                          ; return a timeout value of 0
        B       %15                             ; ... and quit

        ; finished in reasonable time : check time remaining in t1
        ; Time for DMA should be 10.24ms (1024 bytes at 10us/byte)
        ; less up to the time to use the final 16-byte transfer, 160us.

12      STRB    r0, [r3, #Timer1LR]             ; latch the current count
        LDRB    r2, [r3, #Timer1CL]
        LDRB    r0, [r3, #Timer1CH]
        ADD     r2, r2, r0, LSL #8

        SUB     r2, r1, r2
        MOV     r2, r2, LSR #1                  ; Sound DMA time in uS

        LDR     r1, =10030                      ; inside limits ?
        SUBS    r0, r2, r1
        BLE     %F13

        LDR     r1, =260                        ; 10.03  -> 10.29 mS
        CMPS    r0, r1
        MOVLT   r1,#0                           ; inside limits : set Z flag

13      ORRS    r1,r1,r1

        ; return with zero flag set if time (in r2) was within limits

15
        [ MEMC_Type = "IOMD"
        MOV     r0, #IOMD_DMA_C_Bit
        STR     r0, [r3,#IOMD_SD0CR]
        |
        BIC     r0, r0, #MEMC_Son
        STR     r0, [r0]
        ]
        MOV     r0, r2                          ; return the long time value
        MOV     pc, r14

;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; Data tables: VIDC := mode 0, all palette black

TestVIDCTAB

        [ VIDC_Type = "VIDC1a"

        & &00000000
        & &04000000
        & &08000000
        & &0C000000
        & &10000000
        & &14000000
        & &18000000
        & &1C000000
        & &20000000
        & &24000000
        & &28000000
        & &2C000000
        & &30000000
        & &34000000
        & &38000000
        & &3C000000
        & &40000000     ; Border -> black
        & &44000000     ; Cursor -> black
        & &48000000
        & &4C000000     ; Palette programmed (avoid messy screen on reset)
;
; standard mode 0 setup (except display area disabled)
;

        & &807FC000
        & &8408C000
        & &881B0000
        & &8C1EC000     ; HDSR
        & &906EC000     ; HDER
        & &94770000
        & &9C400000
        & &A04DC000
        & &A4008000
        & &A8050000     ; VBSR
        & &AC098000     ; VDSR
        & &B0000000     ; VDER < VDSR to disable screen DMA       B0000000
        & &B44DC000     ; VBER
        & &E00000B2
;
; Additional setup : cursor blanked, sound frequency test bit set 
;
        & &C0000100     ; SFR  NB. TEST BIT! - also DFlynn requested value
        & &98258000     ; HCSR
        & &B8004000     ; VCSR
        & &BC400000     ; VCER
; don't mess with the stereo image registers: sound code will set them.
        & &FFFFFFFF     ; That's the lot

;
; Further registers to turn screen DMA on again (border all over)
; Must have a video start register before video end register to get
; a vertical flyback interrupt.
;
        & &B0494000     ; VDER > VDSR to enable screen DMA
        & &FFFFFFFF
        ]

        [ VIDC_Type = "VIDC20"

; This differs from the default RISC OS VIDCTAB in running from
; the 24MHZ video ref clock. H register contents are increased by 50%.

; Program Control Register first, to clear power-down bit

        & &E0000402     ; CR: FIFO load 16 words, 1 bpp, ck/1, rclk
        & &E0000402     ; 
        & &B1000001     ; SCR: sound disabled (+use 24MHz clock)

; Don't bother programming all 256 palette entries, we'll be here all night
; Since we're setting up a 1 bit-per-pixel mode, just do colours 0 and 1

        & &10000000     ; Palette address register = 0
        & &00000000     ; Colour 0 = black
        & &00000000     ; Colour 1 = black
        & &407f7f7f     ; Border colour = grey
        & &50000000     ; Pointer colour 1 = black
        & &60000000     ; Pointer colour 2 = black
        & &70000000     ; Pointer colour 3 = black

; Get a stable display up so we get stable signals

        & &800005F8     ; HCR  = 114 + 132 + 144 + 960 + 144 + 42
        & &8100006A     ; HSWR = 114
        & &820000EA     ; HBSR = 114 + 132
        & &83000174     ; HDSR = 114 + 132 + 144
        & &84000534     ; HDER = 114 + 132 + 144 + 960
        & &850005CA     ; HBER = 114 + 132 + 144 + 960 + 144
        & &860000F3     ; HCSR = HDSR

        & &90000137     ; VCR  = 3 + 19 + 16 + 256 + 16 + 2
        & &91000002     ; VSWR = 3
        & &92000015     ; VBSR = 3 + 19
        & &93000025     ; VDSR = 3 + 19 + 16
        & &94000024     ; VDER = VDSR -1 to disable sceeen DMA
        & &95000135     ; VBER = 3 + 19 + 16 + 256 + 16
        & &96000025     ; VCSR = VDSR
        & &97000025     ; VCER = VDSR

        & &C00F1003     ; EREG = comp sync, DACs on, ereg output ext lut
        & &D000C385     ; FSYNREG, clk = (3+1)/(5+1) * 24MHz = 16MHz
        & &F0013000     ; DCR: bus D[31:0], Hdisc
        & &FFFFFFFF

        & &94000125     ; VDER > VDSR to enable screen DMA
        & &FFFFFFFF
                        ; FSIZE is one less than number of rasters in Vflyback
        & &00000037     ; (3 + 19 + 16 + 0 + 16 + 2) - 1

        ; Alternate settings for VGA monitor

TestVVIDCTAB
        & &E0000402     ; CR: FIFO load 16 words, 1 bpp, ck/1, rclk
        & &E0000402     ; 
        & &B1000001     ; SCR: sound disabled (+use 24MHz clock)

        & &10000000     ; Palette address register = 0
        & &00000000     ; Colour 0 = black
        & &00000000     ; Colour 1 = black
        & &407f7f7f     ; Border colour = grey
        & &50000000     ; Pointer colour 1 = black
        & &60000000     ; Pointer colour 2 = black
        & &70000000     ; Pointer colour 3 = black

        & &80000310     ; HCR  = 92 + 45 + 0 + 640 + 0 + 16
        & &81000054     ; HSWR = 92
        & &82000080     ; HBSR = 92 + 45
        & &83000080     ; HDSR = 92 + 45 + 0
        & &84000300     ; HDER = 92 + 45 + 0 + 640
        & &85000300     ; HBER = 92 + 45 + 0 + 640 + 0
        & &86000080     ; HCSR = HDSR

        & &9000020B     ; VCR  = 2 + 32 + 0 + 480 + 0 + 11
        & &91000001     ; VSWR = 2
        & &92000021     ; VBSR = 2 + 32
        & &93000021     ; VDSR = 2 + 32 + 0
        & &94000020     ; VDER = VDSR -1 to disable sceeen DMA
        & &95000201     ; VBER = 2 + 32 + 0 + 480 + 0
        & &96000021     ; VCSR = VDSR
        & &97000021     ; VCER = VDSR

        & &C0051003     ; EREG = sep/inv sync, DACs on, ereg output ext lut
        & &F0013000     ; DCR: bus D[31:0], Hdisc
        & &FFFFFFFF

        ]

        END