1
0
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:
Thomas Harte 2018-02-28 22:36:03 -05:00
parent 83f73c3f02
commit 7890506b16
3 changed files with 45 additions and 27 deletions

View File

@ -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);
}

View File

@ -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];

View File

@ -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());