diff --git a/Machines/Amiga/Chipset.cpp b/Machines/Amiga/Chipset.cpp index 2372f7264..6592469b1 100644 --- a/Machines/Amiga/Chipset.cpp +++ b/Machines/Amiga/Chipset.cpp @@ -21,6 +21,8 @@ using namespace Amiga; +// TODO: I don't think the nonsense below, which was intended to allow a typed enum but also +// clean combination, really works. Rethink. namespace { template struct Mask { @@ -34,6 +36,18 @@ template struct Mask { template struct InterruptMask: Mask {}; template struct DMAMask: Mask {}; +constexpr uint16_t AudioFlags[] = { + DMAMask::value, + DMAMask::value, + DMAMask::value, + DMAMask::value, +}; +constexpr auto BlitterFlag = DMAMask::value; +constexpr auto BitplaneFlag = DMAMask::value; +constexpr auto CopperFlag = DMAMask::value; +constexpr auto DiskFlag = DMAMask::value; +constexpr auto SpritesFlag = DMAMask::value; + } #define DMA_CONSTRUCT *this, reinterpret_cast(map.chip_ram.data()), map.chip_ram.size() >> 1 @@ -488,17 +502,6 @@ void Chipset::flush_output() { /// @returns @c true if this was a CPU slot; @c false otherwise. template bool Chipset::perform_cycle() { - constexpr uint16_t AudioFlags[] = { - DMAMask::value, - DMAMask::value, - DMAMask::value, - DMAMask::value, - }; - constexpr auto BlitterFlag = DMAMask::value; - constexpr auto BitplaneFlag = DMAMask::value; - constexpr auto CopperFlag = DMAMask::value; - constexpr auto DiskFlag = DMAMask::value; - constexpr auto SpritesFlag = DMAMask::value; // Update state as to whether bitplane fetching should happen now. // @@ -611,7 +614,7 @@ template bool Chipset::perform_cycle() { constexpr auto sprite_id = (cycle - 0x16) >> 2; static_assert(sprite_id >= 0 && sprite_id < std::tuple_size::value); - if(sprites_[sprite_id].advance_dma((~cycle&2) >> 1)) { + if(sprites_[sprite_id].advance_dma((~cycle&2) >> 1, y_)) { return false; } } @@ -741,10 +744,6 @@ template Chipset::Changes Chipset::run(HalfCycles length) { is_long_field_ ^= interlace_; } - for(auto &sprite: sprites_) { - sprite.advance_line(y_, y_ == vertical_blank_height_); - } - fetch_vertical_ |= y_ == display_window_start_[1]; fetch_vertical_ &= y_ != display_window_stop_[1]; } diff --git a/Machines/Amiga/Sprites.cpp b/Machines/Amiga/Sprites.cpp index b17e3a635..49f53aa8b 100644 --- a/Machines/Amiga/Sprites.cpp +++ b/Machines/Amiga/Sprites.cpp @@ -45,7 +45,6 @@ void Sprite::set_stop_and_control(uint16_t value) { // Disarm the sprite, but expect graphics next from DMA. visible = false; - dma_state_ = DMAState::FetchImage; } void Sprite::set_image_data(int slot, uint16_t value) { @@ -53,36 +52,32 @@ void Sprite::set_image_data(int slot, uint16_t value) { visible |= slot == 0; } -void Sprite::advance_line(int y, bool is_end_of_blank) { - if(dma_state_ == DMAState::FetchImage && y == v_start_) { - visible = true; - } - if(is_end_of_blank || y == v_stop_) { - dma_state_ = DMAState::FetchControl; - } -} - -bool Sprite::advance_dma(int offset) { +bool Sprite::advance_dma(int offset, int y) { assert(offset == 0 || offset == 1); // Determine which word would be fetched, if DMA occurs. // A bit of a cheat. const uint16_t next_word = ram_[pointer_[0] & ram_mask_]; - // Put the fetched word somewhere appropriate and update the DMA state. - switch(dma_state_) { - case DMAState::FetchControl: - if(offset) { - set_stop_and_control(next_word); - } else { - set_start_position(next_word); - } - break; + // "When the vertical position of the beam counter is equal to the VSTOP + // value in the sprite control words, the next two words fetched from the + // sprite data structure are written into the sprite control registers + // instead of being sent to the color registers" + if(y == v_stop_) { + if(offset) { + // Second control word: stop position (mostly). + set_stop_and_control(next_word); + } else { + // First control word: start position. + set_start_position(next_word); + } + } else { + visible |= y == v_start_; + if(!visible) return false; - case DMAState::FetchImage: - if(!visible) return false; - set_image_data(1 - offset, next_word); - break; + // Write colour word 1, then colour word 0; 0 is the word that 'arms' + // the sprite (i.e. makes it visible). + set_image_data(1 - offset, next_word); } // Acknowledge the fetch. diff --git a/Machines/Amiga/Sprites.hpp b/Machines/Amiga/Sprites.hpp index 947b72633..f15f97ad8 100644 --- a/Machines/Amiga/Sprites.hpp +++ b/Machines/Amiga/Sprites.hpp @@ -23,8 +23,7 @@ class Sprite: public DMADevice<1> { void set_stop_and_control(uint16_t value); void set_image_data(int slot, uint16_t value); - void advance_line(int y, bool is_end_of_blank); - bool advance_dma(int offset); + bool advance_dma(int offset, int y); uint16_t data[2]{}; bool attached = false; @@ -33,11 +32,6 @@ class Sprite: public DMADevice<1> { private: uint16_t v_start_ = 0, v_stop_ = 0; - - enum class DMAState { - FetchControl, - FetchImage - } dma_state_ = DMAState::FetchControl; }; class TwoSpriteShifter {