1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-12-27 16:31:31 +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) {
// There are only 16 registers.
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) {
int selected_register = selected_register_;
const int selected_register = selected_register_;
task_queue_.defer([=] () {
// Perform any register-specific mutation to output generation.
uint8_t masked_value = value;
switch(selected_register) {
case 0: case 2: case 4:
@ -208,12 +212,34 @@ void AY38910::set_register_value(uint8_t value) {
envelope_position_ = 0;
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;
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() {
@ -238,6 +264,8 @@ uint8_t AY38910::get_port_output(bool port_b) {
void AY38910::set_port_handler(PortHandler *handler) {
port_handler_ = handler;
set_port_output(true);
set_port_output(false);
}
void AY38910::set_data_input(uint8_t r) {
@ -245,6 +273,16 @@ void AY38910::set_data_input(uint8_t r) {
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() {
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

View File

@ -83,7 +83,7 @@ class AY38910: public ::Outputs::Speaker::SampleSource {
*/
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);
bool is_zero_level();
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_;
int16_t output_volume_;
inline void evaluate_output_volume();
void evaluate_output_volume();
inline void update_bus();
void update_bus();
PortHandler *port_handler_ = nullptr;
void set_port_output(bool port_b);
};
}