mirror of
https://github.com/TomHarte/CLK.git
synced 2025-02-16 18:30:32 +00:00
Gives the SN76489 its proper dividers and personalities.
This commit is contained in:
parent
83f73c3f02
commit
7890506b16
@ -12,7 +12,7 @@
|
||||
|
||||
using namespace TI;
|
||||
|
||||
SN76489::SN76489(Concurrency::DeferringAsyncTaskQueue &task_queue) : task_queue_(task_queue) {
|
||||
SN76489::SN76489(Personality personality, Concurrency::DeferringAsyncTaskQueue &task_queue) : task_queue_(task_queue) {
|
||||
// Build a volume table.
|
||||
double multiplier = pow(10.0, -0.1);
|
||||
double volume = 8191.0f;
|
||||
@ -22,6 +22,21 @@ SN76489::SN76489(Concurrency::DeferringAsyncTaskQueue &task_queue) : task_queue_
|
||||
}
|
||||
volumes_[15] = 0;
|
||||
evaluate_output_volume();
|
||||
|
||||
switch(personality) {
|
||||
case Personality::SN76494:
|
||||
master_divider_period_ = 2;
|
||||
shifter_is_16bit_ = false;
|
||||
break;
|
||||
case Personality::SN76489:
|
||||
master_divider_period_ = 16;
|
||||
shifter_is_16bit_ = false;
|
||||
break;
|
||||
case Personality::SMS:
|
||||
master_divider_period_ = 16;
|
||||
shifter_is_16bit_ = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SN76489::set_register(uint8_t value) {
|
||||
@ -72,10 +87,8 @@ void SN76489::evaluate_output_volume() {
|
||||
}
|
||||
|
||||
void SN76489::get_samples(std::size_t number_of_samples, std::int16_t *target) {
|
||||
// For now: assume a divide by eight.
|
||||
|
||||
std::size_t c = 0;
|
||||
while((master_divider_&7) && c < number_of_samples) {
|
||||
while((master_divider_& (master_divider_period_ - 1)) && c < number_of_samples) {
|
||||
target[c] = output_volume_;
|
||||
master_divider_++;
|
||||
c++;
|
||||
@ -124,12 +137,12 @@ void SN76489::get_samples(std::size_t number_of_samples, std::int16_t *target) {
|
||||
|
||||
evaluate_output_volume();
|
||||
|
||||
for(int ic = 0; ic < 8 && c < number_of_samples; ic++) {
|
||||
for(int ic = 0; ic < master_divider_period_ && c < number_of_samples; ++ic) {
|
||||
target[c] = output_volume_;
|
||||
c++;
|
||||
master_divider_++;
|
||||
}
|
||||
}
|
||||
|
||||
master_divider_ &= 7;
|
||||
master_divider_ &= (master_divider_period_ - 1);
|
||||
}
|
||||
|
@ -16,8 +16,14 @@ namespace TI {
|
||||
|
||||
class SN76489: public Outputs::Speaker::SampleSource {
|
||||
public:
|
||||
enum class Personality {
|
||||
SN76489,
|
||||
SN76494,
|
||||
SMS
|
||||
};
|
||||
|
||||
/// Creates a new SN76489.
|
||||
SN76489(Concurrency::DeferringAsyncTaskQueue &task_queue);
|
||||
SN76489(Personality personality, Concurrency::DeferringAsyncTaskQueue &task_queue);
|
||||
|
||||
/// Writes a new value to the SN76489.
|
||||
void set_register(uint8_t value);
|
||||
@ -26,8 +32,9 @@ class SN76489: public Outputs::Speaker::SampleSource {
|
||||
void get_samples(std::size_t number_of_samples, std::int16_t *target);
|
||||
|
||||
private:
|
||||
std::size_t master_divider_ = 0;
|
||||
int16_t output_volume_ = 0;;
|
||||
int master_divider_ = 0;
|
||||
int master_divider_period_ = 16;
|
||||
int16_t output_volume_ = 0;
|
||||
void evaluate_output_volume();
|
||||
int volumes_[16];
|
||||
|
||||
|
@ -107,9 +107,10 @@ class ConcreteMachine:
|
||||
public:
|
||||
ConcreteMachine() :
|
||||
z80_(*this),
|
||||
sn76489_(audio_queue_),
|
||||
sn76489_(TI::SN76489::Personality::SN76489, audio_queue_),
|
||||
speaker_(sn76489_) {
|
||||
speaker_.set_input_rate(3579545.0f / 2.0f); // TODO: try to find out whether this is correct.
|
||||
// speaker_.set_input_rate(3579545.0f);
|
||||
speaker_.set_input_rate(3579545.0f / 2.0f);
|
||||
set_clock_rate(3579545);
|
||||
joysticks_.emplace_back(new Joystick);
|
||||
joysticks_.emplace_back(new Joystick);
|
||||
@ -158,9 +159,7 @@ class ConcreteMachine:
|
||||
bool set_rom_fetcher(const std::function<std::vector<std::unique_ptr<std::vector<uint8_t>>>(const std::string &machine, const std::vector<std::string> &names)> &roms_with_names) override {
|
||||
auto roms = roms_with_names(
|
||||
"ColecoVision",
|
||||
{
|
||||
"coleco.rom"
|
||||
});
|
||||
{ "coleco.rom" });
|
||||
|
||||
if(!roms[0]) return false;
|
||||
|
||||
@ -172,18 +171,6 @@ class ConcreteMachine:
|
||||
|
||||
// MARK: Z80::BusHandler
|
||||
forceinline HalfCycles perform_machine_cycle(const CPU::Z80::PartialMachineCycle &cycle) {
|
||||
time_since_vdp_update_ += cycle.length;
|
||||
time_since_sn76489_update_ += cycle.length;
|
||||
|
||||
if(time_until_interrupt_ > 0) {
|
||||
time_until_interrupt_ -= cycle.length;
|
||||
if(time_until_interrupt_ <= HalfCycles(0)) {
|
||||
z80_.set_non_maskable_interrupt_line(true, time_until_interrupt_);
|
||||
update_video();
|
||||
time_until_interrupt_ = vdp_->get_time_until_interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t address = cycle.address ? *cycle.address : 0x0000;
|
||||
switch(cycle.operation) {
|
||||
case CPU::Z80::PartialMachineCycle::ReadOpcode:
|
||||
@ -256,11 +243,21 @@ class ConcreteMachine:
|
||||
default: break;
|
||||
}
|
||||
|
||||
time_since_vdp_update_ += cycle.length;
|
||||
time_since_sn76489_update_ += cycle.length;
|
||||
|
||||
if(time_until_interrupt_ > 0) {
|
||||
time_until_interrupt_ -= cycle.length;
|
||||
if(time_until_interrupt_ <= HalfCycles(0)) {
|
||||
z80_.set_non_maskable_interrupt_line(true, time_until_interrupt_);
|
||||
}
|
||||
}
|
||||
|
||||
return HalfCycles(0);
|
||||
}
|
||||
|
||||
void flush() {
|
||||
vdp_->run_for(time_since_vdp_update_.flush());
|
||||
update_video();
|
||||
update_audio();
|
||||
audio_queue_.perform();
|
||||
}
|
||||
@ -268,6 +265,7 @@ class ConcreteMachine:
|
||||
private:
|
||||
void update_audio() {
|
||||
speaker_.run_for(audio_queue_, time_since_sn76489_update_.divide_cycles(Cycles(2)));
|
||||
// speaker_.run_for(audio_queue_, time_since_sn76489_update_.cycles());
|
||||
}
|
||||
void update_video() {
|
||||
vdp_->run_for(time_since_vdp_update_.flush());
|
||||
|
Loading…
x
Reference in New Issue
Block a user