openMSX
PioneerLDControl.cc
Go to the documentation of this file.
1 #include "PioneerLDControl.hh"
2 #include "Rom.hh"
3 #include "CacheLine.hh"
4 #include "serialize.hh"
5 #include "LaserdiscPlayer.hh"
6 #include "MSXPPI.hh"
7 #include "MSXException.hh"
8 #include "VDP.hh"
9 #include "memory.hh"
10 
11 namespace openmsx {
12 
13 /*
14  * Laserdisc Control: there are three bits involved here. There are three
15  * bits/connections involved.
16  * - EXTACK (from Laserdisc -> MSX) will remain low for a while to acknowledge
17  * it has received a command and is executing
18  * - EXTCONTROL (from MSX -> Laserdisc) one bit information which is used for
19  * sending commands
20  * - PULSE (internal to MSX) 8175.5hz signal which used by software to
21  * create the right pulses for communicating with the Laserdisc over
22  * EXTCONTROL.
23  *
24  * Sound Muting: left and right audio channels from Laserdisc input can
25  * be muted independently. After reset or startup both channels are muted.
26  * The left muting is controlled by bit 7 of 0x7fff; set is not muted,
27  * cleared is muted. If this bit changed from 0->1 (rising edge triggered
28  * and inverted) then bit 4 of register C of PPI switches L muting; set
29  * for muting disabled, clear for muting enabled.
30  *
31  * Cassette Input: If the motor relay is OFF then audio on the R channel
32  * ends up in the PSG (regardless of muting); if the motor relay is ON
33  * then normal tape input is used.
34  */
36  : MSXDevice(config)
37  , rom(make_unique<Rom>(getName() + " ROM", "rom", config))
38  , clock(EmuTime::zero)
39  , irq(getMotherBoard(), "PioneerLDControl.IRQdisplayoff")
40  , videoEnabled(false)
41 {
42  if (config.getChildDataAsBool("laserdisc", true)) {
43  laserdisc = make_unique<LaserdiscPlayer>(
44  getHardwareConfig(), *this);
45  }
47 }
48 
50 {
52 
53  const auto& references = getReferences();
54  ppi = references.size() >= 1 ?
55  dynamic_cast<MSXPPI*>(references[0]) : nullptr;
56  if (!ppi) {
57  throw MSXException("Invalid PioneerLDControl configuration: "
58  "need reference to PPI device.");
59  }
60 
61  vdp = references.size() == 2 ?
62  dynamic_cast<VDP*>(references[1]) : nullptr;
63  if (!vdp) {
64  throw MSXException("Invalid PioneerLDControl configuration: "
65  "need reference to VDP device.");
66  }
67 }
68 
70 {
71 }
72 
74 {
75  mutel = muter = true;
76  superimposing = false;
77  extint = false;
78 
79  irq.reset();
80  if (laserdisc) laserdisc->setMuting(mutel, muter, time);
81 }
82 
84 {
85  byte val = PioneerLDControl::peekMem(address, time);
86  if (address == 0x7fff) {
87  extint = false;
88  if (irq.getState()) {
89  irq.reset();
90  }
91  }
92  return val;
93 }
94 
96 {
97  byte val = 0xff;
98 
99  if (address == 0x7fff) {
100  if (videoEnabled) {
101  val &= 0x7f;
102  }
103  if (!extint) {
104  val &= 0xfe;
105  }
106  } else if (address == 0x7ffe) {
107  if (clock.getTicksTill(time) & 1) {
108  val &= 0xfe;
109  }
110  if (laserdisc && laserdisc->extAck(time)) {
111  val &= 0x7f;
112  }
113  } else if (0x4000 <= address && address < 0x6000) {
114  val = (*rom)[address & 0x1fff];
115  }
116  return val;
117 }
118 
120 {
121  if ((start & CacheLine::HIGH) == (0x7FFE & CacheLine::HIGH)) {
122  return nullptr;
123  } else if (0x4000 <= start && start < 0x6000) {
124  return &(*rom)[start & 0x1fff];
125  } else {
126  return unmappedRead;
127  }
128 }
129 
131 {
132  if (address == 0x7fff) {
133  // superimpose
134  superimposing = !(value & 1);
135  if (superimposing) {
136  if (extint && !irq.getState()) {
137  irq.set();
138  }
139  } else if (irq.getState()) {
140  irq.reset();
141  }
142 
143  updateVideoSource();
144 
145  // Muting
146  if (!mutel && !(value & 0x80)) {
147  muter = !(ppi->peekIO(2, time) & 0x10);
148  }
149  mutel = !(value & 0x80);
150  if (laserdisc) laserdisc->setMuting(mutel, muter, time);
151 
152  } else if (address == 0x7ffe) {
153  if (laserdisc) laserdisc->extControl(value & 1, time);
154  }
155 }
156 
158 {
159  if ((start & CacheLine::HIGH) == (0x7FFE & CacheLine::HIGH)) {
160  return nullptr;
161  } else {
162  return unmappedWrite;
163  }
164 }
165 
166 void PioneerLDControl::videoIn(bool enabled)
167 {
168  if (videoEnabled && !enabled) {
169  // raise an interrupt when external video goes off
170  extint = true;
171  if (superimposing) {
172  irq.set();
173  }
174  }
175  videoEnabled = enabled;
176  updateVideoSource();
177 }
178 
179 void PioneerLDControl::updateVideoSource()
180 {
181  auto* videoSource = (videoEnabled && superimposing && laserdisc)
182  ? laserdisc->getRawFrame()
183  : nullptr;
184  vdp->setExternalVideoSource(videoSource);
185 }
186 
187 template<typename Archive>
188 void PioneerLDControl::serialize(Archive& ar, unsigned /*version*/)
189 {
190  ar.serialize("clock", clock);
191  ar.serialize("mutel", mutel);
192  ar.serialize("muter", muter);
193  // videoEnabled is restored from LaserdiscPlayer. Set to false
194  // for now so that the irq does not get changed during load
195  if (ar.isLoader()) {
196  videoEnabled = false;
197  }
198  ar.serialize("superimposing", superimposing);
199  ar.serialize("extint", extint);
200  ar.serialize("irq", irq);
201  if (laserdisc) ar.serialize("laserdisc", *laserdisc);
202 
203  if (ar.isLoader()) {
204  updateVideoSource();
205  if (laserdisc) {
206  laserdisc->setMuting(mutel, muter, getCurrentTime());
207  }
208  }
209 }
210 
213 
214 } // namespace openmsx
virtual void reset(EmuTime::param time)
This method is called on reset.
virtual void init()
Definition: MSXDevice.cc:52
REGISTER_MSXDEVICE(DebugDevice,"DebugDevice")
virtual byte readMem(word address, EmuTime::param time)
Read a byte from a location at a certain time from this device.
void serialize(Archive &ar, unsigned version)
EmuTime::param getCurrentTime() const
Definition: MSXDevice.cc:136
unsigned char byte
8 bit unsigned integer
Definition: openmsx.hh:33
const HardwareConfig & getHardwareConfig() const
Returns the hardwareconfig this device belongs to.
Definition: MSXDevice.hh:41
unsigned getTicksTill(EmuTime::param e) const
Calculate the number of ticks for this clock until the given time.
Definition: Clock.hh:58
bool getChildDataAsBool(string_ref name, bool defaultValue=false) const
Definition: DeviceConfig.cc:56
PioneerLDControl(const DeviceConfig &config)
bool getState() const
Get the interrupt state.
Definition: IRQHelper.hh:95
virtual byte * getWriteCacheLine(word address) const
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for writing...
virtual byte peekMem(word address, EmuTime::param time) const
Read a byte from a given memory location.
const Devices & getReferences() const
Get the device references that are specified for this device.
Definition: MSXDevice.cc:130
An MSXDevice is an emulated hardware component connected to the bus of the emulated MSX...
Definition: MSXDevice.hh:32
unsigned short word
16 bit unsigned integer
Definition: openmsx.hh:38
void reset()
Reset the interrupt request on the bus.
Definition: IRQHelper.hh:85
static byte unmappedRead[0x10000]
Definition: MSXDevice.hh:266
void videoIn(bool enabled)
void set()
Set the interrupt request on the bus.
Definition: IRQHelper.hh:76
Unified implementation of MSX Video Display Processors (VDPs).
Definition: VDP.hh:66
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:802
static byte unmappedWrite[0x10000]
Definition: MSXDevice.hh:267
virtual void writeMem(word address, byte value, EmuTime::param time)
Write a given byte to a given location at a certain time to this device.
virtual const byte * getReadCacheLine(word start) const
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for reading...
const string getName(KeyCode keyCode)
Translate key code to key name.
Definition: Keys.cc:363
virtual byte peekIO(word port, EmuTime::param time) const
Read a byte from a given IO port.
Definition: MSXPPI.cc:88
std::unique_ptr< T > make_unique()
Definition: memory.hh:27
void setExternalVideoSource(const RawFrame *externalSource)
Enable superimposing.
Definition: VDP.hh:505