1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-04 18:29:40 +00:00

Eliminate DMAState; it sounds like VSTOP solves this problem.

This commit is contained in:
Thomas Harte 2022-07-19 16:11:29 -04:00
parent 830704b4a9
commit cb42ee3ade
3 changed files with 35 additions and 47 deletions

View File

@ -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 <typename EnumT, EnumT... T> struct Mask {
@ -34,6 +36,18 @@ template <typename EnumT, EnumT F, EnumT... T> struct Mask<EnumT, F, T...> {
template <InterruptFlag... Flags> struct InterruptMask: Mask<InterruptFlag, Flags...> {};
template <DMAFlag... Flags> struct DMAMask: Mask<DMAFlag, Flags...> {};
constexpr uint16_t AudioFlags[] = {
DMAMask<DMAFlag::AudioChannel0, DMAFlag::AllBelow>::value,
DMAMask<DMAFlag::AudioChannel1, DMAFlag::AllBelow>::value,
DMAMask<DMAFlag::AudioChannel2, DMAFlag::AllBelow>::value,
DMAMask<DMAFlag::AudioChannel3, DMAFlag::AllBelow>::value,
};
constexpr auto BlitterFlag = DMAMask<DMAFlag::Blitter, DMAFlag::AllBelow>::value;
constexpr auto BitplaneFlag = DMAMask<DMAFlag::Bitplane, DMAFlag::AllBelow>::value;
constexpr auto CopperFlag = DMAMask<DMAFlag::Copper, DMAFlag::AllBelow>::value;
constexpr auto DiskFlag = DMAMask<DMAFlag::Disk, DMAFlag::AllBelow>::value;
constexpr auto SpritesFlag = DMAMask<DMAFlag::Sprites, DMAFlag::AllBelow>::value;
}
#define DMA_CONSTRUCT *this, reinterpret_cast<uint16_t *>(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 <int cycle, bool stop_if_cpu> bool Chipset::perform_cycle() {
constexpr uint16_t AudioFlags[] = {
DMAMask<DMAFlag::AudioChannel0, DMAFlag::AllBelow>::value,
DMAMask<DMAFlag::AudioChannel1, DMAFlag::AllBelow>::value,
DMAMask<DMAFlag::AudioChannel2, DMAFlag::AllBelow>::value,
DMAMask<DMAFlag::AudioChannel3, DMAFlag::AllBelow>::value,
};
constexpr auto BlitterFlag = DMAMask<DMAFlag::Blitter, DMAFlag::AllBelow>::value;
constexpr auto BitplaneFlag = DMAMask<DMAFlag::Bitplane, DMAFlag::AllBelow>::value;
constexpr auto CopperFlag = DMAMask<DMAFlag::Copper, DMAFlag::AllBelow>::value;
constexpr auto DiskFlag = DMAMask<DMAFlag::Disk, DMAFlag::AllBelow>::value;
constexpr auto SpritesFlag = DMAMask<DMAFlag::Sprites, DMAFlag::AllBelow>::value;
// Update state as to whether bitplane fetching should happen now.
//
@ -611,7 +614,7 @@ template <int cycle, bool stop_if_cpu> bool Chipset::perform_cycle() {
constexpr auto sprite_id = (cycle - 0x16) >> 2;
static_assert(sprite_id >= 0 && sprite_id < std::tuple_size<decltype(sprites_)>::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 <bool stop_on_cpu> 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];
}

View File

@ -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.

View File

@ -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 {