1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-01-11 08:30:55 +00:00

Attempt volcntrld.

This commit is contained in:
Thomas Harte 2021-12-06 06:35:08 -05:00
parent f02a241249
commit 066e4421e8
2 changed files with 37 additions and 11 deletions

View File

@ -47,12 +47,22 @@ void Audio::set_volume(int channel, uint16_t volume) {
channels_[channel].volume = (volume & 0x40) ? 64 : (volume & 0x3f);
}
void Audio::set_data(int channel, uint16_t data) {
template <bool is_external> void Audio::set_data(int channel, uint16_t data) {
assert(channel >= 0 && channel < 4);
channels_[channel].wants_data = false;
channels_[channel].data = data;
// TODO: "the [PWM] counter is reset when ... AUDxDAT is written", but
// does that just mean written by the CPU, or does it include DMA?
// My guess is the former. But TODO.
if constexpr (is_external) {
channels_[channel].reset_output_phase();
}
}
template void Audio::set_data<false>(int, uint16_t);
template void Audio::set_data<true>(int, uint16_t);
void Audio::set_channel_enables(uint16_t enables) {
channels_[0].dma_enabled = enables & 1;
channels_[1].dma_enabled = enables & 2;
@ -86,7 +96,7 @@ bool Audio::advance_dma(int channel) {
return false;
}
set_data(channel, ram_[channels_[channel].data_address & ram_mask_]);
set_data<false>(channel, ram_[channels_[channel].data_address & ram_mask_]);
++channels_[channel].data_address;
if(channels_[channel].should_reload_address) {
@ -354,7 +364,9 @@ template <> bool Audio::Channel::transit<
// [AUDxIR]: see return result.
// TODO: volcntrld (?)
// volcntrld
volume_latch = volume;
reset_output_phase();
// pbufld1
data_latch = data;
@ -442,7 +454,9 @@ template <> bool Audio::Channel::transit<
Audio::Channel::State::PlayingHigh>(Channel *moduland) {
begin_state<State::PlayingHigh>(moduland);
// TODO: volcntrld (?)
// volcntrld
volume_latch = volume;
reset_output_phase();
// percntrld
period_counter = period;
@ -572,7 +586,10 @@ template <> bool Audio::Channel::transit<
begin_state<State::PlayingHigh>(moduland);
bool wants_interrupt = false;
// TODO: volcntrld?
// volcntrld
volume_latch = volume;
reset_output_phase(); // Is this correct?
// percntrld
period_counter = period;
@ -631,9 +648,12 @@ template <> bool Audio::Channel::output<Audio::Channel::State::PlayingLow>(Chann
bool Audio::Channel::output(Channel *moduland) {
// Update pulse-width modulation.
output_phase = (output_phase + 1) & 63;
output_enabled |= !output_phase;
output_enabled &= output_phase != volume;
output_phase = output_phase + 1;
if(output_phase == 64) {
reset_output_phase();
} else {
output_enabled &= output_phase != volume_latch;
}
switch(state) {
case State::Disabled: return output<State::Disabled>(moduland);

View File

@ -44,7 +44,7 @@ class Audio: public DMADevice<4> {
void set_volume(int channel, uint16_t);
/// Sets the next two samples of audio to output.
void set_data(int channel, uint16_t);
template <bool is_external = true> void set_data(int channel, uint16_t);
/// Provides a copy of the DMA enable flags, for the purpose of
/// determining which channels are enabled for DMA.
@ -90,7 +90,8 @@ class Audio: public DMADevice<4> {
bool attach_volume = false;
// Output volume, [0, 64].
uint8_t volume;
uint8_t volume = 0;
uint8_t volume_latch = 0;
// Indicates whether DMA is enabled for this channel.
bool dma_enabled = false;
@ -137,8 +138,13 @@ class Audio: public DMADevice<4> {
// Output state.
int8_t output_level = 0;
uint8_t output_phase = 0; // TODO: this should count down, not up.
uint8_t output_phase = 0;
bool output_enabled = false;
void reset_output_phase() {
output_phase = 0;
output_enabled = (volume_latch > 0) && !attach_period && !attach_volume;
}
} channels_[4];
// Transient output state, and its destination.