OXYGENHUB
◆ main openmsx / doc / internal / vram-addressing.txt
12.1 KiB · Plain Text · last changed chore(): initial commit 1 month ago source blame history raw
e8555c89 Andy McCall 1
VRAM Addressing
2
===============
3
4
This document describes a model for the way the V9938 VDP calculates
5
addresses in VRAM using base registers and indices.
6
7
General Formula
8
---------------
9
10
General formula for VRAM addressing:
11
  vram_address = index1 & mask
12
where:
13
  vram_address is the index in VRAM
14
  index1 is the index in the particular table, such as the name table or
15
    color table. The unused bits of index are all ones.
16
  mask is the value in the table's base register. The unused bits of mask
17
    are all ones.
18
19
Examples:
20
21
The name table base register is VDP R#2.
22
It contains A16-A10 of the mask, the other bits are 1.
23
If R#2 would contain 24h, the mask would be:
24
  (24h << 10) | ~(-1 << 10) = 093FFh
25
26
In SCREEN1 (Graphic 1) there are usually 24 lines of 32 characters each.
27
However, the actual screen height is 32 lines, as can be seen when the
28
vertical adjust register R#23 is used. So the number of characters per
29
screen is 32*32 = 1024 = 2^10. With one byte per character, the index is
30
10 bits wide.
31
32
If the index would be 157h, this is extended with leading ones for A10 and
33
higher (1FC00h) to become 1FD57h. Then the final address is:
34
  vram_address = 1FD57h & 093FFh = 09157h
35
36
Note that in this case, the final address is equal to:
37
  R#2 * 2^10 + index = 09000h + 157h = 09157h
38
This is true for all display modes in which the used bits in the base
39
register (A16..A10 in this case) do not overlap the bits in the index
40
(A9..A0 in this case). This is also the way application programmers
41
typically use the table base address registers.
42
43
In SCREEN5 (Graphic 4) there are 256 lines of 128 bytes each. Only 212 lines
44
are visible at a time, but using the vertical adjust register R#23 all 256
45
lines can be seen. A line is 256 pixels wide, with 4 bits per pixel that
46
makes 128 bytes per line. So the total number of bytes per screen is
47
256 * 128 = 32768 = 2^15. Therefore the index is 15 bits wide.
48
49
If the index would be 4521h, this is extended with leading ones for A16 and
50
A15 (18000h) to become 1C521h. Using the same mask as before (093FFh), the
51
final address is:
52
  vram_address = 1C521h & 093FFh = 08121h
53
54
Note that in this case, the final address is NOT equal to:
55
  R#2 * 2^10 + index = 09000h + 4521h = 0D521h
56
The VDP data book states that in SCREEN5 bit4 to bit0 should be 1, in those
57
cases the general formula is equivalent to addition. But when some of those
58
bits are zeroes, the general formula gives the same result the real VDP
59
does, while addition does not. The many-scrollers part of Anma's "Source of
60
Power" demo uses this feature to display the same scrolling text many times
61
on the same screen.
62
63
Range Checking
64
--------------
65
66
Different VDP subsystems are interested in different tables. For example,
67
the sprite subsystem is only interested in the sprite name and pattern
68
tables. On reads and writes to tables, interested subsystems must be
69
informed so they can update their internal state. Therefore an algorithm is
70
needed which calculates in which tables (if any) a given address is located.
71
72
Here is the address calculation formula again:
73
  vram_address = index1 & mask
74
The lowest address within the range is when the index is 0, index1 then
75
contains only ones in unused bits. The highest address (inclusive) is when
76
the index is all ones, then index1 is also all ones and the address is equal
77
to the mask. However, not all addresses between the lowest and the highest
78
address actually occur if the mask has one or more zeroes in the bits that
79
overlap with the index.
80
81
Let "inside : Int -> Bool" be the function that tells whether an address is
82
inside a table:
83
  inside.addr = (Exist i : i in Indices : i & mask = addr)
84
In English: there is an index i, for which the VRAM address is addr.
85
86
A convenient formula for the inside function is this one:
87
  inside.addr =
88
    addr & (~mask | (-1 << index_width)) = mask & (-1 << index_width)
89
Note that "addr" only occurs once and all other values are constant for each
90
display mode, so the check takes two operations (one compare and one AND).
91
This is probably the cheapest you can get.
92
93
Index Width
94
-----------
95
96
Which address bits are stored in the table base address registers is
97
documented in the VDP data book, but which address bits are produced by the
98
index is not documented there. This section fills that gap.
99
100
- Name Table -
101
102
Name table base address is [A16..A10] (R#2).
103
104
Display mode:   Index width in bits:
105
   Text 1         12 (*1)
106
   Text 2         12
107
 Multicolor       10 (*2)
108
  Graphic 1       10 (*2)
109
  Graphic 2       10 (*2)
110
  Graphic 3       10 (*2)
111
  Graphic 4       15
112
  Graphic 5       15
113
  Graphic 6       15 + plane (*3)
114
  Graphic 7       15 + plane (*3)
115
(*1) Text 1 index is calculated as 00C00h + position.
116
     On MSX1 it was 10 bits wide. For some reason, unifying address
117
     calculation with Text 2 must have been simpler than keeping it 10 bits
118
     wide, even though unification requires an add operation.
119
(*2) Maybe this is 12 bits and index = 00C00h + position just like Text 1.
120
     That's equivalent to 10 bits though, because there are 1024 characters
121
     per screen.
122
(*3) See "Planar Addressing" section for details.
123
124
- Pattern Table -
125
126
Pattern table base address is [A16..A11] (R#4).
127
128
Display mode:   Index width in bits:
129
   Text 1         11
130
   Text 2         11
131
 Multicolor       11
132
  Graphic 1       11
133
  Graphic 2       13
134
  Graphic 3       13
135
  Graphic 4       -
136
  Graphic 5       -
137
  Graphic 6       -
138
  Graphic 7       -
139
140
- Color Table -
141
142
Color table base address is [A16..A6] (R#3 and R#10).
143
144
Display mode:   Index width in bits:
145
   Text 1         -
146
   Text 2         9
147
 Multicolor       -
148
  Graphic 1       6 (*1)
149
  Graphic 2       13
150
  Graphic 3       13
151
  Graphic 4       -
152
  Graphic 5       -
153
  Graphic 6       -
154
  Graphic 7       -
155
(*1) Bit5 is fixed to zero.
156
157
- Sprite Attribute Table -
158
159
Sprite mode:    Index width in bits:
160
   mode 1         7
161
   mode 2         10 (*1)
162
(*1) Bit9 selects sprite color table (0) or sprite attribute table (1).
163
     Bit8 and Bit7 are fixed to zero for the attribute table.
164
165
- Sprite Pattern Table -
166
167
Sprite mode:    Index width in bits:
168
   mode 1         11
169
   mode 2         11
170
171
Index Calculation
172
-----------------
173
174
The following variables occur in every display mode:
175
  org_line: display line,
176
            0 <= org_line < 256
177
  line:     org_line after scroll adjustment (R#23 is applied),
178
            0 <= line < 256
179
  name:     value in VRAM at address (name_index & name_mask),
180
            0 <= name < 256
181
182
The "/" operation is integer division ("div").
183
The "%" operation is modulo/remainder ("mod").
184
185
- Text 1 -
186
187
Aka SCREEN0, WIDTH40.
188
0 <= x < 40
189
y = org_line / 8
190
name_index = 00C00h + y * 40 + x
191
pattern_index = name * 8 + line % 8
192
193
Adding 00C00h was probably done to make the index 12 bits wide, just like
194
in Text 2 mode. You can see this addition in action if you enable 212 lines
195
display and then play with different values of R#2. Pay attention to the
196
characters displayed in the lower few lines of the screen.
197
198
- Text 2 -
199
200
Aka SCREEN0, WIDTH80.
201
0 <= x < 80
202
y = org_line / 8
203
name_index = y * 80 + x
204
pattern_index = name * 8 + line % 8
205
206
- Multicolor -
207
208
Aka SCREEN3.
209
0 <= x < 32
210
y = line / 8
211
name_index = y * 32 + x
212
pattern_index = name * 8 + line % 4
213
214
- Graphic 1 -
215
216
Aka SCREEN1.
217
0 <= x < 32
218
y = line / 8
219
name_index = y * 32 + x
220
pattern_index = name * 8 + line % 8
221
color_index = name / 8
222
223
- Graphic 2 and 3 -
224
225
These modes are equivalent, except for the sprite mode.
226
Aka SCREEN2 and SCREEN4.
227
0 <= x < 32
228
y = line / 8
229
name_index = y * 32 + x
230
pattern_index = ((line / 64) * 256 + name) * 8 + line % 8
231
color_index = ((line / 64) * 256 + name) * 8 + line % 8
232
233
- Graphic 4 -
234
235
0 <= x < 256
236
name_index = line * 128 + x / 2
237
238
- Graphic 5 -
239
240
0 <= x < 512
241
name_index = line * 128 + x / 4
242
243
- Graphic 6 -
244
245
0 <= x < 512
246
name_index = line * 128 + x / 4
247
plane = (x / 2) % 2
248
249
- Graphic 7 -
250
251
0 <= x < 256
252
name_index = line * 128 + x / 2
253
plane = x % 2
254
255
- Sprite Mode 1 -
256
257
0 <= sprite_nr < 32
258
attrib_index = sprite_nr * 4
259
260
0 <= pattern_nr < 256
261
pattern_index = pattern_nr * 8
262
263
When sprite size is 16x16, Bit1 and Bit0 of the index are ignored.
264
Four patterns define the look of a single sprite, like this:
265
 0 2
266
 1 3
267
268
- Sprite Mode 2 -
269
270
0 <= sprite_nr < 32
271
attrib_index = 512 + sprite_nr * 4
272
color_index = sprite_nr * 16
273
274
0 <= pattern_nr < 256
275
pattern_index = pattern_nr * 8
276
277
When sprite size is 16x16, Bit1 and Bit0 of the index are ignored.
278
Four patterns define the look of a single sprite, like this:
279
 0 2
280
 1 3
281
282
Planar Addressing
283
-----------------
284
285
The V9938 has 3 pins that select a group of VRAM ICs each: CAS0, CAS1 and CASX.
286
CASX is used to select the expansion RAM, which can be accessed through the CPU
287
interface and through commands, but cannot be displayed directly.
288
289
Each VRAM group can be 0K, 16K or 64K. A group can consist of 8 chips of 1-bit
290
wide RAM or 2 chips of 4-bit wide RAM, but for the purpose of addressing we can
291
just pretend it is 1 chip with 8-bit wide RAM.
292
293
In real MSX machines, the following group combinations are used:
294
295
  CAS0:  CAS1:  CASX:   Description:
296
   16K     0K     0K    MSX1 with V9938 and 16K VRAM (*1)
297
   64K     0K     0K    MSX2 with 64K VRAM (*2)
298
   64K    64K     0K    MSX2 with 128K VRAM
299
   64K    64K    64K    MSX2 with 128K VRAM and 64K expansion (*3)
300
301
*1: Examples are the Spectravideo SVI-738 X'PRESS and the Yamaha CX5MII/128.
302
    The only V9938-specific display mode that they can fully display is
303
    80-columns text mode (TEXT2).
304
*2: Known 64K VRAM machines: Canon V-25, Hitachi MB-H3, Talent TPP-311 and 312,
305
    Toshiba HX-23.
306
*3: No known machines shipped with expansion VRAM. It was a popular amateur
307
    upgrade for users of FastCopy, to reduce the number of required disk swaps.
308
309
In most display modes addressing is linear, meaning the lower 64K of address
310
space uses the VRAM connected to CAS0 and the upper 64K of address space uses
311
the VRAM connected to CAS1.
312
313
In SCREEN7/8 (Graphic 6/7) the addressing is planar, meaning that even VRAM
314
addresses are mapped to CAS0 and odd addresses are mapped to CAS1. This means
315
that SCREEN 7/8 are only available on 128K VRAM machines. The most likely
316
reason for using planar addressing is getting a higher bandwidth: even though
317
the data lines are shared between all VRAM groups, the row select has to be
318
done only once.
319
320
VR=0 / VR=1 mode
321
----------------
322
323
The VDP chip has 10 pins that are connected to the VRAM subsystem to control
324
the read/write address. There are 8 address pins, these select the CAS/RAS
325
address. And there is a CAS0 and CAS1 pin, these select one of two ram chip
326
(groups). In total this allows for a 17-bit address space (=128kB). (I'm
327
ignoring the extended VRAM here).
328
329
When the VDP does a memory access, it's puts the 17-bit logical address on
330
these pins. The way how this is done depends on the VR bit (bit 3 of register
331
8), see table below.
332
333
In VR=1 mode, it first puts the bits A15-A8 on the address bus, followed by the
334
bits A7-A0. The whole time either pin CAS0 or CAS1 is selected, depending on
335
address bit A16. In VR=0 mode, .. well see table ;)
336
337
338
  VDP  |         VR=0         |         VR=1         |
339
address|----------------------|----------------------|
340
  pin  | RAS(high) | CAS(low) | RAS(high) | CAS(low) |
341
-------+-----------+----------|-----------+----------|
342
  AD0  |     A6  #2|     1  #1|     A8    |    A0    |
343
  AD1  |     A7    |    A0    |     A9    |    A1    |
344
  AD2  |     A8    |    A1    |    A10    |    A2    |
345
  AD3  |     A9    |    A2    |    A11    |    A3    |
346
  AD4  |    A10    |    A3    |    A12    |    A4    |
347
  AD5  |    A11    |    A4    |    A13    |    A5    |
348
  AD6  |    A12    |    A5    |    A14    |    A6    |
349
  AD7  |    A13    |    A6  #2|    A15    |    A7    |
350
-------+-----------+----------|-----------+----------|
351
CAS0/1 |          A14         |          A16         |
352
353
#1  this pin is always '1' in the CAS phase
354
#2  A6 is output both in CAS and RAS phase, this allows to use both 8/6 and 7/7
355
    RAS/CAS configurations (see VDP data sheet for details)
356
357
358
One important side-effect is that in VR=0 mode, the VDP can only address 32kB
359
memory. This is what makes the demo 'syntax infinity' work even though R14 is
360
programmed 'wrongly' (it writes to address 0x1????, but expects the data to end
361
up at address 0x0????).
362
363
Another side effect is that when switching between VR=0 and VR=1 modes, the
364
address space gets shuffled around, much like bit 7 in VDP register 1 for
365
TMS99x8 chips.