; -> MemSize

; (non-destructive) algorithm to determine MEMC RAM configuration
;
; Dave Flynn and Alasdair Thomas
; 17-March-87
;
; Spooling checkered by NRaine and SSwales !
; 8MByte check bodged in by APT
;
; Set MEMC for 32-k page then analyse signature of possible
; external RAM configurations...
; The configurations are:
;
; Ram Size    Page Size    Configuration    (Phys RAM) Signature
;--------------------------------------------------------------------
;   4Mbyte      32k          32*1Mx1         A13,A21,A20 distinct
;   4Mbyte      32k         4*8*256kx4       A13,A21,A20 distinct
;
;   2Mbyte      32k    expandable 2*8*256kx4 A13,A20 distinct, A21 fails
;   2Mbyte      16k      fixed 2*8*256kx4    A13,A21 distinct, A20 fails
;   
;   1Mbyte       8k          32*256kx1       A13,A20 fail, A19,A18,A12 distinct
;   1Mbyte       8k           8*256kx1       A13,A20 fail, A19,A18,A12 distinct
;   1Mbyte       8k          4*8*64kx4       A13,A20 fail, A19,A18,A12 distinct
;
; 512Kbyte       8k    expandable 2*8*64kx4  A13,A20,A19 fail, A12,A18 distinct
; 512Kbyte       4k      fixed 2*8*64kx4     A13,A21,A12 fail, A21,A19 distinct
;
; 256Kbyte       4K           8*64kx4        A13,A20,A12,A18 fail, A21,A19 ok  
; 256Kbyte       4K          32*64kx1        A13,A20,A12,A18 fail, A21,A19 ok  
;

Z_Flag     * &40000000

; MemSize routine... enter with 32K pagesize set
; R0 returns page size
; R1 returns memory size
; R2 returns value set in MEMC
; uses R3-R7

MemSize ROUT
        MOV   r7, lr
        MOV   R0,#PhysRam
        ADD   R1,R0,#A13
        BL    DistinctAddresses
        BNE   %10
        ADD   R1,R0,#A21
        BL    DistinctAddresses
        MOV   R0,#Page32K
        MOVNE R1,#2048*1024
        BNE   MemSizeDone

        MOV   r0,#PhysRam
        ADD   r1, r0, #4*1024*1024
        BL    DistinctAddresses
        MOV   R0,#Page32K
        MOVEQ r1, #8*1024*1024
        MOVNE r1, #4*1024*1024

        B     MemSizeDone
10      ADD   R1,R0,#A20
        BL    DistinctAddresses
        BNE   %20
        MOV   R0,#Page16K
        MOV   R1,#2048*1024
        B     MemSizeDone
20      ADD   R1,R0,#A19
        BL    DistinctAddresses
        BEQ   %30
        MOV   R0,#Page8K
        MOV   R1,#512*1024
        B     MemSizeDone
30      ADD   R1,R0,#A18
        BL    DistinctAddresses
        BEQ   %40
        MOV   R0,#Page4K
        MOV   R1,#256*1024
        B     MemSizeDone
40      ADD   R1,R0,#A12
        BL    DistinctAddresses
        BEQ   %50
        MOV   R0,#Page4K
        MOV   R1,#512*1024
        B     MemSizeDone
50      MOV   R0,#Page8K
        MOV   R1,#1024*1024

MemSizeDone
        LDR    R2, ResetMemC_Value
        BIC    R2, R2, #&C
        ORR    R2, R2,R0
        STR    R2, [R2]                        ; set MEMC to right state
        MOV    pc, r7


; DistinctAddresses routine...
; R0,R1 are the addresses to check
; uses R2-5
; writes interleaved patterns (to prevent dynamic storage...)
; checks writing every bit low and high...
; return Z-flag set if distinct
DistinctAddresses ROUT
        LDR     R2,[R0] ; preserve
        LDR     R3,[R1]
        LDR     R4,Pattern
        STR     R4,[R0] ; mark first
        MOV     R5,R4,ROR #16
        STR     R5,[R1] ; mark second
        LDR     R5,[R0]
        CMP     R5,R4 ; check first
        BNE     %10   ; exit with Z clear
        LDR     R5,[R1] ; check second
        CMP     R5,R4,ROR #16 ; clear Z if not same
        BNE     %10
; now check inverse bit writes
        STR     R4,[R1] ; mark second
        MOV     R5,R4,ROR #16
        STR     R5,[R0] ; mark first
        LDR     R5,[R1]
        CMP     R5,R4 ; check second
        BNE     %10   ; exit with Z clear
        LDR     R5,[R0] ; check first
        CMP     R5,R4,ROR #16 ; clear Z if not same
10      STR     R3,[R1] ; restore
        STR     R2,[R0]
        ORREQ   R14,R14,#Z_Flag
        BICNE   R14,R14,#Z_Flag
        MOVS    PC,R14

Pattern
        &       &AAFF5500 ; shiftable bit check pattern

; init state with masked out page size

ResetMemC_Value
        & &E010C :OR: MEMCADR       ; slugged ROMs + flyback refresh only + 32K page

; Constants
;
A21 * 1:SHL:21
A20 * 1:SHL:20
A19 * 1:SHL:19
A18 * 1:SHL:18
A13 * 1:SHL:13
A12 * 1:SHL:12

Page32K * &C ; in MEMC control reg patterns...
Page16K * &8
Page8K  * &4
Page4K  * &0


; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; In    r0-r6 trashable
;       r9 = Current MEMC CR

; Out   r9 MEMC value with slowest ROM speed, correct pagesize
;       r7 processor speed in kHz, tbs -> MEMC1a

ncpuloops * 1024 ; don't go longer than 4ms without refresh !
nmulloops * 128

TimeCPU ROUT

        BIC     r9, r9, #3 :SHL: 8
        STR     r9, [r9]                ; turn off refresh for a bit

; Time CPU/Memory speed

        LDR     r1, =&7FFE              ; 32K @ 2MHz = ~16ms limit
        MOV     r3, #IOC

        MOV     r0, r1, LSR #8
        STRB    r1, [r3, #Timer1LL]
        STRB    r0, [r3, #Timer1LH]
        LDR     r0, =ncpuloops
        STRB    r0, [r3, #Timer1GO]     ; start the timer NOW
        B       %FT10                   ; Looks superfluous, but is required
                                        ; to get ncpuloops pipeline breaks

10      SUBS    r0, r0, #1              ; 1S
        BNE     %BT10                   ; 1N + 2S

        STRB    r0, [r3, #Timer1LR]     ; latch count NOW
        LDRB    r2, [r3, #Timer1CL]
        LDRB    r0, [r3, #Timer1CH]
        ADD     r2, r2, r0, LSL #8      ; count after looping is ...

        SUB     r2, r1, r2              ; decrements !
        MOV     r2, r2, LSR #1          ; IOC clock decrements at 2MHz

; Time CPU/MEMC Multiply time

        MOV     r4, #-1                 ; Gives worst case MUL

        MOV     r0, r1, LSR #8
        STRB    r1, [r3, #Timer1LL]
        STRB    r0, [r3, #Timer1LH]
        LDR     r0, =nmulloops
        STRB    r0, [r3, #Timer1GO]     ; start the timer NOW
        B       %FT20                   ; Looks superfluous, but is required
                                        ; to get nmulloops pipeline breaks

20      MUL     r5, r4, r4              ; 1S + 16I
        MUL     r5, r4, r4              ; 1S + 16I
        SUBS    r0, r0, #1              ; 1S
        BNE     %BT20                   ; 1N + 2S

        STRB    r0, [r3, #Timer1LR]     ; latch count NOW
        LDRB    r4, [r3, #Timer1CL]
        LDRB    r0, [r3, #Timer1CH]
        ADD     r4, r4, r0, LSL #8      ; count after looping is ...

        SUB     r4, r1, r4              ; decrements !
        MOV     r4, r4, LSR #1          ; IOC clock decrements at 2MHz

        ORR     r9, r9, #1 :SHL: 8      ; set refresh on flyback
        STR     r9, [r9]                ; restore MEMC state a.s.a.p.

; In ROM - each cpu loop took 4R cycles @ 8/f*500ns/cycle

        LDR     r0, =4*(8*500/1000)*ncpuloops*1000
        DivRem  r7, r0, r2, r1          ; r2 preserved
        MOV     r0, #&80                ; At 8 MHz and below, run fast ROMs
        LDR     r1, =8050               ; Over 8 MHz, need medium ROMs
        CMP     r7, r1
        MOVHI   r0, #&40
        LDR     r1, =13000              ; Over 13 MHz, need slowest ROMs
        CMP     r7, r1
        MOVHI   r0, #&00
        ORR     r9, r9, r0
        STR     r9, [r9]                ; Set ROM speed appropriately

 ASSERT ncpuloops = 8*nmulloops ; for given ratio cutoff <------------

        MOV     r4, r4, LSL #10         ; *1024 to get resolution on divide
        DivRem  r0, r4, r2, r1
        LDR     r1, =1100               ; Cutoff point; MEMC1 longer than this
        CMP     r0, r1
        ORRLO   r7, r7, #1 :SHL: 16     ; Note MEMC1a prescence

        MOV     pc, lr

; Typical figures give (in ROM at 8MHz):

; MEMC1  2048 CPU, 2432 MEMC -> MUL ratio 1216
; MEMC1a 2048       864                    432

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

        LNK    Middle
