diff --git a/Machines/Amiga/Blitter.cpp b/Machines/Amiga/Blitter.cpp index a179d0527..775f9e9d4 100644 --- a/Machines/Amiga/Blitter.cpp +++ b/Machines/Amiga/Blitter.cpp @@ -191,6 +191,34 @@ uint16_t Blitter::get_status() { return result; } +// Due to the pipeline, writes are delayed by one slot — the first write will occur +// after the second set of inputs has been fetched, and every sequence with writes enabled +// will end with an additional write. +// +// USE Code +// in Active +// BLTCON0 Channels Cycle Sequence +// --------- -------- -------------- +// F A B C D A0 B0 C0 - A1 B1 C1 D0 A2 B2 C2 D1 D2 +// E A B C A0 B0 C0 A1 B1 C1 A2 B2 C2 +// D A B D A0 B0 - A1 B1 D0 A2 B2 D1 - D2 +// C A B A0 B0 - A1 B1 - A2 B2 +// B A C D A0 C0 - A1 C1 D0 A2 C2 D1 - D2 +// A A C A0 C0 A1 C1 A2 C2 +// 9 A D A0 - A1 D0 A2 D1 - D2 +// 8 A A0 - A1 - A2 +// 7 B C D B0 C0 - - B1 C1 D0 - B2 C2 D1 - D2 +// 6 B C B0 C0 - B1 C1 - B2 C2 +// 5 B D B0 - - B1 D0 - B2 D1 - D2 +// 4 B B0 - - B1 - - B2 +// 3 C D C0 - - C1 D0 - C2 D1 - D2 +// 2 C C0 - C1 - C2 +// 1 D D0 - D1 - D2 +// 0 none - - - - +// +// +// Table 6-2: Typical Blitter Cycle Sequence + bool Blitter::advance_dma() { if(!height_) return false; diff --git a/Machines/Amiga/Blitter.hpp b/Machines/Amiga/Blitter.hpp index 7ca0b1da3..a2ce3a42c 100644 --- a/Machines/Amiga/Blitter.hpp +++ b/Machines/Amiga/Blitter.hpp @@ -17,6 +17,79 @@ namespace Amiga { +class BlitterSequencer { + public: + enum class Channel { + Write, C, B, A, None + }; + + void set_control(int control) { + control_ = control; + } + + void complete() { + complete_ = true; + } + + Channel next() { + if(complete_ && !index_) { + // TODO: this isn't quite right; some patterns leave a gap before + // the final write, some don't. Figure this out. + return Channel::Write; + } + + Channel next = Channel::None; + + switch(control_) { + default: break; + + case 1: next = next_channel(pattern1); break; + case 2: next = next_channel(pattern2); break; + case 3: next = next_channel(pattern3); break; + case 4: next = next_channel(pattern4); break; + case 5: next = next_channel(pattern5); break; + case 6: next = next_channel(pattern6); break; + case 7: next = next_channel(pattern7); break; + case 8: next = next_channel(pattern8); break; + case 9: next = next_channel(pattern9); break; + case 10: next = next_channel(patternA); break; + case 11: next = next_channel(patternB); break; + case 12: next = next_channel(patternC); break; + case 13: next = next_channel(patternD); break; + case 14: next = next_channel(patternE); break; + case 15: next = next_channel(patternF); break; + } + + return next; + } + + private: + static constexpr std::array pattern1 = { Channel::Write, Channel::None }; + static constexpr std::array pattern2 = { Channel::C, Channel::None }; + static constexpr std::array pattern3 = { Channel::C, Channel::Write, Channel::None }; + static constexpr std::array pattern4 = { Channel::B, Channel::None, Channel::None }; + static constexpr std::array pattern5 = { Channel::B, Channel::Write, Channel::None }; + static constexpr std::array pattern6 = { Channel::B, Channel::C, Channel::None }; + static constexpr std::array pattern7 = { Channel::B, Channel::C, Channel::Write, Channel::None }; + static constexpr std::array pattern8 = { Channel::A, Channel::None }; + static constexpr std::array pattern9 = { Channel::A, Channel::Write }; + static constexpr std::array patternA = { Channel::A, Channel::C }; + static constexpr std::array patternB = { Channel::A, Channel::C, Channel::Write }; + static constexpr std::array patternC = { Channel::A, Channel::B, Channel::None }; + static constexpr std::array patternD = { Channel::A, Channel::B, Channel::Write }; + static constexpr std::array patternE = { Channel::A, Channel::B, Channel::C }; + static constexpr std::array patternF = { Channel::A, Channel::B, Channel::C, Channel::Write }; + template Channel next_channel(const ArrayT &list) { + const Channel result = list[index_]; + index_ = (index_ + 1) % list.size(); + return result; + } + + int control_ = 0; + int index_ = 0; + bool complete_ = false; +}; + class Blitter: public DMADevice<4, 4> { public: using DMADevice::DMADevice;