| e8555c89 Andy McCall |
1 |
<?xml version="1.0" encoding="iso-8859-1"?> |
| 2 |
|
| 3 |
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" |
| 4 |
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> |
| 5 |
|
| 6 |
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> |
| 7 |
<head> |
| 8 |
<link title="Purple" rel="stylesheet" href="manual-purple.css" type="text/css" /> |
| 9 |
<title>V9938 VRAM timings</title> |
| 10 |
</head> |
| 11 |
|
| 12 |
<body> |
| 13 |
|
| 14 |
<h1>V9938 VRAM timings</h1> |
| 15 |
|
| 16 |
Measurements done by: Joost Yervante Damad, Alex Wulms, Wouter Vermaelen<br/> |
| 17 |
Analysis done by: Wouter Vermaelen<br/> |
| 18 |
Text written by: Wouter Vermaelen<br/> |
| 19 |
with help from the rest of the openMSX team. |
| 20 |
|
| 21 |
<h2>Introduction</h2> |
| 22 |
|
| 23 |
<p>This text describes in detail how, when and why the V9938 reads from and |
| 24 |
writes to VRAM in bitmap screen modes (screen 5, 6, 7 and 8). VRAM is accessed |
| 25 |
for bitmap and sprite rendering but also for VDP command execution or by |
| 26 |
CPU VRAM read/write requests.</p> |
| 27 |
|
| 28 |
<h5 id="motivation">motivation</h5> |
| 29 |
<p>Modern MSX emulators like blueMSX and openMSX are already fairly accurate. |
| 30 |
And for most practical applications like games or even demos they are already |
| 31 |
<i>good enough</i>. Though there are cases where you can still clearly see the |
| 32 |
difference between a real and an emulated MSX machine.</p> |
| 33 |
|
| 34 |
<p>For example the following pictures show the speed of the LINE command for |
| 35 |
different slopes of the line. The first two pictures are generated on different |
| 36 |
MSX emulators, the last picture is from a real MSX. Without going into all the |
| 37 |
details: lines are drawn from the center of the image to each point at the |
| 38 |
border. While the LINE commands are executing, the command color register is |
| 39 |
rapidly changed (at a fixed rate). So faster varying colors indicate a slower |
| 40 |
executing command.</p> |
| 41 |
|
| 42 |
<img src="line-speed-old-8.png" width="300"> |
| 43 |
<img src="line-speed-emu-8.png" width="300"> |
| 44 |
<img src="line-speed-real-8.png" width="300"> |
| 45 |
|
| 46 |
<p>From left to right these pictures show:</p> |
| 47 |
<ul> |
| 48 |
<li>(left) The output of MSX emulators that use Alex Wulms' original command |
| 49 |
engine emulation core. All(?) modern MSX emulators use this core, including |
| 50 |
blueMSX, OCM and (older versions of) openMSX. The output are squares, this |
| 51 |
indicates that the speed of a LINE command doesn't depend on the slope of the |
| 52 |
line.</li> |
| 53 |
<li>(center) The output of openMSX version 0.9.1. Here the command engine was |
| 54 |
tweaked to take the slope of the line into account, so the test now generates |
| 55 |
clean octagonals.</li> |
| 56 |
<li>(right) The output of a real MSX. The overall shape is also an octagonal. |
| 57 |
But there are also a lot of irregularities. These irregularities can be |
| 58 |
reproduced when running the test multiple times. So it must be a <i>real</i> |
| 59 |
effect, and not some kind of measurement noise.</li> |
| 60 |
</ul> |
| 61 |
|
| 62 |
<p>This test is derived from NYRIKKI's test program described in this (long) <a |
| 63 |
href="http://www.msx.org/forum/msx-talk/software-and-gaming/line">MRC forum |
| 64 |
thread</a>. This particular test is not that important. But because it |
| 65 |
generates a nice graphical output it allows to show the problem without going |
| 66 |
into too much technical details (yet).</p> |
| 67 |
|
| 68 |
<p>In most MSX applications these LINE speed differences, or small command |
| 69 |
speed differences in general, likely won't cause any problems. (Except of |
| 70 |
course in programs like this that specifically test for it.) But it would still |
| 71 |
be nice to improve the emulators.</p> |
| 72 |
|
| 73 |
<h5>measurements</h5> |
| 74 |
<p>To be able to improve openMSX further we need to have a good understanding |
| 75 |
of what it is exactly that causes these irregularities. It would be very hard |
| 76 |
to figure out this stuff only by using MSX test programs. It might be easier to |
| 77 |
look at the deeper hardware level. More specifically at the communication |
| 78 |
between the VDP (V9938) and the VRAM chips. This should allow us to see when |
| 79 |
exactly the VDP reads or writes which VRAM addresses.</p> |
| 80 |
|
| 81 |
<p>So at the 2013 MSX fair in Nijmegen we (some member of the openMSX team and |
| 82 |
I) connected a logic analyzer to the VDP-VRAM bus in a Philips NMS8250 machine. |
| 83 |
The following picture gives an impression of our measurement setup.</p> |
| 84 |
<img src="v9938-probes.jpg"> |
| 85 |
|
| 86 |
<p>Next we ran some MSX software that puts the VDP in a certain display mode. |
| 87 |
It enables/disables screen and/or sprite rendering. And it optionally executes |
| 88 |
VDP commands and/or accesses VRAM via the CPU. And while this test was running |
| 89 |
we could capture (small chunks of) the communication between the VDP and the |
| 90 |
VRAM. This gives us output (waveforms) like in the following image.</p> |
| 91 |
<img src="gtkwave.png"> |
| 92 |
|
| 93 |
<p>It's not so easy to go from this waveform data to meaningful results about |
| 94 |
how the VDP operates. This text also won't talk about this analysis process. If |
| 95 |
you're interested in the analysis or in the raw measurement data, you can find |
| 96 |
some more details in the <a |
| 97 |
href="https://sourceforge.net/mailarchive/message.php?msg_id=30375119"> |
| 98 |
openmsx-devel mailinglist archive</a>. The rest of this text will only discuss |
| 99 |
the final results of the analysis.</p> |
| 100 |
|
| 101 |
<p>Because one of the primary goals was to improve the command engine emulation |
| 102 |
in openMSX, the measurements mostly focused on the bitmap screen modes (a V9938 |
| 103 |
doesn't allow commands in non-bitmap modes). So the following sections will |
| 104 |
only occasionally mention text or character modes. Because we used a V9938 we |
| 105 |
also couldn't test the YJK modes (screen 11 and 12). But it's highly likely |
| 106 |
that, from a VRAM access point of view, these modes behave the same as screen 8 |
| 107 |
(or as we'll see later, the same as all the bitmap screen modes).</p> |
| 108 |
|
| 109 |
|
| 110 |
|
| 111 |
<h2>VRAM accesses</h2> |
| 112 |
|
| 113 |
<p>Before presenting the actual results of (the analysis of) the measurements, |
| 114 |
this section first explains the general workings of the VDP-VRAM communication. |
| 115 |
This is mostly a description of the functional interface of DRAM chips, but |
| 116 |
then specifically applied to the VDP case. Feel free to skim (or even skip) |
| 117 |
this section.</p> |
| 118 |
|
| 119 |
<p>Like most RAM chips in MSX machines, the VDP uses DRAM chips for the video |
| 120 |
RAM. There exist many variations in DRAM chips. You can find a whole lot of |
| 121 |
information on <a |
| 122 |
href="http://en.wikipedia.org/wiki/Dynamic_random-access_memory"> |
| 123 |
wikipedia</a>. Most of the info in this section can also be found in the 'V9938 |
| 124 |
Technical Data Book'. Often that book goes into a lot more detail than this |
| 125 |
text. Here I highlight (and simplify) the aspects that are relevant to |
| 126 |
understand the later sections in this text.</p> |
| 127 |
|
| 128 |
|
| 129 |
<h3>Connection between VDP and VRAM</h3> |
| 130 |
|
| 131 |
<p>Between the VDP and the VRAM chips there is an 8-bit data bus. This means |
| 132 |
that a single read or write access will transfer 1 byte of data.</p> |
| 133 |
|
| 134 |
<p>There is also an 8-bit address bus. Obviously 8 bits are not enough to |
| 135 |
address the full 128kB or even 192kB VRAM address space. Instead the address is |
| 136 |
transferred in two steps. First the row-address is transferred followed by the |
| 137 |
column address. (Usually) the row address corresponds to bits 15-8 of the full |
| 138 |
address, while the column address corresponds to bits 7-0.</p> |
| 139 |
|
| 140 |
<p>Though this still only allows to address up-to 64kB. To get to 128kB, there |
| 141 |
are 2 separate column-address-select signals (named CAS0 and CAS1). These two |
| 142 |
signals allow to select one of the two available 64kB banks. So combined this |
| 143 |
gives 128kB. (Usually) you can interpret CAS0/CAS1 as bit 16 of the |
| 144 |
address.</p> |
| 145 |
|
| 146 |
<p>In case of a MSX machine with 192kB VRAM there is still a third signal: |
| 147 |
CASX. To simplify the rest of this text, this possibility is ignored. It anyway |
| 148 |
doesn't fundamentally change anything.</p> |
| 149 |
|
| 150 |
<p>Next to the data and address bus there are still some control signals. I've |
| 151 |
already mentioned the CAS signals (used to select the column address). There's |
| 152 |
a similar RAS (row address select) signal. And finally there's a R/W |
| 153 |
(read-write) signal that indicates whether the access is a read or a write.</p> |
| 154 |
|
| 155 |
|
| 156 |
<h3>Timing of the VDP-VRAM signals</h3> |
| 157 |
|
| 158 |
<p>When the VDP wants to read or write a byte from/to VRAM it has to |
| 159 |
<i>wiggle</i> the signals that connect the VDP to the VRAM in a certain way. |
| 160 |
This section describes the timing of those <i>wiggles</i>.</p> |
| 161 |
|
| 162 |
<p>The timing description in this section is different from the description in |
| 163 |
the 'VDP Technical Data Book'. The Data Book has the <i>real</i> timings, |
| 164 |
including all the subtle details for how to build an actual working system. |
| 165 |
This text has all the timings rounded to integer multiples of VDP clock cycles. |
| 166 |
IMHO these simplified timings make the VDP-VRAM connection easier to understand |
| 167 |
from a <i>functional</i> point of view.</p> |
| 168 |
|
| 169 |
|
| 170 |
<h4>A single write</h4> |
| 171 |
|
| 172 |
<p>To write a single byte to VRAM, follow this schema:</p> |
| 173 |
<img src="dram-write.png"> |
| 174 |
<ul> |
| 175 |
<li>Put the row address on the address bus and activate the RAS signal. Most |
| 176 |
signals are active-low, so activating means make the signal low.</li> |
| 177 |
<li>After one cycle (remember these are <i>functional</i> timings, especially |
| 178 |
in this step the <i>real</i> timing rules are more complex):</li> |
| 179 |
<ul> |
| 180 |
<li>Activate (one of) the CAS signals.</li> |
| 181 |
<li>Put the column address on the address bus.</li> |
| 182 |
<li>Set the R/W signal. A low signal means write.</li> |
| 183 |
<li>Put the to-be-written data on the data bus.</li> |
| 184 |
</ul> |
| 185 |
</li> |
| 186 |
<li>After two cycles the CAS signal can be deactivated. At this point the |
| 187 |
value of the R/W signal doesn't matter anymore (it may have any value). But |
| 188 |
measurements show that the VDP restores the R/W signal to a high value at this |
| 189 |
point.</li> |
| 190 |
<li>Again one cycle later, the RAS signal can be deactivated.</li> |
| 191 |
<li>The RAS signal has to remain de-active for at least two cycles.</li> |
| 192 |
</ul> |
| 193 |
|
| 194 |
<p>So a full write cycle takes 6 VDP clock cycles.</p> |
| 195 |
|
| 196 |
|
| 197 |
<h4>A single read</h4> |
| 198 |
|
| 199 |
<p>Reads are very similar to writes, they follow this schema:</p> |
| 200 |
<img src="dram-read.png"> |
| 201 |
<ul> |
| 202 |
<li>Put the row address on the address bus and activate the RAS signal.</li> |
| 203 |
<li>After one cycle:</li> |
| 204 |
<ul> |
| 205 |
<li>Activate (one of) the CAS signals.</li> |
| 206 |
<li>Put the column address on the address bus.</li> |
| 207 |
<li>Set the R/W signal: a high value indicates a read. The VDP keeps this |
| 208 |
signal high between VRAM transactions. So in measurements you don't |
| 209 |
actually see this signal changing for reads.</li> |
| 210 |
</ul> |
| 211 |
</li> |
| 212 |
<li>After two cycles the read data is available on the data bus. The CAS signal |
| 213 |
can be deactivated now.</li> |
| 214 |
<li>After one cycle the RAS signal can be deactivated.</li> |
| 215 |
<li>Wait at least two cycles before starting the next VRAM transaction.</li> |
| 216 |
</ul> |
| 217 |
|
| 218 |
<p>So this is very similar to a write: address selection is identical. |
| 219 |
Obviously the R/W signal and the direction (and timing) of the information on |
| 220 |
the data bus is different. And just like a write, a full read cycle also takes |
| 221 |
6 VDP cycles.</p> |
| 222 |
|
| 223 |
|
| 224 |
<h4>Page mode reads (burst read)</h4> |
| 225 |
|
| 226 |
<p>Often the VDP needs to read data from successive VRAM addresses. If those |
| 227 |
addresses all have the same row address, then there's a faster way to perform |
| 228 |
this compared to doing multiple reads like in the schema above.</p> |
| 229 |
|
| 230 |
<img src="dram-read-burst.png"> |
| 231 |
<ul> |
| 232 |
<li>Put the (common) row address on the address bus and activate the RAS |
| 233 |
signal.</li> |
| 234 |
<li>After one cycle:</li> |
| 235 |
<ul> |
| 236 |
<li>Put the first column address on the address bus.</li> |
| 237 |
<li>Activate (one of) the CAS signals.</li> |
| 238 |
<li>Set the R/W signal (though the VDP already has this signal in the |
| 239 |
correct state).</li> |
| 240 |
</ul> |
| 241 |
<li>After two cycles read the data from the data bus, and deactivate CAS.</li> |
| 242 |
<li>Two cycles later, put the 2nd column address on the address bus and |
| 243 |
re-activate (one of) the CAS signals.</li> |
| 244 |
<li>Again two cycles later read the data and deactivate CAS.</li> |
| 245 |
<li>It's possible to repeat this process for a 3rd, 4th, … byte.</li> |
| 246 |
<li>After one cycle deactivate the RAS signal.</li> |
| 247 |
<li>Wait at least two cycles before starting the next VRAM transaction.</li> |
| 248 |
</ul> |
| 249 |
|
| 250 |
<p>The above diagram shows a burst-length of only two bytes. It's also possible |
| 251 |
to have longer lengths. The VDP uses lengths up-to 4 bytes (or 8, see next |
| 252 |
section).</p> |
| 253 |
|
| 254 |
<p>In this example reading two bytes takes 10 VDP cycles. Doing two single |
| 255 |
reads would take 2×6=12 cycles. When doing longer bursts, the savings |
| 256 |
become bigger. Doing a burst of N reads takes 2+4×N cycles compared to |
| 257 |
6×N cycles for a sequence of single reads.</p> |
| 258 |
|
| 259 |
<p>In principle it's also possible to do burst-writes. Though the VDP doesn't |
| 260 |
use them (it never needs to write more than 1 byte in a sequence).</p> |
| 261 |
|
| 262 |
|
| 263 |
<h4>Multi-bank page mode reads</h4> |
| 264 |
|
| 265 |
<p>Burst reads are already faster than single-reads. But to be able to render |
| 266 |
screen 7 and 8 images, burst reads are still not fast enough. In these two |
| 267 |
screen modes, to be able to read the required data from VRAM fast enough, the |
| 268 |
VDP reads from two banks in parallel.</p> |
| 269 |
|
| 270 |
<img src="dram-read-burst-2banks.png"> |
| 271 |
|
| 272 |
<p>There are 2 banks of 64kB. These two banks share the RAS control signal, but |
| 273 |
they each have their own CAS signal. The address and data signals are also |
| 274 |
shared. This allows to read from both banks <i>almost</i> in parallel:</p> |
| 275 |
<ul> |
| 276 |
<li>In burst mode it was possible to read one byte every 4 VDP cycles. For |
| 277 |
this the CAS signal had two be alternatingly two cycles high and two cycles |
| 278 |
low. The address and data buses are only used during 1 of these 4 cycles.</li> |
| 279 |
<li>Multi-bank mode uses both the CAS0 and the CAS1 signals. CAS0 is high when |
| 280 |
CAS1 is low and vice-versa. When looking at a single bank (which only sees one |
| 281 |
of the two CAS signals) this looks like a normal burst read. The only |
| 282 |
difference is that the RAS signal is at the start or at the end 2 cycles |
| 283 |
longer active than strictly needed. But that's perfectly fine.</li> |
| 284 |
</ul> |
| 285 |
|
| 286 |
<p>So this schema gives (almost) double the VRAM-bandwidth. The only |
| 287 |
requirement is that you alternatingly read from bank0 and bank1. At first sight |
| 288 |
this requirement seems so strict that it is almost never possible to make use of |
| 289 |
this banked reading mode: to render screen 7 or 8 you indeed need to read many |
| 290 |
successive VRAM locations, not locations that alternatingly come from the |
| 291 |
1st and 2nd 64kB bank.</p> |
| 292 |
|
| 293 |
<p>To make it possible to use banked reading mode, the VDP interleaves the two |
| 294 |
banks. This introduces the concept of <i>logical</i> and <i>physical</i> |
| 295 |
addresses:</p> |
| 296 |
<ul> |
| 297 |
<li><i>Logical</i> addresses are the addresses that a programmer of the VDP |
| 298 |
normally uses. For example the bitmap data for screen 8 (possibly) starts at |
| 299 |
address 0x00000 and goes till address 0x0D400.</li> |
| 300 |
<li><i>Physical</i> addresses are the addresses that actually appear on the |
| 301 |
signals between the VDP and the VRAM. So the combination of the row and column |
| 302 |
address and the CAS0 or CAS1 bank-selection.</li> |
| 303 |
</ul> |
| 304 |
|
| 305 |
<p>In most screen modes the logical and the physical addresses are the same. |
| 306 |
But in screen 7 and 8 there's a transformation between the two:</p> |
| 307 |
<p align="center">physical = (logical >> 1) | (logical << 16)</p> |
| 308 |
<p>So the 17-bit logical address is rotated one bit to the right to get the |
| 309 |
physical address. The effect of this transformation is that all even logical |
| 310 |
addresses end up in physical bank0 while all odd logical addresses end up in |
| 311 |
physical bank1. So now when you read from successive logical addresses you read |
| 312 |
from alternating physical banks and thus it is possible to use banked read |
| 313 |
mode.</p> |
| 314 |
|
| 315 |
<p>Usually a VDP programmer doesn't need to be aware of this interleaving. But |
| 316 |
because interleaving is only enabled in screen 7 and 8, this effect can become |
| 317 |
visible when switching between screen modes. <i>An alternative design decision |
| 318 |
could have been to always interleave the addresses. I guess the V9938 designers |
| 319 |
didn't make this choice to allow for single chip configurations in case only |
| 320 |
64kB VRAM is connected.</i></p> |
| 321 |
|
| 322 |
<p>The diagram above shows a read of 2×2 bytes, in reality the VDP only |
| 323 |
uses this schema to read 2×4 bytes. In principle it's also possible to |
| 324 |
write to two banks in parallel, but the VDP never needs this ability.</p> |
| 325 |
|
| 326 |
<h4>Refresh</h4> |
| 327 |
|
| 328 |
<p>DRAM chips need to be refreshed regularly. The VDP is responsible for doing |
| 329 |
this (there are DRAM chips that handle refresh internally, but the VDP doesn't |
| 330 |
use such chips). Many DRAM chips allow a refresh by only activating and |
| 331 |
deactivating the RAS signal, so without actually performing a read or write in |
| 332 |
between. When extrapolating from the above timing diagrams, this would only |
| 333 |
cost 4 cycles. Though the VDP doesn't actually use this RAS-without-CAS refresh |
| 334 |
mode. Instead it performs a regular read access which takes 6 cycles.</p> |
| 335 |
|
| 336 |
<p>Each time a read (or write) is performed on a certain row of a DRAM chip, |
| 337 |
that whole row is refreshed. So to refresh the whole RAM, the VDP has to |
| 338 |
periodically read (any column address of) each of the 256 possible rows.</p> |
| 339 |
|
| 340 |
|
| 341 |
|
| 342 |
<h2>Distribution of VRAM accesses</h2> |
| 343 |
|
| 344 |
<p>The previous section described the details of isolated (single or burst) |
| 345 |
VRAM accesses. This section will look at such accesses as indivisible units and |
| 346 |
examine how these units are grouped together and spread in time to perform all |
| 347 |
the VRAM related stuff the VDP has to do.</p> |
| 348 |
|
| 349 |
<p>The VDP can perform VRAM reads/writes for the following reasons:</p> |
| 350 |
<ul> |
| 351 |
<li>Refresh</li> |
| 352 |
<li>Bitmap rendering</li> |
| 353 |
<li>Sprite rendering</li> |
| 354 |
<li>CPU read/write</li> |
| 355 |
<li>Command read/write</li> |
| 356 |
</ul> |
| 357 |
<p>Note that next to bitmap modes, the VDP also has character and text modes. I |
| 358 |
didn't investigate those modes yet, so this text mostly ignores them.</p> |
| 359 |
|
| 360 |
<p>The rest of this text explains when in time (at which specific VDP |
| 361 |
cycles) accesses of each type are executed.</p> |
| 362 |
|
| 363 |
<p>We'll first focus on refresh and bitmap/sprite rendering. Later we'll add |
| 364 |
CPU and command engine. The reason for this split is that the first group has a |
| 365 |
fairly simple pattern: refreshes always occur at fixed moments in time. |
| 366 |
Enabling bitmap rendering only adds additional VRAM reads but has no influence |
| 367 |
on the timing of the refreshes. Similarly enabling sprite rendering adds even |
| 368 |
more reads without influencing the bitmap or refresh reads. CPU and command |
| 369 |
accesses on the other hand cannot simply be added to this schema without |
| 370 |
influencing each other. So those are postponed till a later section.</p> |
| 371 |
|
| 372 |
<h3>Horizontal line timing</h3> |
| 373 |
|
| 374 |
<p>The VDP renders a full frame line-by-line. For each line the VDP (possibly) |
| 375 |
has to read some bitmap and sprite data from VRAM. It's logical to assume (and |
| 376 |
the measurements confirm this) that the data fetches within one line occur at |
| 377 |
the same relative positions as the corresponding data fetches of another line. |
| 378 |
So if we can figure out the details for one line, we can extrapolate this to a |
| 379 |
whole frame. Similarly we can assume that different frames will have similar |
| 380 |
relative timings. So really all we need to know is the timing of one line.</p> |
| 381 |
|
| 382 |
<p><i>TODO: odd and even frames in interlace mode probably do have timing |
| 383 |
differences. Still need to investigate this.</i> |
| 384 |
</p> |
| 385 |
|
| 386 |
<p>Let's thus first look at what we already know about an horizontal display |
| 387 |
line. The 'V9938 Technical Data Book' contains the following timing info about |
| 388 |
(non-text mode) display lines.</p> |
| 389 |
|
| 390 |
<table> |
| 391 |
<tr><th>Description </th><th>Cycles </th><th>Length</th></tr> |
| 392 |
<tr><td>Synchronize signal</td><td>[0 - 100)</td><td> 100</td></tr> |
| 393 |
<tr><td>Left erase time </td><td>[100 - 202)</td><td> 102</td></tr> |
| 394 |
<tr><td>Left border </td><td>[202 - 258)</td><td> 56</td></tr> |
| 395 |
<tr><td>Display cycle </td><td>[258 - 1282)</td><td>1024</td></tr> |
| 396 |
<tr><td>Right border </td><td>[1282 - 1341)</td><td> 59</td></tr> |
| 397 |
<tr><td>Right erase time </td><td>[1341 - 1368)</td><td> 27</td></tr> |
| 398 |
<tr><td>Total </td><td>[0 - 1368)</td><td>1368</td></tr> |
| 399 |
</table> |
| 400 |
|
| 401 |
<p>So one display line is divided in 6 periods. The total length of one line is |
| 402 |
1368 cycles. The previous section showed how long individual VRAM accesses |
| 403 |
take. The next sections will figure out how all the required accesses fit in |
| 404 |
this per-line budget of 1368 cycles.</p> |
| 405 |
|
| 406 |
<p>A note about the timing notation: in this text all the timing numbers are |
| 407 |
VDP cycles relative within one line. For example in the table above the display |
| 408 |
period starts at cycle 258. The display period of the next line will start at |
| 409 |
cycle 258+1368=1626, the next at cycle 2994 and so on. To make the values |
| 410 |
smaller, all cycle numbers will be folded to the interval [0, 1368). The |
| 411 |
staring point (cycle=0) has no special meaning. We could have taken any other |
| 412 |
point and called that the starting point. (For the current choice, the external |
| 413 |
VDP HSYNC pin gets activated at cycle=0, so it was a convenient point to |
| 414 |
synchronize the measurements on).</p> |
| 415 |
|
| 416 |
<p><i>TODO horizontal set-adjust: The numbers in the above table are valid for |
| 417 |
horizontal set-adjust=0. Similarly all our measurements were done with |
| 418 |
set-adjust=0. Using different set-adjust values will make the left/right border |
| 419 |
bigger/smaller. I still need to figure out which timing values of the next |
| 420 |
sections are changed by this. E.g. are all the VRAM accesses in a line shifted |
| 421 |
as a whole, or are just the bitmap data fetches shifted and remain (some) other |
| 422 |
accesses fixed?</i></p> |
| 423 |
|
| 424 |
<p><i>TODO bits S1,S0 in VDP register R#9: The above table is valid for |
| 425 |
S1,S0=0,0. In other cases the length of a display line is only 1365 cycles |
| 426 |
instead of 1368. The rest of this text assumes a line length of 1368 cycles. I |
| 427 |
still need to figure out where exactly in the line this difference of 3 cycles |
| 428 |
is located.</i></p> |
| 429 |
|
| 430 |
|
| 431 |
|
| 432 |
|
| 433 |
|
| 434 |
|
| 435 |
|
| 436 |
|
| 437 |
|
| 438 |
<h3>Sneak preview</h3> |
| 439 |
|
| 440 |
<p>The following image graphically summarizes the results of the rest of this |
| 441 |
section. This is a very wide image, it is much larger than what can be shown |
| 442 |
inline in this text (click to see the full image). It's highly recommended to |
| 443 |
open this image in an external image viewer that allows to easily zoom in and |
| 444 |
out and scroll the image.</p> |
| 445 |
|
| 446 |
<a href="vdp-timing.png"> |
| 447 |
<img src="vdp-timing.png" width="1200"> |
| 448 |
</a> |
| 449 |
|
| 450 |
<p>Here's an overview of the most important items in this image:</p> |
| 451 |
<ul> |
| 452 |
<li>Horizontally there are 6 regions in the image (each has a slightly |
| 453 |
different background color). These regions correspond to the 'synchronize', |
| 454 |
'left/right erase', 'left/right border' and 'display' regions in the table from |
| 455 |
the previous section.</li> |
| 456 |
<li>Horizontally you also see a timeline going from 0 to 1368 cycles. This |
| 457 |
corresponds to one full display line.</li> |
| 458 |
<li>Vertically there are 3 big groups: 'screen off', 'no sprites' and |
| 459 |
'sprites', see next section for why these groups are important.</li> |
| 460 |
<li>Within one vertical group there is one color-coded band and a set of |
| 461 |
RAS/CAS signals. Usually there's one RAS and 2 CAS signals, but the 'sprites |
| 462 |
off' group has 2 pairs of CAS signals. For the 'sprites off' and 'sprites on' |
| 463 |
groups there are subtle differences in the CAS0/1 signals between screen modes |
| 464 |
5/6 and 7/8. But to save space these differences are only shown once.</li> |
| 465 |
<li>The colors in the color-coded band have the following meaning:</li> |
| 466 |
<ul> |
| 467 |
<li>red: refresh read</li> |
| 468 |
<li>green: bitmap data read (dark-green is dummy bitmap read)</li> |
| 469 |
<li>yellow: sprite data read (brown is dummy sprite read)</li> |
| 470 |
<li>blue: potential CPU or command engine read or write</li> |
| 471 |
<li>dark-grey: dummy read</li> |
| 472 |
<li>light-gray: idle (no read or write)</li> |
| 473 |
</ul> |
| 474 |
<li>The CAS signals are drawn in either a full or a stippled line. Full means |
| 475 |
the signal is definitely high/low at this point. Stippled means, it can be high |
| 476 |
or low depending on whether there was a CPU request or VDP command executing at |
| 477 |
that point. Note that the RAS signal always toggles, even if there is no CPU or |
| 478 |
command access required.</li> |
| 479 |
</ul> |
| 480 |
|
| 481 |
<p>The next sections will go into a lot more detail. It's probably a good idea |
| 482 |
to have this (zoomed in) image open while reading those later sections.</p> |
| 483 |
|
| 484 |
|
| 485 |
<h3>3 operating modes</h3> |
| 486 |
|
| 487 |
<p>When looking from a VDP-VRAM interaction point of view, the VDP can operate |
| 488 |
in 3 modes:</p> |
| 489 |
<ul> |
| 490 |
<li>Screen disabled (sprite status doesn't matter). This is the same as |
| 491 |
vertical border.</li> |
| 492 |
<li>Screen enabled, sprites disabled.</li> |
| 493 |
<li>Screen enabled, sprites enabled.</li> |
| 494 |
</ul> |
| 495 |
|
| 496 |
<p>Note that the (bitmap) screen mode (screen 5, 6, 7, or 8) largely doesn't |
| 497 |
matter for the VRAM access pattern.</p> |
| 498 |
|
| 499 |
<p><i>TODO sprite fetching happens 1 line earlier than displaying those sprites |
| 500 |
(see below for details). This means that the last line of the vertical border |
| 501 |
before the display area likely uses a 'mixed mode' where it doesn't yet fetch |
| 502 |
bitmap data but it does already fetch sprite data. I didn't specifically |
| 503 |
measure this condition, so I can't really tell anything about this mixed mode. |
| 504 |
(One possibility is that it's just like a normal display line, but the fetched |
| 505 |
bitmap data is ignored.) Similarly the last line of the display area doesn't |
| 506 |
strictly need to fetch new sprite data.</i></p> |
| 507 |
|
| 508 |
<p>We'll now look at these 3 modes in more detail.</p> |
| 509 |
|
| 510 |
|
| 511 |
<h4>Screen disabled</h4> |
| 512 |
|
| 513 |
<h5>refresh</h5> |
| 514 |
<p>Screen rendering can be disabled via bit 6 in VDP register R#1. There's also |
| 515 |
no screen rendering when the VDP is showing a vertical border line. From a |
| 516 |
VRAM-access point of view both cases are identical.</p> |
| 517 |
|
| 518 |
<p>In this mode the VDP doesn't need to fetch any data from VRAM for |
| 519 |
rendering. It only needs to refresh the VRAM. As already mentioned earlier, |
| 520 |
the VDP uses a regular read to refresh the RAM, so this takes 6 cycles.</p> |
| 521 |
|
| 522 |
<p>The VDP executes 8 refresh actions per display line. They start at the |
| 523 |
following moments in time (the red blocks in the big timing diagram):</p> |
| 524 |
<table> |
| 525 |
<tr><td>284</td><td>412</td><td>540</td><td>668</td> |
| 526 |
<td>796</td><td>924</td><td>1052</td><td>1180</td></tr> |
| 527 |
</table> |
| 528 |
|
| 529 |
<h5>refresh-addresses</h5> |
| 530 |
<p><i>I didn't investigate this refresh-address-stuff in detail because it |
| 531 |
doesn't matter for emulation accuracy</i>.</p> |
| 532 |
|
| 533 |
<p>The logical addresses used for refresh reads seems to be of the form:</p> |
| 534 |
<p align="center">N×0x10101 | 0x3F</p> |
| 535 |
<p>Where N increases on each refresh action. So each refresh the row address |
| 536 |
increases by one and every other refresh either the CAS0 or the CAS1 signal |
| 537 |
gets used (the columns address doesn't matter for refresh). Note that this |
| 538 |
formula is for the logical address, in screen 7/8 this still gets transformed |
| 539 |
to a physical address. So in screen 7/8 a refresh action always uses the CAS1 |
| 540 |
signal. That means that in screen 7/8 the DRAM chip(s) of bank0 actually do get |
| 541 |
refreshed using the RAS-without-CAS refresh mode.</p> |
| 542 |
|
| 543 |
<p>The refresh timings are the same for all non-text screen modes. But in text |
| 544 |
modes there are only 7 refreshes per line and they are also located at |
| 545 |
different relative positions than in the table above. I didn't investigate |
| 546 |
this further.</p> |
| 547 |
|
| 548 |
|
| 549 |
<h5>dummy reads</h5> |
| 550 |
<p>Next to the refresh reads, in 'screen disabled' mode, the VDP still performs |
| 551 |
4 reads of address 0x1FFFF. At the following moments (marked with dark-grey |
| 552 |
blocks on the timeline):</p> |
| 553 |
<table><tr><td>1236</td><td>1244</td><td>1252</td><td>1260</td></tr></table> |
| 554 |
|
| 555 |
<p>I can't image any use for these reads, so let's call them dummy reads. In all |
| 556 |
our measurements these dummy reads always re-occur in these same positions, so |
| 557 |
it's not a fluke in (only one of) the measurements.</p> |
| 558 |
|
| 559 |
<p>The refresh actions remain exactly the same in the other two modes. But |
| 560 |
these dummy reads are different in the mode 'sprites off' or disappear |
| 561 |
completely in the mode 'sprites on'. (This confirms that nothing 'useful' is |
| 562 |
done by these dummy reads).</p> |
| 563 |
|
| 564 |
<p>Anyway for emulation we can mostly ignore these dummy reads. It only matters |
| 565 |
that at these moments in time there cannot be CPU or command VRAM reads or |
| 566 |
writes.</p> |
| 567 |
|
| 568 |
|
| 569 |
<h4>screen enabled, sprites disabled</h4> |
| 570 |
|
| 571 |
<h5>refresh and dummy reads</h5> |
| 572 |
|
| 573 |
<p>Refresh works exactly the same as in the previous mode. The dummy reads |
| 574 |
are a bit different. Now there are only 3 dummy reads at slightly different |
| 575 |
moments (also shown in dark-grey):</p> |
| 576 |
<table><tr><td>1242</td><td>1250</td><td>1258</td></tr></table> |
| 577 |
|
| 578 |
<p>The first of these 3 reads is always from address 0x1FFFF. The second and |
| 579 |
third dummy read have a pattern in their address. For example:</p> |
| 580 |
<table> |
| 581 |
<tr><th>1st</th><th>2nd</th><th>3rd</th></tr> |
| 582 |
<tr><td>0x1FFFF</td><td>0x03B80</td><td>0x03B82</td></tr> |
| 583 |
<tr><td>0x1FFFF</td><td>0x03C00</td><td>0x03C02</td></tr> |
| 584 |
<tr><td>0x1FFFF</td><td>0x03C80</td><td>0x03C82</td></tr> |
| 585 |
<tr><td>0x1FFFF</td><td>0x03D00</td><td>0x03D02</td></tr> |
| 586 |
</table> |
| 587 |
<p>This table shows the addresses of the 3 dummy reads for 4 successive display |
| 588 |
lines (this is data from an actual measurement, unfortunately our equipment |
| 589 |
could only buffer up to 4 lines). The lower 7 bits of the address of the 2nd |
| 590 |
read always seem to be zero. The address of the 3rd read is the same as for the |
| 591 |
2nd read except that bit 1 is set to 1. When going from one line to the next, |
| 592 |
the address increases by 0x80. Our measurements captured 10 independent sets of |
| 593 |
4 successive lines. Each time bits 16-15 were zero (bits 14-7 do take different |
| 594 |
values). This could be a coincidence, or it could be that these bits really |
| 595 |
aren't included in the counter. Note that again these are logical addresses (so |
| 596 |
still transformed for screen 7/8). I didn't investigate these dummy reads in |
| 597 |
more detail because they mostly don't matter for emulation.</p> |
| 598 |
|
| 599 |
|
| 600 |
<h5>bitmap reads</h5> |
| 601 |
<p>The major change compared to the previous mode is that now the VDP needs to |
| 602 |
fetch extra data for the bitmap rendering. These fetches happen in 32 blocks of |
| 603 |
4 bytes (screen 5/6) or 8 bytes (screen 7/8). The fetches within one block |
| 604 |
happen in burst mode. This means that one block takes 18 cycles (screen 5/6) or |
| 605 |
20 cycles (screen 7/8). Though later we'll see that the two spare cycles for |
| 606 |
screen 5/6 are not used for anything else, so for simplicity we can say that in |
| 607 |
all bitmap modes a bitmap-fetch-block takes 20 cycles. This is even clearer if |
| 608 |
you look at the RAS signal: this signal follows the exact same pattern in all |
| 609 |
(bitmap) screen modes, so in screen 5/6 it remains active for two cycles longer |
| 610 |
than strictly necessary.</p> |
| 611 |
|
| 612 |
<p>Actually before these 32 blocks there's one extra dummy block. This block |
| 613 |
has the same timing as the other blocks, but it always reads address 0x1FFFF. |
| 614 |
From an emulator point of view, these dummy reads don't matter, it only matters |
| 615 |
that at those moments no other VRAM accesses can occur.</p> |
| 616 |
|
| 617 |
<p>The start of these 1+32 blocks are located at these moments in time (these |
| 618 |
are the green blocks in the big timing diagram):</p> |
| 619 |
<table> |
| 620 |
<tr><td>(195)</td><td> 227</td><td> 259</td><td> 291</td><td> 323</td> |
| 621 |
<td> 355</td><td> 387</td><td> 419</td><td> 451</td></tr> |
| 622 |
<tr><td> </td><td> 483</td><td> 515</td><td> 547</td><td> 579</td> |
| 623 |
<td> 611</td><td> 643</td><td> 675</td><td> 707</td></tr> |
| 624 |
<tr><td> </td><td> 739</td><td> 771</td><td> 803</td><td> 835</td> |
| 625 |
<td> 867</td><td> 899</td><td> 931</td><td> 963</td></tr> |
| 626 |
<tr><td> </td><td> 995</td><td>1027</td><td>1059</td><td>1091</td> |
| 627 |
<td>1123</td><td>1155</td><td>1187</td><td>1219</td></tr> |
| 628 |
</table> |
| 629 |
|
| 630 |
<p><i>The following is only speculation: I wonder why there is such a dummy |
| 631 |
preamble block. Theoretically this <b>could</b> have been used (or reserved) to |
| 632 |
implement V9958-like horizontal scrolling without having to mask 8 border |
| 633 |
pixels. Unfortunately horizontal scrolling on a V9958 doesn't work like that |
| 634 |
:(</i></p> |
| 635 |
|
| 636 |
<h4>screen enabled, sprites enabled</h4> |
| 637 |
|
| 638 |
<h5>refresh, dummy reads, bitmap reads</h5> |
| 639 |
<p>Refresh and bitmap reads are exactly the same as in the previous mode. But |
| 640 |
the 3 or 4 dummy reads from the previous 2 modes are not present in this |
| 641 |
mode.</p> |
| 642 |
|
| 643 |
<h5>sprite reads</h5> |
| 644 |
<p><i>I've only investigated bitmap modes, that means the stuff below applies |
| 645 |
only to sprite mode 2.</i></p> |
| 646 |
|
| 647 |
<p>For sprite rendering you need to: |
| 648 |
<ul> |
| 649 |
<li>Figure out which sprites are visible: There are 32 positions in the |
| 650 |
sprite attribute table, and of those maximum 8 sprites can be visible |
| 651 |
(per line).</li> |
| 652 |
<li>For the visible sprites, fetch the required data so that it can actually |
| 653 |
be drawn. This data is: the x- and y-coordinates, the sprite pattern number, |
| 654 |
the pattern data and the color data.</li> |
| 655 |
</ul> |
| 656 |
|
| 657 |
<p>Figuring out which sprites are visible is done by reading the y-coordinates |
| 658 |
of each of the 32 possible sprites. These reads happen interleaved between the |
| 659 |
32 block-reads of the bitmap data, so read one byte between each bitmap-block. |
| 660 |
Because of this interleaving it's not possible to use burst mode, so each read |
| 661 |
takes 6 cycles. There's also 1 dummy read of address 0x1FFFF at the end. The |
| 662 |
reads happen at these moments in time (yellow blocks between the green blocks in |
| 663 |
the diagram):</p> |
| 664 |
<table> |
| 665 |
<tr><td> 182</td><td> 214</td><td> 246</td><td> 278</td> |
| 666 |
<td> 310</td><td> 342</td><td> 374</td><td> 406</td></tr> |
| 667 |
<tr><td> 438</td><td> 470</td><td> 502</td><td> 534</td> |
| 668 |
<td> 566</td><td> 598</td><td> 630</td><td> 662</td></tr> |
| 669 |
<tr><td> 694</td><td> 726</td><td> 758</td><td> 790</td> |
| 670 |
<td> 822</td><td> 854</td><td> 886</td><td> 918</td></tr> |
| 671 |
<tr><td> 950</td><td> 982</td><td>1014</td><td>1046</td> |
| 672 |
<td>1078</td><td>1110</td><td>1142</td><td>1174</td><td>(1206)</td></tr> |
| 673 |
</table> |
| 674 |
|
| 675 |
<p>In the worst case, the 8 last sprites of the attribute table are visible. In |
| 676 |
that case all 32 reads are really required. Though even if the limit of 8 |
| 677 |
visible sprites is reached earlier, the VDP continues fetching all 32+1 bytes. |
| 678 |
Also if one y-coordinate is equal to 216 (meaning that all later sprites are |
| 679 |
invisible), still all 32+1 fetches are executed.</p> |
| 680 |
|
| 681 |
<p>Once the VDP has figured out which sprites are visible it needs to fetch the |
| 682 |
data to actually draw the sprites. This VRAM access pattern is relatively |
| 683 |
complex:</p> |
| 684 |
<ul> |
| 685 |
<li>In the worst case there are 8 visible sprites. This requires reading |
| 686 |
8×6 bytes. Some of these reads can be done in burst mode, others are |
| 687 |
single byte reads.</li> |
| 688 |
<li>Even if there are less than 8 sprites to display, all read accesses do |
| 689 |
still occurs. It <i>seems</i> to be that the useless reads are duplicates of |
| 690 |
sprite 0. (Or is it the first visible sprite? I didn't look in detail because |
| 691 |
it's not important for our purpose. It only matters that the VRAM bus remains |
| 692 |
occupied).</li> |
| 693 |
<li>The data fetches happens in 4 chunks of each 2 sprites. Each chunk |
| 694 |
reads:</li> |
| 695 |
<ul> |
| 696 |
<li>Y-coordinate, x-coordinate and pattern-number of 1st sprite. Burst of 3 |
| 697 |
reads, takes 13(!)cycles.</li> |
| 698 |
<li>Y-coordinate, x-coordinate and pattern-number of 2nd sprite. Burst of 3 |
| 699 |
reads, takes 13(!)cycles.</li> |
| 700 |
<li>Pause of 6 or 10(!) cycles</li> |
| 701 |
<li>2 pattern bytes of 1st sprite. Burst of 2 reads, takes 10 cycles.</li> |
| 702 |
<li>Color attribute of 1st sprite. Single read, takes 6 cycles.</li> |
| 703 |
<li>2 pattern bytes of 2nd sprite. Burst of 2 reads, takes 10 cycles.</li> |
| 704 |
<li>Color attribute of 2nd sprite. Single read, takes 6 cycles.</li> |
| 705 |
</ul> |
| 706 |
<li>Note that the burst of 3 reads only takes 13 instead of the expected 14 |
| 707 |
cycles. If you look at the RAS/CAS signals you see that this uses an illegal(?) |
| 708 |
RAM access pattern: RAS is released together with CAS (even slightly before if |
| 709 |
you look at the raw measured data). But obviously this seems to work fine |
| 710 |
<i>… makes me wonder why the VDP doesn't always use this faster |
| 711 |
access pattern.</i></li> |
| 712 |
<li>Even for 8x8 sprites, the VDP always fetches 2 bytes of pattern-data per |
| 713 |
sprite line (and the 2nd byte is ignored).</li> |
| 714 |
<li>Note that the y-coordinate is fetched again. It was already fetched to |
| 715 |
figure out which sprites are visible.</li> |
| 716 |
<li>The positions in time of these reads (single or burst) are like this |
| 717 |
(yellow blocks (mostly) in the border period in the big timing diagram): |
| 718 |
<table> |
| 719 |
<tr><td>1238</td><td>1251</td><td>1270</td><td>1280</td><td>1286</td><td>1296</td></tr> |
| 720 |
<tr><td>1302</td><td>1315</td><td>1338</td><td>1348</td><td>1354</td><td>1364</td></tr> |
| 721 |
<tr><td> 2</td><td> 15</td><td> 34</td><td> 44</td><td> 50</td><td> 60</td></tr> |
| 722 |
<tr><td> 66</td><td> 79</td><td> 98</td><td> 108</td><td> 114</td><td> 124</td></tr> |
| 723 |
</table> |
| 724 |
Note that some of these fetches occur in the previous and some in the current |
| 725 |
display line. Though the start of the display line was chosen arbitrary (we |
| 726 |
could have picked the staring point so that these numbers don't wrap). It only |
| 727 |
matters that all sprite data is fetched before the display rendering |
| 728 |
starts.</li> |
| 729 |
<li>Also note that the timing is slightly irregular: in the 1st, 3rd and 4th |
| 730 |
group there's a pause of 6 cycles, there fits exactly one other access in this |
| 731 |
gap. But in the 2nd group there's a pause of 10 cycles. There also only fits |
| 732 |
one other access in this gap, and the timing is 2+6+2, so 2 'wasted' cycles |
| 733 |
before and after that other access. <i>I suspect that these 2+2 cycles are |
| 734 |
related to the R#9 S1,S0 bits. TODO measure this</i>.</li> |
| 735 |
</ul> |
| 736 |
|
| 737 |
<p>It's worth repeating that whenever sprites are enabled, the VDP |
| 738 |
<b>always</b> performs the same fetch-pattern. So even if no sprites are |
| 739 |
actually visible, or if sprites are partially disabled (with y=216), and even |
| 740 |
with 8x8 vs 16x16 sprites, magnified or not. This confirms the fact that the |
| 741 |
VDP command engine is slowed down by the exact same amount in all these |
| 742 |
situation. Also all (bitmap) screen modes behave exactly the same with respect |
| 743 |
to sprite data fetches.</p> |
| 744 |
|
| 745 |
|
| 746 |
|
| 747 |
<h3>CPU and command reads/writes</h3> |
| 748 |
|
| 749 |
<h5>position of access slots</h5> |
| 750 |
<p>The previous sections explained when the VDP reads from VRAM for refresh and |
| 751 |
bitmap/sprite rendering (and even some dummy reads). Depending on the mode |
| 752 |
(screen/sprites enabled/disabled), this takes more or less of the available |
| 753 |
VRAM-bandwidth. The portion of the VRAM bandwidth that is not used for |
| 754 |
rendering can be used for CPU or command engine VRAM reads or writes.</p> |
| 755 |
|
| 756 |
<p>All CPU and command engine accesses are single (non-burst) accesses, so they |
| 757 |
take 6 cycles each. However it is <b>not</b> the case that whenever the VRAM |
| 758 |
bus is idle for 6 cycles, it can be used for CPU or command engine |
| 759 |
accesses.</p> |
| 760 |
|
| 761 |
<p>Instead there are fixed moments in time where there could <i>possibly</i> |
| 762 |
start a cpu or command access, let's call these moments access slots. Each slot |
| 763 |
can be used for either CPU or command accesses (there are no slots that are |
| 764 |
uniquely reserved for either CPU or for commands). The position and the amount |
| 765 |
of access slots <i>only</i> depends on the VDP mode (screen off, sprites off, |
| 766 |
sprites on), not for example on the amount of actually visible sprites or on |
| 767 |
the (bitmap) screen mode.</p> |
| 768 |
|
| 769 |
<p>The 3 tables below show the amount and the positions of the possible access |
| 770 |
slots for the 3 different modes (in the timing diagram these are the blue |
| 771 |
blocks):</p> |
| 772 |
|
| 773 |
<p><table> |
| 774 |
<caption>screen off, 154 possible slots</caption> |
| 775 |
<tr><td> 0</td><td> 8</td><td> 16</td><td> 24</td><td> 32</td> |
| 776 |
<td> 40</td><td> 48</td><td> 56</td><td> 64</td><td> 72</td></tr> |
| 777 |
<tr><td> 80</td><td> 88</td><td> 96</td><td> 104</td><td> 112</td> |
| 778 |
<td> 120</td><td> 164</td><td> 172</td><td> 180</td><td> 188</td></tr> |
| 779 |
<tr><td> 196</td><td> 204</td><td> 212</td><td> 220</td><td> 228</td> |
| 780 |
<td> 236</td><td> 244</td><td> 252</td><td> 260</td><td> 268</td></tr> |
| 781 |
<tr><td> 276</td><td> 292</td><td> 300</td><td> 308</td><td> 316</td> |
| 782 |
<td> 324</td><td> 332</td><td> 340</td><td> 348</td><td> 356</td></tr> |
| 783 |
<tr><td> 364</td><td> 372</td><td> 380</td><td> 388</td><td> 396</td> |
| 784 |
<td> 404</td><td> 420</td><td> 428</td><td> 436</td><td> 444</td></tr> |
| 785 |
<tr><td> 452</td><td> 460</td><td> 468</td><td> 476</td><td> 484</td> |
| 786 |
<td> 492</td><td> 500</td><td> 508</td><td> 516</td><td> 524</td></tr> |
| 787 |
<tr><td> 532</td><td> 548</td><td> 556</td><td> 564</td><td> 572</td> |
| 788 |
<td> 580</td><td> 588</td><td> 596</td><td> 604</td><td> 612</td></tr> |
| 789 |
<tr><td> 620</td><td> 628</td><td> 636</td><td> 644</td><td> 652</td> |
| 790 |
<td> 660</td><td> 676</td><td> 684</td><td> 692</td><td> 700</td></tr> |
| 791 |
<tr><td> 708</td><td> 716</td><td> 724</td><td> 732</td><td> 740</td> |
| 792 |
<td> 748</td><td> 756</td><td> 764</td><td> 772</td><td> 780</td></tr> |
| 793 |
<tr><td> 788</td><td> 804</td><td> 812</td><td> 820</td><td> 828</td> |
| 794 |
<td> 836</td><td> 844</td><td> 852</td><td> 860</td><td> 868</td></tr> |
| 795 |
<tr><td> 876</td><td> 884</td><td> 892</td><td> 900</td><td> 908</td> |
| 796 |
<td> 916</td><td> 932</td><td> 940</td><td> 948</td><td> 956</td></tr> |
| 797 |
<tr><td> 964</td><td> 972</td><td> 980</td><td> 988</td><td> 996</td> |
| 798 |
<td>1004</td><td>1012</td><td>1020</td><td>1028</td><td>1036</td></tr> |
| 799 |
<tr><td>1044</td><td>1060</td><td>1068</td><td>1076</td><td>1084</td> |
| 800 |
<td>1092</td><td>1100</td><td>1108</td><td>1116</td><td>1124</td></tr> |
| 801 |
<tr><td>1132</td><td>1140</td><td>1148</td><td>1156</td><td>1164</td> |
| 802 |
<td>1172</td><td>1188</td><td>1196</td><td>1204</td><td>1212</td></tr> |
| 803 |
<tr><td>1220</td><td>1228</td><td>1268</td><td>1276</td><td>1284</td> |
| 804 |
<td>1292</td><td>1300</td><td>1308</td><td>1316</td><td>1324</td></tr> |
| 805 |
<tr><td>1334</td><td>1344</td><td>1352</td><td>1360</td></tr> |
| 806 |
</table></p> |
| 807 |
|
| 808 |
<p><table> |
| 809 |
<caption>sprites off, 88 possible slots</caption> |
| 810 |
<tr><td> 6</td><td> 14</td><td> 22</td><td> 30</td><td> 38</td> |
| 811 |
<td> 46</td><td> 54</td><td> 62</td><td> 70</td><td> 78</td></tr> |
| 812 |
<tr><td> 86</td><td> 94</td><td> 102</td><td> 110</td><td> 118</td> |
| 813 |
<td> 162</td><td> 170</td><td> 182</td><td> 188</td><td> 214</td></tr> |
| 814 |
<tr><td> 220</td><td> 246</td><td> 252</td><td> 278</td><td> 310</td> |
| 815 |
<td> 316</td><td> 342</td><td> 348</td><td> 374</td><td> 380</td></tr> |
| 816 |
<tr><td> 406</td><td> 438</td><td> 444</td><td> 470</td><td> 476</td> |
| 817 |
<td> 502</td><td> 508</td><td> 534</td><td> 566</td><td> 572</td></tr> |
| 818 |
<tr><td> 598</td><td> 604</td><td> 630</td><td> 636</td><td> 662</td> |
| 819 |
<td> 694</td><td> 700</td><td> 726</td><td> 732</td><td> 758</td></tr> |
| 820 |
<tr><td> 764</td><td> 790</td><td> 822</td><td> 828</td><td> 854</td> |
| 821 |
<td> 860</td><td> 886</td><td> 892</td><td> 918</td><td> 950</td></tr> |
| 822 |
<tr><td> 956</td><td> 982</td><td> 988</td><td>1014</td><td>1020</td> |
| 823 |
<td>1046</td><td>1078</td><td>1084</td><td>1110</td><td>1116</td></tr> |
| 824 |
<tr><td>1142</td><td>1148</td><td>1174</td><td>1206</td><td>1212</td> |
| 825 |
<td>1266</td><td>1274</td><td>1282</td><td>1290</td><td>1298</td></tr> |
| 826 |
<tr><td>1306</td><td>1314</td><td>1322</td><td>1332</td><td>1342</td> |
| 827 |
<td>1350</td><td>1358</td><td>1366</td></tr> |
| 828 |
</table></p> |
| 829 |
|
| 830 |
<p><table> |
| 831 |
<caption>sprites on, 31 possible slots</caption> |
| 832 |
<tr><td> 28</td><td> 92</td><td> 162</td><td> 170</td><td> 188</td> |
| 833 |
<td> 220</td><td> 252</td><td> 316</td><td> 348</td><td> 380</td></tr> |
| 834 |
<tr><td> 444</td><td> 476</td><td> 508</td><td> 572</td><td> 604</td> |
| 835 |
<td> 636</td><td> 700</td><td> 732</td><td> 764</td><td> 828</td></tr> |
| 836 |
<tr><td> 860</td><td> 892</td><td> 956</td><td> 988</td><td>1020</td> |
| 837 |
<td>1084</td><td>1116</td><td>1148</td><td>1212</td><td>1264</td></tr> |
| 838 |
<tr><td>1330</td></tr> |
| 839 |
</table></p> |
| 840 |
|
| 841 |
<p>Note that even in the mode 'screen off', when the VRAM bus is otherwise |
| 842 |
mostly idle, the access slots are still at least 8 cycles apart. A single |
| 843 |
access takes only 6 cycles, so 2 cycles are wasted.</p> |
| 844 |
|
| 845 |
<p>Very roughly speaking in mode 'screen off' there are about twice as many |
| 846 |
access slots as in the mode 'sprites off' and about 5 times as many as in the |
| 847 |
mode 'sprites on'. This does however <b>not</b> mean that in these modes the |
| 848 |
command engine will execute respectively 2× and 5× as fast. Instead |
| 849 |
in the mode 'sprites on' the speed of command execution is mostly limited by |
| 850 |
the amount of available access slots, while in the mode 'screen off', the |
| 851 |
bottleneck is mostly the speed of the command engine itself.</p> |
| 852 |
|
| 853 |
<p>Also note that the access slots are not evenly spread in time. For |
| 854 |
example:</p> |
| 855 |
<ul> |
| 856 |
<li>In mode 'screen off', the slots are often only 8 cycles apart (measured |
| 857 |
from the start of the 1st to the start of the 2nd slot). Though starting |
| 858 |
at cycle=120 there's a gap of 44 cycles.</li> |
| 859 |
<li>In mode 'sprites off', during the horizontal border, the access slots are |
| 860 |
roughly 8 cycles apart like in the previous mode, but during the display |
| 861 |
period, the spacing is more like 26 or 32 cycles. The largest gap is now 54 |
| 862 |
cycles starting at cycle=1212.</li> |
| 863 |
<li>In mode 'sprites on', the pattern is again completely different. Here the |
| 864 |
slots are roughly 32 or 64 cycles apart. (The border even has slightly larger |
| 865 |
gaps than the display area. So contrary to some speculations, the commands do |
| 866 |
not execute faster in the horizontal border in this mode). The largest gap is |
| 867 |
now 70 cycles, starting at cycle=92. There's even one location where the |
| 868 |
smallest gap is also only 8 cycles. (Though if you look at the measurements |
| 869 |
you'll see that the slot right after this smallest gap (at cycle=170) is rarely |
| 870 |
actually used, even though the command engine is starved for VRAM |
| 871 |
bandwidth).</li> |
| 872 |
</ul> |
| 873 |
|
| 874 |
<p>These large gaps between the access slots are important. For example if the |
| 875 |
CPU is sending data to the VDP at a too fast rate, and this happens right at a |
| 876 |
moment where there are no access slots available, then some of the data send by |
| 877 |
the CPU is lost. We'll see later in this text that this can even happen |
| 878 |
when the time between the incoming CPU requests is (slightly) larger than the |
| 879 |
size of the largest gap.</p> |
| 880 |
|
| 881 |
|
| 882 |
<h5>allocation of access slots</h5> |
| 883 |
<p>The access slots can be used for either CPU or VDP command reads or writes. |
| 884 |
This section explains how the slots are allocated to these two subsystems.</p> |
| 885 |
|
| 886 |
<p>The basic principle is very simple: the CPU or the command engine take the |
| 887 |
first available access slot. And when the CPU and command engine both require |
| 888 |
an access slot at the same time, then the CPU gets priority. Though if you look |
| 889 |
at the details it is a bit more complicated:</p> |
| 890 |
|
| 891 |
<ul> |
| 892 |
<li>When the CPU sends a read or write VRAM request to the VDP, this request is |
| 893 |
put in a buffer until it can be handled.</li> |
| 894 |
<li>When the CPU sends a new request when there's still a previous request |
| 895 |
pending then the old request is lost. More on this below. <i>TODO most logical |
| 896 |
is that the old (not the new) request is lost, but actually check this. Though |
| 897 |
the Z80 might be too slow to be able to test this.</i></li> |
| 898 |
<li>Similarly when the VDP command engine needs to perform a VRAM read or |
| 899 |
write, this request is also put in a buffer. This is a different buffer than |
| 900 |
the one for CPU requests.</li> |
| 901 |
<li>In contrast to the CPU, the command engine is stalled when the command |
| 902 |
engine buffer holds a request. So command engine requests can never get |
| 903 |
lost.</li> |
| 904 |
<li>16 cycles in advance of an access slot the VDP checks whether there is |
| 905 |
either a pending CPU or command request. If there's a pending CPU request, that |
| 906 |
request will be executed (16 cycles later). If there's no cpu request but there |
| 907 |
is a command request then that one will be executed (16 cycles later). So the |
| 908 |
CPU takes priority over the command engine. And very important, if there's no |
| 909 |
request pending yet, then 16 cycles later nothing will be executed, not even if |
| 910 |
a request does arrive within 16 cycles.</li> |
| 911 |
</ul> |
| 912 |
|
| 913 |
|
| 914 |
<h5>cpu access slows down command execution</h5> |
| 915 |
<p>A surprising result (at least to me) of these measurements is that the |
| 916 |
speed of VDP command execution is reduced while simultaneously doing CPU VRAM |
| 917 |
accesses. Looking back this makes sense because the same VRAM access slots are |
| 918 |
shared between CPU and command engine and the CPU gets priority.</p> |
| 919 |
|
| 920 |
<p>This effect is clearly noticeable in the mode 'sprites on' but much less in |
| 921 |
the other two modes. This is easily explained by looking at the amount of |
| 922 |
available access slots in these modes.</p> |
| 923 |
|
| 924 |
<p>The most extreme situation occurs in this test. Execute a HMMV VDP command |
| 925 |
(this is the fastest command, see below) while simultaneously executing a long |
| 926 |
series of <code>OUT (#98),A</code> instructions (the fastest way to send CPU |
| 927 |
write requests). In our measurements, in the mode 'sprites on' the command |
| 928 |
execution speed was approximately cut in half! But in the other two modes, the |
| 929 |
execution speed was barely influenced. (Actually our test program wasn't |
| 930 |
accurate enough to measure any significant speed difference, but theoretically |
| 931 |
also in the latter two modes the execution speed should be reduced by a small |
| 932 |
amount).</p> |
| 933 |
|
| 934 |
|
| 935 |
<h5>too fast CPU access</h5> |
| 936 |
<p>The fastest way for the Z80 to send read or write VRAM request to the VDP is |
| 937 |
by using a sequence of <code>IN A,(#98)</code> or <code>OUT (#98),A</code> |
| 938 |
instructions (of course such a sequence always writes the same value or ignores |
| 939 |
all but the last read value). This takes 12 Z80 clock cycles per request. |
| 940 |
(Instructions like <code>OUT (C),r</code> or <code>OUTI</code> are all slower). |
| 941 |
The VDP is clocked at 6× the Z80 speed. So when the Z80 sends multiple |
| 942 |
requests to the VDP, the minimal distance between these requests, translated to |
| 943 |
VDP cycles, is at least 72 VDP cycles. Earlier we saw that the maximal gap |
| 944 |
between access slots was 70 VDP cycles, so at first sight there's no problem. |
| 945 |
However consider this scenario:</p> |
| 946 |
|
| 947 |
<ul> |
| 948 |
<li>Suppose we're in 'sprites on' mode. At time=236, we're 16 cycles before an |
| 949 |
access slot. Suppose there's no pending CPU nor command request at this |
| 950 |
time. So nothing will get executed at time=252.</li> |
| 951 |
<li>A bit later at time=240 there arrives a CPU write request. This request |
| 952 |
gets buffered.</li> |
| 953 |
<li>At time=252 there is an access slot, but nothing will get executed in this |
| 954 |
slot (because this slot wasn't allocated at time=236).</li> |
| 955 |
<li>At time=300 we're again 16 cycles before an access slot. Now there is a |
| 956 |
pending CPU request, so we'll execute that at time=316.</li> |
| 957 |
<li>At time=312 we receive a new CPU write request. This is 312-240=72 VDP |
| 958 |
cycles (or 12 Z80 cycles, the duration of a <code>OUT (#98),A</code> |
| 959 |
instruction) after the previous request. But the buffer still contains the |
| 960 |
previous unhandled request. The new request overwrites the old request!</li> |
| 961 |
<li>At time=316 there's an access slot and we've allocated this slot to the CPU |
| 962 |
(at time=300). So the pending CPU request gets executed. Though this writes the |
| 963 |
data from the new request, the data from the old request is never written!</li> |
| 964 |
</ul> |
| 965 |
|
| 966 |
<p>Note that this scenario used a gap of only 64 VDP cycles between access |
| 967 |
slots, while there were 72 cycles between the CPU requests. (And the largest |
| 968 |
gap between access slots is 70 cycles).</p> |
| 969 |
|
| 970 |
|
| 971 |
|
| 972 |
|
| 973 |
|
| 974 |
|
| 975 |
|
| 976 |
|
| 977 |
<h2>Command engine timing</h2> |
| 978 |
|
| 979 |
<p>The command engine needs access to VRAM. In the previous section we saw when |
| 980 |
the VDP will grand access to this subsystem: when there's an access slot |
| 981 |
available and when that slot is not already allocated to CPU access. In this |
| 982 |
section we'll see when exactly the command engine will generate VRAM access |
| 983 |
requests. Obviously the type (read or write) and the rate of these requests |
| 984 |
depends on the type of the VDP command that is executing.</p> |
| 985 |
|
| 986 |
<p>Some commands (like HMMV) only need to write to VRAM. Other commands (like |
| 987 |
LMMM) need 2 reads and 1 write per pixel. Many commands execute on a block (a |
| 988 |
rectangle) of pixels. Such a block is executed line per line (all pixels within |
| 989 |
one horizontal line are processed before moving to the next line). Moving from |
| 990 |
one line to the next takes some amount of time (but YMMM is an exception, see |
| 991 |
below). This means that e.g. a HMMM command on a 20x4 rectangle executes faster |
| 992 |
than on a 4x20 rectangle (same amount of pixels in both cases, but a different |
| 993 |
rectangle shape).</p> |
| 994 |
|
| 995 |
<p>The following table summarizes the timing for all measured commands:</p> |
| 996 |
<table> |
| 997 |
<tr><th>Command</th><th>Per pixel</th><th>Per line</th></tr> |
| 998 |
<tr><td>HMMV</td><td>48 W </td><td>56</td></tr> |
| 999 |
<tr><td>YMMM</td><td>40 R 24 W </td><td>0 </td></tr> |
| 1000 |
<tr><td>HMMM</td><td>64 R 24 W </td><td>64</td></tr> |
| 1001 |
<tr><td>LMMV</td><td>72 R 24 W </td><td>64</td></tr> |
| 1002 |
<tr><td>LMMM</td><td>64 R 32 R 24 W</td><td>64</td></tr> |
| 1003 |
<tr><td>LINE</td><td>88 R 24 W </td><td>32</td></tr> |
| 1004 |
</table> |
| 1005 |
<p><i>TODO timing for PSET, POINT, SRCH</i></p> |
| 1006 |
|
| 1007 |
<p>I'll explain the notation in this table with an example. Take the LMMM |
| 1008 |
command:</p> |
| 1009 |
<ul> |
| 1010 |
<li>Per pixel the LMMM command needs to: |
| 1011 |
<ul><li>Read a byte from the source.</li> |
| 1012 |
<li>Read a byte from the destination</li> |
| 1013 |
<li>Calculate the result: extract the pixel value from source and |
| 1014 |
destination, combine the two (possibly with a logical operation), insert |
| 1015 |
the result in the destination byte. And write the result back to the |
| 1016 |
destination.</li> |
| 1017 |
</ul></li> |
| 1018 |
<li>So per pixel, the LMMM command will generate 3 VRAM accesses: 2 read |
| 1019 |
followed by one write. Between these accesses there will be some amount of |
| 1020 |
time.</li> |
| 1021 |
<li>For LMMM the table lists '64 R 32 R 24 W'. Let's start at the 1st 'R' |
| 1022 |
character, this represents the 1st read. Next there's the value 32 and a 2nd |
| 1023 |
'R', this means that the 2nd read comes <i>at least</i> 32 cycles after the 1st |
| 1024 |
read. Then there's '24 W', meaning there are <i>at least</i> 24 cycles between |
| 1025 |
the 2nd read and the write. And the initial value '64' means that there are |
| 1026 |
<i>at least</i> 64 cycles between the write and the 1st read for the next |
| 1027 |
pixel.</li> |
| 1028 |
<li>When moving from one horizontal line to the next in a block command, there |
| 1029 |
is some extra delay. For the LMMM command this takes 64 extra cycles. So |
| 1030 |
64+64=128 cycles from the last write of a line till the first read of the next |
| 1031 |
line.</li> |
| 1032 |
<li>Note that all these values are the <i>optimal</i> timing values. The actual |
| 1033 |
delay can be longer because there is no access slot available or the slot is |
| 1034 |
already allocated for CPU access.</li> |
| 1035 |
</ul> |
| 1036 |
|
| 1037 |
<p>All the commands in the table above are block commands except for 'LINE'. |
| 1038 |
For the LINE command the meaning of the columns 'Per pixel' and 'Per line' may |
| 1039 |
not be immediately clear:</p> |
| 1040 |
<ul> |
| 1041 |
<li>The VDP uses the <a href="http://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm"> |
| 1042 |
Bresenham algorithm</a> the calculate which pixels are part of the line.</li> |
| 1043 |
<li>This algorithm takes at each iteration one step in the <i>major</i> |
| 1044 |
direction. The timings for such an iteration are written in the 'Per pixel' |
| 1045 |
column for the LINE command.</li> |
| 1046 |
<li>Depending on the slope of the line, in some iterations the Bresenham |
| 1047 |
algorithm also takes a step in the <i>minor</i> direction. For the VDP such a |
| 1048 |
minor step takes some extra time (32 cycles). This is written in the 'Per line' |
| 1049 |
column of the LINE command. (If you look back at the very beginning of this |
| 1050 |
text, these major and minor steps explain the general octagonal shapes in the |
| 1051 |
images. The uneven distribution of the access slots explain the |
| 1052 |
irregularities.)</li> |
| 1053 |
</ul> |
| 1054 |
|
| 1055 |
<p>Note that for the YMMM command there's no extra overhead when going from one |
| 1056 |
horizontal line to the next. This might be related to the fact that a line of |
| 1057 |
a YMMV command always starts at the left or right border of the screen.</p> |
| 1058 |
|
| 1059 |
<p><i>TODO What we didn't measure (also couldn't measure with our test setup) |
| 1060 |
was the delay between the start of the command (when the CPU sends the command |
| 1061 |
byte to the VDP) and the moment the command actually starts executing (e.g. |
| 1062 |
when the first read or write command access is send to VRAM). It's logical to |
| 1063 |
assume that the 'per line' overhead also occurs at the start of the command. |
| 1064 |
But it's possible there is also some additional 'per command' overhead.</i></p> |
| 1065 |
|
| 1066 |
<h5>speculation on the slowness of the command engine</h5> |
| 1067 |
<p>When looking at the above table, we see that the command engine is very |
| 1068 |
slow. For example in a HMMM command there are 24 cycles between reading a byte |
| 1069 |
and writing that byte to the new location. Or in a LINE command it takes 32 |
| 1070 |
cycles to take a step in the minor direction. I <i>believe</i> there are two |
| 1071 |
main reasons for this slowness:</p> |
| 1072 |
<ul> |
| 1073 |
<li>I believe that internally the VDP command engine subsystem runs at 1/8 of |
| 1074 |
the master VDP clock frequency. This matches the observation that all values in |
| 1075 |
the above table are multiples of 8. It also explains why the access slots are |
| 1076 |
always at least 8 cycles apart (while a VRAM access only requires 6 |
| 1077 |
cycles).</li> |
| 1078 |
<li>The command engine gets stalled whenever there's a pending command engine |
| 1079 |
VRAM request. A VRAM request (CPU or command) only gets handled after it's been |
| 1080 |
pending for at least 16 cycles. So combined this means the command engine gets |
| 1081 |
stalled for 16 cycles on every VRAM request it makes. (Note that especially |
| 1082 |
this point is just speculation).</li> |
| 1083 |
</ul> |
| 1084 |
|
| 1085 |
<p>Taking these two points into account, the above table can be rewritten |
| 1086 |
as:</p> |
| 1087 |
<table> |
| 1088 |
<tr><th>Command</th><th>Per pixel</th><th>Per line</th></tr> |
| 1089 |
<tr><td>HMMV</td><td>(4×8+16) W </td><td>7×8</td></tr> |
| 1090 |
<tr><td>YMMM</td><td>(3×8+16) R (1×8+16) W </td><td>0×8</td></tr> |
| 1091 |
<tr><td>HMMM</td><td>(6×8+16) R (1×8+16) W </td><td>8×8</td></tr> |
| 1092 |
<tr><td>LMMV</td><td>(7×8+16) R (1×8+16) W </td><td>8×8</td></tr> |
| 1093 |
<tr><td>LMMM</td><td>(6×8+16) R (2×8+16) R (1×8+16) W</td><td>8×8</td></tr> |
| 1094 |
<tr><td>LINE</td><td>(9×8+16) R (1×8+16) W </td><td>4×8</td></tr> |
| 1095 |
</table> |
| 1096 |
|
| 1097 |
<p>When you look at the data in this way, the numbers already look more |
| 1098 |
reasonable.</p> |
| 1099 |
|
| 1100 |
|
| 1101 |
|
| 1102 |
<h2>Next steps</h2> |
| 1103 |
|
| 1104 |
<p>All the information above <i>should</i> already be enough to significantly |
| 1105 |
improve the accuracy of MSX emulators. The following months I plan to work on |
| 1106 |
improving openMSX.</p> |
| 1107 |
<ul> |
| 1108 |
<li>First I'd like to improve the CPU-VRAM access stuff, so that e.g. too fast |
| 1109 |
CPU accesses actually result in dropped requests.</li> |
| 1110 |
<li>Next step is the timing of the VDP commands. This depends on the previous |
| 1111 |
step because e.g. CPU access slows down command execution.</li> |
| 1112 |
<li>Still a later step could be to more accurately in time fetch the data |
| 1113 |
required for display rendering (bitmap, sprites). This is lower priority |
| 1114 |
because: |
| 1115 |
<ul> |
| 1116 |
<li>These effects are limited to the visual output. Errors can't influence |
| 1117 |
the 'state' of the MSX machine. So it's impossible to write a MSX program |
| 1118 |
that checks (= makes a decision based on) the rendering accuracy. (OTOH it is |
| 1119 |
possible to check for dropped CPU requests or the speed of the |
| 1120 |
commands).</li> |
| 1121 |
<li>I don't know of any <i>existing</i> MSX software where this will make a |
| 1122 |
noticeable difference. Maybe an idea for a <i>new</i> test is to vary the |
| 1123 |
y-coordinates of the sprite(s) within one display line. Thus causing the |
| 1124 |
sprite engine to use two different values in the two phases of sprite |
| 1125 |
rendering.</li> |
| 1126 |
<li>Hmm … or maybe there is an existing program: the <a |
| 1127 |
href="http://users.skynet.be/bk263586/verti.zip">verti</a> demo. On current |
| 1128 |
emulators the vertical bars are all equally wide. But on a real MSX there |
| 1129 |
are wider and smaller bars, but all are multiples of 8 pixels.</a> |
| 1130 |
</ul> |
| 1131 |
</ul> |
| 1132 |
<p>I'm afraid this will all still take quite a bit of work.</p> |
| 1133 |
|
| 1134 |
<p>Anyway, I hope the information in this document is useful. For (other) MSX |
| 1135 |
emulator developers or for MSX developers in general.</p> |
| 1136 |
|
| 1137 |
<hr/> |
| 1138 |
<p align="right" style="font-size:smaller;"> |
| 1139 |
2013/03/30, Wouter Vermaelen |
| 1140 |
</p> |
| 1141 |
|
| 1142 |
</body> |
| 1143 |
</html> |