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:
commit
cfebf1dc4a
@ -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
|
||||||
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user