; > TestSrc.Begin

        TTL RISC OS 2+ Power-On Self-Test
;
; Startup code for RISC OS ROM Self-Test.
;
; Performs ROM test patterns, determines test strategy and enters
; external or internal test code.
;
; A minimal set of opcodes should be used (ideally, only B, LDR and ADDS)
; so that a processor test may be validly included in the internal test
; sequence.
;
;------------------------------------------------------------------------
; History
;
; Date          Name    Rel     Comment
; ----          ----    ---     -------
; 23-Feb-93     ArtG    2.00    Experimental ARM 600 / Jordan mods
; 20-Oct-93     ARTG    2.02    Changed to new conditional assembly scheme
; 18-Nov-94     RCM     2.05    Morris changes
;
;------------------------------------------------------------------------

; TS_STATUS should be one of :
;
; 'R'   RISC OS POST
; 'S'   Standalone version (with a2 memory test instead of RISCOS)
; 'T'   Test build - development only
;

TS_STATUS       *       "R"     ;  Medusa POST version 2.0x
;
TS_RELEASE      *       20
TS_CHANGES      *       5


                GBLL    POSTenabled
POSTenabled     SETL    {TRUE}          ; don't permit POST for ordinary startup

ts_Rom_bits     *       21                              ; Widest ROM address
ts_Rom_length   *       1 :SHL: ts_Rom_bits             ; Longest ROM
ts_highaddr_bit *       1 :SHL: 25                      ; ARM address width
ts_Alias_bits   *       (1 :SHL: 23)                    ; I/F output bits
ts_recover_time *       (1 :SHL: 8)                     ; inter-twiddle delay
ts_pause_time   *       200                             ; Display pause time
ts_S5_base      *       &3350000                        ; IO register base address
ts_IOEB_ID      *       (ts_S5_base + &50)              ; IOE_B ASIC identification
ts_IOEB_ident   *       &5                              ; the value found there
ts_PCaddress    *       &3010000                        ; PC IO world base address
ts_ReadyByte_00 *       &90                             ; signal 'Here I am' to ExtIO
ts_BBRAM        *       &A0                             ; IIC address of clock/ram chip
ts_RamChunk     *       &2000                           ; gap between data line tests
ts_MaxRamTest   *       4*1024*1024                     ; Max. DRAM tested on normal reset
ts_VIDCPhys     *       &3400000                        ; Real location of VIDC

;
; Border colours used for self-test indicators
;
        [ VIDC_Type = "VIDC1a"
C_ARMOK         *       &40000000+&70C  ; testing ROM
C_RAMTEST       *       &40000000+&C70  ; testing RAM
C_FAULT         *       &40000000+&00F  ; failed tests
C_PASSED        *       &40000000+&7C0  ; all passed
C_WARMSTART     *       &40000000+&777  ; not tested
        ]

        [ VIDC_Type = "VIDC20"
C_ARMOK         *       &40000000+&7000C0  ; testing ROM
C_RAMTEST       *       &40000000+&C07000  ; testing RAM
C_FAULT         *       &40000000+&0000F0  ; failed tests
C_PASSED        *       &40000000+&70C000  ; all passed
C_WARMSTART     *       &40000000+&707070  ; not tested
        ]

;
; Responses to external commands
;

ErrorCmd        *       &00FF


;
; Control bitmasks used to indicate results of test to RISCOS
;

R_SOFT          *       0               ; not a power-on reset
R_HARD          *       1               ; Self-test run due to POR
R_EXTERN        *       2               ; external tests performed
R_TESTED        *       4               ; Self-test run due to test link
R_MEMORY        *       8               ; Memory has been tested
R_ARM3          *       &10             ; ARM 3 fitted
R_MEMSKIP       *       &20             ; long memory test disabled
R_IOEB          *       &40             ; PC-style IO controller
R_VRAM          *       &80             ; VRAM present

R_STATUS        *       &1ff            ; bits that aren't a fault

R_CHKFAILBIT    *       &100            ; CMOS contents failed checksum
R_ROMFAILBIT    *       &200            ; ROM failed checksum
R_CAMFAILBIT    *       &400            ; CAM failed
R_PROFAILBIT    *       &800            ; MEMC protection failed
R_IOCFAILBIT    *       &1000           ; IOC register test failed
R_INTFAILBIT    *       &2000           ; Cannot clear interrupts
R_VIDFAILBIT    *       &4000           ; VIDC flyback failure
R_SNDFAILBIT    *       &8000           ; Sound DMA failure
R_CMSFAILBIT    *       &10000          ; CMOS unreadable
R_LINFAILBIT    *       &20000          ; Page zero RAM failure
R_MEMFAILBIT    *       &40000          ; Main RAM test failure
R_CACFAILBIT    *       &80000          ; ARM 3 Cache test failure
;
 [ MorrisSupport
Kludge * 96
 |
Kludge * 0
 ]
        SUBT    Exception vectors
;
; These vectors are available for use while the Rom is mapped into
; low memory addresses. The Reset vector will be copied to low RAM
; as part of a software reset sequence : therefore it must perform
; a fixed operation to ensure compatibility with future versions
; of RISC-OS.
;

Reset
ts_start
        $DoMorrisROMHeader

 [ :LNOT: MorrisSupport
  [ ResetIndirected
        LDR     pc,.+ResetIndirection   ; load pc from vector at &118
  |
        B       ts_RomPatt + PhysROM    ; Jump to normal ROM space
  ]
 ]
01
        &       ts_Rom_length           ; gets patched by ROM builder
02
        &       (ts_ROM_cvectors - ROM) ; pointer to code vector table
03
        &       (ts_ROM_dvectors - ROM) ; pointer to data vector table
04
        &       (ts_ROM_bvectors - ROM) ; pointer to branch table
        B       Reset                   ; not currently used
        B       Reset
        B       Reset


ts_ROMSIZE      *       %BT01 - ts_start
ts_CVECTORS     *       %BT02 - ts_start
ts_DVECTORS     *       %BT03 - ts_start
ts_BVECTORS     *       %BT04 - ts_start

 ! 0, "ts_Rom_length held at ":CC::STR:(%BT01 - ROM)


;
; Selftest version ID
;

00
        ASSERT  %B00 <= (ts_start + &2c + Kludge)
        %       ((ts_start + &2c + Kludge) - %B00)

ts_ID   &       ((TS_STATUS :SHL: 24) + (TS_RELEASE :SHL: 16) + TS_CHANGES)

ts_ID_text
ts_himsg
        =       "SELFTEST"                      ; **DISPLAY_TEXT**
        =       &89                             ; Cursor position
        =       TS_STATUS
        =       ("0" + (TS_RELEASE /     10))
        =       "."
        =       ("0" + (TS_RELEASE :MOD: 10))
        =       ("0" + (TS_CHANGES :MOD: 10))
        =       0


;
; These vector tables permit access by the external (or downloaded) test
; software to data and code in the POST modules.
; Find the start of these tables through the 2nd and 3rd vectors at
; the start of the ROM.
;

ts_ROM_dvectors
01
        &       ts_ID                   ; Selftest identification number
02
        &       (ts_ID_text - ROM)      ; Selftest identification text


;
; vectors ORd with these flags to assure proper mode when
; executed by host thro' vector table.
;

ts_runflags     *       (I_bit :OR: F_bit :OR: SVC_mode)

ts_ROM_cvectors
        &       ts_RomPatt              :OR: ts_runflags
        &       ts_User_startup         :OR: ts_runflags
        &       ts_Self_test_startup    :OR: ts_runflags
        &       ts_Dealer_startup       :OR: ts_runflags
        &       ts_Forced_startup       :OR: ts_runflags
        &       ts_GetCommand           :OR: ts_runflags
        &       ts_Softstart            :OR: ts_runflags
        &       ts_Hardstart            :OR: ts_runflags


;
; ROM branch vectors - intended primarily so downloaded programs
; may use standard subroutines.  This table should be in a fixed place.
;

00
        ASSERT  %B00 <= (ts_start + 128 + Kludge)
        %       ((ts_start + 128 + Kludge) - %B00)

ts_ROM_bvectors
        B       ts_RomPatt
        B       ts_GetCommand
        B       ts_SendByte
        B       ts_SendWord
        B       ts_GetByte
        B       ts_GetWord
        B       ts_SendText
        B       ts_MoreText
        B       ts_SendLCDCmd


;
; Pad out until the location of the ResetIndirection vector
;

        ASSERT  .-ROM <= ResetIndirection
        %       ResetIndirection-(.-ROM)
        &       ts_RomPatt-ROM+PhysROM

;
; ROM test code
;
; Note : the register order in ADDS ...pc.. is often critical.
; If we want to adjust pc, use ADDS pc,rn,pc so that the PSR is
; rewritten with it's original value.
; If we want to do some pc-relative arithmetic, use ADDS rn,pc,rn
; so that the bits from PSR are NOT used in the address calculation.
;

        SUBT    Macros

        MACRO
        MODE    $mode_bits
        TEQP    psr,#($mode_bits :OR: I_bit :OR: F_bit)
        NOP
        MEND

        MACRO
        MOV_fiq $dest,$src
        MODE    FIQ_mode
        MOV     $dest,$src
        MODE    SVC_mode
        MEND

        MACRO
        FAULT   $code
        MODE    FIQ_mode
        ORR     r12_fiq,r12_fiq,$code
        MODE    SVC_mode
        MEND

        MACRO
        M32_fiq $dest,$src,$tmp1,$tmp2
        SetMode FIQ32_mode,$tmp1,$tmp2
        MOV     $dest,$src
        msr     AL,CPSR_all,$tmp2
        MEND

        MACRO
        FAULT32 $code,$tmp
        SetMode FIQ32_mode,$tmp
        ORR     r12_fiq,r12_fiq,$code
        SetMode SVC32_mode,$tmp
        MEND

 [ StrongARM_POST
;  ensure 26-bit mode for StrongARM or ARM 8 (since there is no 26 bit configuration)
        MACRO
        Ensure26bit_ARM8A $tmp
        ARM_read_ID $tmp
        AND     $tmp, $tmp, #&F000
        CMP     $tmp, #&A000
        CMPNE   $tmp, #&8000
        mrs     EQ, $tmp, CPSR_all
        BICEQ   $tmp, $tmp, #&10
        msr     EQ, CPSR_all, $tmp
        MEND
  ]

;
; Define an area of storage with the required set of data bus patterns
; These are used both for testing the complete width of the data bus
; during ROM pattern testing, and will provide a tidy set of patterns
; if the reset is held, while the ARM increments addresses.
;

        SUBT    ROM Address and Data Patterns

DataPatterns

        GBLA    dmask
dmask   SETA    &80000000

        DCD     &FFFFFFFF               ; first two : all set
        DCD     &0                      ;             all clear

        GBLA    OldOpt                  ; don't list all the walking
OldOpt  SETA    {OPT}                   ; patterns
        OPT     OptNoList

        WHILE   dmask > 0               ; then for each bit
        DCD     &$dmask                 ; set it
        DCD     :NOT: &$dmask           ; and clear it
dmask   SETA    dmask :SHR: 1
        WEND
        OPT     OldOpt
DEnd


        OPT     OptList
;
;
; Read the ROM at a series of addresses
; such that :   a) all the address lines are exercised individually
;               b) all the data lines are exercised individually
;
; Data and address lines are exercised as walking-0 and walking-1.
; The test is performed as a series of LDR operations to avoid using
; a larger instruction set.
;

ts_RomPatt ROUT

        ; Patterns which will exercise most of the data bus.
        ; All are arbitrary instructions with NV execution

        DCD     &F0000000               ; walking 1

OldOpt  SETA    {OPT}                   ; patterns
        OPT     OptNoList

dmask   SETA    &08000000
        WHILE   dmask > 0
        DCD     dmask :OR: &F0000000
dmask   SETA    dmask :SHR: 1
        WEND

        DCD     &FFFFFFFF               ; walking 0

dmask   SETA    &08000000
        WHILE   dmask > 0
        DCD     (:NOT: dmask) :OR: &F0000000
dmask   SETA    dmask :SHR: 1
        WEND

        OPT     OldOpt

        ; Now some proper code :
        ; Initialise address pointer and make MemC safe

        LDR     r0,%01
        ADD     pc,r0,pc
01
        &       0                       ; useful constant

        [ IO_Type = "IOC-A1"            ;;!! unsafe if we execute ROM at zero
        LDR     r1,%02
        ADD     pc,r0,pc
02                                      ;;!! This remaps MEMC's ROM
        &       &E000C :OR: MEMCADR     ;;!! addressing if it hasn't
        STR     r1,[r1]                 ;;!! already happened.
        ]

        LDR     r5,%03                  ; Load r5 with a constant which
        ADD     pc,r0,pc                ; may be added to ROM plus a
03                                      ; walking-zero bitmask to create
        &       ts_Rom_length - 3       ; a valid word address in ROM.
        LDR     r2,%04                  ; Offset from ROM start to here
        ADD     pc,r0,pc
04
        &       ROM - pcfromstart

        ADD     r2,pc,r2                ; pointer to start of ROM
        ADD     r3,r2,r0                ; pointer to start of ROM
pcfromstart
        ADD     r4,r2,r0                ; pointer to start of ROM

        ; assembly-time loop - only 32 iterations required

OldOpt  SETA    {OPT}

        GBLA    doffset
doffset SETA    DataPatterns
        WHILE   doffset < DEnd

        LDR     r0,doffset              ; walking 1 data pattern
        LDR     r1,doffset+4            ; walking 0 data pattern
        LDR     r6,[r2]                 ; walking 1 address pattern
        LDR     r6,[r3]                 ; walking 0 address pattern

        [ (doffset - DataPatterns) > ((32 - ts_Rom_bits) * 8)
        [ (doffset - DataPatterns) < (31 * 8)
        ADD     r2,r4,r0                ; r2 = ROM + walking 1 pattern
        ADD     r3,r4,r1                ; r3 = ROM + walking 0 pattern
        ADD     r3,r3,r5                ; adjust to a valid address
        ]
        ]

        OPT     OptNoList

doffset SETA    doffset + 8
        WEND

        ASSERT  (. - doffset < 4095)    ; in range without barrel shift ?

        OPT     OldOpt


;
; External interface drivers -
; provides entry points to send byte- and word- and string-sized objects
; and to receive byte- and word-sized objects
;
; Continue into GetCommand, which determines adapter type (or no adapter)
; and jumps to an ExtCmd handler, ts_User_startup, ts_Forced_startup or
; ts_Dealer_startup as appropriate.
;
        B       ts_GetCommand

        GET     TestSrc.ExtIO

;
; External command handlers - respond to commands given through the
; external test interface.
;

        GET     TestSrc.ExtCmd


        SUBT    Selftest
;
; There is no attached test interface. Is this a power-on reset ?
; Addressing IOC will make MEMC1a remap the ROM to high memory if
; it hasn't already done it, so be careful to ensure that the
; ARM is addressing normally-addressed ROM when this code runs.
;

ts_User_startup    ROUT
        LDR     r0,%01
        ADD     pc,r0,pc
01
        &       0
;
; IOMD will only access the ROM until a write to IOMD has been made -
; make this write also switch on refresh so the DRAM has a chance to
; get running before the memory test starts.
;
        [ MEMC_Type = "IOMD"
        LDR     r1,%02
        ADD     pc,r0,pc
02
        &       (IOMD_Base+IOMD_VREFCR)
        LDR     r2,%03
        ADD     pc,r0,pc
03
        &       IOMD_VREFCR_REF_16
        STR     r2, [r1,#0]
        ]

        [ POSTenabled
        LDR     r1,%12                  ; load address of IOC IRQ register
        ADD     pc,r0,pc
12
        &       IOC+IOCIRQSTAA

        LDR     r1, [r1,#0]             ; Get IRQSTAA register (hence POR bit)
        LDR     r2, %13
        ADD     pc,r0,pc                ; Constant to shift por to bit 31
13
        &       por_bit :SHL: 1
14      ADD     r1,r1,r1
        ADDS    r2,r2,r2
        BCC     %14                     ; loop until por_bit is at bit 31
        ADDS    r1,r1,r1                ; then shift it into carry
        BCC     ts_Self_test_end        ; POR bit clear - do soft reset.

; it's a power-on reset, so assume we can't be in 32-bit mode for ARM 6/7

  [ StrongARM_POST
    ; make sure we are in 26-bit mode (ARM 6/7 reset in 26-bit config)
    ; note that MOV_fiq macro assumes 26-bit, so must sort this now
    Ensure26bit_ARM8A r0
  ]
        MOV_fiq r12_fiq, #R_HARD
        B       ts_Self_test_startup
        |
        B       CONT                    ; if user POST disabled
        ]
;
; Perform self - tests
;
; Any distinction between test operation for Power-up, Display-only
; and Forced tests needs to be made between these three entry points.
;


; This is where tests start if a dumb test link is fitted
; (a diode from A21 to *ROMCS, disabling the ROMs when A21 is high)

ts_Forced_startup  ROUT

  [ StrongARM_POST
    ; make sure we are in 26-bit mode (ARM 6/7 reset in 26-bit config)
    ; note that MOV_fiq macro assumes 26-bit, so must sort this now
    Ensure26bit_ARM8A r0
  ]
        MOV_fiq r12_fiq, #R_TESTED
        B       ts_Self_test_startup

; This is where the tests start if an external display adapter is fitted

ts_Dealer_startup  ROUT

  [ StrongARM_POST
    ; make sure we are in 26-bit mode (ARM 6/7 reset in 26-bit config)
    ; note that MOV_fiq macro assumes 26-bit, so must sort this now
    Ensure26bit_ARM8A r4
  ]
        MOV_fiq r12_fiq, #R_EXTERN

        LDR     r4,%FT02                ; make a pointer to signon string
01      ADD     r4,pc,r4
        ADD     pc,r0,pc
02
        &       (ts_himsg - %BT01 - 8)

        ADD     r14,pc,r0               ; make a return address for this 'call'
        ASSERT  (.+4 = ts_Self_test_startup)    ; PC must point there already !
        B       ts_SendText

ts_Self_test_startup ROUT

; This is where the power-on test starts (every user gets this)


;
; Processor test would go here .... if there was one.
;

 [ MorrisSupport
;
; On startup Morris defaults to dividing all its clocks by two and
; accessing ROM at the slowest possible access speed. So check for
; Morris and set to sensible values.
;
        MOV     r2, #IOMD_Base

        LDRB    r0, [r2, #IOMD_ID0]
        CMP     r0, #&E7
        LDRB    r0, [r2, #IOMD_ID1]
        CMPEQ   r0, #&D4
        BEQ     %FT10

 [ RO371Timings

        MOV     r0, #0                  ;Calling from POST
        BL      TimeCPU                 ;just sets things according to assumed bus speeds for each IOMD id, in this case

 | ; else if not RO371Timings

;
; PSwindell wants all prescalers set to divide by 1
;
        MOV     r0, #IOMD_CLKCTL_CpuclkNormal + IOMD_CLKCTL_MemclkNormal + IOMD_CLKCTL_IOclkNormal
        STRB    r0, [r2, #IOMD_CLKCTL] ; initialise all prescalers to div1
;
; Set ROM speed, take care to preserve 16-bit mode bit...
;
; According to RJKing on 6/5/94, Kryten will use burst mode roms: use 93nS burst, 156nS initial.
;
; We assume that the extension ROMs are the same access time and width as the main OS ROMS.
;
        LDRB    r1, [r2, #IOMD_ROMCR0]
        AND     r1, r1, #&40            ; clear all but 16-bit mode bit

 [ :LNOT: AutoSpeedROMS
  [ NormalSpeedROMS
   ;Normal code
        ORR     r1, r1, #IOMD_ROMCR_Normal + IOMD_ROMCR_156 + IOMD_ROMCR_Burst93
                                                                ; initialise ROM speed to 156.25nS, 93.75nS burst
        ; the fast EPROMS used for Kryten testing should be able to cope even though they aren't
        ; burst devices
  |
   ;Slow ROM access for PSwindells test EPROMS. Paul requested 156nS (or slower), burst off.
        ORR     r1, r1, #IOMD_ROMCR_Normal + IOMD_ROMCR_187 + IOMD_ROMCR_BurstOff

        ! 0, "*** WARNING *** Slow ROM version ment for PSwindell"
  ]

        STRB    r1, [r2, #IOMD_ROMCR0]
        STRB    r1, [r2, #IOMD_ROMCR1]         ; and do the same for extension ROMs (just in case)
 |
        MOV     r0, #0                  ;Don't muck with the CPU coprocessor regs
        BL      TimeCPU                 ;This times the memory bus & sets the ROM speed accordingly
 ]

 ] ;RO371Timings conditional

;
10
 ]
;
; From this point on we assume we can safely use all the processor
;
; Initialise VIDC : Sync mode 0, border covers screen
;

ts_InitVIDC
        [ IO_Type = "IOMD"              ; If POSTbox fitted, ROM may still be mapped everywhere
        MOV     r2, #IOMD_Base
        MOV     r0, #IOMD_VREFCR_REF_16 ; switch on DRAM refresh
        STR     r0, [r2, #IOMD_VREFCR]

        ; choose monitor settings from ID bit 0
        MOV     r1,#ts_VIDCPhys
        ADRL    r2,TestVIDCTAB
        LDR     r0,=IOMD_MonitorType
        LDR     r0,[r0]
        ANDS    r0,r0,#IOMD_MonitorIDMask
        ADDEQ   r2,r2,#(TestVVIDCTAB-TestVIDCTAB)

        |                               ; not IOMD
        MOV     r1,#ts_VIDCPhys
        ADRL    r2,TestVIDCTAB
        ]

10      LDR     r0, [r2],#4
        CMP     r0, #-1
        STRNE   r0, [r1]
        BNE     %BT10

 [ :LNOT: StrongARM_POST
   ;skip POST for StrongARM or ARM8
        ARM_read_ID r0
        AND     r0,r0,#&F000
        CMP     r0,#&A000              ;if we are a StrongARM...
        CMPNE   r0,#&8000              ;or an ARM8...
        LDREQ   r0,=C_WARMSTART        ;the colour that indicates no POST performed
        STREQ   r0,[r1]
        BEQ     ts_Hardstart           ;RISC OS - right now!
 ]

 [ ARM810support :LAND: (:LNOT: ARM810_POST)
   ;just too horrible to fix POST for ARM 8 at the moment
        ARM_read_ID r0
        AND     r0,r0,#&F000
        CMP     r0,#&8000              ;if we are an ARM 8
        LDREQ   r0,=C_WARMSTART        ;the colour that indicates no POST performed
        STREQ   r0,[r1]
        BEQ     ts_Hardstart           ;RISC OS - right now!
 ]

        LDR     r0,=C_ARMOK     ; set initial screen colour
        STR     r0, [r1]

        B       ts_RomTest


        LTORG
        ROUT

;
; Calculate ROM checksum : display status and calculated checksum.
;

1
        =       "ROM   :",0
2
        =       "ROM bad",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0
3
        =       "ROM size",&8A,&ff,&ff,&ff,&ff,&ff,&ff,0
        ALIGN

ts_RomTest
        ADR     r4,%BT1
        BL      ts_SendText

        BL      ts_ROM_checksum
        BEQ     %20
        ADR     r4,%BT2                 ; Failed message
        FAULT   #R_ROMFAILBIT           ; set ROM bit in r12_fiq
        MOV     r8,r0                   ; calculated checksum
        BL      ts_SendText

        BL      ts_ROM_alias            ; Checksum failed :-
        ADR     r4,%BT3                 ; hunt for first alias
        MOV     r8,r0, LSL #8
        BL      ts_SendText             ; and report it.
20

        [ IO_Type = "IOC-A1"            ; Don't use RISC OS MemSize
                                        ; until much later - it sets up
                                        ; the ARM600 MMU as well.
        B       ts_MEMCset

;
; Do MEMC setup and memory size determination (the first time).
;
        LTORG
        ROUT

1
        =       "M Size :",0
2
        =       "M Size",&89,&ff,&ff,&ff,&ff,".",&ff,&ff,0
        ALIGN

ts_MEMCset
        MOV     r12,#0
        ADR     r4,%BT1
        BL      ts_SendText
        LDR     r1,=(&E000C :OR: MEMCADR)       ; MemSize expects 32k page
        STR     r1,[r1]
        BL      MemSize

;
; MemSize returns with  r0 = page size   (now in bytes, *NOT* in MEMC control patterns),
;                       r1 = memory size (in bytes)
;                       r2 = MEMC control value
;
; Translate these into a number that looks like :
;
;                       mmmm.pp
;
; where mmmm is memory size in hex Kbytes, pp is page size in hex Kbytes.
;
        MODE    FIQ_mode                        ; Save memory size and
        MOV     r11_fiq,r2                      ; MEMC setup value for
        MOV     r10_fiq,r1                      ; later use
        MODE    SVC_mode

        MOV     r8, r0, LSR #2                  ; MemSize now returns actual page size in r0
        ADD     r8,r8,r1,LSL #6
        ADR     r4,%BT2
        BL      ts_SendText

        ]

;
; Test data, address and byte strobe lines.
; On MEMC systems, this calls MemSize and tests the memory that finds.
; On IOMD systems, memory sizing is performed along with the data line
; tests, and that result is used for address line testing.
;

        B       ts_LineTest

                GBLS    tsGetMem1
tsGetMem1       SETS    "GET TestSrc.Mem1" :CC: MEMC_Type
                $tsGetMem1

;
; Test IOC.
; This shuld require vector space to work (for testing interrupts),
; but the current version just reports the status register contents.
;
; Display is    ccaabbff
;
;  where cc is the control register
;        aa is IRQ status register A
;        bb is IRQ status register B
;        ff is FIQ status register
;

        B       ts_IOCTest

        LTORG
        ROUT

        [ IO_Type = "IOMD"
1
        =       "IOMD  :",0
2
        =       "IOMD-F",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0
3
        =       "IOMD-V"
4
        =       &88,&ff,&ff,&ff,&ff," V.",&ff,0
        |
1
        =       "IOC   :",0
2
        =       "IOC-F",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0
3
        =       "IOC"
4
        =       &88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0
        ]
        ALIGN

ts_IOCTest
        ADR     r4,%BT1
        BL      ts_SendText
        BL      ts_IOCreg       ; check register integrity
        BEQ     %FT8
        ADR     r4,%BT2
        BL      ts_SendText     ; report if failure

        FAULT   #R_IOCFAILBIT
8
        ADR     r4,%BT1
        BL      ts_SendText
        BL      ts_IOCstat
        BEQ     %FT10           ; fail message only printed if
        ADR     r4,%BT3         ; ID code unrecognised
        BL      ts_SendText
        FAULT   #R_IOCFAILBIT   ; .. and set error bit if IOMD code is wrong
        B       %FT11
10
        ADR     r4,%BT4         ; print the status value
        BL      ts_MoreText
11

        [ IO_Type = "IOMD"
        B       ts_CMOStest
        |
        B       ts_IOEBtest
        ]

        LTORG
        ROUT

;
; Check for presence of IOEB ASIC
;

        [ IO_Type = "IOEB"

1
        =       "IOEB  :",0
2
        =       "IOEB",&88,"exists",0


        ALIGN

ts_IOEBtest
        ADR     r4,%BT1
        BL      ts_SendText

        LDR     r0,=ts_IOEB_ID                  ; read an ID register in the IOEB ASIC
        LDRB    r0, [r0]
        AND     r0, r0, #&f
        CMPS    r0, #ts_IOEB_ident              ; if it looks right ( == 5) ..
        BNE     %10

        FAULT   #R_IOEB                         ; set that bit in the result word
        ADR     r4, %BT2
        BL      ts_SendText
10      B       ts_CMOStest
        ] ; IOEB IO world
;
; Read CMOS
; Check the checksum, read the memory test flag.
;

1
        =       "SRAM  :",0
2
        =       "SRAM-F",0
3
        =       "SRAM-C",&8e,&ff,&ff,0
        ALIGN

ts_CMOStest
        ADR     r4,%BT1
        BL      ts_SendText

        [ ChecksumCMOS

        LDR     r0,=(ts_BBRAM + &4000)
        MOV     r1,#&C0                 ; Get first RAM area
        MOV     r2,#CMOSxseed
        BL      ts_CMOSread
        BNE     %20
        MOV     r2, r0
        LDR     r0,=(ts_BBRAM + &1000)  ; Accumulate the second RAM area
        MOV     r1,#&2F
        BL      ts_CMOSread
        BNE     %20
        RSB     r2, r0, #0              ; Subtract from the checksum byte
        LDR     r0,=(ts_BBRAM + &3F00)
        MOV     r1,#1
        BL      ts_CMOSread
        BNE     %20
        MOV     r8, r0, LSL #24
        ANDS    r0, r0, #&FF            ; A zero result ?
        MOV     r1, #R_CHKFAILBIT
        ADR     r4,%BT3                 ; Report checksum failure
        BNE     %21                     ; failed .. report error
        ]                               ; end ChecksumCMOS

        LDR     r0,=(ts_BBRAM + &FC00)  ; Read Misc1CMOS byte
        MOV     r1,#1
        MOV     r2,#0
        BL      ts_CMOSread
        BNE     %20
        ANDS    r0,r0,#&80              ; Test the memory-test-disable bit
        BEQ     %25
        FAULT   #R_MEMSKIP              ; If set, skip the memory test
        B       %25

20
        MOV     r1,#R_CMSFAILBIT        ; Real fault - set the fault bit
        ADR     r4,%BT2                 ; Report fault accessing IIC
                                        ; (Bitmap & POST display)
21
        FAULT   r1
        BL      ts_SendText             ; Report one fault or another
25
        B       ts_IOinit

        LTORG
        ROUT
;
; Initialize  various machine registers - e.g, turn off the floppy
; drive, etc, etc.
;

1
        =       "IOinit:",0
        ALIGN

ts_IOinit
        ADR     r4,%BT1
        BL      ts_SendText
        ADRL    r2,ts_IOinitab
10
        LDR     r0,[r2],#4              ; Get address
        LDR     r1,[r2],#4              ; Get initialization data
        CMPS    r0,#(-1)
        STRNE   r1,[r0]                 ; write to IO port
        BNE     %10
        B       Speedset
;
; Use the RISC OS MEMC setup code to guess the proper processor / memory
; configuration. The memory speed can then be set up correctly for
; fastest possible working, and the memory array tested in the
; configuration RISC OS expects.
;
; Display the results of the TimeCPU test as :
;
;               ssss.m.r
;
; where ssss is the processor speed in hex kHz,
;       m    is 0 for MEMC, 1 for MEMC1a
;       r    is the MEMC rom speed switch setting.
;
        ROUT

1
        =       "Speed :",0
2
        =       "Speed",&88,&ff,&ff,&ff,&ff,".",&ff,".",&ff,0

        ALIGN

Speedset
        ADR     r4,%BT1
        BL      ts_SendText

        [ MEMC_Type = "IOMD"
        MOV     r9,#0
        |
        MOV_fiq r0, r11_fiq                     ; get MEMC setup
        MOV     r9,r0                           ; compare IOC and CPU clocks
        ]

        MOV     r0, #0                          ; Make sure TimeCPU doesn't fiddle with the cache
        BL      TimeCPU
        MOV     r0,r9
        MOV_fiq r11_fiq,r0

        MOV     r8,r7,LSL #16
        TST     r7, #1 :SHL: 16                 ; test bit 16 of r7 :
        ADDNE   r8,r8,#&1000                    ; MEMC1 / MEMC1a detected
        AND     r9,r9,#&C0                      ; get High ROM access bits
        ADD     r8,r8,r9, LSL #2
        ADR     r4,%BT2
        BL      ts_SendText
        B       RAMtest


;
; Long RAM test, ideally exercising all memory.
; In order to keep boot time short, the following scheme is used :
;
; Normal power-on boot - test VRAM and up to 4M of first DRAM entry
; CMOS disable set     - test nothing
; Test hardware fitted - test entire memory
;

        ROUT


1
        =       "RAM   :",0
2
        =       "RAM bad",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0
3
        =       &89,"skipped",0
4
        =       "RAM   :",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0


        ALIGN

RAMtest
        ADR     r4,%BT1
        BL      ts_SendText
;
; if (R_MEMSKIP && R_HARD)
;       skip all the remaining tests
; if (!R_LINFAILBIT)
;       perform the long memory test
;
        MOV_fiq r0,r12_fiq              ; skip this test if data line fault
        AND     r1,r0,#(R_MEMSKIP :OR: R_HARD)  ; or the user didn't want it
        TEQS    r1,#(R_MEMSKIP :OR: R_HARD)
        ANDNE   r1,r1,#R_LINFAILBIT
        TEQNE   r1,#R_LINFAILBIT
        BNE     %12
        ADR     r4,%BT3                 ; skipping memory test ....
        BL      ts_MoreText
        B       ts_Report
12
        LDR     r1,=C_RAMTEST           ; doing at least part of the long memory test
        LDR     r0,=ts_VIDCPhys         ; write the border colour
        STR     r1,[r0]

        BL      MemSize                 ; Set MMU up, mapping (some) RAM at logical address 0
                                        ; Note that this returns with the MMU enabled,
                                        ; the ROM remapped to it's ORGed address,
        RSB     r4,r4,#PhysROM          ; and r4 the offset from physical to ORGed ROM addresses
        ADD     r4,r4,#PhysSpace
        SetMode SVC32_mode,r0           ; Must do this, as PhysSpace is outside 26 bit addressing
        ADD     pc,pc,r4                ; Jump into the ROM at its image in PhysSpace
        NOP                             ; this instruction skipped by pc adjustment

;
; Modify the PhysRamTable so only VRAM and the first ts_MaxRamTest of DRAM gets tested
;
        M32_fiq r0,r12_fiq,r1,r2        ; get the test condition flags

        ANDS    r0,r0,#(R_EXTERN :OR: R_TESTED)
        BNE     %FT16                   ; do full test if test adapter is present
        MOV     r9,#PhysRamTable
        ADD     r10,r9,#(PhysRamTableEnd-PhysRamTable)
14
        LDR     r1,[r9, #4]
        ADD     r0,r0,r1                ; r0 = running sum of memory sizes
        SUBS    r2,r0,#ts_MaxRamTest    ; r2 = excess over ts_MaxRamTest
        SUBHI   r1,r1,r2                ; r1 = current size truncated
        STRHI   r1,[r9, #4]
        MOVHI   r0,#ts_MaxRamTest       ; truncate running sum to MaxRamTest

        ADD     r9,r9,#(DRAMPhysAddrB-DRAMPhysAddrA)
        CMPS    r9,r10
        BNE     %BT14
16
        FAULT32 #R_MEMORY,r0            ; memory tests were attempted

        MOV     r9,#VideoPhysAddr
        LDR     r8,[r9]                 ; report the test address
        ADRL    r4,%BT4
        BL      ts_SendText
        LDR     r0,[r9]                 ; get VRAM start address and size
        LDR     r1,[r9,#4]
        ADD     r0,r0,#PhysSpace
        BL      ts_RamTest
        BNE     %FT20                   ; failed - abort ram testing

;
; VRAM (or 1st MB of DRAM, if no VRAM fitted) looks OK - move the translation
; table there so memory tests can proceed without smashing it.
;
        MOV     r9,#PhysRamTable
        LDR     r0,[r9,#VideoPhysAddr-PhysRamTable]     ; get address of video RAM
        LDR     r1,[r9,#DRAMPhysAddrA-PhysRamTable]     ; get address of 1st DRAM bank
        LDR     r3, =DRAMOffset_L2PT
        ADD     r1, r1, r3              ; make r1 -> L2PT
        ADD     r0, r0, r3              ; make r0 -> temporary L2PT
        BL      ts_remap_ttab           ; copy ttab at r1 to r0 and change table base

;
; Now run the RAM test at each DRAMPhysAddr until the end of the table or a zero entry
; is reached. Mark tested entries by setting the PhysSpace address, so a pointer to the
; next entry need not be kept.
;
18
        MOV     r9,#DRAMPhysAddrA
        ADD     r10,r9,#(PhysRamTableEnd-DRAMPhysAddrA)
19
        CMPS    r9,r10                  ; reached end of table ?
        LDRNE   r0,[r9]
        TSTNE   r0,r0                   ; reached unused entries ?
        LDRNE   r1,[r9,#4]              ; or blanked-out entries ?
        TSTNE   r1,r1
        BEQ     %FT21                   ; .. all passed OK
        TSTS    r0,#PhysSpace
        ADDNE   r9,r9,#(DRAMPhysAddrB-DRAMPhysAddrA)
        BNE     %BT19                   ; this entry done .. find the next

        MOV     r8,r0                   ; report address of this block
        ADRL    r4,%BT4
        BL      ts_SendText

        LDR     r0,[r9]                 ; start testing it
        ADD     r0,r0,#PhysSpace
        LDR     r1,[r9, #4]
        STR     r0,[r9]                 ; mark block so it isn't retested
        MOV     r2,#PhysRamTable
        LDMIA   r2,{r3-r14}             ; save the PhysRamTable
        STMIA   r0,{r3-r14}
        BL      ts_RamTest
        LDMIA   r13,{r1-r11,r14}        ; restore the PhysRamTable
        MOV     r13,#PhysRamTable
        STMIA   r13,{r1-r11,r14}
        BEQ     %BT18                   ; if it passed, go look for another block

20
        FAULT32 #R_MEMFAILBIT,r2        ; failed - report fault address
        ADRL    r4,%BT2
        MOV     r11,r1                  ; Save failed data
        MOV     r8,r0                   ; first failing address
        BL      ts_SendText
        MOV     r4,r12                  ; get fault message
        MOV     r8,r11                  ; and fault data
        BL      ts_SendText
21

 [ MEMM_Type = "MEMC1"

;
; Test the CAMs - for each fitted MEMC, go through all the CAM entries
; remapping logical memory and testing against physical correspondence.
; Then try out the protection bits in each CAM entry and various
; processor modes.
; These tests return pointers to their own fault report strings.
;
        B       ts_CAMtest
        ROUT
1
        =       "CAMs :",0
2
        =       "PPLs :",0
3
        =       &89,"skipped",0
        ALIGN

ts_CAMtest
        LDR     r4,=%BT1
        BL      ts_SendText

        MOV_fiq r0,r12_fiq              ; skip this test if memory fault
        MOV     r1,#(R_LINFAILBIT :OR: R_MEMFAILBIT)
        ANDS    r0,r0,r1
        BEQ     %08
        LDR     r4,=%BT3
        BL      ts_MoreText
        B       %20

08
        BL      ts_CAM
        BEQ     %10
        BL      ts_SendText
        FAULT   #R_CAMFAILBIT
10
        LDR     r4,=%BT2
        BL      ts_SendText

        MOV_fiq r0,r12_fiq              ; skip this test if memory fault
        MOV     r1,#(R_LINFAILBIT :OR: R_MEMFAILBIT)
        ANDS    r0,r0,r1
        BEQ     %18
        LDR     r4,=%BT3
        BL      ts_MoreText
        B       %20
18
        BL      ts_memc_prot
        BEQ     %20
        BL      ts_SendText
        FAULT   #R_PROFAILBIT
20

 ]

;
; After testing memory and translation, turn MMU off again before running remainder
; of tests. This simplifies finishing up (where system must be put back into 26-bit
; mode before initialising RISCOS) if memory tests were deselected.
; Take care to poke the real translation table - it's been relocated to video
; RAM during the memory tests.
;

ts_restore_physical

  [ StrongARM_POST
    ;make sure ARM810 cache or StrongARM data cache is cleaned/flushed, because we are going to remap
        ARM_read_ID r5
        AND     r5,r5,#&F000
        CMP     r5,#&8000
        BNE     %FT22
;ARM810
;;;        ARM8_cleanflush_IDC r5  ;not implemented yet
        B       %FT24
22
        CMP     r5,#&A000
        BNE     %FT24
;StrongARM
;tricky...we'll read 16k of data in current ROM space, to act as clean and flush of current data
        MOV     r3,pc
        BIC     r3,r3,#31      ;32 byte aligned
        ARMA_clean_DC r3,r5,r7
24
  ] ;StrongARM_POST

        MOV     r5, pc                          ; obtain current address
        SUB     r5, r5,#PhysSpace               ; adjust to point to unmapped version
        MOV     r5, r5, LSR #20                 ; divide by 1MB
        MOV     r7, r5, LSL #20                 ; r7 = physical address of base of section
        ORR     r7, r7, #(AP_None * L1_APMult)
        ORR     r7, r7, #L1_Section
        MOV     r3, #VideoPhysAddr              ; find the copied translation table
        LDR     r3, [r3]
        ADD     r3, r3, #PhysSpace
        ADD     r3, r3, #DRAMOffset_L1PT
        STR     r7, [r3, r5, LSL #2]            ; store replacement entry in L1 (not U,C or B)

  [ StrongARM_POST
    ;flush cache if ARM 6/7 (ARM 8,StrongARM already sorted, above)
    ;flush TLB(s)
        ARM_read_ID r4
        AND      r4,r4,#&F000
        CMP      r4,#&8000   ;ARM 8?
        CMPNE    r4,#&A000   ;or StrongARM?
        MCRNE    ARM_config_cp,0,R0,ARM67_cacheflush_reg,C0,0   ;flush 6/7 cache
        MCRNE    ARM_config_cp,0,R0,ARM67_TLBflush_reg,C0,0     ;flush 6/7 TLB
        MCREQ    ARM_config_cp,0,R0,ARM8A_TLB_reg,C7,0          ;flush 8/StrongARM TLB(s)
  |
        SetCop  r7, CR_IDCFlush                 ; flush cache + TLB just in case
        SetCop  r7, CR_TLBFlush                 ; (data written is irrelevant)
  ]

; The ROM should now be mapped at the present address less PhysSpace, which is where it
; would be if the MMU were turned off.

        MOV     r4,#PhysSpace
        SUB     pc,pc,r4
        NOP                             ; this instruction is skipped

; now turn the MMU off, also ensures 26 bit mode, if ARM 6/7 (since P bit zero)
        MOV     r7, #MMUC_D
        SetCop  r7, CR_Control

  [ StrongARM_POST
        Ensure26bit_ARM8A r7
        MOV     r7, #MMUC_D    ;avoid corrupting r7, just in case
  ]

        B       ts_VIDCtest

;
; The VIDC tests check vertical blanking frequency in a fixed video
; mode and measure the time taken for sound DMA.
;

        ROUT

1
        =       "VIDC  :",0
2
        =       "Virq bad",&88,' ',&ff,'.',&ff,&ff,&ff,&ff,&ff,0
3
        =       "Sirq bad",&8B,&ff,&ff,&ff,&ff,&ff,0
4
        =       &8A,"Mid0 ",&ff,0

        ALIGN

ts_VIDCtest
        ADR     r4,%BT1
        BL      ts_SendText
        [ IO_Type = "IOMD"
        LDR     r0,=IOMD_MonitorType    ; Indicate monitor ID bit's value
        LDR     r0,[r0]
        AND     r0,r0,#IOMD_MonitorIDMask
        MOV     r8,r0,LSL #28
        ADR     r4,%BT4
        BL      ts_MoreText
        ]

 [ MorrisSupport
        MOV     r3, #IOMD_Base

        LDRB    r0, [r3, #IOMD_ID0]
        CMP     r0, #&E7
        LDRB    r0, [r3, #IOMD_ID1]
        CMPEQ   r0, #&D4                ; skip Virq test on Morris
        BNE     %FT10
 ]

        BL      ts_VIDC_period
        BEQ     %10
        ADR     r4,%B2
        MOV     r8, r0, LSL #8
        BL      ts_SendText             ; Display Virq fail msg
        FAULT   #R_VIDFAILBIT
10
        [ IO_Type = "IOMD"
  ; RCM thinks this is no longer needed - all IOMD's are issue two
  ;     besides, the test takes no account of Morris reusing the number space!
  ;      MOV     r3,#IOMD_Base           ; skip Sirq test on version 1 IOMD
  ;      LDRB    r0,[r3,#IOMD_VERSION]
  ;      CMPS    r0,#1
  ;      BEQ     %FT20
        ]
        BL      ts_SIRQ_period
        BEQ     %20
        ADR     r4,%B3
        MOV     r8, r0, LSL #12
        BL      ts_SendText             ; Display Sirq fail msg
        FAULT   #R_SNDFAILBIT
20
        MOV     r1,#ts_VIDCPhys         ; Restore full-screen
        ADRL    r2,TestVIDCTAB          ; border colour.
        [ IO_Type = "IOMD"
        LDR     r0,=IOMD_MonitorType
        LDR     r0,[r0]
        ANDS    r0,r0,#IOMD_MonitorIDMask
        ADDEQ   r2,r2,#(TestVVIDCTAB-TestVIDCTAB)
        ]
30      LDR     r0, [r2],#4
        CMP     r0, #-1
        STRNE   r0, [r1]
        BNE     %BT30
        LDR     r0,=C_ARMOK             ; set initial screen colour
        STR     r0, [r1]

        B       ts_ARMtype_test

;
; Read the ARM3 identification register.
; If memory tests failed, this won't be performed since the vector
; page must exist for error recovery on ARM2 systems.
;

        ROUT
1
        =       "ARM ID:",0
2
        =       "ARM ID",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0
3
        =       &89,"skipped",0

        ALIGN

ts_ARMtype_test

        ADR     r4,%BT1
        BL      ts_SendText

        MOV_fiq r0,r12_fiq              ; skip this test if memory fault
        LDR     r1,=((R_LINFAILBIT :OR: R_MEMFAILBIT) :OR: (R_CAMFAILBIT :OR: R_PROFAILBIT))
        ANDS    r0,r0,r1
        BEQ     %05
        ADR     r4,%BT3
        BL      ts_MoreText
        B       %08                     ; and quit

05
        BL      ts_ARM_type
        MOVS    r8, r0                  ; ready to display ID code
        ADR     r4,%BT2

        BEQ     %FT07                   ; ARM 2 : skip cache test
        FAULT   #R_ARM3                 ; not really a fault, just status
07
        BL      ts_SendText

08
        B       ts_Report



;
; Report the test results to the user
;
; If this was a forced test (test adapter fitted) then pause even when
; test passed : otherwise, pause only on error.
;

ts_passmsg
        =       "PASS  :",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0
ts_failmsg
        =       "FAIL  :",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0

ts_R00  &       00

ts_Report       ROUT
        MOV_fiq r7,r12_fiq              ; check for fault bits set
        LDR     r0,=R_STATUS
        BICS    r0,r7,r0

        ADREQ   r4, ts_passmsg          ; tests passed
        LDREQ   r9,=C_PASSED

        ADRNE   r4, ts_failmsg          ; tests failed
        LDRNE   r9,=C_FAULT

        LDR     r0,=ts_VIDCPhys         ; write the border colour
        STR     r9,[r0]

        MOV     r8,r7
        BL      ts_SendText             ; write the message and fault code

        ; if the test adapter is present, leave green screen awhile
        ; otherwise, wait only if there's a fault.

        LDR     r3,=ts_recover_time
00      ADDS    r3,r3,r3                ; 16-loop delay
        BCC     %B00                    ; - let the adapter recover
                                        ; from previous bus activity
        ADR     r2,ts_R00
        ORR     r2,r2,#ts_Alias_bits
        LDR     r3,[r2]
        MOV     r2,#-1
        ADDS    r3,r3,r2
        BCS     ts_Report_wait

        MOV_fiq r0,r12_fiq
        LDR     r2,=R_STATUS
        BICS    r0,r0,r2
        BEQ     ts_Hardstart

ts_Report_wait        ROUT

;
; Indicate fault found : Set the border to the fault colour and flash
; the disk LED, using the fault bitmap in r12_fiq to modulate the flashing.

ts_oldLED_on       *       &be0000         ; assert SEL0 and INUSE
ts_oldLED_off      *       &ff0000         ; on machines with 1772 controller
ts_oldLEDaddr      *       (ts_S5_base :OR: &40)

ts_710LED_on       *       &100000         ; assert SEL0 and MotorEN0
ts_710LED_off      *       &110000         ; on machines with 82C710 controller
ts_710LEDaddr      *       (ts_PCaddress :OR: (&3f2 :SHL: 2))

ts_665LED_on       *       &10          ; assert SEL0 and MotorEN0
ts_665LED_off      *       &11          ; on machines with 37665 controller
                                        ; and Medusa low-byte I/O world
ts_665LEDaddr      *       (ts_PCaddress :OR: (&3f2 :SHL: 2))


01      MOV_fiq r6,r12_fiq
        LDR     r2,=&11111111
        LDR     r7,=(35000 * 8)         ; 1/4 second pause loop count

        [ IO_Type = "IOMD"
        LDRNE   r1,=ts_665LEDaddr       ; set up for Medusa disc address
        MOVNE   r8,#ts_665LED_on
        MOVNE   r9,#ts_665LED_off
        |
        TST     r6, #R_IOEB             ; determine original / 710 disc controller
        LDREQ   r1,=ts_oldLEDaddr       ; set up for Archimedes disc address
        MOVEQ   r8,#ts_oldLED_on
        MOVEQ   r9,#ts_oldLED_off
        LDRNE   r1,=ts_710LEDaddr       ; set up for Brisbane disc address
        MOVNE   r8,#ts_710LED_on
        MOVNE   r9,#ts_710LED_off
        ]

02      MOV     r0,r7
03      SUBS    r0,r0,#1                ; pause for a 1/4 second
        BNE     %03

        MOV     r0,r8                   ; turn the LED on
        STR     r0,[r1]

        MOV     r0,r7
04      SUBS    r0,r0,#1                ; pause for a 1/4 second
        BNE     %04
        ADDS    r6,r6,r6                ; if a '1' is to be written,
        BCC     %06
        MOV     r0,r7,LSL #1            ; then pause another 1/2 second
05      SUBS    r0,r0,#1
        BNE     %05

06
        MOV     r0, r9                  ; turn the LED off
        STR     r0,[r1]

;
; Count down 32 bits. Every 4 bits, insert an extra pause to simplify
; reading the flashes.
;
        ADDS    r2,r2,r2
        BCC     %08
        MOV     r0,r7,LSL #2            ; then pause another second
05      SUBS    r0,r0,#1
        BNE     %05
08
        ANDS    r2,r2,r2                ; all the bits displayed now ?
        BNE     %02
        MOV_fiq r0,r12_fiq              ; restore the faultcode bits

        ANDS    r0,r0,#(R_EXTERN :OR: R_TESTED) ; If test adapter present,
        BNE     Reset                   ; repeat test forever

        B       CONT                    ; otherwise, run RISC OS

ts_Hardstart
        MOVS    r0,#R_HARD              ; and report a hard start
        B       CONT                    ; to RISC OS

;
; Tests skipped : fall into RISC-OS
;

ts_Self_test_end

        LDR     r1,=C_WARMSTART
        LDR     r0,=ts_VIDCPhys         ; write the border colour
        STR     r1,[r0]

ts_Softstart
        MOVS    r0,#R_SOFT              ; soft reset indicator
        B       CONT


        ROUT

;
; This table consists of a series of address/data pairs for IO
; initialization.
; Note that these addresses are likely to be in the IO world,
; and hence the data written is that from the MOST significant
; 16 bits of the data bus.
; An 'address' of -1 terminates the table.
;

ts_IOinitab
        [ IO_Type = "IOMD"
        |
        & ts_S5_base :OR: &10,  &000000         ; Printer port data
        & ts_S5_base :OR: &18,  &000000         ; FDC control & printer strobes
        & ts_S5_base :OR: &40,  &ff0000         ; FDD select lines
        & ts_S5_base :OR: &48,  &000000         ; VIDC clock control
        ]
        & (-1)





;
;
;---------------------------------------------------------------------------

        LTORG


; Include test modules executed by call, rather than inline

        GET     TestSrc.Mem2
        GET     TestSrc.Mem3
        GET     TestSrc.Mem4
        GET     TestSrc.Mem5
        GET     TestSrc.Vidc
        GET     TestSrc.Ioc
        GET     TestSrc.Cmos
        GET     TestSrc.Arm3

        END