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  struct SyncCmdEnd final : SyncBase {
408  explicit SyncCmdEnd(V9990& v9990) : SyncBase(v9990) {}
409  void executeUntil(EmuTime::param time) override {
410  auto& v9990 = OUTER(V9990, syncCmdEnd);
411  v9990.execCheckCmdEnd(time);
412  }
413  } syncCmdEnd;
414 
415  void execVSync(EmuTime::param time);
416  void execDisplayStart(EmuTime::param time);
417  void execVScan(EmuTime::param time);
418  void execHScan();
419  void execSetMode(EmuTime::param time);
420  void execCheckCmdEnd(EmuTime::param time);
421 
422  // --- types ------------------------------------------------------
423 
426  enum IRQType {
427  VER_IRQ = 1,
428  HOR_IRQ = 2,
429  CMD_IRQ = 4
430  };
431 
434  enum PortId {
435  VRAM_DATA = 0,
436  PALETTE_DATA,
437  COMMAND_DATA,
438  REGISTER_DATA,
439  REGISTER_SELECT,
440  STATUS,
441  INTERRUPT_FLAG,
442  SYSTEM_CONTROL,
443  KANJI_ROM_0,
444  KANJI_ROM_1,
445  KANJI_ROM_2,
446  KANJI_ROM_3,
447  RESERVED_0,
448  RESERVED_1,
449  RESERVED_2,
450  RESERVED_3
451  };
452 
455  enum RegisterId {
456  VRAM_WRITE_ADDRESS_0 = 0,
457  VRAM_WRITE_ADDRESS_1,
458  VRAM_WRITE_ADDRESS_2,
459  VRAM_READ_ADDRESS_0,
460  VRAM_READ_ADDRESS_1,
461  VRAM_READ_ADDRESS_2,
462  SCREEN_MODE_0,
463  SCREEN_MODE_1,
464  CONTROL,
465  INTERRUPT_0,
466  INTERRUPT_1,
467  INTERRUPT_2,
468  INTERRUPT_3,
469  PALETTE_CONTROL,
470  PALETTE_POINTER,
471  BACK_DROP_COLOR,
472  DISPLAY_ADJUST,
473  SCROLL_CONTROL_AY0,
474  SCROLL_CONTROL_AY1,
475  SCROLL_CONTROL_AX0,
476  SCROLL_CONTROL_AX1,
477  SCROLL_CONTROL_BY0,
478  SCROLL_CONTROL_BY1,
479  SCROLL_CONTROL_BX0,
480  SCROLL_CONTROL_BX1,
481  SPRITE_PATTERN_ADDRESS,
482  LCD_CONTROL,
483  PRIORITY_CONTROL,
484  SPRITE_PALETTE_CONTROL,
485  CMD_PARAM_SRC_ADDRESS_0 = 32,
486  CMD_PARAM_SRC_ADDRESS_1,
487  CMD_PARAM_SRC_ADDRESS_2,
488  CMD_PARAM_SRC_ADDRESS_3,
489  CMD_PARAM_DEST_ADDRESS_0,
490  CMD_PARAM_DEST_ADDRESS_1,
491  CMD_PARAM_DEST_ADDRESS_2,
492  CMD_PARAM_DEST_ADDRESS_3,
493  CMD_PARAM_SIZE_0,
494  CMD_PARAM_SIZE_1,
495  CMD_PARAM_SIZE_2,
496  CMD_PARAM_SIZE_3,
497  CMD_PARAM_ARGUMENT,
498  CMD_PARAM_LOGOP,
499  CMD_PARAM_WRITE_MASK_0,
500  CMD_PARAM_WRITE_MASK_1,
501  CMD_PARAM_FONT_COLOR_FC0,
502  CMD_PARAM_FONT_COLOR_FC1,
503  CMD_PARAM_FONT_COLOR_BC0,
504  CMD_PARAM_FONT_COLOR_BC1,
505  CMD_PARAM_OPCODE,
506  CMD_PARAM_BORDER_X_0,
507  CMD_PARAM_BORDER_X_1
508  };
509 
510  // --- members ----------------------------------------------------
511 
512  struct RegDebug final : SimpleDebuggable {
513  explicit RegDebug(V9990& v9990);
514  byte read(unsigned address) override;
515  void write(unsigned address, byte value, EmuTime::param time) override;
516  } v9990RegDebug;
517 
518  struct PalDebug final : SimpleDebuggable {
519  explicit PalDebug(V9990& v9990);
520  byte read(unsigned address) override;
521  void write(unsigned address, byte value, EmuTime::param time) override;
522  } v9990PalDebug;
523 
524  IRQHelper irq;
525 
526  Display& display;
527 
530  std::unique_ptr<V9990VRAM> vram;
531  unsigned vramReadPtr, vramWritePtr;
532  byte vramReadBuffer;
533 
536  std::unique_ptr<V9990CmdEngine> cmdEngine;
537 
540  std::unique_ptr<V9990Renderer> renderer;
541 
545 
548  EmuTime hScanSyncTime;
549 
552  const V9990DisplayPeriod* horTiming;
553  const V9990DisplayPeriod* verTiming;
554 
557  V9990DisplayMode mode;
558 
561  byte palette[0x100];
562 
565  byte status;
566 
569  byte pendingIRQs;
570 
573  byte regs[0x40];
574  byte regSelect;
575 
578  bool palTiming;
579 
583  bool interlaced;
584 
587  bool isDisplayArea;
588 
594  bool displayEnabled;
595 
604  byte scrollAYHigh;
605  byte scrollBYHigh;
606 
611  bool systemReset;
612 
617  bool externalVideoSource;
618 
622  bool superimposing;
623 
624  // --- methods ----------------------------------------------------
625 
626  void setHorizontalTiming();
627  void setVerticalTiming();
628 
629  V9990ColorMode getColorMode(byte pal_ctrl) const;
630 
635  inline unsigned getVRAMAddr(RegisterId base) const;
636 
641  inline void setVRAMAddr(RegisterId base, unsigned addr);
642 
648  byte readRegister(byte reg, EmuTime::param time) const;
649 
655  void writeRegister(byte reg, byte val, EmuTime::param time);
656 
662  void writePaletteRegister(byte reg, byte val, EmuTime::param time);
663 
666  void syncAtNextLine(SyncBase& type, EmuTime::param time);
667 
671  void createRenderer(EmuTime::param time);
672 
676  void frameStart(EmuTime::param time);
677 
681  void raiseIRQ(IRQType irqType);
682 
685  void calcDisplayMode();
686 
691  void scheduleHscan(EmuTime::param time);
692 
695  void scheduleCmdEnd(EmuTime::param time);
696 };
698 
699 } // namespace openmsx
700 
701 #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:112
void powerUp(EmuTime::param time) override
This method is called when MSX is powered up.
Definition: V9990.cc:121
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:127
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:225
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:288
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:163
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:812
~V9990() override
Definition: V9990.cc:107
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:696
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:903
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