1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
; 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.
;
; > MEMC2
; MEMC interface file - MEMC2 version
; Created by TMD 10-Aug-90
PhysRAML2PT * &02000000 + (512+64)*1024
; Synonyms
VInit * MEMC2Address + MEMC2_VINITe
VStart * MEMC2Address + MEMC2_VSTRTe
VEnd * MEMC2Address + MEMC2_VENDe
CInit * MEMC2Address + MEMC2_CINIT
; *****************************************************************************
;
; 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,r1"
CMP r1, #MEMCDAG_MaxReason
EXIT HI
ADR r14, DAGAddressTable
LDR r14, [r14, r1, LSL #2] ; load base address in MEMC2
MOV r1, r0, LSR #16 ; r1 is top 16 bits
EOR r0, r0, r1, LSL #16 ; and r0 is bottom 16 bits
BIC r0, r0, #&0F ; bits 0..3 must be clear
BIC r1, r1, #&F000 ; and bits 28..31 must be clear
STMIA r14, {r0, r1} ; atomic update (we believe)
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 - Update CAM entry and soft copy
;
; This part of the routine has to do more work on MEMC2
;
; First look in the CamEntries table to find the logical address L this physical page is
; currently allocated to. Then check in the Level 2 page tables to see if page L is currently
; at page R2. If it is, then map page L to be inaccessible, otherwise leave page L alone.
; Then map logical page R3 to physical page R2.
;
; in: r2 = physical page number
; r3 = logical address
; r9 = current MEMC1 control register (irrelevant on MEMC2)
; r11 = PPL
;
; out: r0, r1, r4, r6 corrupted
; r2, r3, r5, r7-r12 preserved
;
; NB Use of stack is allowed in this routine
BangCamUpdate ROUT
MOV r1, #0
LDR r1, [r1, #CamEntriesPointer]
LDR r0, [r1, r2, LSL #2] ; r0 = current logaddress + PPL for phys page r2
ORR r4, r3, r11, LSL #28 ; new entry for CamEntries
STR r4, [r1, r2, LSL #2] ; update
BIC r0, r0, #&F0000000 ; just get logical address
LDR r1, =PhysRAML2PT ; point to page tables
LDR r4, [r1, r0, LSR #11] ; get physical page + PPL for this logical page
TEQ r2, r4, LSR #3 ; see if still there
BNE %FT10 ; if not there, then just put in new page
Push "r3, r14"
MOV r3, r0 ; map out old page at this logical address
MOV r0, #0 ; physical page 0 but PPL(MEMC2)=0 ie no access, not even for me!
BL BangL2PT ; map page out
Pull "r3, r14"
10
; and drop thru to ...
; **************************************************************************************
;
; BangCam - Update CAM entry, but not soft copy
;
; This routine maps a physical page to a given logical address
; For MEMC2, I assume that the physical page was previously not mapped
; anywhere else - on MEMC1 it would automatically unmap any logical
; address that the physical page was previously at, but on MEMC2 it won't
;
; in: r2 = physical page number
; r3 = logical address
; r9 = current MEMC1 control register (irrelevant on MEMC2)
; r11 = PPL
;
; out: r0, r1, r4, r6 corrupted
; r2, r3, r5, r7-r12 preserved
;
; NB Can't use stack - there might not be one!
BangCam
ADR r0, PPLTrans ; translate MEMC1 PPL to MEMC2 PPL
LDRB r0, [r0, r11]
ORR r0, r0, r2, LSL #3 ; value to store in level 2 page table
; is PPL :OR: (phys page number << 3)
LDR r1, =PhysRAML2PT ; point to level 2 page tables
BangL2PT ; internal entry point used only by BangCamUpdate
BICS r4, r3, #(3 :SHL: 11) ; ensure going to be on word boundary (EQ => logical page zero)
STR r0, [r1, r4, LSR #11] ; update level 2 page table
MOV r6, #MEMC2Address
STREQ r0, [r6, #MEMC2_SuperPageZero] ; if logical page 0 then update special entry
MOV r0, #0 ; now flush the TLB
STR r0, [r6, #MEMC2_Flush]
MOV pc, lr
PPLTrans
= 6 ; R any W any
= 3 ; R any W sup
= 2 ; R sup W sup
= 2 ; R sup W sup
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]
; We now have to mimic the relevant bits of the MEMC1 control register
;
; bits 0,1 => unused
; bits 2,3 => page size, irrelevant since always 8K
; bits 4,5 => low ROM access time, irrelevant since this has to be fixed
; bits 6,7 => hi ROM access time, -----------------""------------------
; bits 8,9 => DRAM refresh control, irrelevant (refresh must always be on)
; bit 10 => Video/cursor DMA enable, corresponds to bit venbe of VATT
; (and possibly bit venbo of IATT for interlaced displays)
; Unfortunately VATT (and IATT) is a write-only register. Later on
; we might have a soft copy of these, but for now just write whole
; register.
; bit 11 => Sound DMA enable, ignore for now
; bit 12 => OS mode, ignore
; Program all of VATT
;
; vdis = 0 (don't disable DMA after one buffer)
; venbe = (bit 10 of r11)
; vrnw = 1 (read from RAM, not write)
; vmske = 0 (no interrupts at end of buffer)
MOV r12, # (0 * VATT_vdis) + (0 * VATT_venbe) + (1 * VATT_vrnw) + (0 * VATT_vmske)
TST r11, # (1 :SHL: 10)
ORRNE r12, r12, # VATT_venbe
MOV r10, #MEMC2Address
STR r12, [r10, #MEMC2_VATT]
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.
;
; On MEMC2 it also has to avoid the pages where the level 2 page tables are
;
; 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 r11, #0
MOV r4, #PhysRam
CMP r13, #512*1024
ADDEQ r10, r4, #(512-64)*1024 ; get address that's logram 0
ADDNE r10, r4, #512*1024
ADD r13, r13, #PhysRam ; end of memory
ADD r12, r4, #PhysRAML2PT-PhysRam
ADD r4, r4, #4*8 ; skip minimal startup workspace
10
CMP r4, r10
ADDEQ r4, r4, #4*8 ; skip physram that's logram 0
CMP r4, r12
ADDEQ r4, r4, #32*1024 ; skip 32K of L2PT
STMNEIA r4!, {r0-r3}
CMP r4, 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
MOV r0, # MEMC2Address
MOV r1, # Control_romfast
STR r1, [r0, #MEMC2_Control] ; make ROMS go fast
ADR r1, ClockTimingTable ; initialise CLK block
LDMIA r1, {r2-r5}
ADD r1, r0, #MEMC2_clkj0
STMIA r1, {r2-r5}
ADR r1, DRAMTimingTable ; initialise DRAM block
LDMIA r1, {r2-r8}
ADD r1, r0, #MEMC2_rwt0
STMIA r1, {r2-r8}
LDR r1, rtype_value
STR r1, [r0, #MEMC2_rtype]
LDR r1, refr_value
STR r1, [r0, #MEMC2_refr]
MOV r1, # (PhysRAML2PT-PhysRam)/(8*1024) ; level 1 entry (paged) for 0..16M
MOV r2, # (PhysRAML2PT+8*1024-PhysRam)/(8*1024) ; level 1 entry (paged) for 16M..32M
MOV r3, # Prot_UrwSRW+(L1D_RAM :SHL: 3)+(L1D_RAM :SHL: 5)+(L1D_RAM :SHL: 7)+(L1D_RAM :SHL: 9)+(0 :SHL: 11)
; level 1 entry (direct) for 32M..48M (all RAM, base 0)
LDR r4, = Prot_URwSRW+(L1D_IO :SHL: 3)+(L1D_PROG :SHL: 5)+(L1D_ROM :SHL: 7)+(L1D_ROM :SHL: 9)+(0 :SHL: 11)
; level 1 entry (direct) for 48M..64M (IO,PROG,ROM,ROM)
ADD r5, r0, #MEMC2_Level1+L1_Paged+L1_Sec0
ADD r6, r5, #4*2*16 ; cycle thru all 4 bus masters and (USR,SPV)
ADD r7, r5, #(L1_Direct+L1_Sec2)-(L1_Paged+L1_Sec0)
10
STMIA r5, {r1,r2} ; set up the paged sections 0,1
STMIA r7, {r3,r4} ; set up the direct sections 2,3
ADD r5, r5, #16
ADD r7, r7, #16
TEQ r5, r6 ; have we got to the end ?
BNE %BT10
; Now turn on the translation, but don't set up the level 2 page tables until later,
; when we know the DRAM multiplex option
LDR r1, = Control_ton + Control_l1on + Control_romfast
STR r1, [r0, #MEMC2_Control]
; now set up VINC
MOV r1, #&10 ; low bits
MOV r2, #&00 ; high bits
ADD r3, r0, #MEMC2_VINC
STMIA r3, {r1,r2}
MOV pc, lr
ClockTimingTable
J0 & &F200 ; 3 / 2
J1 & &F200 ; 3 / 2
RSPEED & &1C00 ; 3 / 3
ISPEED & &B800 ; 2.5 / 2.5
DRAMTimingTable
RWT0 & &2A320
RRD0 & &2AC80
RSQ0 & &0B200
B0Dummy & 0
RWT1 & &2A320
RRD1 & &2AC80
RSQ1 & &0B200
rtype_value & &3333 ; Bank Type [x,bank,s1,s0] * 4 ; set largest memory type by default
refr_value & &1086 ; Enable refresh, refresh length = 10 hclk ticks, refresh period = 12us
; -> 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
[ {TRUE} ; now work on different configurations, but only bank zero
MOV r7, lr
; first find out appropriate rtype value
; initial routine has set DRAM type to 3
MOV r0, #PhysRam
ADD r1, r0, #A9 ; if A9 ghosts
BL DistinctAddresses
MOVNE r0, #2_00 ; then type 00
BNE %FT10
ADD r1, r0, #A11 ; else if A11 ghosts
BL DistinctAddresses
MOVNE r0, #2_01 ; then type 01
BNE %FT10
ADD r1, r0, #A12 ; else if A12 ghosts
BL DistinctAddresses
MOVNE r0, #2_01 ; then type 01
MOVEQ r0, #2_11 ; else type 11
10
LDR r1, rtype_value
BIC r1, r1, #2_11
ORR r1, r1, r0
MOV r0, #MEMC2Address
STR r1, [r0, #MEMC2_rtype]
; having set up the DRAM multiplexing correctly, we can now zap the L2PT
; to no access for any page
LDR r1, =PhysRAML2PT
ADD r2, r1, #2*8*1024 ; two L2PT tables at the moment
MOV r3, #0 ; page 0, no access
MOV r4, #0
MOV r5, #0
MOV r6, #0
15
STMIA r1!,{r3-r6}
TEQ r1, r2
BNE %BT15
STR r3, [r0, #MEMC2_SuperPageZero] ; don't forget super page zero
; now find out the memory size
MOV r0, #PhysRam
MOV r6, #256*1024
20
ADD r1, r0, r6
BL DistinctAddresses ; try next address line
BNE %FT30 ; if ghosts or not there then finish
MOV r6, r6, LSL #1
CMP r6, #16*1024*1024 ; give up if we've got 16MBytes or more
BCC %BT20
30
MOV r1, r6
LDR r2, ResetMemC_Value
BIC r2, r2, #&C
ORR r2, r2, #Page8K
MOV r0, #8*1024 ; fixed 8K page size
MOV pc, r7
|
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
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
;
A0 * 1 :SHL: 00
A1 * 1 :SHL: 01
A2 * 1 :SHL: 02
A3 * 1 :SHL: 03
A4 * 1 :SHL: 04
A5 * 1 :SHL: 05
A6 * 1 :SHL: 06
A7 * 1 :SHL: 07
A8 * 1 :SHL: 08
A9 * 1 :SHL: 09
A10 * 1 :SHL: 10
A11 * 1 :SHL: 11
A12 * 1 :SHL: 12
A13 * 1 :SHL: 13
A14 * 1 :SHL: 14
A15 * 1 :SHL: 15
A16 * 1 :SHL: 16
A17 * 1 :SHL: 17
A18 * 1 :SHL: 18
A19 * 1 :SHL: 19
A20 * 1 :SHL: 20
A21 * 1 :SHL: 21
A22 * 1 :SHL: 22
A23 * 1 :SHL: 23
A24 * 1 :SHL: 24
A25 * 1 :SHL: 25
A26 * 1 :SHL: 26
A27 * 1 :SHL: 27
A28 * 1 :SHL: 28
A29 * 1 :SHL: 29
A30 * 1 :SHL: 30
A31 * 1 :SHL: 31
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, bit 16 => can do STM to I/O (ie MEMC1a, MEMC2), bit 17 => MEMC2
ncpuloops * 1024 ; don't go longer than 4ms without refresh !
nmulloops * 128
TimeCPU ROUT
[ {TRUE}
; fudge it for now
LDR r7, =6000 + (3 :SHL: 16) ; pretend 6MHz system, and MEMC2
MOV pc, lr
|
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