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 , irq(getMotherBoard(), "PioneerLDControl.IRQdisplayoff")
36{
37 if (config.getChildDataAsBool("laserdisc", true)) {
38 laserdisc.emplace(getHardwareConfig(), *this);
39 }
41}
42
44{
46
47 const auto& refs = getReferences();
48 ppi = refs.size() >= 1 ? dynamic_cast<MSXPPI*>(refs[0]) : nullptr;
49 if (!ppi) {
50 throw MSXException("Invalid PioneerLDControl configuration: "
51 "need reference to PPI device.");
52 }
53
54 vdp = refs.size() == 2 ? dynamic_cast<VDP*>(refs[1]) : nullptr;
55 if (!vdp) {
56 throw MSXException("Invalid PioneerLDControl configuration: "
57 "need reference to VDP device.");
58 }
59}
60
62
63void PioneerLDControl::reset(EmuTime::param time)
64{
65 muteL = muteR = true;
66 superimposing = false;
67 extInt = false;
68
69 irq.reset();
70 if (laserdisc) laserdisc->setMuting(muteL, muteR, time);
71}
72
73byte PioneerLDControl::readMem(word address, EmuTime::param time)
74{
75 byte val = PioneerLDControl::peekMem(address, time);
76 if (address == 0x7fff) {
77 extInt = false;
78 irq.reset();
79 }
80 return val;
81}
82
83byte PioneerLDControl::peekMem(word address, EmuTime::param time) const
84{
85 byte val = 0xff;
86
87 if (address == 0x7fff) {
88 if (videoEnabled) {
89 val &= 0x7f;
90 }
91 if (!extInt) {
92 val &= 0xfe;
93 }
94 } else if (address == 0x7ffe) {
95 if (clock.getTicksTill(time) & 1) {
96 val &= 0xfe;
97 }
98 if (laserdisc && laserdisc->extAck(time)) {
99 val &= 0x7f;
100 }
101 } else if (0x4000 <= address && address < 0x6000) {
102 val = rom[address & 0x1fff];
103 }
104 return val;
105}
106
107const byte* PioneerLDControl::getReadCacheLine(word address) const
108{
109 if ((address & CacheLine::HIGH) == (0x7FFE & CacheLine::HIGH)) {
110 return nullptr;
111 } else if (0x4000 <= address && address < 0x6000) {
112 return &rom[address & 0x1fff];
113 } else {
114 return unmappedRead.data();
115 }
116}
117
118void PioneerLDControl::writeMem(word address, byte value, EmuTime::param time)
119{
120 if (address == 0x7fff) {
121 // superimpose
122 superimposing = !(value & 1);
123 irq.set(superimposing && extInt);
124
125 updateVideoSource();
126
127 // Muting
128 if (!muteL && !(value & 0x80)) {
129 muteR = !(ppi->peekIO(2, time) & 0x10);
130 }
131 muteL = !(value & 0x80);
132 if (laserdisc) laserdisc->setMuting(muteL, muteR, time);
133
134 } else if (address == 0x7ffe) {
135 if (laserdisc) laserdisc->extControl(value & 1, time);
136 }
137}
138
140{
141 if ((address & CacheLine::HIGH) == (0x7FFE & CacheLine::HIGH)) {
142 return nullptr;
143 } else {
144 return unmappedWrite.data();
145 }
146}
147
149{
150 if (videoEnabled && !enabled) {
151 // raise an interrupt when external video goes off
152 extInt = true;
153 if (superimposing) irq.set();
154 }
155 videoEnabled = enabled;
156 updateVideoSource();
157}
158
159void PioneerLDControl::updateVideoSource()
160{
161 const auto* videoSource = (videoEnabled && superimposing && laserdisc)
162 ? laserdisc->getRawFrame()
163 : nullptr;
164 vdp->setExternalVideoSource(videoSource);
165}
166
167template<typename Archive>
168void PioneerLDControl::serialize(Archive& ar, unsigned /*version*/)
169{
170 ar.serialize("clock", clock,
171 "mutel", muteL,
172 "muter", muteR);
173 // videoEnabled is restored from LaserdiscPlayer. Set to false
174 // for now so that the irq does not get changed during load
175 if constexpr (Archive::IS_LOADER) {
176 videoEnabled = false;
177 }
178 ar.serialize("superimposing", superimposing,
179 "extint", extInt,
180 "irq", irq);
181 if (laserdisc) ar.serialize("laserdisc", *laserdisc);
182
183 if constexpr (Archive::IS_LOADER) {
184 updateVideoSource();
185 if (laserdisc) {
186 laserdisc->setMuting(muteL, muteR, getCurrentTime());
187 }
188 }
189}
190
193
194} // namespace openmsx
#define REGISTER_MSXDEVICE(CLASS, NAME)
Definition MSXDevice.hh:356
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
void set()
Set the interrupt request on the bus.
Definition IRQHelper.hh:76
void reset()
Reset the interrupt request on the bus.
Definition IRQHelper.hh:85
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:306
const HardwareConfig & getHardwareConfig() const
Returns the hardwareconfig this device belongs to.
Definition MSXDevice.hh:49
static std::array< byte, 0x10000 > unmappedWrite
Definition MSXDevice.hh:307
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
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:66
void setExternalVideoSource(const RawFrame *externalSource)
Enable superimposing.
Definition VDP.hh:656
constexpr unsigned HIGH
Definition CacheLine.hh:10
This file implemented 3 utility functions:
Definition Autofire.cc:11
uint16_t word
16 bit unsigned integer
Definition openmsx.hh:29
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)