diff --git a/Machines/Apple/AppleII/AppleII.cpp b/Machines/Apple/AppleII/AppleII.cpp index f2bc2e0ac..d54ba8722 100644 --- a/Machines/Apple/AppleII/AppleII.cpp +++ b/Machines/Apple/AppleII/AppleII.cpp @@ -61,40 +61,10 @@ constexpr int MockingboardSlot = 4; // Conventional Mockingboard slot. // * ... and hence seven pixels per memory access window clock in high-res mode, 14 in double high-res, etc. constexpr float master_clock = 14318180.0; -class AYPair { - public: - AYPair(Concurrency::AsyncTaskQueue &queue) : - ays_{ - {GI::AY38910::Personality::AY38910, queue}, - {GI::AY38910::Personality::AY38910, queue}, - } {} - - void advance() { - ays_[0].advance(); - ays_[1].advance(); - } - - void set_sample_volume_range(std::int16_t range) { - ays_[0].set_sample_volume_range(range >> 1); - ays_[1].set_sample_volume_range(range >> 1); - } - - bool is_zero_level() const { - return ays_[0].is_zero_level() && ays_[1].is_zero_level(); - } - - Outputs::Speaker::MonoSample level() const { - return ays_[0].level() + ays_[1].level(); - } - - private: - GI::AY38910::AY38910SampleSource ays_[2]; -}; - /// Provides an AY that runs at the CPU rate divided by 4 given an input of the master clock divided by 2, /// allowing for stretched CPU clock cycles. struct StretchedAYPair: - AYPair, + Apple::II::AYPair, public Outputs::Speaker::BufferSource { using AYPair::AYPair; @@ -681,7 +651,7 @@ template if(target.has_mockingboard) { // The Mockingboard has a parasitic relationship with this class due to the way // that audio outputs are implemented in this emulator. - install_card(MockingboardSlot, new Apple::II::Mockingboard()); + install_card(MockingboardSlot, new Apple::II::Mockingboard(ays_)); } rom_ = std::move(roms.find(system)->second); diff --git a/Machines/Apple/AppleII/Mockingboard.hpp b/Machines/Apple/AppleII/Mockingboard.hpp index b56ebecc5..b3a3c1dcf 100644 --- a/Machines/Apple/AppleII/Mockingboard.hpp +++ b/Machines/Apple/AppleII/Mockingboard.hpp @@ -12,15 +12,48 @@ #include "../../../Components/6522/6522.hpp" - namespace Apple::II { +class AYPair { + public: + AYPair(Concurrency::AsyncTaskQueue &queue) : + ays_{ + {GI::AY38910::Personality::AY38910, queue}, + {GI::AY38910::Personality::AY38910, queue}, + } {} + + void advance() { + ays_[0].advance(); + ays_[1].advance(); + } + + void set_sample_volume_range(std::int16_t range) { + ays_[0].set_sample_volume_range(range >> 1); + ays_[1].set_sample_volume_range(range >> 1); + } + + bool is_zero_level() const { + return ays_[0].is_zero_level() && ays_[1].is_zero_level(); + } + + Outputs::Speaker::MonoSample level() const { + return ays_[0].level() + ays_[1].level(); + } + + GI::AY38910::AY38910SampleSource &get(int index) { + return ays_[index]; + } + + private: + GI::AY38910::AY38910SampleSource ays_[2]; +}; + class Mockingboard: public Card { public: - Mockingboard() : - vias_{ {handlers_[0]}, {handlers_[1]} } { + Mockingboard(AYPair &ays) : + vias_{ {handlers_[0]}, {handlers_[1]} }, + handlers_{ {*this, ays.get(0)}, {*this, ays.get(1)}} { set_select_constraints(0); - handlers_[0].card = handlers_[1].card = this; } void perform_bus_operation(Select select, bool is_read, uint16_t address, uint8_t *value) final { @@ -55,13 +88,42 @@ class Mockingboard: public Card { private: struct AYVIA: public MOS::MOS6522::PortHandler { + AYVIA(Mockingboard &card, GI::AY38910::AY38910SampleSource &ay) : + card(card), ay(ay) {} + void set_interrupt_status(bool status) { interrupt = status; - card->did_change_interrupt_flags(); + card.did_change_interrupt_flags(); + } + + void set_port_output(MOS::MOS6522::Port port, uint8_t value, uint8_t) { + if(port) { + using ControlLines = GI::AY38910::ControlLines; + ay.set_control_lines( + ControlLines( + ((value & 1) ? ControlLines::BC1 : 0) | + ((value & 2) ? ControlLines::BDIR : 0) | + ((value & 4) ? ControlLines::BC2 : 0) + ) + ); + + // TODO: all lines disabled sees to map to reset? Possibly? + // Cf. https://gswv.apple2.org.za/a2zine/Docs/Mockingboard_MiniManual.html + } else { + ay.set_data_input(value); + } + } + + uint8_t get_port_input(MOS::MOS6522::Port port) { + if(!port) { + return ay.get_data_output(); + } + return 0xff; } bool interrupt; - Mockingboard *card = nullptr; + Mockingboard &card; + GI::AY38910::AY38910SampleSource &ay; }; MOS::MOS6522::MOS6522 vias_[2];