1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-02-16 18:30:32 +00:00

Provide a loop count directly from the sequencer.

This avoids the caller having to take a guess at iterations.
This commit is contained in:
Thomas Harte 2022-07-29 12:14:59 -04:00
parent d85d70a133
commit 1ac0a4e924
2 changed files with 51 additions and 27 deletions

View File

@ -49,40 +49,38 @@ class BlitterSequencer {
/// Sets the current control value, which indicates which /// Sets the current control value, which indicates which
/// channels are enabled. /// channels are enabled.
void set_control(int control) { void set_control(int control) {
control_ = control; control_ = control & 0xf;
index_ = 0; index_ = 0; // TODO: this probably isn't accurate; case caught is a change
// of control values during a blit.
} }
/// Indicates that blitting should conclude after this step, i.e. /// Indicates that blitting should conclude after this step, i.e.
/// whatever is being fetched now is part of the final set of input data; /// whatever is being fetched now is part of the final set of input data;
/// this is safe to call following a fetch request on any channel. /// this is safe to call following a fetch request on any channel.
void complete() { void complete() {
phase_ = next_phase_ =
(control_ == 0x9 || control_ == 0xb || control_ == 0xd) ? (control_ == 0x9 || control_ == 0xb || control_ == 0xd) ?
Phase::PauseAndComplete : Phase::Complete; Phase::PauseAndComplete : Phase::Complete;
} }
/// Begins a blit operation. /// Begins a blit operation.
void begin() { void begin() {
phase_ = Phase::Ongoing; phase_ = next_phase_ = Phase::Ongoing;
index_ = 0; index_ = loop_ = 0;
} }
/// Provides the next channel to fetch from, or that a write is required. /// Provides the next channel to fetch from, or that a write is required,
Channel next() { /// along with a count of complete channel iterations so far completed.
std::pair<Channel, int> next() {
switch(phase_) { switch(phase_) {
default: break; default: break;
case Phase::Complete: case Phase::Complete:
if(!index_) return Channel::Write; return std::make_pair(Channel::Write, loop_);
break;
case Phase::PauseAndComplete: case Phase::PauseAndComplete:
if(!index_) { phase_ = Phase::Complete;
phase_ = Phase::Complete; return std::make_pair(Channel::None, loop_);
return Channel::None;
}
break;
} }
Channel next = Channel::None; Channel next = Channel::None;
@ -107,7 +105,7 @@ class BlitterSequencer {
case 15: next = next_channel(patternF); break; case 15: next = next_channel(patternF); break;
} }
return next; return std::make_pair(next, loop_);
} }
private: private:
@ -127,16 +125,40 @@ class BlitterSequencer {
static constexpr std::array<Channel, 3> patternE = { Channel::A, Channel::B, Channel::C }; static constexpr std::array<Channel, 3> patternE = { Channel::A, Channel::B, Channel::C };
static constexpr std::array<Channel, 4> patternF = { Channel::A, Channel::B, Channel::C, Channel::Write }; static constexpr std::array<Channel, 4> patternF = { Channel::A, Channel::B, Channel::C, Channel::Write };
template <typename ArrayT> Channel next_channel(const ArrayT &list) { template <typename ArrayT> Channel next_channel(const ArrayT &list) {
loop_ += index_ / list.size();
index_ %= list.size();
const Channel result = list[index_]; const Channel result = list[index_];
index_ = (index_ + 1) % list.size(); ++index_;
if(index_ == list.size()) {
phase_ = next_phase_;
}
return result; return result;
} }
// Current control flags, i.e. which channels are enabled.
int control_ = 0; int control_ = 0;
// Index into the pattern table for this blit.
size_t index_ = 0; size_t index_ = 0;
// Number of times the entire pattern table has been completed.
int loop_ = 0;
enum class Phase { enum class Phase {
Ongoing, PauseAndComplete, Complete /// Return the next thing in the pattern table and advance.
} phase_ = Phase::Complete; /// If looping from the end of the pattern table to the start,
/// set phase_ to next_phase_.
Ongoing,
/// Return a Channel::None and advancce to phase_ = Phase::Complete.
PauseAndComplete,
/// Return Channel::Write indefinitely.
Complete
};
// Current sequencer pahse.
Phase phase_ = Phase::Complete;
// Phase to assume at the end of this iteration of the sequence table.
Phase next_phase_ = Phase::Complete;
}; };
class Blitter: public DMADevice<4, 4> { class Blitter: public DMADevice<4, 4> {

View File

@ -294,13 +294,12 @@ using WriteVector = std::vector<std::pair<uint32_t, uint16_t>>;
/* F */ @"A0 B0 C0 - A1 B1 C1 D0 A2 B2 C2 D1 D2", /* F */ @"A0 B0 C0 - A1 B1 C1 D0 A2 B2 C2 D1 D2",
]; ];
for(int c = 0; c < 16; c++) { for(int c = 0; c < 16; c++) {
Amiga::BlitterSequencer sequencer; Amiga::BlitterSequencer sequencer;
sequencer.set_control(c); sequencer.set_control(c);
sequencer.begin(); sequencer.begin();
int counts[4]{}; int writes = 0;
const int writes = 2;
NSUInteger length = [[patterns[c] componentsSeparatedByString:@" "] count]; NSUInteger length = [[patterns[c] componentsSeparatedByString:@" "] count];
bool is_first_write = c > 1; // control = 1 is D only, in which case don't pipeline. bool is_first_write = c > 1; // control = 1 is D only, in which case don't pipeline.
NSMutableArray<NSString *> *const components = [[NSMutableArray alloc] init]; NSMutableArray<NSString *> *const components = [[NSMutableArray alloc] init];
@ -309,24 +308,27 @@ using WriteVector = std::vector<std::pair<uint32_t, uint16_t>>;
const auto next = sequencer.next(); const auto next = sequencer.next();
using Channel = Amiga::BlitterSequencer::Channel; using Channel = Amiga::BlitterSequencer::Channel;
switch(next) { switch(next.first) {
case Channel::None: [components addObject:@"-"]; break; case Channel::None: [components addObject:@"-"]; break;
case Channel::A: [components addObject:[NSString stringWithFormat:@"A%d", counts[0]++]]; break; case Channel::A: [components addObject:[NSString stringWithFormat:@"A%d", next.second]]; break;
case Channel::B: [components addObject:[NSString stringWithFormat:@"B%d", counts[1]++]]; break; case Channel::B: [components addObject:[NSString stringWithFormat:@"B%d", next.second]]; break;
case Channel::C: [components addObject:[NSString stringWithFormat:@"C%d", counts[2]++]]; break; case Channel::C: [components addObject:[NSString stringWithFormat:@"C%d", next.second]]; break;
case Channel::Write: case Channel::Write:
if(is_first_write) { if(is_first_write) {
is_first_write = false; is_first_write = false;
[components addObject:@"-"]; [components addObject:@"-"];
} else { } else {
[components addObject:[NSString stringWithFormat:@"D%d", counts[3]++]]; [components addObject:[NSString stringWithFormat:@"D%d", writes++]];
if(counts[3] == writes) sequencer.complete();
} }
break; break;
default: break; default: break;
} }
if(next.second == 2) {
sequencer.complete();
}
} }
NSString *pattern = [components componentsJoinedByString:@" "]; NSString *pattern = [components componentsJoinedByString:@" "];