mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-19 08:31:11 +00:00
Adds a begin_state template.
This commit is contained in:
parent
57789092c1
commit
42d3bdd373
@ -29,18 +29,7 @@ Audio::Audio(Chipset &chipset, uint16_t *ram, size_t word_size, float output_rat
|
|||||||
speaker_.set_input_rate(output_rate);
|
speaker_.set_input_rate(output_rate);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Audio::advance_dma(int channel) {
|
// MARK: - Exposed setters.
|
||||||
if(!channels_[channel].wants_data) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
set_data(channel, ram_[pointer_[size_t(channel) & ram_mask_]]);
|
|
||||||
if(channels_[channel].state != Channel::State::WaitingForDummyDMA) {
|
|
||||||
++pointer_[size_t(channel)];
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Audio::set_length(int channel, uint16_t length) {
|
void Audio::set_length(int channel, uint16_t length) {
|
||||||
assert(channel >= 0 && channel < 4);
|
assert(channel >= 0 && channel < 4);
|
||||||
@ -80,6 +69,21 @@ void Audio::set_interrupt_requests(uint16_t requests) {
|
|||||||
channels_[3].interrupt_pending = requests & uint16_t(InterruptFlag::AudioChannel3);
|
channels_[3].interrupt_pending = requests & uint16_t(InterruptFlag::AudioChannel3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - DMA and mixing.
|
||||||
|
|
||||||
|
bool Audio::advance_dma(int channel) {
|
||||||
|
if(!channels_[channel].wants_data) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
set_data(channel, ram_[pointer_[size_t(channel) & ram_mask_]]);
|
||||||
|
if(channels_[channel].state != Channel::State::WaitingForDummyDMA) {
|
||||||
|
++pointer_[size_t(channel)];
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void Audio::output() {
|
void Audio::output() {
|
||||||
constexpr InterruptFlag interrupts[] = {
|
constexpr InterruptFlag interrupts[] = {
|
||||||
InterruptFlag::AudioChannel0,
|
InterruptFlag::AudioChannel0,
|
||||||
@ -133,6 +137,8 @@ void Audio::output() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - Per-channel logic.
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Big spiel on the state machine:
|
Big spiel on the state machine:
|
||||||
|
|
||||||
@ -300,13 +306,19 @@ void Audio::output() {
|
|||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Non-action fallback transition.
|
// Non-action fallback transition and setter, plus specialised begin_state declarations.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
template <Audio::Channel::State end> void Audio::Channel::begin_state() {
|
||||||
|
state = end;
|
||||||
|
}
|
||||||
|
template <> void Audio::Channel::begin_state<Audio::Channel::State::PlayingHigh>();
|
||||||
|
template <> void Audio::Channel::begin_state<Audio::Channel::State::PlayingLow>();
|
||||||
|
|
||||||
template <
|
template <
|
||||||
Audio::Channel::State begin,
|
Audio::Channel::State begin,
|
||||||
Audio::Channel::State end> bool Audio::Channel::transit() {
|
Audio::Channel::State end> bool Audio::Channel::transit() {
|
||||||
state = end;
|
begin_state<end>();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -317,7 +329,7 @@ template <
|
|||||||
template <> bool Audio::Channel::transit<
|
template <> bool Audio::Channel::transit<
|
||||||
Audio::Channel::State::Disabled,
|
Audio::Channel::State::Disabled,
|
||||||
Audio::Channel::State::WaitingForDummyDMA>() {
|
Audio::Channel::State::WaitingForDummyDMA>() {
|
||||||
state = State::WaitingForDummyDMA;
|
begin_state<State::WaitingForDummyDMA>();
|
||||||
|
|
||||||
period_counter = period; // i.e. percntrld
|
period_counter = period; // i.e. percntrld
|
||||||
length_counter = length; // i.e. lencntrld
|
length_counter = length; // i.e. lencntrld
|
||||||
@ -328,7 +340,7 @@ template <> bool Audio::Channel::transit<
|
|||||||
template <> bool Audio::Channel::transit<
|
template <> bool Audio::Channel::transit<
|
||||||
Audio::Channel::State::Disabled,
|
Audio::Channel::State::Disabled,
|
||||||
Audio::Channel::State::PlayingHigh>() {
|
Audio::Channel::State::PlayingHigh>() {
|
||||||
state = State::PlayingHigh;
|
begin_state<State::PlayingHigh>();
|
||||||
|
|
||||||
data_latch = data; // i.e. pbufld1
|
data_latch = data; // i.e. pbufld1
|
||||||
wants_data = true;
|
wants_data = true;
|
||||||
@ -359,7 +371,7 @@ template <> bool Audio::Channel::output<Audio::Channel::State::Disabled>() {
|
|||||||
template <> bool Audio::Channel::transit<
|
template <> bool Audio::Channel::transit<
|
||||||
Audio::Channel::State::WaitingForDummyDMA,
|
Audio::Channel::State::WaitingForDummyDMA,
|
||||||
Audio::Channel::State::WaitingForDMA>() {
|
Audio::Channel::State::WaitingForDMA>() {
|
||||||
state = State::WaitingForDMA;
|
begin_state<State::WaitingForDMA>();
|
||||||
|
|
||||||
wants_data = true;
|
wants_data = true;
|
||||||
if(length == 1) {
|
if(length == 1) {
|
||||||
@ -389,7 +401,7 @@ template <> bool Audio::Channel::output<Audio::Channel::State::WaitingForDummyDM
|
|||||||
template <> bool Audio::Channel::transit<
|
template <> bool Audio::Channel::transit<
|
||||||
Audio::Channel::State::WaitingForDMA,
|
Audio::Channel::State::WaitingForDMA,
|
||||||
Audio::Channel::State::PlayingHigh>() {
|
Audio::Channel::State::PlayingHigh>() {
|
||||||
state = State::PlayingHigh;
|
begin_state<State::PlayingHigh>();
|
||||||
|
|
||||||
data_latch = data;
|
data_latch = data;
|
||||||
wants_data = true;
|
wants_data = true;
|
||||||
@ -417,7 +429,7 @@ template <> bool Audio::Channel::output<Audio::Channel::State::WaitingForDMA>()
|
|||||||
template <> bool Audio::Channel::transit<
|
template <> bool Audio::Channel::transit<
|
||||||
Audio::Channel::State::PlayingHigh,
|
Audio::Channel::State::PlayingHigh,
|
||||||
Audio::Channel::State::PlayingLow>() {
|
Audio::Channel::State::PlayingLow>() {
|
||||||
state = State::PlayingLow;
|
begin_state<State::PlayingLow>();
|
||||||
|
|
||||||
// TODO: if AUDxAP, then pubfid2
|
// TODO: if AUDxAP, then pubfid2
|
||||||
// TODO: if AUDxAP and AUDxON, then AUDxDR
|
// TODO: if AUDxAP and AUDxON, then AUDxDR
|
||||||
@ -441,6 +453,13 @@ template <> bool Audio::Channel::transit<
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <> void Audio::Channel::begin_state<Audio::Channel::State::PlayingHigh>() {
|
||||||
|
state = Audio::Channel::State::PlayingHigh;
|
||||||
|
|
||||||
|
// Output high byte.
|
||||||
|
output_level = int8_t(data_latch >> 8);
|
||||||
|
}
|
||||||
|
|
||||||
template <> bool Audio::Channel::output<Audio::Channel::State::PlayingHigh>() {
|
template <> bool Audio::Channel::output<Audio::Channel::State::PlayingHigh>() {
|
||||||
-- period_counter;
|
-- period_counter;
|
||||||
|
|
||||||
@ -450,9 +469,6 @@ template <> bool Audio::Channel::output<Audio::Channel::State::PlayingHigh>() {
|
|||||||
return transit<State::PlayingHigh, State::PlayingLow>();
|
return transit<State::PlayingHigh, State::PlayingLow>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Output high byte.
|
|
||||||
output_level = int8_t(data_latch >> 8);
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -463,7 +479,7 @@ template <> bool Audio::Channel::output<Audio::Channel::State::PlayingHigh>() {
|
|||||||
template <> bool Audio::Channel::transit<
|
template <> bool Audio::Channel::transit<
|
||||||
Audio::Channel::State::PlayingLow,
|
Audio::Channel::State::PlayingLow,
|
||||||
Audio::Channel::State::PlayingHigh>() {
|
Audio::Channel::State::PlayingHigh>() {
|
||||||
state = State::PlayingHigh;
|
begin_state<State::PlayingHigh>();
|
||||||
|
|
||||||
// TODO: include napnav in tests
|
// TODO: include napnav in tests
|
||||||
|
|
||||||
@ -484,6 +500,13 @@ template <> bool Audio::Channel::transit<
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <> void Audio::Channel::begin_state<Audio::Channel::State::PlayingLow>() {
|
||||||
|
state = Audio::Channel::State::PlayingLow;
|
||||||
|
|
||||||
|
// Output low byte.
|
||||||
|
output_level = int8_t(data_latch & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
template <> bool Audio::Channel::output<Audio::Channel::State::PlayingLow>() {
|
template <> bool Audio::Channel::output<Audio::Channel::State::PlayingLow>() {
|
||||||
-- period_counter;
|
-- period_counter;
|
||||||
|
|
||||||
@ -497,8 +520,6 @@ template <> bool Audio::Channel::output<Audio::Channel::State::PlayingLow>() {
|
|||||||
return transit<State::PlayingLow, State::PlayingHigh>();
|
return transit<State::PlayingLow, State::PlayingHigh>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Output low byte.
|
|
||||||
output_level = int8_t(data_latch & 0xff);
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -100,10 +100,23 @@ class Audio: public DMADevice<4> {
|
|||||||
PlayingLow, // 011
|
PlayingLow, // 011
|
||||||
} state = State::Disabled;
|
} state = State::Disabled;
|
||||||
|
|
||||||
|
/// Dispatches to the appropriate templatised output for the current state.
|
||||||
|
/// @returns @c true if an interrupt should be posted; @c false otherwise.
|
||||||
bool output();
|
bool output();
|
||||||
|
|
||||||
|
/// Applies dynamic logic for @c state, mostly testing for potential state transitions.
|
||||||
|
/// @returns @c true if an interrupt should be posted; @c false otherwise.
|
||||||
template <State state> bool output();
|
template <State state> bool output();
|
||||||
|
|
||||||
|
/// Transitions from @c begin to @c end, calling the appropriate @c begin_state
|
||||||
|
/// and taking any steps specific to that particular transition.
|
||||||
|
/// @returns @c true if an interrupt should be posted; @c false otherwise.
|
||||||
template <State begin, State end> bool transit();
|
template <State begin, State end> bool transit();
|
||||||
|
|
||||||
|
/// Begins @c state, performing all fixed logic that would otherwise have to be
|
||||||
|
/// repeated endlessly in the relevant @c output.
|
||||||
|
template <State state> void begin_state();
|
||||||
|
|
||||||
// Output state.
|
// Output state.
|
||||||
int8_t output_level = 0;
|
int8_t output_level = 0;
|
||||||
uint8_t output_phase = 0; // TODO: this should count down, not up.
|
uint8_t output_phase = 0; // TODO: this should count down, not up.
|
||||||
|
Loading…
Reference in New Issue
Block a user