OXYGENHUB
◆ main openmsx / doc / internal / r800-refresh.txt
12.8 KiB · Plain Text · last changed chore(): initial commit 1 month ago source blame history raw
e8555c89 Andy McCall 1
I was investigating whether the 'R' register behaves the same on Z80 and R800.
2
I initially wrote this program:
3
4
	di
5
	ld	hl,#0100
6
	xor	a
7
	ld	b,a
8
	ld	r,a
9
loop:	ld	a,r        ; (2)
10
	ld	(hl),a     ; (4)
11
	inc	hl         ; (1)
12
	djnz	loop       ; (3)
13
	ei
14
	ret
15
16
17
On Z80, for every iteration of this loop, R is increased by 5 (+2 for 'ld a,r'
18
and +1 for the other 3 instructions). On R800 R is also increased by 5 each
19
iteration. Though sometimes it's increased by 6!
20
21
The increase by 6 instead of 5 happened every 18th or 19th (alternating)
22
Iteration. One iteration takes 10 cycles (taking R800-page-breaks into account),
23
so that's on average every 185th clock cycle.
24
25
This number 185 is very close to the number of useful cycles in a full R800
26
refresh cycle. Currently (2010-08-16) R800-refresh in openmsx stalls the R800
27
for 26 cycles every 210 cycles (so that leaves 210-26=184 useful cycles).
28
29
So all this lead me to the hypotheses that a R800-refresh cycle also increases
30
the R register by one.
31
32
This would be very useful because it would allow to measure in more detail how
33
refresh works exactly on R800 (the current model in openMSX (210/26) is not
34
100% correct). So that's what I'll do in the rest of this document.
35
36
37
38
39
New test program. This records sequences longer than 256, it's important that
40
each iteration takes the same amount of cycles. So I had to replace the djnz
41
instruction.
42
43
	di
44
	ld	hl,#0100
45
	xor	a
46
	ld	r,a
47
loop:	ld	a,r        ; (2)
48
	ld	(hl),a     ; (4)
49
	inc	hl         ; (1)
50
	ld	a,h        ; (1)
51
	cp	#c0        ; (2)
52
	jr	nz,loop    ; (3)
53
54
	[ some code to transform memory block #0100-#C000 into
55
	  the differential of this block, so it's easy to see by
56
	  how much R increased each iteration ]
57
58
Each iteration takes 13 cycles. Per iteration R is increased by either 7 or 8.
59
60
The difference table (a small portion) looked like this:
61
   07 07 07 07 07 07 07 07  07 07 07 07 07 08 07 07
62
   07 07 07 07 07 07 07 07  07 07 07 08 07 07 07 07
63
   07 07 07 07 07 07 07 07  07 08 07 07 07 07 07 07
64
   07 07 07 07 07 07 07 08  07 07 07 07 07 07 07 07
65
   07 07 07 07 07 07 08 07  07 07 07 07 07 07 07 07
66
   07 07 07 07 08 07 07 07  07 07 07 07 07 07 07 07
67
   07 07 08 07 07 07 07 07  07 07 07 07 07 07 07 07
68
   08 07 07 07 07 07 07 07  07 07 07 07 07 07 07 08
69
   07 07 07 07 07 07 07 07  07 07 07 07 07 07 08 07
70
   07 07 07 07 07 07 07 07  07 07 07 07 08 07 07 07
71
   ...
72
73
These tables always have only two different numbers, in this case a series of
74
7's followed by one 8, then again a series of 7's followed by one 8 and so one.
75
The actual number '7' or '8' is not important for timing, only the pattern of
76
these numbers in the table is important. So I'll create a more compact notation
77
for the table above:
78
79
  14 14 14 14 15 14 14 14 14 15 14 ...       (these are decimal numbers)
80
or even
81
  4*14 15 ...
82
83
This means there are 4 repetitions of '13*0x07 + 1* 0x08' (length 14) followed by
84
one time '14*0x07 + 1*0x08' (length 15).
85
86
So this notation indicates how many iterations there are before there is a
87
refresh.
88
89
For this test on average there are '(4 * 14 + 1 * 15) / 5 = 14.2' iterations
90
between two refresh cycles. Each iteration takes 13 cycles. So that's 184.6
91
useful clock cycles between refresh cycles.
92
93
94
95
96
Next I realized this test program could be speed up one cycle:
97
98
	ld	c,#c0
99
loop:	ld	a,r        ; (2)
100
	ld	(hl),a     ; (4)
101
	inc	hl         ; (1)
102
	ld	a,h        ; (1)
103
	cp	c          ; (1)
104
	jr	nz,loop    ; (3)
105
106
An iteration now takes 12 cycles (R is still increased by 7 or 8).
107
108
Difference table looks like this
109
  16 3*15 16 2*15 16 2*15    (this sequence repeats all the time)
110
111
That's (3*16+7*15)/10 = 15.3 iteration
112
or 15.3*12 = 183.6 clock cycles between refresh.
113
114
115
116
117
Then I started inserting extra instructions in this test program:
118
119
	ld	c,#c0
120
loop:	ld	a,r        ; (2)
121
	ld	(hl),a     ; (4)
122
	[***]
123
	inc	hl         ; (1)
124
	ld	a,h        ; (1)
125
	cp	c          ; (1)
126
	djnz	loop       ; (3)
127
128
129
* NOP
130
  13 cycles per iteration  (R increases 8 or 9)
131
  pattern: 8*14 15
132
  cycles between refresh: 183.44      (8*14+15)/9*13
133
134
* 2 x NOP
135
  14 cycles/iteration  (R incr 9 or 10)
136
  pattern: 5*13 14
137
  cycles/refresh = 184.33
138
139
  I noticed the start of the difference table was a bit different, it went like
140
  this:
141
     9*13 14 7*13 14 5*13 14 5*13 14 5*13 14
142
  So it took some time before it stabilized on the '5*13 14' pattern. For the
143
  rest of the tests I didn't look at the start of the table anymore. I only
144
  searched for the 'stable' pattern.
145
146
  I ran this same test again, but now the (stable) pattern was
147
     9*13 14
148
  that gives
149
     cycles/refresh = 183.4
150
151
  This is very interesting behaviour, depending on some (yet unknown) initial
152
  conditions, _the_whole_test_ runs slightly faster or slower. This is
153
  interesting because it may give a clue to why there is considerable variation
154
  to *some* speed measurements on a real R800 (see doc/r800-test.txt) while for
155
  other tests the results are much more stable. (Also in the current R800 openMSX
156
  emulation, the speed measurements are always stable).
157
158
  I didn't repeat the previous tests. Maybe they also show different patterns
159
  on different runs. I did repeat all future tests (there always seems to be
160
  either only 1 or 2 different stable patterns)
161
162
* NEG   (like 2xNOP also takes 2 cycles)
163
  14 cycles/iteration (R incr 9 or 10)
164
  pattern: 7*13 14
165
  cycles/refresh = 183.75
166
167
* 3 x NOP
168
  15 cycles/iteration (R incr 10 or 11)
169
  pattern: 2*12 13
170
           3*12 13
171
  cycles/refresh = 185
172
                   183.75
173
174
* IM 1   (3 cycles, like 3xNOP)
175
  15 cycles/iteration (R incr 9 or 10)
176
  pattern: same as 3 x NOP
177
178
* 4 x NOP
179
  16 cycles/iteration (R incr 11 or 12)
180
  pattern: 11 12
181
  cycles/refresh = 184
182
183
* LD (HL),A  (4 cycles (with page-breaks))
184
  16 cycles/iteration (R incr 8 or 9)
185
  pattern: same as 4 x NOP
186
187
* 5 x NOP
188
  17 cycles/iteration (R incr 12 or 13)
189
  pattern: 4*11 10
190
           7*11 10 6*11 10
191
  cycles/refresh = 183.6
192
                   184.73
193
194
* BIT 0,(HL)   (5 cycles)
195
  17 cycles/iteration (R incr 9 or 10)
196
  pattern: 5*11 10 4*11 10
197
           6*11 10
198
  cycles/refresh = 183.90
199
                   184.57
200
201
202
203
204
205
I still need to do more experiments, but some *guesses* so far: useful number
206
of cycles always seems to be within (183, 185]. That's a variation of more than
207
one clock cycle. Maybe refresh also waits for an even clock cycle (just like IO
208
does). This could explain why there are two stable patterns for some tests (in
209
one case you have to insert an extra cycle to align to an even number of
210
cycles, in the other case you're already aligned). This could explain why there
211
can be variation in speed between different runs of the same test. And finally
212
it explains why the documentation (e.g. atoc or even the turbor datapack) talks
213
about half clock cycles for the duration of the refresh (in 50% of the cases it
214
needs to add one cycle). Those docs talk about 21.5 cycles refresh every 222
215
cycles, those number seem wrong to me (don't match measurements on real HW),
216
but at least I now have an idea about that half clock cycle.
217
218
219
---------
220
221
222
I implemented the above guess (refresh waits for even clock cycle) in openMSX
223
revision 11643. I can now more or less reproduce the results above: The
224
number of useful clock cycles per refresh is also in range (183, 185], but the
225
number per test is not the same as above (the 'stable patterns' from the tests
226
above are different). Also in openMSX there's always only one stable pattern,
227
while on a real R800, for some test, there clearly were two different possible
228
patterns.
229
230
231
232
233
234
235
New test: above we measured the number of useful clock cycles per 'refresh
236
cycle'. Now we're going to measure how many cycles the refresh itself takes.
237
The idea goes like this: by observing the R register we can detect that there
238
was a refresh, so by doing a longer test we can count how many refresh cycles
239
there were. We can combine this with measuring the total time of the test
240
(using the E6-timer). We can also calculate how many 'useful' cycles there
241
were in the whole test. So the difference between actual and useful cycles
242
must be cycles spend on refresh. And finally if we divide that by the counted
243
number of refreshes, we should know how many cycles a single refresh takes.
244
245
Full test program:
246
247
        org     #c000
248
249
        di
250
        ld      hl,#0100
251
        ld      c,#bc
252
253
        ld      e,3
254
l1      ld      a,r        ; This loop waits till there was a refresh.
255
        ld      d,a        ; It's an attempt to get more stable measurements.
256
        ld      a,r        ; Note that this loop will not terminate in Z80
257
        sub     d          ; mode.
258
        sub     e
259
        jr      z,l1
260
261
        out     (#e6),a
262
263
loop    ld      a,r        ; (2)   Actual test loop, same as in tests above
264
        ld      (hl),a     ; (4)   One iteration takes 12 cycles
265
        inc     hl         ; (1)
266
        ;[***]             ;       extra instructions here (see below)
267
        ld      a,h        ; (1)
268
        cp      c          ; (1)
269
        jr      nz,loop    ; (3/2) 3 cycles when jump is taken, 2 otherwise
270
271
        in      a,(#e6)
272
        ld      l,a
273
        in      a,(#e7)
274
        ld      h,a
275
        ld      (#be00),hl ; store total duration of the test
276
277
        ld      hl,#0100   ; Next we do some post-processing on the data:
278
l2      inc     hl         ; First calculate the difference table, same
279
        ld      a,(hl)     ; routine as in tests above (though not shown
280
        dec     hl         ; there).
281
        sub     (hl)
282
        ld      (hl),a
283
        inc     hl
284
        ld      a,h
285
        cp      c
286
        jr      nz,l2
287
288
        ld      hl,#bc00
289
        ld      de,#bc00+1
290
        ld      bc,#200-1
291
        ld      (hl),0
292
        ldir
293
294
        ld      de,#100    ; Next we calculate a histogram.
295
        ld      hl,#bc00   ; We expect this histogram to be all zero, except for
296
l3      ld      a,(de)     ; two entries: the iterations with and without a
297
        ld      l,a        ; refresh cycle.
298
        inc     (hl)       ; There is a single other point in this histogram,
299
        jr      nz,nc      ; that's because we don't calculate the difference of
300
        inc     h          ; the very last iteration correctly (we'd have to
301
        inc     (hl)       ; sample the R register one more time outside the
302
        dec     h          ; loop). But for now we ignore this outlier.
303
nc      inc     de
304
        ld      a,d
305
        cp      h
306
        jr      nz, l3
307
308
        ei
309
        ret
310
311
312
Test results:
313
314
* no extra instructions:
315
   real machine:
316
     histogram: 0x07: 0xAECE
317
                0x08: 0x0C31
318
                0x66: 0x0001 -> belongs to 0x07, can be seen by the pattern
319
                                in the difference table, I won't show this
320
                                entry anymore in the next results
321
     E6-ticks:  0x5B75
322
323
     total cycles: E6-timer * 28 cycles/E6-tick = 655564 cycles
324
     useful cycles: 0xBB00 iterations * 12 cycles/iteration = 574464 cycles
325
     overhead cycles: 655564 - 574464 = 81100 cycles
326
     cycles per refresh = 81100 cycles / 0xc31 refreshes
327
                        = 25.985 cycles/refresh
328
329
   openMSX revision 11648:
330
     histogram: 0x07: 0xAECD+1
331
                0x08: 0x0C32
332
     E6-ticks:  0x5B78
333
      --> 26.004 cycles/refresh
334
335
* extra instruction: NOP (1 cycles, increases R by 1)
336
   real machine:
337
     histogram: 0x8: 0xADCA
338
                0x9: 0x0D36
339
     E6-ticks:  0x6318
340
      --> 26.011 cycles/refresh
341
342
   openMSX revision 11648:
343
     histogram: 0x8: 0xADC8
344
                0x9: 0x0D38
345
     E6-ticks:  0x632A
346
      --> 26.144 cycles/refresh
347
348
* extra instruction: IM 1 (3 cycles, incr R 2)
349
   real machine:
350
     histogram: 0x9: 0xABCA
351
                0xA: 0x0F36
352
     E6-ticks:  0x721B
353
      --> 25.636 cycles/refresh
354
355
   openMSX revision 11648:
356
     histogram: 0x9: 0xABBC
357
                0xA: 0x0F44
358
     E6-ticks:  0x727E
359
      --> 26.25 cycles/refresh
360
361
   !! Big difference between openmsx and real MSX !!
362
363
* extra instructions: EXX ; MULUW HL,BC ; EXX (1+36+1 cycles, incr R 1+2+1)
364
   real machine:
365
     histogram: 0xB: 0x882D
366
                0xC: 0x32D3
367
     E6-ticks:  0x17D33  (of course I couldn't measure how many times the
368
                          timer overflowed, but it must be one time)
369
      --> 26.042 cycles/refresh
370
371
   openMSX revision 11648:
372
     histogram: 0xB: 0x8801
373
                0xC: 0x32FF
374
     E6-ticks:  0x17E80
375
      --> 26.669 cycles/refresh
376
377
   !! Big difference between openmsx and real MSX !!
378
379
380
381
Preliminary conclusion:
382
  Refresh seems to take about 26 cycles, this is also the value we currently
383
  use in openMSX. Though especially for the 'IM 1' case there's still a
384
  relatively big difference between openMSX and the real hardware. Needs
385
  more experiments.
386
387
388
389
390
391
One other difference between Z80 and R800
392
	di
393
	xor	a
394
	ld      r,a
395
	ld	a,r
396
	ld	c,a	; Z80: c=2   R800: c=1
397
	ld	a,r
398
	ld	b,a     ; Z80: b=5   R800: b=4
399
	ld	a,r     ; Z80: a=8   R800: a=7
400
And of course once in a while the numbers for R800 are (partially) increased by
401
one.
402
403
This difference can possibly be explained by a difference in the order of
404
storing the result to the 'R' register and increasing the 'R' register on each
405
M1 cycle.