OXYGENHUB
◆ main openmsx / doc / internal / r800test.txt
23.5 KiB · Plain Text · last changed chore(): initial commit 1 month ago source blame history raw
1
2
3
The test program, in short:
4
  Execute the same instruction (or short instruction sequence) number of
5
  times and use the E6 timer to measure how long it took.
6
7
The E6 timer has a resolution of 255682Hz (3579545Hz / 14). R800 runs at
8
7159090Hz (2 * 3579545Hz). So the timer ticks once every 28 R800 ticks.
9
10
11
-----------------------------------------------
12
13
	org	#c000
14
15
start	equ	#0100
16
17
	ld	de,start
18
	ld	hl,begin
19
	ld	bc,begin1-begin
20
	ldir
21
	push	de
22
	ld	hl,loop
23
	ld	bc,loop1-loop
24
	ldir
25
	pop	hl
26
	ld	bc,(20000-1)*(loop1-loop) ; number varies depending on
27
	ldir                              ; length of the test-sequence
28
	ld	hl,end
29
	ld	bc,end1-end
30
	ldir
31
	jp	start
32
33
begin	di
34
	out	(#e6),a
35
begin1
36
37
loop	muluw   hl,bc                     ; test sequence
38
loop1
39
40
end	in	a,(#e6)
41
	ld	l,a
42
	in	a,(#e7)
43
	ld	h,a
44
	ei
45
	ret
46
end1
47
48
-----------------------------------------------
49
50
51
Below are the results, it's formatted like this
52
53
  ----------------------------------------------
54
  [ prologue ]
55
  instruction-sequence  [ repeat-count ]
56
    result: <raw-result>
57
    cycles: <cycles>  [ instruction break-down ]
58
    notes:
59
  ----------------------------------------------
60
61
Prologue are extra setup instructions, they are only executed once, only a few
62
test have them
63
64
Instruction-sequence is the actual instruction that's been tested. Mostly this
65
is a single instruction, but sometimes there is a pair of instructions.
66
67
repeat-count indicates how many times the instruction-sequence is repeated.
68
I tried to repeat the instruction as much as possible. But to fit longer
69
instruction sequences (longer in number of opcode bytes) in memory, the
70
repeat count is sometimes reduced.
71
72
raw-result: this is the value of the E6 timer at the end of the test. Note
73
that you cannot directly compare this number to other test because other
74
test might have a different repeat-count.
75
76
cycles: here I calculated the number of cycles required per
77
'instruction-sequence'-iteration. I calculated this by comparing the result
78
to the 'nop' instruction (a nop takes 1 cycle). Note that the duration
79
of most instructions in almost never exactly an integer multiple of the
80
duration of the nop instruction. A possible explanation might be the
81
refresh (only happens at the end of an instruction, so for longer instructions
82
the chance of a refresh is relatively less). But we need additional test to
83
fully explain the refresh behaviour.
84
85
Instruction break-down: Here I tried to split the instruction into micro-ops.
86
I used the following notation:
87
  f  opcode fetch, no page-break, takes 1 cycle
88
  r  data read,    no page-break, takes 1 cycle
89
  w  data write,   no page-break, takes 1 cycle
90
  F  opcode fetch,    page-break, takes 2 cycles
91
  R  data read,       page-break, takes 2 cycles
92
  W  data write,      page-break, takes 2 cycles
93
  x  extra cycle (for various stuff)
94
  i  IO
95
96
97
---------------------------------------------------------------
98
99
100
101
* Instructions that don't do additional bus transactions (read, write, IO).
102
103
nop  [x 40000]
104
  result:           1629-1645
105
  openmsx-rev11643: 1637-1638
106
  cycles: 1  [f]
107
108
add hl,bc  [x 40000]
109
  result:           1633-1645
110
  openmsx-rev11643: 1637-1638
111
  cycles: 1  [f]
112
113
cpl  [x 40000]
114
  result:  varies between 1628-1647, most often around 1638
115
  openmsx-rev11643: 1637-1638
116
  cycles: 1  [f]
117
  note: same result for cpl, daa, ccf, scf, exx, ex af,af', ld sp,hl, rrca, ...
118
119
neg  [x 20000]
120
  result:           1637  (most often 1637, sometimes 1638)
121
  openmsx-rev11643: 1643-1645
122
  cycles: 2  [ff]
123
  note: - measurement on real HW is MUCH more stable for this test compared to
124
          previous tests
125
        - same result for ld {a,i,r},{a,i,r}
126
        - all results below for the real HW probably vary as well, though in
127
          my initial tests on the real HW I only noted the most often
128
          occuring value. I should re-test, but that's a lot of work.
129
130
im 0/1/2  [x 20000]
131
  result:           2453-2360, most often 2456
132
  openmsx-rev11643: 2459-2460
133
  cycles: 2  [ffx]
134
135
di  [x 40000]
136
  result:           3267
137
  openmsx-old:      3267
138
  openmsx-rev11643: 3273-3274
139
  cycles: 2  [fx]
140
  note: I added 'openmsx-old' tags where older openmsx revisions were better
141
        (possibly by accident) than the current revision.
142
143
ei  [x 40000]   (VDP irq disabled)
144
  result:           1435 (!)
145
  openmsx-rev11643: 1434-1436
146
  cycles: 1  [f]
147
  note: This is faster than nop!!
148
        Both instructions are one cycle, but it seems there's no refresh delay
149
        after a 'ei' instructions. At least with this assumption the theory
150
        matches very closely the measurment.... Implemented like this in openMSX
151
        and it matches the measurement very well.
152
        I verified that 'VDP irq disabled' has no influence on speed: I mean
153
        even with VDP irq disabled, the speed of 'nop' is the same as before.
154
155
ld a,ixh  [x 20000]
156
  result:           1637
157
  openmsx-old:      1636
158
  openmsx-rev11643: 1643-1545
159
  cycles: 2  [ff]
160
161
muluw hl,bc  [x 20000]
162
  result:           29354
163
  openmsx-rev11643: 29360-29361
164
  cycles: 36  [ffx34]
165
166
mulub a,b  [x 20000]
167
  result:           11419
168
  openmsx-rev11643: 11425-11427
169
  cycles: 14  [ffx12]
170
171
172
173
* Instructions that do a single read/write operation
174
175
ld (#d000),a  [x 10000]
176
  result:           2449
177
  openmsx-rev11643: 2446-2447
178
  cycles: 6  [FffW]
179
  note: page-break when switching from opcode fetching to data writes
180
        and again when switching from data write to opcode fetching
181
182
ld a,(#d000)  [x 10000]
183
  result:           2449
184
  openmsx-rev11643: 2445-2447
185
  cycles: 6  [FffR]
186
  note: same as above but for read
187
188
ld a,(#0100) [x 80(!)]
189
  result:           20
190
  openmsx-rev11643: 20
191
  cycles: 6  [FffR]
192
  note: opcode fetch and read are in the same 256-byte page,
193
        but still there is a page-break when switching from
194
        opcode reading to data reading
195
196
[ ld hl,#d000 ]
197
ld a,(hl)  [x 40000]
198
  result:           6522
199
  openmsx-rev11643: 6522-6523
200
  cycles: 4  [FR]
201
202
[ ld hl,#d000 ; ld bc,0 ]
203
ld a,(hl) ; add hl,bc  [x 20000]
204
  result:           4054
205
  openmsx-rev11643: 4054-4055
206
  cycles: 3 + 2  [fR F]
207
208
[ ld hl,start+XX ; ld bc,2 ]
209
ld a,(hl) ; add hl,bc  [x 20000]
210
  result:           4055
211
  openmsx-rev11643: 4054-4055
212
  cycles: 3 + 2  [fR F]
213
  note: same test as above, but now the data is in the same page as
214
        the instructions. There is still a page-break.
215
216
[ ld hl,start+XX ; ld bc,2 ]
217
ld (hl),a ; add hl,bc  [x 20000]
218
  result:           4054
219
  openmsx-rev11643: 4054-4055
220
  cycles: 3 + 2  [fW F]
221
  note: same as above but for writes
222
223
ld r,(ix+o)  [x 10000]
224
  result:           2854
225
  openmsx-rev11643: 2848-2849
226
  cycles: 7  [FffxR]
227
  note: between opcode fetching (3 bytes) and read there is one additional
228
        cycle to calculate the result of IX+o
229
230
ld (ix+o),r  [x 10000]
231
  result:           2854
232
  openmsx-rev11643: 2848-2849
233
  cycles: 7  [FffxW]
234
  note: same as above, but for write
235
236
ld (ix+o),n  [x 10000]
237
  result:           2861
238
  openmsx-rev11643: 2848-2849
239
  cycles: 7  [FfffW]
240
  note: Has the same number of cycles as 'ld (ix+o),r' even though this
241
        instruction is one byte longer. The IX+o calculation is done
242
        in parallel with fetching the last opcode byte.
243
        Z80 shows the same parallelism.
244
  note: Even though it has the same number of cycles as 'ld (ix+o),r', it
245
        is consistently slightly slower. A possible explanation is that there
246
        are page-breaks on opcode fetches in this test, since this instruction
247
        has length 4 instead of 3.
248
249
bit 0,a  [x 20000]
250
  result:           1637
251
  openmsx-old:      1636
252
  openmsx-rev11643: 1643-1645
253
  cycles: 2  [ff]
254
255
bit 0,(hl)  [x 20000]
256
  result:           4055
257
  openmsx-rev11643: 4065-4066
258
  cycles: 5  [FfR]
259
260
bit 0,(ix+o)  [x 10000]
261
  result:           2861
262
  openmsx-rev11643: 2848-2849
263
  cycles: 7  [FfffR]
264
  note: I always found it strange that the format of these instructions is
265
           <0xDD> <0xCB> <offset> <function>     (offset before function)
266
        But this allows to hide the latency of calculating IX+o. The same
267
        happens on a Z80.
268
269
270
271
* Instructions that read/write 2 bytes
272
273
ld (#d000),hl  [x 10000]
274
  result:           2854
275
  openmsx-rev11643: 2848-2849
276
  cycles: 7  [FffWw]
277
  note: no page-break for the second data write
278
279
ld (#d0ff),hl  [x 10000]
280
  result:           3264
281
  openmsx-rev11643: 3260-3262
282
  cycles: 8  [FffWW]
283
  note: of course here there must be a page-break
284
285
ld hl,(#d000)  [x 10000]
286
  result:           2854
287
  openmsx-rev11643: 2848-2849
288
  cycles: 7  [FffRr]
289
  note: similar for read
290
291
ld hl,(#d0ff)  [x 10000]
292
  result:           3264
293
  openmsx-rev11643: 3260-3262
294
  cycles: 8  [FffRR]
295
296
push hl ; pop hl  [x 20000]
297
  result:           8956
298
  openmsx-old:      8950
299
  openmsx-rev11643: 8928-8930
300
  cycles: 6 + 5  [FxWw FRr]
301
  note: push is once cycle slower than pop, probably because push first has
302
        to decrease SP, while pop can directly put the value of SP on the bus
303
304
305
306
* Read-modify-write instructions (single byte)
307
308
inc a  [x 40000]
309
  result:           1628-1642
310
  openmsx-rev11643: 1637-1638
311
  cycles: 1  [f]
312
313
inc (hl)  [x 40000]
314
  result:           11393
315
  openmsx-rev11643: 11392-11393
316
  cycles: 7  [FRxW]
317
  note: This instructions is slower than I expected, but it can be explained
318
        like this:
319
         - there is one cycle between data read and data write to get the
320
           time to actually increase the value
321
         - when switching from data-read to data-write there is a page-break
322
           (even though the address is identical)
323
        But see also the 'ex (sp),hl' instruction below
324
325
inc (ix+o)  [x 10000]
326
  result:           4080
327
  openmsx-rev11643: 4076-4077
328
  cycles: 10  [FffxRxW]
329
  note: similar as above, but 3 cycles longer:
330
          - need to fetch 2 more opcode bytes
331
          - need to calculate IX+o before data read can be executed
332
333
res 0,a  [x 20000]
334
  result:           1637
335
  openmsx-old:      1637
336
  openmsx-rev11643: 1643-1645
337
  cycles: 2  [ff]
338
339
res 0,(hl)  [x 20000]
340
  result:           6523
341
  openmsx-rev11643: 6522-6523
342
  cycles: 8  [FfRxW]
343
  note: similar to 'inc (hl)' but opcode is one byte longer
344
345
res 0,(ix+o)  [x 10000]
346
  result:           4083
347
  openmsx-rev11643: 4076-4077
348
  cycles: 10  [FfffRxW]
349
  note: similar to 'inc (ix+o)'. Opcode is one byte longer, but cost
350
        of IX+o can be hidden
351
352
rld  [x 20000]
353
  result:           6529
354
  openmsx-old:      6528
355
  openmsx-rev11643: 6521-6523
356
  cycles: 8 cycles  [FfRxW]
357
  note: similar to 'res 0,(hl)'
358
359
ld hl,#0000 ; ld de,#0100 ; ld bc,40000 ; ldir  [no repeat]   (src != dst)
360
  result:           11393
361
  openmsx-rev11643: 11393-11394
362
  cycles: 7  [FfRW]
363
  note: - as expected, 3 page-breaks are needed
364
        - there's no extra cycle needed to repeat the instruction
365
          TODO make a specific test for this   ldi <-> ldir
366
367
ld hl,#0100 ; ld de,#0100 ; ld bc,40000 ; ldir  [no repeat]   (src == dst)
368
  result:           11393
369
  openmsx-rev11643: 11393-11394
370
  cycles: 7  [FfRW]
371
  note: same timing as above, even though the read and write addresses are
372
        the same, there is a page-break in between
373
374
375
* Read-modify-write 2 bytes
376
377
ex (sp),hl  [x 40000]
378
  result:           11393
379
  openmsx-rev11643: 11392-11393
380
  cycles: 7  [FRrww]
381
  note: - This result was unexpected to me: based on the results in the previous
382
          section, I expected a page-break between the read and writes.
383
        - 7 cycles is really the minimum. There are 5 bus transactions (1 opcode
384
          fetch, 2 data reads and 2 data writes). Stack and instructions are in
385
          different pages so there must be at least 2 page-breaks.
386
        - I've confirmed the [frrww] order, see exsphl.txt for details.
387
388
[ ld sp,#xxFF ]
389
ex (sp),hl  [x 40000]
390
  result:           14660
391
  openmsx-rev11643: 14634-14635
392
  cycles: 9  [FRRwW]
393
  note: - Now we forced a page-break between reading/writing of the word. So two
394
          additional cycles.
395
        - This confirms that first two bytes are read and only then two byte are
396
          written: the order [FRwRw] would only require 8 cycles
397
398
[ ld sp,#01F0 ]
399
ex (sp),hl  [x 200(!)]
400
  result:           58
401
  openmsx-rev11643: 56-58
402
  cycles: 7  [FRrww]
403
  note: Stack pointer in same page as instructions. But there still seems to be
404
        a pagebreak between instructions and data.
405
406
ex (sp),ix  [x 20000]
407
  result:           6529
408
  openmsx-rev11643: 6521-6523
409
  cycles: 8  [FfRrww]
410
411
[ ld sp,#xxFF ]
412
ex (sp),ix  [x 20000]
413
  result:           8153
414
  openmsx-rev11643: 8152-8153
415
  cycles: 10  [FfRRwW]
416
417
418
419
* Jump instructions
420
421
jr $+2   [x 20000]
422
  result:           2455
423
  openmsx-rev11643: 2459-2460
424
  cycles: 3  [ffx]
425
  note: one additional cycle to calculate PC+offset
426
427
jr $+3 ; nop  [x 10000]    <- nop is skipped
428
  result:           1229
429
  openmsx-rev11643: 1229-1230
430
  cycles: 3  [ffx]
431
  note: - even if opcode fetching is not contiguous there is no extra
432
          page-break
433
        - slightly slower than test above, because code is less dense
434
          and thus overall there are more opcode-fetch page-breaks
435
436
jr $+2 ; nop  [x 10000]
437
  result:           1636
438
  openmsx-rev11643: 1637-1638
439
  cycles: 3 + 1  [ffx f]
440
441
[ ld a,0 ; or a ]
442
jr z,$+2  [x 20000]
443
  result:           2454
444
  openmsx-rev11643: 2459-2460
445
  cycles: 3  [ffx]
446
  note: condition is true, jump is taken
447
448
[ ld a,1 ; or a ]
449
jr z,$+2  [x 20000]
450
  result:           1637
451
  openmsx-old:      1636
452
  openmsx-rev11643: 1641-1642
453
  cycles: 2  [ff]
454
  note: condition is false, jump not taken
455
        PC+offset does not need to be calculated, so no extra cycle
456
457
djnz $+2  [x 20000]
458
  result:           2454
459
  openmsx-rev11643: 2457-2459
460
  cycles: 3  [ffx]
461
  note: - whether the jump is taken or not does not matter for the program flow
462
        - 1/256 of the times the jump is not taken, this can explain why this
463
          test is slightly faster than 'jr $+2' (but it's well within measure
464
          error margin)
465
466
[ ld b,0 ]
467
djnz $+0  [x 2000(!)]
468
  result:  i        63014
469
  openmsx-rev11643: 62707-62708  (1)
470
  openmsx-rev11643: 63013-63014  (2)
471
  cycles: 3  [ffx]
472
  note: - Only repeated instruction 2000 times (iso 20000) because otherwise
473
          timer would overflow.
474
        - The difference between (1) and (2) is that in (1) the djnz instruction
475
          is 2-bytes aligned, while in (2) it's mis-aligned. This matters
476
          because it will cause a lot more page-breaks. Maybe some of the
477
          regression in the other tests could also be explained like this?
478
          Till now I didn't pay much attention to instruction alignment.
479
480
[ ld b,1 ]
481
djnz $ ; inc b  [x 10000]
482
  result:           1228
483
  openmsx-rev11643: 1229-1230
484
  cycles: 3  [ff f]
485
  note: djnz only takes 2 cycles when it doesn't jump, same result as for jr
486
487
jp $+3  [x 10000]
488
  result:           2028
489
  openmsx-old:      2040
490
  openmsx-rev11643: not yet retested
491
  cycles: 5  [Fffx]
492
  note: Two additional cycles are unexpected. It can either be explained as
493
        two 'x' cycles or as one 'x' cycles plus a forced page-break.
494
        See also tests below.
495
496
[ ld a,0 ; or a ]
497
jp z,$+3  [x 10000]
498
  result:           2029
499
  openmsx:          2041
500
  openmsx-rev11643: not yet retested
501
  cycles: 5  [Fffx]
502
  note: condition is true, jump is taken
503
504
[ ld a,1 ; or a ]
505
jp z,$+3  [x 10000]
506
  result:           1229
507
  openmsx:          1227
508
  openmsx-rev11643: not yet retested
509
  cycles: 3  [fff]
510
  note: condition is false, jump not taken
511
        extra 2 cycles are gone
512
513
[ ld hl,start+XX ; ld bc,2 ]
514
add hl,bc ; jp (hl)  [x 20000]
515
  result:           3260
516
  openmsx-rev11643: 3266-3268
517
  cycles: 4  [F fx]
518
  note: Similar as above, 2 extra cycles
519
520
[ ld hl,start+XX ; ld bc,#0102 ; ld de,#FF02 ]
521
add hl,bc ; jp (hl) ; add hl,de ; jp (hl)  [x 10000]
522
  result:           3241
523
  openmsx-old:      3240
524
  openmsx-rev11643: 3201   TODO retest on real machine, I have the feeling
525
                                I'm not doing the exact same test now and before
526
  cycles: 8 cycles [F fx F fx]
527
  note: In this test every jump has a destination in a different 256-byte page.
528
        A single 'jp (hl)' instruction is still responsible for 3 cycles
529
        (though the cost of the forced page-break is pushed to the next
530
        instruction). This confirms that the two extra cycles in a jump are
531
        one 'x' cycle plus one forced page-break (in case of two 'x' cycles,
532
        this test would show yet an additional cost for the page-break).
533
  note: The 64 backward jumps in the first 256-byte page and the 64 forward
534
        jumps in the last page in this test are not executed.
535
536
call $+3 ; pop hl  [x 10000]
537
  result:           4880
538
  openmsx-old:      4891
539
  openmsx-rev11643: not yet retested
540
  cycles: 7 + 5  [FffWw FRr]
541
  note: This is again as expected, though the two extra cycles can be hidden
542
        by the data-writes.
543
544
[ ld a,0 ; or a ]
545
call z,$+3 ; pop hl  [x 10000]
546
  result:           4880
547
  openmsx-old:      4891
548
  openmsx-rev11643: not yet retested
549
  cycles: 7 + 5  [FffWw FRr]
550
  note: condition is true, call is executed
551
        as expected, same result as unconditional call
552
553
[ ld a,1 ; or a ]
554
call z,$+3  [x 10000]
555
  result:           1229
556
  openmsx-old:      1228
557
  openmsx-rev11643: not yet retested
558
  cycles: 3  [fff]
559
  note: condition is false, call not executed
560
561
[ ld hl,start+XX ; ld bc,3 ]
562
add hl,bc ; push hl ; ret  [x 10000]
563
  result:           4884-4887
564
  openmsx-rev11643: 4885-4886
565
  cycles: 12 [F fxWw FRr]
566
  note: 'RET' probably behaves as a 'JP (HL)' (two extra cycles), but these
567
        cycles can be hidden by the two data reads
568
569
[ ld hl,start+XX ; ld bc,3 ; ld a,0 ; or a ]
570
add hl,bc ; push hl ; ret z  [x 10000]
571
  result:           4884-4887
572
  openmsx-rev11643: 4885-4886
573
  cycles: 12 [F fxWw FRr]
574
  note: Same test as above, but with a conditional ret that is always executed.
575
        As expected same result as above.
576
577
[ ld a,1 ; or a ]
578
ret z  [x 40000]
579
  result:           1644
580
  openmsx-rev11643: 1637-1638
581
  cycles: 1  [f]
582
583
584
* IO instructions
585
586
in a,(0)  [x 20000]
587
  result:           8066
588
  openmsx-old:      8126
589
  openmsx-rev11643: 8152-8153
590
  cycles: 10  [ffI8]
591
  note: - 8 cycles for IO seems a lot, but this makes it the same speed as Z80
592
             Z80:  4 cycles @ 3.5MHz
593
             R800: 8 cycles @ 7MHz
594
          This is needed to keep the timing on the external cartridge slots
595
          the same.
596
        - Besides IO port 0, i checked a lot of other ports, but not all.
597
          I did check some random unused port numbers and at least one input
598
          port from each IO-device in the turbor. Only the VDP ports are
599
          different (see below)
600
601
in a,(#98)  [x 20000]
602
  result:           44286
603
  openmsx-rev11643: 40713
604
  cycles: +/- 54
605
  note: - Can be explained by the 'intelligent' VDP-delay added by the S1990
606
          Need additional tests to accurately measure this.
607
        - Only IO ports 0x98-0x9B show this behaviour
608
        - TODO this still differs a lot between emulation and real HW
609
610
[ ld b,0 ]
611
in a,(0) ; djnz $-2  [x 1]   [no page-break between in/djnz]
612
  result:           126
613
  openmsx-old:      132 136
614
  openmsx-rev11643: not yet retested
615
  cycles: 13  [ffI8 ffx]
616
617
[ ld b,0 ]
618
in a,(0) ; djnz $-2  [x 1]   [page-break between in/djnz]
619
  result:           145
620
  openmsx-old:      156
621
  openmsx-rev11643: not yet retested
622
  cycles: 15  [FfI8 Ffx]
623
  note: - we forced a page-break between the in and the djnz instruction by
624
          properly aligning the start address
625
        - 2 extra cycles compared to test above, this confirms the decomposition
626
          of the in instruction is [ffI8] (as opposed to [ffI7 + page-break])
627
628
out (0),a  [x 20000]
629
  result:           8065
630
  openmsx-old:      8125
631
  openmsx-rev11643: 8152-8153
632
  cycles: 10  [ffI8]
633
  note: similar to 'in a,(0)'
634
635
out (#98),a  [x 20000]
636
  result:           44285
637
  openmsx-rev11643: 40713
638
  cycles: +/- 54
639
  note: similar to 'in a,(#98)'
640
641
642
Theory: R800 is connected to a 7MHz bus, but IO is done over a 3.5MHz bus. If
643
        the start of IO is at an odd clock cycle (so not at a clock edge at the
644
        slower bus) there is an extra wait cycle required.
645
646
in a,(0) ; [nop] x A [x 8000]
647
  result:  A=0 -> 3226
648
           A=1 -> 3274
649
           A=2 -> 3872
650
           A=3 -> 3932
651
           A=4 -> 4525
652
  openmsx-old: A=0 -> 3248
653
               A=1 -> 3255
654
               A=2 -> 3893
655
               A=3 -> 3913
656
               A=4 -> 4557
657
  openmsx-rev11643: A=0 -> 3261
658
                    A=1 -> 3269
659
                    A=2 -> 3914
660
                    A=3 -> 3926
661
                    A=4 -> 4565
662
  cycles: A=0 -> 10  [ffxoI6]
663
          A=1 -> 10  [f ffxI6]
664
          A=2 -> 12  [f f ffxoI6]
665
          A=3 -> 12  [f f f ffxI6]
666
          A=4 -> 14  [f f f f ffxoI6]
667
  note: When there are an odd number of NOP instructions between two OUT
668
        instructions, one of the NOPs can be executed seemingly 'for free'.
669
        Or in other words when there's an even number of NOP instructions, the
670
        OUT instruction has an extra penality cycle.
671
        These results could be explained by assuming the following structure for
672
        the out command:  3 cycles [ffx..] followed by possibly one extra
673
        cycle to align to the slow 3.5MHz bus, followed by 6 cycles (= 3 cycles
674
        on the slow bus) for the actual IO.
675
676
677
* Internal-ROM
678
679
ld hl,(#xxyy)  [x 10000]
680
  with yy=#00 -> no page break
681
    with xx in normal RAM
682
      result: 2855
683
      cycles: 7  [FffRr]
684
    with xx in ROM, DRAM mode
685
      result: 2855
686
      cycles: 7  [FffRr]
687
    with xx in ROM
688
      result: 4080
689
      cycles: 10  [FffRmRm]     (m -> memory wait cycle)
690
  with yy=#ff -> page break during read
691
    with xx in normal RAM
692
      result: 3265
693
      cycles: 8  [FffRR]
694
    with xx in ROM, DRAM mode
695
      result: 3264
696
      cycles: 8  [FffRR]
697
    with xx in ROM
698
      result: 4080
699
      cycles: 10  [FffRmRm]
700
  note: - RAM or ROM in DRAM mode seems to have the same speed, including
701
          page break optimization
702
        - reads from ROM take 3 cycles, they don't become slower in case
703
          of a page break. So it seem there are always 2 cycles to set the
704
          address plus one wait cycle.
705
        - I did the same test with the 'ld (#xxyy),hl' instruction (even
706
          though writing to ROM doesn't make sense). I got the same results.
707
708
[ ld a,128 ; or a ]
709
[ BIOS ROM contains    nop (x 11) ; ret m    at address #1EB2 ]
710
call #1EB2  [x 10000]
711
  result: [(D)RAM]  9763-9770
712
          [ROM]    18757
713
  cycles: [(D)RAM] 24  [FffWw F  f  f  f  f  f  f  f  f  f  f  fRr ]   (<- 23 !!)
714
          [ROM]    46  [FffWw Fm Fm Fm Fm Fm Fm Fm Fm Fm Fm Fm FmRr ]
715
  note: - this confirm 3 cycles per memory read from ROM
716
        - we measured 24 cycles for (D)RAM while there should only be 23,
717
          this might be a measurement error though: to calculate the number
718
          of cycles (in long code sequences) I compare it with the duration
719
          of a NOP instruction, for long durations differences this may be
720
          inaccurate
721
722
723
* External-slot
724
725
ld hl,(#4000)  [x 5000]
726
  result: 2857
727
  cycles: 14  [FffRmmmRmmm] ??
728
  note: 5 cycles per memory access, close to 3 cycles (@ 3.5MHz) on Z80
729
        but I'd expected it to match exactly. It's strange to have halve
730
        cycles on the external 3.5MHz cartridge slots.
731
732
ld (#4000),hl  [x 5000]
733
  result: 2857
734
  cycles: 14  [FffRmmmRmmm] ??
735
736
ld a,(#4000)  [x 5000]
737
  result: 1634
738
  cycles: 8  [FffRmm] ??
739
740
ld (#4000),a  [x 5000]
741
  result: 1634
742
  cycles: 8  [FffWmm] ??
743
744
[ ld hl,#4000 ]
745
ld a,(hl)  [x 15000]
746
  result: 3669
747
  cycles: 6  [FRmm] ??
748
749
[ ld hl,#4000 ]
750
ld (hl),a  [x 15000]
751
  result: 3669
752
  cycles: 6  [FWmm] ??
753
754
[ ld hl,#4000 ]
755
inc (hl)  [x 15000]
756
  result: 7337
757
  cycles: 12  [FRmmxWmmm] ??
758
759
760
761
762
763
TODO: RETN, RST
764
      CPI(R), LDI(R), INI(R), OUTI(R)
765
      HALT (how to test?)
766
767
768
769
770
771
772
773
774
775
776
777
* refresh
778
779
780
	org #c000
781
782
	di
783
	ld	b,0
784
	ld	c,0
785
	out	(#e6),a
786
loop	nop		; variable number of nops
787
	djnz	loop
788
	dec	c
789
	jr	nz,loop
790
	in	a,(#e6)
791
	ld	l,a
792
	in	a,(#e7)
793
	ld	h,a
794
	ret
795
796
797
nops | real  | openmsx-old
798
-----+-------+---------
799
   0 |  8088 |  8036
800
   1 | 10717 | 10716
801
   2 | 13336 | 13382
802
   3 | 16079 | 16042
803
   4 | 18740 | 18726
804
  10 | 34778 | 34753
805
806
cycles (without refresh) = 65536 * nops + 197375