1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-12-02 02:49:28 +00:00

Merge branch 'master' into DisplayMetrics

This commit is contained in:
Thomas Harte 2019-03-05 20:21:44 -05:00
commit cfebf1dc4a
2 changed files with 46 additions and 7 deletions

View File

@ -173,11 +173,15 @@ void AY38910::select_register(uint8_t r) {
} }
void AY38910::set_register_value(uint8_t value) { void AY38910::set_register_value(uint8_t value) {
// There are only 16 registers.
if(selected_register_ > 15) return; if(selected_register_ > 15) return;
registers_[selected_register_] = value;
// If this is a register that affects audio output, enqueue a mutation onto the
// audio generation thread.
if(selected_register_ < 14) { if(selected_register_ < 14) {
int selected_register = selected_register_; const int selected_register = selected_register_;
task_queue_.defer([=] () { task_queue_.defer([=] () {
// Perform any register-specific mutation to output generation.
uint8_t masked_value = value; uint8_t masked_value = value;
switch(selected_register) { switch(selected_register) {
case 0: case 2: case 4: case 0: case 2: case 4:
@ -208,12 +212,34 @@ void AY38910::set_register_value(uint8_t value) {
envelope_position_ = 0; envelope_position_ = 0;
break; break;
} }
// Store a copy of the current register within the storage used by the audio generation
// thread, and apply any changes to output volume.
output_registers_[selected_register] = masked_value; output_registers_[selected_register] = masked_value;
evaluate_output_volume(); evaluate_output_volume();
}); });
} else {
if(port_handler_) port_handler_->set_port_output(selected_register_ == 15, value);
} }
// Decide which outputs are going to need updating (if any).
bool update_port_a = false;
bool update_port_b = true;
if(port_handler_) {
if(selected_register_ == 7) {
const uint8_t io_change = registers_[7] ^ value;
update_port_b = !!(io_change&0x80);
update_port_a = !!(io_change&0x40);
} else {
update_port_b = selected_register_ == 15;
update_port_a = selected_register_ != 15;
}
}
// Keep a copy of the new value that is usable from the emulation thread.
registers_[selected_register_] = value;
// Update ports as required.
if(update_port_b) set_port_output(true);
if(update_port_a) set_port_output(false);
} }
uint8_t AY38910::get_register_value() { uint8_t AY38910::get_register_value() {
@ -238,6 +264,8 @@ uint8_t AY38910::get_port_output(bool port_b) {
void AY38910::set_port_handler(PortHandler *handler) { void AY38910::set_port_handler(PortHandler *handler) {
port_handler_ = handler; port_handler_ = handler;
set_port_output(true);
set_port_output(false);
} }
void AY38910::set_data_input(uint8_t r) { void AY38910::set_data_input(uint8_t r) {
@ -245,6 +273,16 @@ void AY38910::set_data_input(uint8_t r) {
update_bus(); update_bus();
} }
void AY38910::set_port_output(bool port_b) {
// Per the data sheet: "each [IO] pin is provided with an on-chip pull-up resistor,
// so that when in the "input" mode, all pins will read normally high". Therefore,
// report programmer selection of input mode as creating an output of 0xff.
if(port_handler_) {
const bool is_output = !!(registers_[7] & (port_b ? 0x80 : 0x40));
port_handler_->set_port_output(port_b, is_output ? registers_[port_b ? 15 : 14] : 0xff);
}
}
uint8_t AY38910::get_data_output() { uint8_t AY38910::get_data_output() {
if(control_state_ == Read && selected_register_ >= 14 && selected_register_ < 16) { if(control_state_ == Read && selected_register_ >= 14 && selected_register_ < 16) {
// Per http://cpctech.cpc-live.com/docs/psgnotes.htm if a port is defined as output then the // Per http://cpctech.cpc-live.com/docs/psgnotes.htm if a port is defined as output then the

View File

@ -83,7 +83,7 @@ class AY38910: public ::Outputs::Speaker::SampleSource {
*/ */
void set_port_handler(PortHandler *); void set_port_handler(PortHandler *);
// to satisfy ::Outputs::Speaker (included via ::Outputs::Filter; not for public consumption // to satisfy ::Outputs::Speaker (included via ::Outputs::Filter.
void get_samples(std::size_t number_of_samples, int16_t *target); void get_samples(std::size_t number_of_samples, int16_t *target);
bool is_zero_level(); bool is_zero_level();
void set_sample_volume_range(std::int16_t range); void set_sample_volume_range(std::int16_t range);
@ -128,10 +128,11 @@ class AY38910: public ::Outputs::Speaker::SampleSource {
uint8_t data_input_, data_output_; uint8_t data_input_, data_output_;
int16_t output_volume_; int16_t output_volume_;
inline void evaluate_output_volume(); void evaluate_output_volume();
inline void update_bus(); void update_bus();
PortHandler *port_handler_ = nullptr; PortHandler *port_handler_ = nullptr;
void set_port_output(bool port_b);
}; };
} }