mirror of
https://github.com/TomHarte/CLK.git
synced 2025-02-16 18:30:32 +00:00
Adds some semblance of an AY.
This commit is contained in:
parent
87a6d22894
commit
3bb0bf9e14
@ -12,8 +12,13 @@
|
|||||||
|
|
||||||
#include "../../Processors/68000/68000.hpp"
|
#include "../../Processors/68000/68000.hpp"
|
||||||
|
|
||||||
|
#include "../../Components/AY38910/AY38910.hpp"
|
||||||
|
|
||||||
#include "Video.hpp"
|
#include "Video.hpp"
|
||||||
#include "../../ClockReceiver/JustInTime.hpp"
|
#include "../../ClockReceiver/JustInTime.hpp"
|
||||||
|
#include "../../ClockReceiver/ForceInline.hpp"
|
||||||
|
|
||||||
|
#include "../../Outputs/Speaker/Implementation/LowpassSpeaker.hpp"
|
||||||
|
|
||||||
#include "../Utility/MemoryPacker.hpp"
|
#include "../Utility/MemoryPacker.hpp"
|
||||||
#include "../Utility/MemoryFuzzer.hpp"
|
#include "../Utility/MemoryFuzzer.hpp"
|
||||||
@ -31,8 +36,11 @@ class ConcreteMachine:
|
|||||||
public CRTMachine::Machine {
|
public CRTMachine::Machine {
|
||||||
public:
|
public:
|
||||||
ConcreteMachine(const Target &target, const ROMMachine::ROMFetcher &rom_fetcher) :
|
ConcreteMachine(const Target &target, const ROMMachine::ROMFetcher &rom_fetcher) :
|
||||||
mc68000_(*this) {
|
mc68000_(*this),
|
||||||
|
ay_(audio_queue_),
|
||||||
|
speaker_(ay_) {
|
||||||
set_clock_rate(CLOCK_RATE);
|
set_clock_rate(CLOCK_RATE);
|
||||||
|
speaker_.set_input_rate(CLOCK_RATE / 4);
|
||||||
|
|
||||||
ram_.resize(512 * 512);
|
ram_.resize(512 * 512);
|
||||||
Memory::Fuzz(ram_);
|
Memory::Fuzz(ram_);
|
||||||
@ -58,13 +66,17 @@ class ConcreteMachine:
|
|||||||
memory_map_[0xff] = BusDevice::IO;
|
memory_map_[0xff] = BusDevice::IO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
~ConcreteMachine() {
|
||||||
|
audio_queue_.flush();
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: CRTMachine::Machine
|
// MARK: CRTMachine::Machine
|
||||||
void set_scan_target(Outputs::Display::ScanTarget *scan_target) final {
|
void set_scan_target(Outputs::Display::ScanTarget *scan_target) final {
|
||||||
video_->set_scan_target(scan_target);
|
video_->set_scan_target(scan_target);
|
||||||
}
|
}
|
||||||
|
|
||||||
Outputs::Speaker::Speaker *get_speaker() final {
|
Outputs::Speaker::Speaker *get_speaker() final {
|
||||||
return nullptr;
|
return &speaker_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void run_for(const Cycles cycles) final {
|
void run_for(const Cycles cycles) final {
|
||||||
@ -75,7 +87,7 @@ class ConcreteMachine:
|
|||||||
using Microcycle = CPU::MC68000::Microcycle;
|
using Microcycle = CPU::MC68000::Microcycle;
|
||||||
HalfCycles perform_bus_operation(const CPU::MC68000::Microcycle &cycle, int is_supervisor) {
|
HalfCycles perform_bus_operation(const CPU::MC68000::Microcycle &cycle, int is_supervisor) {
|
||||||
// Advance time.
|
// Advance time.
|
||||||
video_ += cycle.length;
|
advance_time(cycle.length);
|
||||||
|
|
||||||
// A null cycle leaves nothing else to do.
|
// A null cycle leaves nothing else to do.
|
||||||
if(!(cycle.operation & (Microcycle::NewAddress | Microcycle::SameAddress))) return HalfCycles(0);
|
if(!(cycle.operation & (Microcycle::NewAddress | Microcycle::SameAddress))) return HalfCycles(0);
|
||||||
@ -83,6 +95,7 @@ class ConcreteMachine:
|
|||||||
/* TODO: DTack, bus error, VPA. */
|
/* TODO: DTack, bus error, VPA. */
|
||||||
|
|
||||||
auto address = cycle.word_address();
|
auto address = cycle.word_address();
|
||||||
|
if(cycle.data_select_active()) printf("%c %06x\n", (cycle.operation & Microcycle::Read) ? 'r' : 'w', *cycle.address & 0xffffff);
|
||||||
uint16_t *memory;
|
uint16_t *memory;
|
||||||
switch(memory_map_[address >> 15]) {
|
switch(memory_map_[address >> 15]) {
|
||||||
case BusDevice::MostlyRAM:
|
case BusDevice::MostlyRAM:
|
||||||
@ -118,11 +131,51 @@ class ConcreteMachine:
|
|||||||
return HalfCycles(0);
|
return HalfCycles(0);
|
||||||
|
|
||||||
case BusDevice::Unassigned:
|
case BusDevice::Unassigned:
|
||||||
|
assert(false);
|
||||||
return HalfCycles(0);
|
return HalfCycles(0);
|
||||||
|
|
||||||
case BusDevice::IO:
|
case BusDevice::IO:
|
||||||
assert(false);
|
switch(address) {
|
||||||
break;
|
default:
|
||||||
|
assert(false);
|
||||||
|
|
||||||
|
case 0x7fc000:
|
||||||
|
/* Memory controller configuration:
|
||||||
|
b0, b1: bank 1
|
||||||
|
b2, b3: bank 0
|
||||||
|
|
||||||
|
00 = 128k
|
||||||
|
01 = 512k
|
||||||
|
10 = 2mb
|
||||||
|
11 = reserved
|
||||||
|
*/
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x7fc400: /* PSG: write to select register, read to read register. */
|
||||||
|
case 0x7fc401: /* PSG: write to write register. */
|
||||||
|
if(!cycle.data_select_active()) return HalfCycles(0);
|
||||||
|
|
||||||
|
// TODO: byte accesses to the odd addresses shouldn't obey logic below.
|
||||||
|
advance_time(HalfCycles(2));
|
||||||
|
update_audio();
|
||||||
|
if(cycle.operation & Microcycle::Read) {
|
||||||
|
ay_.set_control_lines(GI::AY38910::ControlLines(GI::AY38910::BC2 | GI::AY38910::BC1));
|
||||||
|
cycle.value->halves.low = ay_.get_data_output();
|
||||||
|
ay_.set_control_lines(GI::AY38910::ControlLines(0));
|
||||||
|
} else {
|
||||||
|
if(address == 0x7fc400) {
|
||||||
|
ay_.set_control_lines(GI::AY38910::BC1);
|
||||||
|
ay_.set_data_input(cycle.value->halves.low);
|
||||||
|
ay_.set_control_lines(GI::AY38910::ControlLines(0));
|
||||||
|
} else {
|
||||||
|
ay_.set_control_lines(GI::AY38910::ControlLines(GI::AY38910::BC2 | GI::AY38910::BDIR));
|
||||||
|
ay_.set_data_input(cycle.value->halves.low);
|
||||||
|
ay_.set_control_lines(GI::AY38910::ControlLines(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return HalfCycles(2);
|
||||||
|
}
|
||||||
|
return HalfCycles(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If control has fallen through to here, the access is either a read from ROM, or a read or write to RAM.
|
// If control has fallen through to here, the access is either a read from ROM, or a read or write to RAM.
|
||||||
@ -150,10 +203,28 @@ class ConcreteMachine:
|
|||||||
return HalfCycles(0);
|
return HalfCycles(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void flush() {
|
||||||
|
audio_queue_.perform();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
forceinline void advance_time(HalfCycles length) {
|
||||||
|
video_ += length;
|
||||||
|
cycles_since_audio_update_ += length;
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_audio() {
|
||||||
|
speaker_.run_for(audio_queue_, cycles_since_audio_update_.divide_cycles(Cycles(4)));
|
||||||
|
}
|
||||||
|
|
||||||
CPU::MC68000::Processor<ConcreteMachine, true> mc68000_;
|
CPU::MC68000::Processor<ConcreteMachine, true> mc68000_;
|
||||||
JustInTimeActor<Video, HalfCycles> video_;
|
JustInTimeActor<Video, HalfCycles> video_;
|
||||||
|
|
||||||
|
Concurrency::DeferringAsyncTaskQueue audio_queue_;
|
||||||
|
GI::AY38910::AY38910 ay_;
|
||||||
|
Outputs::Speaker::LowpassSpeaker<GI::AY38910::AY38910> speaker_;
|
||||||
|
HalfCycles cycles_since_audio_update_;
|
||||||
|
|
||||||
std::vector<uint16_t> ram_;
|
std::vector<uint16_t> ram_;
|
||||||
std::vector<uint16_t> rom_;
|
std::vector<uint16_t> rom_;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user