; Copyright 1996 Acorn Computers Ltd ; ; Licensed under the Apache License, Version 2.0 (the "License"); ; you may not use this file except in compliance with the License. ; You may obtain a copy of the License at ; ; http://www.apache.org/licenses/LICENSE-2.0 ; ; Unless required by applicable law or agreed to in writing, software ; distributed under the License is distributed on an "AS IS" BASIS, ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ; See the License for the specific language governing permissions and ; limitations under the License. ; ; > MEMC1 ; MEMC interface file - MEMC1 version ; Created by TMD 10-Aug-90 VInit * &03600000 VStart * &03620000 VEnd * &03640000 CInit * &03660000 ; SStart * &03680000 ; SEnd * &036A0000 ; SPtr * &036C0000 ; ***************************************************************************** ; ; SetDAG - Program DMA address generator R1 with physical address R0 ; ; in: r0 = physical address ; r1 = index of DMA address generator to program, as defined in vdudecl ; ; out: All registers preserved, operation ignored if illegal ; SetDAG ENTRY "r0" CMP r1, #MEMCDAG_MaxReason EXIT HI ADR r14, DAGAddressTable LDR r14, [r14, r1, LSL #2] ; load base address in MEMC1 MOV r0, r0, LSR #4 ; bottom 4 bits irrelevant CMP r0, #(1 :SHL: 15) ; ensure in range ORRCC r14, r14, r0, LSL #2 STRCC r14, [r14] ; any old data will do EXIT GBLA DAGIndex DAGIndex SETA 0 MACRO DAGTab $reason, $address ASSERT ($reason)=DAGIndex & $address DAGIndex SETA DAGIndex + 1 MEND DAGAddressTable DAGTab MEMCDAG_VInit, VInit DAGTab MEMCDAG_VStart, VStart DAGTab MEMCDAG_VEnd, VEnd DAGTab MEMCDAG_CInit, CInit ;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; CAM manipulation utility routines BangCamUpdate ROUT ; R2 = CAM entry no ; R3 = logaddr ; R9 = current MEMC value ; R11 = PPL ; set and update tables MOV R4, #0 LDR R4, [R4, #CamEntriesPointer] ORR r0, r3, r11, LSL #28 ; top nibble is PPL STR r0, [R4, R2, LSL #2] BangCam ; r0 corrupted ; r1 corrupted ; R2 = CAM entry no ; R3 = logaddr ; r4 corrupted ; r5 spare! ; r6 corrupted ; r7, r8 spare ; R9 = current MEMC value ; r10 spare ; R11 = PPL ; r12 spare AND R4, R9, #&C ; pagesize ADR R0, PageMangleTable LDR R0, [R0, R4] ; load data table pointer MOV R4, #0 01 LDR R1, [R0], #4 CMP R1, #-1 BEQ %FT02 AND R6, R2, R1 LDR R1, [R0], #4 CMP R1, #0 RSBMI R1, R1, #0 ORRPL R4, R4, R6, LSL R1 ORRMI R4, R4, R6, LSR R1 B %BT01 02 LDR R1, [R0], #4 CMP R1, #-1 BEQ %FT03 AND R6, R3, R1 LDR R1, [R0], #4 CMP R1, #0 RSBMI R1, R1, #0 ORRPL R4, R4, R6, LSL R1 ORRMI R4, R4, R6, LSR R1 B %BT02 03 ORR R4, R4, #CAM ORR R4, R4, R11, LSL #8 ; stuff in PPL STR R4, [R4] ; and write it MOV PC, LR ; Data to drive CAM setting PageMangleTable & PageMangle4K & PageMangle8K & PageMangle16K & PageMangle32K ; For each page size, pairs of masks and shift factors to put the bits in the ; right place. Two sets: operations on Physical Page Number, operations on ; Logical Page Number. ; Shifts are Shift Left values (<<). Each section terminated by -1 PageMangle4K ; PPN: & 2_011111111 & 0 ; bits in right place & -1 ; LPN: & 2_1100000000000:SHL:12 & (11-12)-12 ; LPN[12:11] -> A[11:10] & 2_0011111111111:SHL:12 & (22-10)-12 ; LPN[10:0 ] -> A[22:12] & -1 PageMangle8K ; PPN: & 2_010000000 & 7-7 ; PPN[7] -> A[7] & 2_001000000 & 0-6 ; PPN[6] -> A[0] & 2_000111111 & 6-5 ; PPN[5:0] -> A[6:1] & -1 ; LPN: & 2_110000000000:SHL:13 & (11-11)-13 ; LPN[11:10] -> A[11:10] & 2_001111111111:SHL:13 & (22-9)-13 ; LPN[9:0] -> A[22:13] & -1 PageMangle16K ; PPN: & 2_010000000 & 7-7 ; PPN[7] -> A[7] & 2_001100000 & 1-6 ; PPN[6:5] -> A[1:0] & 2_000011111 & 6-4 ; PPN[4:0] -> A[6:2] & -1 ; LPN: & 2_11000000000:SHL:14 & (11-10)-14 ; LPN[10:9] -> A[11:10] & 2_00111111111:SHL:14 & (22-8)-14 ; LPN[8:0] -> A[22:14] & -1 PageMangle32K ; PPN: & 2_100000000 & 12-8 ; PPN[8] -> A[12] & 2_010000000 & 7-7 ; PPN[7] -> A[7] & 2_001000000 & 1-6 ; PPN[6] -> A[1] & 2_000100000 & 2-5 ; PPN[5] -> A[2] & 2_000010000 & 0-4 ; PPN[4] -> A[0] & 2_000001111 & 6-3 ; PPN[3:0] -> A[6:3] & -1 ; LPN: & 2_1100000000:SHL:15 & (11-9)-15 ; LPN[9:8] -> A[11:10] & 2_0011111111:SHL:15 & (22-7)-15 ; LPN[7:0] -> A[22:15] & -1 PageSizes & 4*1024 ; 0 is 4K & 8*1024 ; 4 is 8K & 16*1024 ; 8 is 16 & 32*1024 ; C is 32 PageShifts = 12, 13, 0, 14 ; 1 2 3 4 = 0, 0, 0, 15 ; 5 6 7 8 ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; SWI OS_UpdateMEMC: Read/write MEMC1 control register SSETMEMC ROUT AND r10, r0, r1 MOV r12, #0 TEQP pc, #SVC_mode+I_bit+F_bit LDR r0, [r12, #MEMC_CR_SoftCopy] ; return old value BIC r11, r0, r1 ORR r11, r11, R10 BIC r11, r11, #&FF000000 BIC r11, r11, #&00F00000 ORR r11, r11, #MEMCADR STR r11, [r12, #MEMC_CR_SoftCopy] STR r11, [r11] TEQP pc, #SVC_mode+I_bit ExitSWIHandler ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; ; ClearPhysRAM - Routine to clear "all" memory ; ; While this routine is running, keyboard IRQs may happen. For this reason ; it avoids LogRAM 0..31 (where hardware IRQ vector is) and PhysRAM ; 0..31 where the IRQ workspace is. ; ; r7 contains memory speed and must be preserved ; r8 contains page size and must be preserved ; r9 contains MEMC control register and must be preserved ; ClearPhysRAM ROUT MOV r0, #0 MOV r1, #0 MOV r2, #0 MOV r3, #0 MOV r4, #0 MOV r5, #0 MOV r6, #0 MOV r11, #0 MOV r12, #PhysRam CMP r13, #512*1024 ADDEQ r10, r12, #(512-64)*1024 ; get address that's logram 0 ADDNE r10, r12, #512*1024 ADD r13, r13, #PhysRam ; end of memory ADD r12, r12, #4*8 ; skip minimal startup workspace 10 CMP r12, R10 ADDEQ r12, r12, #4*8 ; skip physram that's logram 0 STMNEIA r12!, {r0-r6, r11} CMP r12, r13 BNE %BT10 SUB r13, r13, #PhysRam LDR r0, =OsbyteVars + :INDEX: LastBREAK MOV r1, #&80 STRB r1, [r0] ; flag the fact that RAM cleared MOV pc, lr ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; ; InitMEMC - Initialise memory controller ; InitMEMC ROUT LDR R0, ResetMemC_Value STR R0, [R0] ; set ROM access times, refresh on flyback, no DMA MOV pc, lr ; -> 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 ; ; NOTE: Routines MemSize and TimeCPU are called by the power-on test software, ; so their specifications MUST not change. ; ; 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 ;-------------------------------------------------------------------- ; 16MByte 32k 4*32*1Mx1 A13,A20,A21,A22,A23,A23.5 distinct ; 16MByte 32k 16*8*256kx4 A13,A20,A21,A22,A23,A23.5 distinct ; ; 12MByte 32k 3*32*1Mx1 A13,A20,A21,A22,A23 OK, A23.5 fail ; 12MByte 32k 12*8*256kx4 A13,A20,A21,A22,A23 OK, A23.5 fail ; ; 8MByte 32k 2*32*1Mx1 A13,A20,A21,A22 distinct, A23 fail ; 8MByte 32k 8*8*256kx4 A13,A20,A21,A22 distinct, A23 fail ; ; 4Mbyte 32k 32*1Mx1 A13,A21,A20 distinct, A22,A23 fail ; 4Mbyte 32k 4*8*256kx4 A13,A21,A20 distinct, A22,A23 fail ; ; 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,A20,A12 fail, A19,A18 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 MOVNE r0, #Page32K MOVNE r1, #2048*1024 BNE MemSizeDone MOV r0, #PhysRam ADD r1, r0, #4*1024*1024 BL DistinctAddresses MOVNE r0, #Page32K MOVNE r1, #4*1024*1024 BNE MemSizeDone MOV r0, #PhysRam ADD r1, r0, #8*1024*1024 BL DistinctAddresses MOVNE r0, #Page32K MOVNE r1, #8*1024*1024 BNE MemSizeDone MOV r0, #PhysRam ADD r1, r0, #12*1024*1024 BL DistinctAddresses MOV r0, #Page32K MOVNE r1, #12*1024*1024 MOVEQ r1, #16*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 ADR r3, PageSizes LDR r0, [r3, r0] ; r0 = convert from page size indicator into actual page size (in bytes) 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 lr, lr, #Z_Flag BICNE lr, lr, #Z_Flag MOVS pc, lr 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 ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ END