openMSX
MSXTurboRPCM.cc
Go to the documentation of this file.
1#include "MSXTurboRPCM.hh"
2#include "MSXMotherBoard.hh"
3#include "MSXMixer.hh"
4#include "narrow.hh"
5#include "serialize.hh"
6#include "unreachable.hh"
7
8namespace openmsx {
9
11 : MSXDevice(config)
12 , mixer(getMotherBoard().getMSXMixer())
13 , connector(getPluggingController(), "pcminput")
14 , dac("PCM", "Turbo-R PCM", config)
15 , reference(getCurrentTime())
16{
18}
19
21{
22 hardwareMute(false);
23}
24
25void MSXTurboRPCM::reset(EmuTime::param time)
26{
27 reference.reset(time);
28 status = 0;
29 DValue = 0x80; // TODO correct initial value?
30 hold = 0x80; // avoid UMR
31 dac.reset(time);
32 hardwareMute(false);
33}
34
35byte MSXTurboRPCM::readIO(word port, EmuTime::param time)
36{
37 return peekIO(port, time);
38}
39
40byte MSXTurboRPCM::peekIO(word port, EmuTime::param time) const
41{
42 switch (port & 0x01) {
43 case 0:
44 // bit 0-1 15.700kHz counter
45 // bit 2-7 not used
46 return reference.getTicksTill(time) & 0x03;
47 case 1:
48 // bit 0 BUFF 0->D/A TODO check this bit
49 // 1->A/D
50 // bit 1 MUTE mute ALL sound 0->muted
51 // bit 2 FILT filter 0->standard signal
52 // 1->filtered signal
53 // bit 3 SEL select 0->D/A
54 // 1->Mic/Jack
55 // bit 4 SMPL sample/hold 0->sample
56 // 1->hold
57 // bit 5-6 not used
58 // bit 7 COMP comparator result 0->greater
59 // 1->smaller
60 return (getComp(time) ? 0x80 : 0x00) | (status & 0x1F);
61 default: // unreachable, avoid warning
62 UNREACHABLE; return 0;
63 }
64}
65
66void MSXTurboRPCM::writeIO(word port, byte value, EmuTime::param time)
67{
68 switch (port & 0x01) {
69 case 0:
70 // While playing: sample value
71 // recording: compare value
72 // Resets counter
73 reference.advance(time);
74 DValue = value;
75 if (status & 0x02) { // not muted
76 assert(reference.getTime() <= time);
77 auto time2 = (status & 0x01) // BUFF
78 ? reference.getFastAdd(1) // value only updates on the next clock
79 : time;
80 assert(time <= time2);
81 dac.writeDAC(DValue, time2);
82 }
83 break;
84
85 case 1:
86 // bit 0 BUFF
87 // bit 1 MUTE mute _all_ sound 0->no sound
88 // bit 2 FILT filter 1->filter on
89 // bit 3 SEL select 1->Mic/Jack 0->D/A
90 // bit 4 SMPL sample/hold 1->hold
91 // bit 5-7 not used
92 byte change = status ^ value;
93 status = value;
94
95 if ((change & 0x01) && ((status & 0x01) == 0)) {
96 dac.writeDAC(DValue, time);
97 }
98 // TODO status & 0x08
99 if ((change & 0x10) && (status & 0x10)) {
100 hold = getSample(time);
101 }
102 hardwareMute(!(status & 0x02));
103 break;
104 }
105}
106
107byte MSXTurboRPCM::getSample(EmuTime::param time) const
108{
109 return (status & 0x04)
110 ? narrow<byte>((connector.readSample(time) / 256) + 0x80)
111 : 0x80; // TODO check
112}
113
114bool MSXTurboRPCM::getComp(EmuTime::param time) const
115{
116 // TODO also when D/A ??
117 byte sample = (status & 0x10) ? hold : getSample(time);
118 return sample >= DValue;
119}
120
121void MSXTurboRPCM::hardwareMute(bool mute)
122{
123 if (mute == hwMute) return;
124
125 hwMute = mute;
126 if (hwMute) {
127 mixer.mute();
128 } else {
129 mixer.unmute();
130 }
131}
132
133
134template<typename Archive>
135void MSXTurboRPCM::serialize(Archive& ar, unsigned /*version*/)
136{
137 ar.template serializeBase<MSXDevice>(*this);
138 ar.serialize("audioConnector", connector,
139 "reference", reference,
140 "status", status,
141 "DValue", DValue,
142 "hold", hold,
143 "DAC", dac);
144
145 hardwareMute(!(status & 0x02)); // restore hwMute
146}
149
150} // namespace openmsx
#define REGISTER_MSXDEVICE(CLASS, NAME)
Definition MSXDevice.hh:354
int16_t readSample(EmuTime::param time) const
constexpr void reset(EmuTime::param e)
Reset the clock to start ticking at the given time.
Definition Clock.hh:102
constexpr EmuTime getFastAdd(unsigned n) const
Like operator+() but faster, though the step can't be too big (max a little over 1 second).
Definition Clock.hh:93
constexpr EmuTime::param getTime() const
Gets the time at which the last clock tick occurred.
Definition Clock.hh:46
constexpr void advance(EmuTime::param e)
Advance this clock in time until the last tick which is not past the given time.
Definition Clock.hh:110
constexpr unsigned getTicksTill(EmuTime::param e) const
Calculate the number of ticks for this clock until the given time.
Definition Clock.hh:58
void reset(EmuTime::param time)
void writeDAC(uint8_t value, EmuTime::param time)
Definition DACSound8U.cc:17
An MSXDevice is an emulated hardware component connected to the bus of the emulated MSX.
Definition MSXDevice.hh:36
EmuTime::param getCurrentTime() const
Definition MSXDevice.cc:125
void mute()
TODO This methods (un)mute the sound.
Definition MSXMixer.cc:609
MSXTurboRPCM(const DeviceConfig &config)
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.
byte peekIO(word port, EmuTime::param time) const override
Read a byte from a given IO port.
void serialize(Archive &ar, unsigned version)
void reset(EmuTime::param time) override
This method is called on reset.
This file implemented 3 utility functions:
Definition Autofire.cc:9
uint16_t word
16 bit unsigned integer
Definition openmsx.hh:29
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
#define UNREACHABLE