openMSX
V9990.hh
Go to the documentation of this file.
1 #ifndef V9990_HH
2 #define V9990_HH
3 
4 #include "MSXDevice.hh"
5 #include "Schedulable.hh"
7 #include "IRQHelper.hh"
8 #include "V9990DisplayTiming.hh"
9 #include "V9990ModeEnum.hh"
10 #include "SimpleDebuggable.hh"
11 #include "Clock.hh"
12 #include "serialize_meta.hh"
13 #include "openmsx.hh"
14 #include "outer.hh"
15 #include "unreachable.hh"
16 #include <memory>
17 
18 namespace openmsx {
19 
20 class PostProcessor;
21 class Display;
22 class V9990VRAM;
23 class V9990CmdEngine;
24 class V9990Renderer;
25 
29 class V9990 final : public MSXDevice, private VideoSystemChangeListener
30 {
31 public:
32  explicit V9990(const DeviceConfig& config);
33  ~V9990() override;
34 
35  // MSXDevice interface:
36  void powerUp(EmuTime::param time) override;
37  void reset(EmuTime::param time) override;
38  byte readIO(word port, EmuTime::param time) override;
39  byte peekIO(word port, EmuTime::param time) const override;
40  void writeIO(word port, byte value, EmuTime::param time) override;
41 
47 
50  inline V9990VRAM& getVRAM() {
51  return *vram;
52  }
53 
57  inline bool isInterlaced() const {
58  return interlaced;
59  }
60 
64  inline bool isEvenOddEnabled() const {
65  return (regs[SCREEN_MODE_1] & 0x04) != 0;
66  }
67 
71  inline bool getEvenOdd() const {
72  return (status & 0x02) != 0;
73  }
74 
80  inline bool isDisplayEnabled() const {
81  return isDisplayArea && displayEnabled;
82  }
83 
87  inline bool spritesEnabled() const {
88  return !(regs[CONTROL] & 0x40);
89  }
90 
96  inline byte getPaletteOffset() const {
97  return (regs[PALETTE_CONTROL] & 0x0F);
98  }
99 
111  void getPalette(int index, byte& r, byte& g, byte& b, bool& ys) const;
112 
117  inline int getUCTicksThisFrame(EmuTime::param time) const {
118  return frameStartTime.getTicksTill_fast(time);
119  }
120 
125  inline bool isPalTiming() const {
126  return palTiming;
127  }
128 
131  inline bool isOverScan() const {
132  return (mode == B0) || (mode == B2) || (mode == B4);
133  }
134 
141  inline bool isSuperimposing() const {
142  return superimposing;
143  }
144 
146  void setExternalVideoSource(bool enable) {
147  externalVideoSource = enable;
148  }
149 
154  inline unsigned getCursorYOffset() const {
155  // TODO vertical set-adjust may or may not influence this,
156  // need to investigate that.
157  if (!isOverScan()) return 0;
158  return isPalTiming()
161  }
162 
169  static inline int UCtoX(int ticks, V9990DisplayMode mode) {
170  int x;
172  switch (mode) {
173  case P1: x = ticks / 8; break;
174  case P2: x = ticks / 4; break;
175  case B0: x = ticks /12; break;
176  case B1: x = ticks / 8; break;
177  case B2: x = ticks / 6; break;
178  case B3: x = ticks / 4; break;
179  case B4: x = ticks / 3; break;
180  case B5: x = 1; break;
181  case B6: x = 1; break;
182  case B7: x = ticks / 2; break;
183  default: x = 1;
184  }
185  return x;
186  }
187 
191  return mode;
192  }
193 
197 
205  inline unsigned getColorDepth() const {
206  return regs[SCREEN_MODE_0] & 0x03;
207  }
208 
212  inline byte getBackDropColor() const {
213  return regs[BACK_DROP_COLOR];
214  }
215 
218  inline unsigned getScrollAX() const {
219  return regs[SCROLL_CONTROL_AX0] + 8 * regs[SCROLL_CONTROL_AX1];
220  }
221 
224  inline unsigned getScrollAY() const {
225  return regs[SCROLL_CONTROL_AY0] + 256 * scrollAYHigh;
226  }
227 
230  inline unsigned getScrollBX() const {
231  return regs[SCROLL_CONTROL_BX0] + 8 * regs[SCROLL_CONTROL_BX1];
232  }
233 
236  inline unsigned getScrollBY() const {
237  return regs[SCROLL_CONTROL_BY0] + 256 * scrollBYHigh;
238  }
239 
242  inline unsigned getRollMask(unsigned maxMask) const {
243  static unsigned rollMasks[4] = {
244  0xFFFF, // no rolling (use maxMask)
245  0x00FF,
246  0x01FF,
247  0x00FF // TODO check this (undocumented)
248  };
249  unsigned t = regs[SCROLL_CONTROL_AY1] >> 6;
250  return t ? rollMasks[t] : maxMask;
251  }
252 
255  inline unsigned getImageWidth() const {
256  switch (regs[SCREEN_MODE_0] & 0xC0) {
257  case 0x00: // P1
258  return 256;
259  case 0x40: // P2
260  return 512;
261  case 0x80: // Bx
262  default: // standby TODO check this
263  return (256 << ((regs[SCREEN_MODE_0] & 0x0C) >> 2));
264  }
265  }
268  inline unsigned getLineWidth() const {
269  switch (getDisplayMode()) {
270  case B0: return 213;
271  case P1: case B1: return 320;
272  case B2: return 426;
273  case P2: case B3: return 640;
274  case B4: return 853;
275  case B5: case B6: return 1; // not supported
276  case B7: return 1280;
277  default:
278  UNREACHABLE; return 0;
279  }
280  }
281 
284  inline void cmdReady() {
285  raiseIRQ(CMD_IRQ);
286  }
287 
291  switch (m) {
292  case P1:
293  return (int(regs[SPRITE_PATTERN_ADDRESS] & 0x0E) << 14);
294  case P2:
295  return (int(regs[SPRITE_PATTERN_ADDRESS] & 0x0F) << 15);
296  default:
297  return 0;
298  }
299  }
300 
303  inline byte getSpritePaletteOffset() const {
304  return regs[SPRITE_PALETTE_CONTROL] << 2;
305  }
306 
309  inline const V9990DisplayPeriod& getHorizontalTiming() const {
310  return *horTiming;
311  }
312 
316  inline int getLeftBorder() const {
317  return horTiming->blank + horTiming->border1 +
318  (((regs[DISPLAY_ADJUST] & 0x0F) ^ 7) - 8) * 8;
319  }
323  inline int getRightBorder() const {
324  return getLeftBorder() + horTiming->display;
325  }
326 
329  inline const V9990DisplayPeriod& getVerticalTiming() const {
330  return *verTiming;
331  }
332 
333  inline int getTopBorder() const {
334  return verTiming->blank + verTiming->border1 +
335  (((regs[DISPLAY_ADJUST] >> 4) ^ 7) - 8);
336  }
337  inline int getBottomBorder() const {
338  return getTopBorder() + verTiming->display;
339  }
340 
341  inline unsigned getPriorityControlX() const {
342  unsigned t = regs[PRIORITY_CONTROL] & 0x03;
343  return (t == 0) ? 256 : t << 6;
344  }
345  inline unsigned getPriorityControlY() const {
346  unsigned t = regs[PRIORITY_CONTROL] & 0x0C;
347  return (t == 0) ? 256 : t << 4;
348  }
349 
350  template<typename Archive>
351  void serialize(Archive& ar, unsigned version);
352 
353 private:
354  // VideoSystemChangeListener interface:
355  void preVideoSystemChange() override;
356  void postVideoSystemChange() override;
357 
358  // Scheduler stuff
359  struct SyncBase : Schedulable {
360  explicit SyncBase(V9990& v9990) : Schedulable(v9990.getScheduler()) {}
363  protected:
364  ~SyncBase() = default;
365  };
366 
367  struct SyncVSync final : SyncBase {
368  explicit SyncVSync(V9990& v9990) : SyncBase(v9990) {}
369  void executeUntil(EmuTime::param time) override {
370  auto& v9990 = OUTER(V9990, syncVSync);
371  v9990.execVSync(time);
372  }
373  } syncVSync;
374 
375  struct SyncDisplayStart final : SyncBase {
376  explicit SyncDisplayStart(V9990& v9990) : SyncBase(v9990) {}
377  void executeUntil(EmuTime::param time) override {
378  auto& v9990 = OUTER(V9990, syncDisplayStart);
379  v9990.execDisplayStart(time);
380  }
381  } syncDisplayStart;
382 
383  struct SyncVScan final : SyncBase {
384  explicit SyncVScan(V9990& v9990) : SyncBase(v9990) {}
385  void executeUntil(EmuTime::param time) override {
386  auto& v9990 = OUTER(V9990, syncVScan);
387  v9990.execVScan(time);
388  }
389  } syncVScan;
390 
391  struct SyncHScan final : SyncBase {
392  explicit SyncHScan(V9990& v9990) : SyncBase(v9990) {}
393  void executeUntil(EmuTime::param /*time*/) override {
394  auto& v9990 = OUTER(V9990, syncHScan);
395  v9990.execHScan();
396  }
397  } syncHScan;
398 
399  struct SyncSetMode final : SyncBase {
400  explicit SyncSetMode(V9990& v9990) : SyncBase(v9990) {}
401  void executeUntil(EmuTime::param time) override {
402  auto& v9990 = OUTER(V9990, syncSetMode);
403  v9990.execSetMode(time);
404  }
405  } syncSetMode;
406 
407  void execVSync(EmuTime::param time);
408  void execDisplayStart(EmuTime::param time);
409  void execVScan(EmuTime::param time);
410  void execHScan();
411  void execSetMode(EmuTime::param time);
412 
413  // --- types ------------------------------------------------------
414 
417  enum IRQType {
418  VER_IRQ = 1,
419  HOR_IRQ = 2,
420  CMD_IRQ = 4
421  };
422 
425  enum PortId {
426  VRAM_DATA = 0,
427  PALETTE_DATA,
428  COMMAND_DATA,
429  REGISTER_DATA,
430  REGISTER_SELECT,
431  STATUS,
432  INTERRUPT_FLAG,
433  SYSTEM_CONTROL,
434  KANJI_ROM_0,
435  KANJI_ROM_1,
436  KANJI_ROM_2,
437  KANJI_ROM_3,
438  RESERVED_0,
439  RESERVED_1,
440  RESERVED_2,
441  RESERVED_3
442  };
443 
446  enum RegisterId {
447  VRAM_WRITE_ADDRESS_0 = 0,
448  VRAM_WRITE_ADDRESS_1,
449  VRAM_WRITE_ADDRESS_2,
450  VRAM_READ_ADDRESS_0,
451  VRAM_READ_ADDRESS_1,
452  VRAM_READ_ADDRESS_2,
453  SCREEN_MODE_0,
454  SCREEN_MODE_1,
455  CONTROL,
456  INTERRUPT_0,
457  INTERRUPT_1,
458  INTERRUPT_2,
459  INTERRUPT_3,
460  PALETTE_CONTROL,
461  PALETTE_POINTER,
462  BACK_DROP_COLOR,
463  DISPLAY_ADJUST,
464  SCROLL_CONTROL_AY0,
465  SCROLL_CONTROL_AY1,
466  SCROLL_CONTROL_AX0,
467  SCROLL_CONTROL_AX1,
468  SCROLL_CONTROL_BY0,
469  SCROLL_CONTROL_BY1,
470  SCROLL_CONTROL_BX0,
471  SCROLL_CONTROL_BX1,
472  SPRITE_PATTERN_ADDRESS,
473  LCD_CONTROL,
474  PRIORITY_CONTROL,
475  SPRITE_PALETTE_CONTROL,
476  CMD_PARAM_SRC_ADDRESS_0 = 32,
477  CMD_PARAM_SRC_ADDRESS_1,
478  CMD_PARAM_SRC_ADDRESS_2,
479  CMD_PARAM_SRC_ADDRESS_3,
480  CMD_PARAM_DEST_ADDRESS_0,
481  CMD_PARAM_DEST_ADDRESS_1,
482  CMD_PARAM_DEST_ADDRESS_2,
483  CMD_PARAM_DEST_ADDRESS_3,
484  CMD_PARAM_SIZE_0,
485  CMD_PARAM_SIZE_1,
486  CMD_PARAM_SIZE_2,
487  CMD_PARAM_SIZE_3,
488  CMD_PARAM_ARGUMENT,
489  CMD_PARAM_LOGOP,
490  CMD_PARAM_WRITE_MASK_0,
491  CMD_PARAM_WRITE_MASK_1,
492  CMD_PARAM_FONT_COLOR_FC0,
493  CMD_PARAM_FONT_COLOR_FC1,
494  CMD_PARAM_FONT_COLOR_BC0,
495  CMD_PARAM_FONT_COLOR_BC1,
496  CMD_PARAM_OPCODE,
497  CMD_PARAM_BORDER_X_0,
498  CMD_PARAM_BORDER_X_1
499  };
500 
501  // --- members ----------------------------------------------------
502 
503  struct RegDebug final : SimpleDebuggable {
504  explicit RegDebug(V9990& v9990);
505  byte read(unsigned address) override;
506  void write(unsigned address, byte value, EmuTime::param time) override;
507  } v9990RegDebug;
508 
509  struct PalDebug final : SimpleDebuggable {
510  explicit PalDebug(V9990& v9990);
511  byte read(unsigned address) override;
512  void write(unsigned address, byte value, EmuTime::param time) override;
513  } v9990PalDebug;
514 
515  IRQHelper irq;
516 
517  Display& display;
518 
521  std::unique_ptr<V9990VRAM> vram;
522  unsigned vramReadPtr, vramWritePtr;
523  byte vramReadBuffer;
524 
527  std::unique_ptr<V9990CmdEngine> cmdEngine;
528 
531  std::unique_ptr<V9990Renderer> renderer;
532 
536 
539  EmuTime hScanSyncTime;
540 
543  const V9990DisplayPeriod* horTiming;
544  const V9990DisplayPeriod* verTiming;
545 
548  V9990DisplayMode mode;
549 
552  byte palette[0x100];
553 
556  byte status;
557 
560  byte pendingIRQs;
561 
564  byte regs[0x40];
565  byte regSelect;
566 
569  bool palTiming;
570 
574  bool interlaced;
575 
578  bool isDisplayArea;
579 
585  bool displayEnabled;
586 
595  byte scrollAYHigh;
596  byte scrollBYHigh;
597 
602  bool systemReset;
603 
608  bool externalVideoSource;
609 
613  bool superimposing;
614 
615  // --- methods ----------------------------------------------------
616 
617  void setHorizontalTiming();
618  void setVerticalTiming();
619 
620  V9990ColorMode getColorMode(byte pal_ctrl) const;
621 
626  inline unsigned getVRAMAddr(RegisterId base) const;
627 
632  inline void setVRAMAddr(RegisterId base, unsigned addr);
633 
639  byte readRegister(byte reg, EmuTime::param time) const;
640 
646  void writeRegister(byte reg, byte val, EmuTime::param time);
647 
653  void writePaletteRegister(byte reg, byte val, EmuTime::param time);
654 
657  void syncAtNextLine(SyncBase& type, EmuTime::param time);
658 
662  void createRenderer(EmuTime::param time);
663 
667  void frameStart(EmuTime::param time);
668 
672  void raiseIRQ(IRQType irqType);
673 
676  void calcDisplayMode();
677 
682  void scheduleHscan(EmuTime::param time);
683 };
685 
686 } // namespace openmsx
687 
688 #endif
Implementation of the Yamaha V9990 VDP as used in the GFX9000 cartridge by Sunrise.
Definition: V9990.hh:29
int getUCTicksThisFrame(EmuTime::param time) const
Get the number of elapsed UC ticks in this frame.
Definition: V9990.hh:117
PostProcessor * getPostProcessor() const
Used by Video9000 to be able to couple the VDP and V9990 output.
Definition: V9990.cc:111
void powerUp(EmuTime::param time) override
This method is called when MSX is powered up.
Definition: V9990.cc:120
unsigned getImageWidth() const
Return the image width.
Definition: V9990.hh:255
Represents the output window/screen of openMSX.
Definition: Display.hh:31
V9990(const DeviceConfig &config)
Definition: V9990.cc:54
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
static const V9990DisplayPeriod displayPAL_MCLK
PAL display timing, when using MCLK: Normal display mode with borders.
bool isInterlaced() const
Get interlace status.
Definition: V9990.hh:57
bool isDisplayEnabled() const
Is the display enabled? Note this is simpler than the V99x8 version.
Definition: V9990.hh:80
void reset(EmuTime::param time) override
This method is called on reset.
Definition: V9990.cc:126
uint8_t byte
8 bit unsigned integer
Definition: openmsx.hh:26
const V9990DisplayPeriod & getVerticalTiming() const
Get vertical display timings.
Definition: V9990.hh:329
V9990DisplayMode getDisplayMode() const
Return the current display mode.
Definition: V9990.hh:190
unsigned getLineWidth() const
Return the display width.
Definition: V9990.hh:268
static int UCtoX(int ticks, V9990DisplayMode mode)
Convert UC ticks to V9990 pixel position on a line.
Definition: V9990.hh:169
bool isSuperimposing() const
Should this frame be superimposed? This is a combination of bit 5 (YSE) in R#8 and the presence of an...
Definition: V9990.hh:141
byte peekIO(word port, EmuTime::param time) const override
Read a byte from a given IO port.
Definition: V9990.cc:223
int getTopBorder() const
Definition: V9990.hh:333
bool isPalTiming() const
Is PAL timing active? This setting is fixed at start of frame.
Definition: V9990.hh:125
void writeIO(word port, byte value, EmuTime::param time) override
Write a byte to a given IO port at a certain time to this device.
Definition: V9990.cc:286
int getLeftBorder() const
Get the number of VDP clockticks between the start of the line and the end of the left border...
Definition: V9990.hh:316
int getBottomBorder() const
Definition: V9990.hh:337
bool getEvenOdd() const
Is the even or odd field being displayed?
Definition: V9990.hh:71
byte readIO(word port, EmuTime::param time) override
Read a byte from an IO port at a certain time from this device.
Definition: V9990.cc:161
A period, either horizontal or vertical, starts with a synchronisation pulse followed by a blank peri...
Every class that wants to get scheduled at some point must inherit from this class.
Definition: Schedulable.hh:33
static const int UC_TICKS_PER_LINE
The number of clockticks per line is independent of the crystal used or the display mode (NTSC/PAL) ...
SERIALIZE_CLASS_VERSION(CassettePlayer, 2)
unsigned getColorDepth() const
Return the amount of bits per pixels.
Definition: V9990.hh:205
bool isEvenOddEnabled() const
Get even/odd page alternation status.
Definition: V9990.hh:64
byte getPaletteOffset() const
Get palette offset.
Definition: V9990.hh:96
unsigned getPriorityControlX() const
Definition: V9990.hh:341
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
An MSXDevice is an emulated hardware component connected to the bus of the emulated MSX...
Definition: MSXDevice.hh:31
V9990ColorMode getColorMode() const
Return the current color mode.
Definition: V9990.cc:790
~V9990() override
Definition: V9990.cc:106
unsigned getScrollBY() const
Returns the Y scroll offset for screen B of P1 mode.
Definition: V9990.hh:236
bool isOverScan() const
Returns true iff in overscan mode.
Definition: V9990.hh:131
unsigned getScrollBX() const
Returns the X scroll offset for screen B of P1 mode.
Definition: V9990.hh:230
Scheduler & getScheduler() const
Definition: MSXDevice.cc:145
Video RAM for the V9990.
Definition: V9990VRAM.hh:15
void cmdReady()
Command execution ready.
Definition: V9990.hh:284
static const V9990DisplayPeriod displayNTSC_MCLK
NTSC display timing, when using MCLK: Normal display mode with borders.
uint16_t word
16 bit unsigned integer
Definition: openmsx.hh:29
int g
unsigned getScrollAX() const
Returns the X scroll offset for screen A of P1 and other modes.
Definition: V9990.hh:218
Abstract base class for post processors.
void getPalette(int index, byte &r, byte &g, byte &b, bool &ys) const
Get palette entry.
Definition: V9990.cc:668
unsigned getCursorYOffset() const
In overscan mode the cursor position is still specified with &#39;normal&#39; (non-overscan) y-coordinates...
Definition: V9990.hh:154
void serialize(Archive &ar, unsigned version)
Definition: V9990.cc:880
unsigned getPriorityControlY() const
Definition: V9990.hh:345
const V9990DisplayPeriod & getHorizontalTiming() const
Get horizontal display timings.
Definition: V9990.hh:309
int getRightBorder() const
Get the number of VDP clockticks between the start of the line and the end of the right border...
Definition: V9990.hh:323
unsigned getScrollAY() const
Returns the Y scroll offset for screen A of P1 and other modes.
Definition: V9990.hh:224
byte getSpritePaletteOffset() const
return sprite palette offset
Definition: V9990.hh:303
V9990VRAM & getVRAM()
Obtain a reference to the V9990&#39;s VRAM.
Definition: V9990.hh:50
void setExternalVideoSource(bool enable)
Is there an external video source available to superimpose on.
Definition: V9990.hh:146
#define OUTER(type, member)
Definition: outer.hh:38
bool spritesEnabled() const
Are sprites (cursors) enabled?
Definition: V9990.hh:87
void setSyncPoint(EmuTime::param timestamp)
Definition: Schedulable.cc:23
unsigned getTicksTill_fast(EmuTime::param e) const
Same as above, only faster, Though the time interval may not be too large.
Definition: Clock.hh:70
byte getBackDropColor() const
Return the current back drop color.
Definition: V9990.hh:212
TclObject t
#define UNREACHABLE
Definition: unreachable.hh:38