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