openMSX
MSXMatsushita.cc
Go to the documentation of this file.
1 #include "MSXMatsushita.hh"
2 #include "MSXCPU.hh"
3 #include "SRAM.hh"
4 #include "VDP.hh"
5 #include "MSXCPUInterface.hh"
6 #include "CliComm.hh"
7 #include "MSXException.hh"
8 #include "serialize.hh"
9 #include "xrange.hh"
10 
11 namespace openmsx {
12 
13 constexpr byte ID = 0x08;
14 
16  : MSXDevice(config)
17  , MSXSwitchedDevice(getMotherBoard(), ID)
18  , cpu(getCPU()) // used frequently, so cache it
19  , vdp(nullptr)
20  , lastTime(EmuTime::zero())
21  , firmwareSwitch(config)
22  , sram(config.findChild("sramname") ? std::make_unique<SRAM>(getName() + " SRAM", 0x800, config) : nullptr)
23  , turboAvailable(config.getChildDataAsBool("hasturbo", false))
24  , turboEnabled(false)
25 {
26  // TODO find out what ports 0x41 0x45 0x46 are used for
27 
28  reset(EmuTime::dummy());
29 }
30 
32 {
34 
35  const auto& refs = getReferences();
36  vdp = !refs.empty() ? dynamic_cast<VDP*>(refs[0]) : nullptr;
37  if (!vdp) {
38  // No (valid) reference to the VDP found. We do allow this to
39  // model MSX machines where the Matsushita device does not
40  // influence the VDP timing. It's not know whether such
41  // machines actually exist.
42  return;
43  }
44 
45  // Wrap the VDP ports.
46  auto& cpuInterface = getCPUInterface();
47  bool error = false;
48  for (auto i : xrange(2)) {
49  error |= !cpuInterface.replace_IO_In (0x98 + i, vdp, this);
50  }
51  for (auto i : xrange(4)) {
52  error |= !cpuInterface.replace_IO_Out(0x98 + i, vdp, this);
53  }
54  if (error) {
55  unwrap();
56  throw MSXException(
57  "Invalid Matsushita configuration: "
58  "VDP not on IO-ports 0x98-0x9B.");
59  }
60 }
61 
63 {
64  if (!vdp) return;
65  unwrap();
66 }
67 
68 void MSXMatsushita::unwrap()
69 {
70  // Unwrap the VDP ports.
71  auto& cpuInterface = getCPUInterface();
72  for (auto i : xrange(2)) {
73  cpuInterface.replace_IO_In (0x98 + i, this, vdp);
74  }
75  for (auto i : xrange(4)) {
76  cpuInterface.replace_IO_Out(0x98 + i, this, vdp);
77  }
78 }
79 
80 void MSXMatsushita::reset(EmuTime::param /*time*/)
81 {
82  color1 = color2 = pattern = address = 0; // TODO check this
83 }
84 
85 byte MSXMatsushita::readSwitchedIO(word port, EmuTime::param time)
86 {
87  // TODO: Port 7 and 8 can be read as well.
88  byte result = peekSwitchedIO(port, time);
89  switch (port & 0x0F) {
90  case 3:
91  pattern = (pattern << 2) | (pattern >> 6);
92  break;
93  case 9:
94  address = (address + 1) & 0x1FFF;
95  break;
96  }
97  return result;
98 }
99 
100 byte MSXMatsushita::peekSwitchedIO(word port, EmuTime::param /*time*/) const
101 {
102  switch (port & 0x0F) {
103  case 0:
104  return byte(~ID);
105  case 1: {
106  byte result = firmwareSwitch.getStatus() ? 0x7F : 0xFF;
107  // bit 0: turbo status, 0=on
108  if (turboEnabled) {
109  result &= ~0x01;
110  }
111  // bit 2: 0 = turbo feature available
112  if (turboAvailable) {
113  result &= ~0x04;
114  }
115  return result;
116  }
117  case 3:
118  return (((pattern & 0x80) ? color2 : color1) << 4)
119  | ((pattern & 0x40) ? color2 : color1);
120  case 9:
121  if (address < 0x800 && sram) {
122  return (*sram)[address];
123  } else {
124  return 0xFF;
125  }
126  default:
127  return 0xFF;
128  }
129 }
130 
131 void MSXMatsushita::writeSwitchedIO(word port, byte value, EmuTime::param /*time*/)
132 {
133  switch (port & 0x0F) {
134  case 1:
135  // the turboEnabled flag works even though no turbo is available
136  if (value & 1) {
137  // bit0 = 1 -> 3.5MHz
138  if (turboAvailable) {
139  getCPU().setZ80Freq(3579545);
140  }
141  turboEnabled = false;
142  } else {
143  // bit0 = 0 -> 5.3MHz
144  if (turboAvailable) {
145  getCPU().setZ80Freq(5369318); // 3579545 * 3/2
146  }
147  turboEnabled = true;
148  }
149  break;
150  case 3:
151  color2 = (value & 0xF0) >> 4;
152  color1 = value & 0x0F;
153  break;
154  case 4:
155  pattern = value;
156  break;
157  case 7:
158  // set address (low)
159  address = (address & 0xFF00) | value;
160  break;
161  case 8:
162  // set address (high)
163  address = (address & 0x00FF) | ((value & 0x1F) << 8);
164  break;
165  case 9:
166  // write sram
167  if (address < 0x800 && sram) {
168  sram->write(address, value);
169  }
170  address = (address + 1) & 0x1FFF;
171  break;
172  }
173 }
174 
175 byte MSXMatsushita::readIO(word port, EmuTime::param time)
176 {
177  // TODO also delay on read?
178  assert(vdp);
179  return vdp->readIO(port, time);
180 }
181 
182 byte MSXMatsushita::peekIO(word port, EmuTime::param time) const
183 {
184  assert(vdp);
185  return vdp->peekIO(port, time);
186 }
187 
188 void MSXMatsushita::writeIO(word port, byte value, EmuTime::param time)
189 {
190  assert(vdp);
191  delay(time);
192  vdp->writeIO(port, value, lastTime.getTime());
193 }
194 
195 void MSXMatsushita::delay(EmuTime::param time)
196 {
197  if (turboAvailable && turboEnabled) {
198  lastTime += 46; // 8us, like in S1990
199  if (time < lastTime.getTime()) {
200  cpu.wait(lastTime.getTime());
201  return;
202  }
203  }
204  lastTime.reset(time);
205 }
206 
207 template<typename Archive>
208 void MSXMatsushita::serialize(Archive& ar, unsigned version)
209 {
210  ar.template serializeBase<MSXDevice>(*this);
211  // no need to serialize MSXSwitchedDevice base class
212 
213  if (sram) ar.serialize("SRAM", *sram);
214  ar.serialize("address", address,
215  "color1", color1,
216  "color2", color2,
217  "pattern", pattern);
218 
219  if (ar.versionAtLeast(version, 2)) {
220  ar.serialize("lastTime", lastTime,
221  "turboEnabled", turboEnabled);
222  } else {
223  // keep 'lastTime == zero'
224  // keep 'turboEnabled == false'
226  "Loading an old savestate: the timing of the CPU-VDP "
227  "communication emulation has changed. This may cause "
228  "synchronization problems in replay.");
229  }
230 }
231 
234 
235 } // namespace openmsx
void printWarning(std::string_view message)
Definition: CliComm.cc:10
constexpr void reset(EmuTime::param e)
Reset the clock to start ticking at the given time.
Definition: Clock.hh:102
constexpr EmuTime::param getTime() const
Gets the time at which the last clock tick occurred.
Definition: Clock.hh:46
void setZ80Freq(unsigned freq)
Switch the Z80 clock freq.
Definition: MSXCPU.cc:312
void wait(EmuTime::param time)
Definition: MSXCPU.cc:317
An MSXDevice is an emulated hardware component connected to the bus of the emulated MSX.
Definition: MSXDevice.hh:33
virtual void init()
Definition: MSXDevice.cc:45
CliComm & getCliComm() const
Definition: MSXDevice.cc:142
MSXCPU & getCPU() const
Definition: MSXDevice.cc:130
const Devices & getReferences() const
Get the device references that are specified for this device.
Definition: MSXDevice.cc:120
MSXCPUInterface & getCPUInterface() const
Definition: MSXDevice.cc:134
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.
byte readIO(word port, EmuTime::param time) override
Read a byte from an IO port at a certain time from this device.
void serialize(Archive &ar, unsigned version)
void init() override
MSXMatsushita(const DeviceConfig &config)
void reset(EmuTime::param time) override
This method is called on reset.
byte peekSwitchedIO(word port, EmuTime::param time) const override
byte peekIO(word port, EmuTime::param time) const override
Read a byte from a given IO port.
void writeSwitchedIO(word port, byte value, EmuTime::param time) override
byte readSwitchedIO(word port, EmuTime::param time) override
Unified implementation of MSX Video Display Processors (VDPs).
Definition: VDP.hh:63
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: VDP.cc:650
byte peekIO(word port, EmuTime::param time) const override
Read a byte from a given IO port.
Definition: VDP.cc:982
byte readIO(word port, EmuTime::param time) override
Read a byte from an IO port at a certain time from this device.
Definition: VDP.cc:962
std::string getName(KeyCode keyCode)
Translate key code to key name.
Definition: Keys.cc:741
This file implemented 3 utility functions:
Definition: Autofire.cc:9
uint8_t byte
8 bit unsigned integer
Definition: openmsx.hh:26
constexpr byte ID
Definition: MSXKanji12.cc:8
REGISTER_MSXDEVICE(ChakkariCopy, "ChakkariCopy")
uint16_t word
16 bit unsigned integer
Definition: openmsx.hh:29
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:998
constexpr auto xrange(T e)
Definition: xrange.hh:155