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