Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/dosbox-staging/dosbox-staging.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkcgen <kcgen@users.noreply.github.com>2022-09-17 21:29:44 +0300
committerkcgen <kcgen@users.noreply.github.com>2022-09-17 22:54:56 +0300
commit128e500cb23ab6e9610be5904561d997b13f255e (patch)
tree73ab700f96efd29282c11df2a722b72a6732589b
parentd1af01bb65e466e2e2ece0b2c4c002a3b53a325d (diff)
Make CMS SAA-1099 chips standalone deviceskc/separate-cms-chips-1
-rw-r--r--src/hardware/gameblaster.cpp213
-rw-r--r--src/hardware/gameblaster.h88
2 files changed, 181 insertions, 120 deletions
diff --git a/src/hardware/gameblaster.cpp b/src/hardware/gameblaster.cpp
index 42e44c43d..48032a2a2 100644
--- a/src/hardware/gameblaster.cpp
+++ b/src/hardware/gameblaster.cpp
@@ -24,63 +24,41 @@
#include "setup.h"
#include "pic.h"
-void GameBlaster::Open(const int port_choice, const std::string &card_choice,
- const std::string &filter_choice)
+#include <bitset>
+
+void Saa1099::Open(const io_port_t port, const std::string &filter_choice)
{
Close();
assert(!is_open);
- is_standalone_gameblaster = (card_choice == "gb");
-
- // Ports are filtered and corrected by the conf system, so we simply
- // assert here
- const std::vector<io_port_t> valid_gb_ports = {0x210, 0x220, 0x230, 0x240, 0x250, 0x260};
- const std::vector<io_port_t> valid_cms_ports = {0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0x300};
- const auto valid_ports = is_standalone_gameblaster ? valid_gb_ports
- : valid_cms_ports;
- base_port = check_cast<io_port_t>(port_choice);
- assert(contains(valid_ports, base_port));
-
- // Create the SAA1099 devices
- for (auto &d : devices) {
- d = std::make_unique<saa1099_device>(machine_config(), "", nullptr, chip_clock, render_divisor);
- d->device_start();
- }
+ // Create the SAA1099 device
+ device = std::make_unique<saa1099_device>(machine_config(),
+ "",
+ nullptr,
+ saa1099_chip_clock,
+ saa1099_rate_divisor);
+ device->device_start();
// Creative included CMS chips on several Sound Blaster cards, which
// games could use (in addition to the SB features), so we always setup
// those handlers - even if the card type isn't a GameBlaster.
using namespace std::placeholders;
- const auto data_to_left = std::bind(&GameBlaster::WriteDataToLeftDevice, this, _1, _2, _3);
- const auto control_to_left = std::bind(&GameBlaster::WriteControlToLeftDevice, this, _1, _2, _3);
- const auto data_to_right = std::bind(&GameBlaster::WriteDataToRightDevice, this, _1, _2, _3);
- const auto control_to_right = std::bind(&GameBlaster::WriteControlToRightDevice, this, _1, _2, _3);
+ const auto write_data = std::bind(&Saa1099::WriteData, this, _1, _2, _3);
+ const auto write_control = std::bind(&Saa1099::WriteControl, this, _1, _2, _3);
- write_handlers[0].Install(base_port, data_to_left, io_width_t::byte);
- write_handlers[1].Install(base_port + 1, control_to_left, io_width_t::byte);
- write_handlers[2].Install(base_port + 2, data_to_right, io_width_t::byte);
- write_handlers[3].Install(base_port + 3, control_to_right, io_width_t::byte);
+ write_handlers[0].Install(port, write_data, io_width_t::byte);
+ write_handlers[1].Install(port + 1, write_control, io_width_t::byte);
- // However, standalone GameBlaster cards came with a dedicated chip on
- // it that could be used for detection. So we setup those handlers for
- // this chip only if the card-type is a GameBlaster:
- if (is_standalone_gameblaster) {
- const auto read_from_detection_port = std::bind(&GameBlaster::ReadFromDetectionPort, this, _1, _2);
- const auto write_to_detection_port = std::bind(&GameBlaster::WriteToDetectionPort, this, _1, _2, _3);
-
- read_handler_for_detection.Install(base_port, read_from_detection_port, io_width_t::byte, 16);
- write_handler_for_detection.Install(base_port + 4,
- write_to_detection_port,
- io_width_t::byte,
- 12);
- }
+ const auto read_control = std::bind(&Saa1099::ReadControl, this, _1, _2);
+ read_handler.Install(port + 1, read_control, io_width_t::byte);
// Setup the mixer and level controls
- const auto audio_callback = std::bind(&GameBlaster::AudioCallback, this, _1);
+ const auto audio_callback = std::bind(&Saa1099::AudioCallback, this, _1);
+ assert(chip_name);
channel = MIXER_AddChannel(audio_callback,
use_mixer_rate,
- CardName(),
+ chip_name,
{ChannelFeature::Sleep,
ChannelFeature::Stereo,
ChannelFeature::ReverbSend,
@@ -99,7 +77,7 @@ void GameBlaster::Open(const int port_choice, const std::string &card_choice,
} else if (!channel->TryParseAndSetCustomFilter(filter_choice)) {
if (filter_choice != "off")
LOG_WARNING("%s: Invalid 'cms_filter' value: '%s', using 'off'",
- CardName(),
+ chip_name,
filter_choice.c_str());
channel->SetLowPassFilter(FilterState::Off);
@@ -111,44 +89,28 @@ void GameBlaster::Open(const int port_choice, const std::string &card_choice,
// Setup the resampler to convert from the render rate to the mixer's frame rate
const auto max_freq = std::max(frame_rate_hz * 0.9 / 2, 8000.0);
for (auto &r : resamplers)
- r.reset(reSIDfp::TwoPassSincResampler::create(render_rate_hz, frame_rate_hz, max_freq));
-
- LOG_MSG("%s: Running on port %xh with two %0.3f MHz Phillips SAA-1099 chips",
- CardName(),
- base_port,
- chip_clock / 1e6);
+ r.reset(reSIDfp::TwoPassSincResampler::create(saa1099_chip_clock / saa1099_rate_divisor,
+ frame_rate_hz,
+ max_freq));
assert(channel);
- assert(devices[0]);
- assert(devices[1]);
+ assert(device);
assert(resamplers[0]);
assert(resamplers[1]);
-
- is_open = true;
}
-bool GameBlaster::MaybeRenderFrame(AudioFrame &frame)
+bool Saa1099::MaybeRenderFrame(AudioFrame &frame)
{
// Static containers setup once and reused
- static std::array<int16_t, 2> buf = {}; // left and right
- static int16_t *p_buf[] = {&buf[0], &buf[1]};
static device_sound_interface::sound_stream stream;
- // Accumulate the samples from both SAA-1099 devices
- devices[0]->sound_stream_update(stream, 0, p_buf, 1);
- int left_accum = buf[0];
- int right_accum = buf[1];
-
- devices[1]->sound_stream_update(stream, 0, p_buf, 1);
- left_accum += buf[0];
- right_accum += buf[1];
-
- // Increment our time datum up to which the device has rendered
+ // Update the stream and increment our time datum
+ device->sound_stream_update(stream, 0, p_buf, 1);
last_rendered_ms += ms_per_render;
// Resample the limited frame
- const auto l_ready = resamplers[0]->input(left_accum);
- const auto r_ready = resamplers[1]->input(right_accum);
+ const auto l_ready = resamplers[0]->input(buf[0]);
+ const auto r_ready = resamplers[1]->input(buf[1]);
assert(l_ready == r_ready);
const auto frame_is_ready = l_ready && r_ready;
@@ -160,7 +122,7 @@ bool GameBlaster::MaybeRenderFrame(AudioFrame &frame)
return frame_is_ready;
}
-void GameBlaster::RenderUpToNow()
+void Saa1099::RenderUpToNow()
{
const auto now = PIC_FullIndex();
@@ -178,31 +140,31 @@ void GameBlaster::RenderUpToNow()
}
}
-void GameBlaster::WriteDataToLeftDevice(io_port_t, io_val_t value, io_width_t)
+void Saa1099::WriteData(io_port_t, io_val_t value, io_width_t)
{
RenderUpToNow();
- devices[0]->data_w(0, 0, check_cast<uint8_t>(value));
+ LOG_MSG("%s write data = %u", chip_name, value);
+ device->data_w(0, 0, check_cast<uint8_t>(value));
}
-void GameBlaster::WriteControlToLeftDevice(io_port_t, io_val_t value, io_width_t)
+void Saa1099::WriteControl(io_port_t, io_val_t value, io_width_t)
{
RenderUpToNow();
- devices[0]->control_w(0, 0, check_cast<uint8_t>(value));
-}
+ const auto control_bits = std::bitset<8>(static_cast<uint8_t>(value));
+ LOG_MSG("%s write ctrl = %s", chip_name, control_bits.to_string().c_str());
+ device->control_w(0, 0, check_cast<uint8_t>(value));
-void GameBlaster::WriteDataToRightDevice(io_port_t, io_val_t value, io_width_t)
-{
- RenderUpToNow();
- devices[1]->data_w(0, 0, check_cast<uint8_t>(value));
+ constexpr uint8_t cmd_range = 0b00011111;
+ control_cmd = value & cmd_range;
}
-void GameBlaster::WriteControlToRightDevice(io_port_t, io_val_t value, io_width_t)
+uint8_t Saa1099::ReadControl(const io_port_t, const io_width_t)
{
- RenderUpToNow();
- devices[1]->control_w(0, 0, check_cast<uint8_t>(value));
+ LOG_MSG("%s read control = %u", chip_name, control_cmd);
+ return control_cmd;
}
-void GameBlaster::AudioCallback(const uint16_t requested_frames)
+void Saa1099::AudioCallback(const uint16_t requested_frames)
{
assert(channel);
@@ -227,6 +189,79 @@ void GameBlaster::AudioCallback(const uint16_t requested_frames)
last_rendered_ms = PIC_FullIndex();
}
+void Saa1099::Close()
+{
+ if (!is_open)
+ return;
+
+ // Drop access to the IO ports
+ for (auto &w : write_handlers)
+ w.Uninstall();
+ read_handler.Uninstall();
+
+ // Stop playback
+ if (channel)
+ channel->Enable(false);
+
+ // Remove the mixer channel, SAA-1099 device, and resamplers
+ channel.reset();
+ device.reset();
+ resamplers[0].reset();
+ resamplers[1].reset();
+
+ is_open = false;
+}
+
+void GameBlaster::Open(const int port_choice, const std::string &card_choice,
+ const std::string &filter_choice)
+{
+ Close();
+ assert(!is_open);
+
+ is_standalone_gameblaster = (card_choice == "gb");
+
+ // Ports are filtered and corrected by the conf system, so we simply
+ // assert here
+ const std::vector<io_port_t> valid_gb_ports = {
+ 0x210, 0x220, 0x230, 0x240, 0x250, 0x260};
+ const std::vector<io_port_t> valid_cms_ports = {
+ 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0x300};
+ const auto valid_ports = is_standalone_gameblaster ? valid_gb_ports
+ : valid_cms_ports;
+ base_port = check_cast<io_port_t>(port_choice);
+ assert(contains(valid_ports, base_port));
+
+ saa1099[0].Open(base_port, filter_choice);
+ saa1099[1].Open(base_port + 2, filter_choice);
+
+ // Standalone GameBlaster cards came with a dedicated chip on
+ // it that could be used for detection. So we setup those handlers for
+ // this chip only if the card-type is a GameBlaster:
+ using namespace std::placeholders;
+ if (is_standalone_gameblaster) {
+ const auto read_from_detection_port = std::bind(
+ &GameBlaster::ReadFromDetectionPort, this, _1, _2);
+ const auto write_to_detection_port = std::bind(
+ &GameBlaster::WriteToDetectionPort, this, _1, _2, _3);
+
+ read_handler_for_detection.Install(base_port + 4,
+ read_from_detection_port,
+ io_width_t::byte,
+ 16);
+ write_handler_for_detection.Install(base_port + 4,
+ write_to_detection_port,
+ io_width_t::byte,
+ 12);
+ }
+
+ LOG_MSG("%s: Running on port %xh with two %0.3f MHz Phillips SAA-1099 chips",
+ CardName(),
+ base_port,
+ saa1099_chip_clock / 1e6);
+
+ is_open = true;
+}
+
void GameBlaster::WriteToDetectionPort(io_port_t port, io_val_t value, io_width_t)
{
switch (port - base_port) {
@@ -262,22 +297,12 @@ void GameBlaster::Close()
LOG_INFO("%s: Shutting down the card on port %xh", CardName(), base_port);
- // Drop access to the IO ports
- for (auto &w : write_handlers)
- w.Uninstall();
write_handler_for_detection.Uninstall();
read_handler_for_detection.Uninstall();
- // Stop playback
- if (channel)
- channel->Enable(false);
-
- // Remove the mixer channel, SAA-1099 devices, soft-limiter, and resamplers
- channel.reset();
- devices[0].reset();
- devices[1].reset();
- resamplers[0].reset();
- resamplers[1].reset();
+ // Stop the devices
+ saa1099[0].Close();
+ saa1099[1].Close();
is_open = false;
}
diff --git a/src/hardware/gameblaster.h b/src/hardware/gameblaster.h
index 2b81d5a9c..52011fa7e 100644
--- a/src/hardware/gameblaster.h
+++ b/src/hardware/gameblaster.h
@@ -38,29 +38,79 @@
#include "mame/saa1099.h"
#include "../libs/residfp/resample/TwoPassSincResampler.h"
-class GameBlaster {
+constexpr auto saa1099_chip_clock = 14318180 / 2;
+constexpr auto saa1099_rate_divisor = 10;
+
+class Saa1099 {
public:
- void Open(const int port_choice, const std::string &card_choice,
- const std::string &filter_choice);
+ Saa1099(const char *name) : chip_name(name)
+ {
+ assert(chip_name);
+ }
+ Saa1099() = delete;
+ Saa1099(const Saa1099 &) = delete;
+ Saa1099 &operator=(const Saa1099 &) = delete;
+
+ void Open(const io_port_t port, const std::string &filter_choice);
void Close();
- ~GameBlaster() { Close(); }
+ ~Saa1099()
+ {
+ Close();
+ }
-private:
// Audio rendering
bool MaybeRenderFrame(AudioFrame &frame);
std::vector<int16_t> GetFrame();
void AudioCallback(const uint16_t requested_frames);
void RenderUpToNow();
- // IO callbacks to the left SAA1099 device
- void WriteDataToLeftDevice(io_port_t port, io_val_t value, io_width_t width);
- void WriteControlToLeftDevice(io_port_t port, io_val_t value, io_width_t width);
+ // IO callback
+ void WriteData(io_port_t port, io_val_t value, io_width_t width);
+ void WriteControl(io_port_t port, io_val_t value, io_width_t width);
+
+ uint8_t ReadControl(const io_port_t, const io_width_t);
+
+private:
+ // Managed objects
+ mixer_channel_t channel = nullptr;
+
+ IO_WriteHandleObject write_handlers[2] = {};
+ IO_ReadHandleObject read_handler = {};
+
+ std::unique_ptr<saa1099_device> device = {};
+ std::unique_ptr<reSIDfp::TwoPassSincResampler> resamplers[2] = {};
+
+ std::queue<AudioFrame> fifo = {};
+
+ // Static rate-related configuration
+ static constexpr auto ms_per_render = millis_in_second /
+ (saa1099_chip_clock /
+ saa1099_rate_divisor);
+
+ // Runtime state
+ std::array<int16_t, 2> buf = {}; // left and right
+
+ int16_t *p_buf[2] = {&buf[0], &buf[1]};
+
+ double last_rendered_ms = 0;
+ uint8_t control_cmd = 0;
+ const char *chip_name = nullptr;
+ bool is_open = false;
+};
+
+class GameBlaster {
+public:
+ void Open(const int port_choice, const std::string &card_choice,
+ const std::string &filter_choice);
- // IO callbacks to the right SAA1099 device
- void WriteDataToRightDevice(io_port_t port, io_val_t value, io_width_t width);
- void WriteControlToRightDevice(io_port_t port, io_val_t value, io_width_t width);
+ void Close();
+ ~GameBlaster()
+ {
+ Close();
+ }
+private:
// IO callbacks to the GameBlaster detection chip
void WriteToDetectionPort(io_port_t port, io_val_t value, io_width_t width);
uint8_t ReadFromDetectionPort(io_port_t port, io_width_t width) const;
@@ -68,26 +118,12 @@ private:
const char *CardName() const;
// Managed objects
- mixer_channel_t channel = nullptr;
+ Saa1099 saa1099[2] = {"SAA1099_0", "SAA1099_1"};
- IO_WriteHandleObject write_handlers[4] = {};
IO_WriteHandleObject write_handler_for_detection = {};
IO_ReadHandleObject read_handler_for_detection = {};
- std::unique_ptr<saa1099_device> devices[2] = {};
- std::unique_ptr<reSIDfp::TwoPassSincResampler> resamplers[2] = {};
-
- std::queue<AudioFrame> fifo = {};
-
- // Static rate-related configuration
- static constexpr auto chip_clock = 14318180 / 2;
- static constexpr auto render_divisor = 32;
- static constexpr auto render_rate_hz = ceil_sdivide(chip_clock,
- render_divisor);
- static constexpr auto ms_per_render = millis_in_second / render_rate_hz;
-
// Runtime states
- double last_rendered_ms = 0;
io_port_t base_port = 0;
bool is_standalone_gameblaster = false;
bool is_open = false;