openMSX
V9990P2Converter.cc
Go to the documentation of this file.
1 #include "V9990P2Converter.hh"
2 #include "V9990VRAM.hh"
3 #include "V9990.hh"
4 #include "MemoryOps.hh"
5 #include "build-info.hh"
6 #include "components.hh"
7 #include <algorithm>
8 #include <cstdint>
9 
10 namespace openmsx {
11 
12 template <class Pixel>
14  : vdp(vdp_), vram(vdp.getVRAM()), palette64(palette64_)
15 {
16 }
17 
18 template <class Pixel>
20  Pixel* linePtr, unsigned displayX, unsigned displayWidth,
21  unsigned displayY, unsigned displayYA, bool drawSprites)
22 {
23  unsigned displayAX = (displayX + vdp.getScrollAX()) & 1023;
24 
25  unsigned scrollY = vdp.getScrollAY();
26  unsigned rollMask = vdp.getRollMask(0x1FF);
27  unsigned scrollYBase = scrollY & ~rollMask & 0x1FF;
28  unsigned displayAY = scrollYBase + ((displayYA + scrollY) & rollMask);
29 
30  unsigned displayEnd = displayX + displayWidth;
31 
32  // backdrop color
33  Pixel bgcol = palette64[vdp.getBackDropColor()];
35  memset(linePtr, displayWidth, bgcol);
36 
37  // back sprite plane
38  int visibleSprites[16 + 1];
39  if (drawSprites) {
40  determineVisibleSprites(visibleSprites, displayY);
41  renderSprites(linePtr, displayX, displayEnd, displayY,
42  visibleSprites, false);
43  }
44 
45  // image plane
46  byte pal = (vdp.getPaletteOffset() & 0x03) << 4;
47  renderPattern(linePtr, displayWidth, displayAX, displayAY, pal);
48 
49  // front sprite plane
50  if (drawSprites) {
51  renderSprites(linePtr, displayX, displayEnd, displayY,
52  visibleSprites, true);
53  }
54 }
55 
56 template <class Pixel>
58  Pixel* __restrict buffer, unsigned width, unsigned x, unsigned y,
59  byte pal)
60 {
61  static const unsigned patternTable = 0x00000;
62  static const unsigned nameTable = 0x7C000;
63 
64  x &= 1023;
65  const Pixel* palette = palette64 + pal;
66 
67  unsigned nameAddr = nameTable + (((y / 8) * 128 + (x / 8)) * 2);
68  y = (y & 7) * 256;
69 
70  if (x & 7) {
71  unsigned patternNum = (vram.readVRAMDirect(nameAddr + 0) +
72  vram.readVRAMDirect(nameAddr + 1) * 256) & 0x1FFF;
73  unsigned x2 = (patternNum % 64) * 4 + ((x & 7) / 2);
74  unsigned y2 = (patternNum / 64) * 2048 + y;
75  unsigned address = patternTable + y2 + x2;
76  byte data = vram.readVRAMBx(address);
77 
78  while ((x & 7) && width) {
79  byte p;
80  if (x & 1) {
81  p = data & 0x0F;
82  ++address;
83  } else {
84  data = vram.readVRAMBx(address);
85  p = data >> 4;
86  }
87  if (p) buffer[0] = palette[p];
88  ++x;
89  ++buffer;
90  --width;
91  }
92  nameAddr = (nameAddr & ~255) | ((nameAddr + 2) & 255);
93  }
94  assert((x & 7) == 0 || (width == 0));
95  while (width & ~7) {
96  unsigned patternNum = (vram.readVRAMDirect(nameAddr + 0) +
97  vram.readVRAMDirect(nameAddr + 1) * 256) & 0x1FFF;
98  unsigned x2 = (patternNum % 64) * 4;
99  unsigned y2 = (patternNum / 64) * 2048 + y;
100  unsigned address = patternTable + y2 + x2;
101 
102  byte data0 = vram.readVRAMBx(address + 0);
103  byte p0 = data0 >> 4;
104  if (p0) buffer[0] = palette[p0];
105  byte p1 = data0 & 0x0F;
106  if (p1) buffer[1] = palette[p1];
107 
108  byte data1 = vram.readVRAMBx(address + 1);
109  byte p2 = data1 >> 4;
110  if (p2) buffer[2] = palette[p2];
111  byte p3 = data1 & 0x0F;
112  if (p3) buffer[3] = palette[p3];
113 
114  byte data2 = vram.readVRAMBx(address + 2);
115  byte p4 = data2 >> 4;
116  if (p4) buffer[4] = palette[p4];
117  byte p5 = data2 & 0x0F;
118  if (p5) buffer[5] = palette[p5];
119 
120  byte data3 = vram.readVRAMBx(address + 3);
121  byte p6 = data3 >> 4;
122  if (p6) buffer[6] = palette[p6];
123  byte p7 = data3 & 0x0F;
124  if (p7) buffer[7] = palette[p7];
125 
126  width -= 8;
127  buffer += 8;
128  nameAddr = (nameAddr & ~255) | ((nameAddr + 2) & 255);
129  }
130  assert(width < 8);
131  if (width) {
132  unsigned patternNum = (vram.readVRAMDirect(nameAddr + 0) +
133  vram.readVRAMDirect(nameAddr + 1) * 256) & 0x1FFF;
134  unsigned x2 = (patternNum % 64) * 4;
135  unsigned y2 = (patternNum / 64) * 2048 + y;
136  unsigned address = patternTable + y2 + x2;
137  do {
138  byte data = vram.readVRAMBx(address++);
139  byte p0 = data >> 4;
140  if (p0) buffer[0] = palette[p0];
141  if (width != 1) {
142  byte p1 = data & 0x0F;
143  if (p1) buffer[1] = palette[p1];
144  }
145  width -= 2;
146  buffer += 2;
147  } while (int(width) > 0);
148  }
149 }
150 
151 template <class Pixel>
153  int* __restrict visibleSprites, int displayY)
154 {
155  static const unsigned spriteTable = 0x3FE00;
156 
157  int index = 0;
158  int index_max = 16;
159  for (int sprite = 0; sprite < 125; ++sprite) {
160  int spriteInfo = spriteTable + 4 * sprite;
161  byte spriteY = vram.readVRAMDirect(spriteInfo) + 1;
162  byte posY = displayY - spriteY;
163  if (posY < 16) {
164  byte attr = vram.readVRAMDirect(spriteInfo + 3);
165  if (attr & 0x10) {
166  // Invisible sprites do contribute towards the
167  // 16-sprites-per-line limit.
168  index_max--;
169  } else {
170  visibleSprites[index++] = sprite;
171  }
172  if (index == index_max) break;
173  }
174  }
175  // draw sprites in reverse order
176  std::reverse(visibleSprites, visibleSprites + index);
177  visibleSprites[index] = -1;
178 }
179 
180 
181 template <class Pixel>
183  Pixel* __restrict buffer, int displayX, int displayEnd, unsigned displayY,
184  const int* __restrict visibleSprites, bool front)
185 {
186  static const unsigned spriteTable = 0x3FE00;
187  unsigned spritePatternTable = vdp.getSpritePatternAddress(P1); // TODO P2 ???
188 
189  for (unsigned sprite = 0; visibleSprites[sprite] != -1; ++sprite) {
190  unsigned addr = spriteTable + 4 * visibleSprites[sprite];
191  byte spriteAttr = vram.readVRAMDirect(addr + 3);
192  if (front ^ !!(spriteAttr & 0x20)) {
193  int spriteX = vram.readVRAMDirect(addr + 2);
194  spriteX += 256 * (spriteAttr & 0x03);
195  if (spriteX > 1008) spriteX -= 1024; // hack X coord into -16..1008
196  byte spriteY = vram.readVRAMDirect(addr + 0);
197  byte spriteNo = vram.readVRAMDirect(addr + 1);
198  spriteY = displayY - (spriteY + 1);
199  unsigned patAddr = spritePatternTable
200  + (256 * (((spriteNo & 0xE0) >> 1) + spriteY))
201  + ( 8 * (spriteNo & 0x1F));
202  const Pixel* palette = palette64 + ((spriteAttr >> 2) & 0x30);
203  for (int x = 0; x < 16; x +=2) {
204  byte data = vram.readVRAMBx(patAddr++);
205  int xPos = spriteX + x;
206  if ((displayX <= xPos) && (xPos < displayEnd)) {
207  byte p = data >> 4;
208  if (p) buffer[xPos - displayX] = palette[p];
209  }
210  ++xPos;
211  if ((displayX <= xPos) && (xPos < displayEnd)) {
212  byte p = data & 0x0F;
213  if (p) buffer[xPos - displayX] = palette[p];
214  }
215  }
216  }
217  }
218 }
219 
220 // Force template instantiation
221 #if HAVE_16BPP
222 template class V9990P2Converter<uint16_t>;
223 #endif
224 #if HAVE_32BPP || COMPONENT_GL
225 template class V9990P2Converter<uint32_t>;
226 #endif
227 
228 } // namespace openmsx
Implementation of the Yamaha V9990 VDP as used in the GFX9000 cartridge by Sunrise.
Definition: V9990.hh:29
void convertLine(Pixel *linePtr, unsigned displayX, unsigned displayWidth, unsigned displayY, unsigned displayYA, bool drawSprites)
V9990P2Converter(V9990 &vdp_, const Pixel *palette64)
unsigned getRollMask(unsigned maxMask) const
Returns the vertical roll mask.
Definition: V9990.hh:242
int getSpritePatternAddress(V9990DisplayMode m) const
Return the sprite pattern table base address.
Definition: V9990.hh:290
byte readVRAMBx(unsigned address)
Definition: V9990VRAM.hh:54
uint8_t byte
8 bit unsigned integer
Definition: openmsx.hh:26
mat3 p3(vec3(1, 2, 3), vec3(4, 5, 6), vec3(7, 0, 9))
uint32_t Pixel
constexpr auto data(C &c) -> decltype(c.data())
Definition: span.hh:69
auto reverse(Range &&range)
Definition: view.hh:306
byte getPaletteOffset() const
Get palette offset.
Definition: V9990.hh:96
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
mat4 p4(vec4(1, 2, 3, 4), vec4(3, 4, 5, 6), vec4(5, 0, 7, 8), vec4(7, 8, 9, 0))
unsigned getScrollAX() const
Returns the X scroll offset for screen A of P1 and other modes.
Definition: V9990.hh:218
byte readVRAMDirect(unsigned address)
Definition: V9990VRAM.hh:74
unsigned getScrollAY() const
Returns the Y scroll offset for screen A of P1 and other modes.
Definition: V9990.hh:224
byte getBackDropColor() const
Return the current back drop color.
Definition: V9990.hh:212