1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-05 10:28:58 +00:00

Sprites: infer part of DMA state from slot, no access during blank.

Also sets the proper vertical blank length.
This commit is contained in:
Thomas Harte 2021-11-26 09:37:52 -05:00
parent 0ab5177637
commit ce6877d6e4
2 changed files with 34 additions and 46 deletions

View File

@ -92,7 +92,7 @@ Chipset::Chipset(MemoryMap &map, int input_clock_rate) :
// Very conservatively crop, to roughly the centre 88% of a frame.
// This rectange was specifically calibrated around the default Workbench display.
crt_.set_visible_area(Outputs::Display::Rect(0.05f, 0.047f, 0.88f, 0.88f));
crt_.set_visible_area(Outputs::Display::Rect(0.05f, 0.055f, 0.88f, 0.88f));
}
#undef DMA_CONSTRUCT
@ -445,9 +445,9 @@ template <int cycle, bool stop_if_cpu> bool Chipset::perform_cycle() {
}
if constexpr (cycle >= 0x15 && cycle < 0x35) {
if((dma_control_ & SpritesFlag) == SpritesFlag) {
if((dma_control_ & SpritesFlag) == SpritesFlag && y_ >= vertical_blank_height_) {
constexpr auto sprite_id = (cycle - 0x15) >> 2;
if(sprites_[sprite_id].advance_dma(y_)) {
if(sprites_[sprite_id].advance_dma(cycle&2)) {
return false;
}
}
@ -575,14 +575,13 @@ template <bool stop_on_cpu> Chipset::Changes Chipset::run(HalfCycles length) {
// TODO: the manual is vague on when this happens. Try to find out.
copper_.reload<0>();
// TODO: is this really how sprite DMA proceeds?
for(int c = 0; c < 8; c++) {
sprites_[c].reset_dma();
}
// Toggle next field length if interlaced.
is_long_field_ ^= interlace_;
}
for(int c = 0; c < 8; c++) {
sprites_[c].advance_line(y_, y_ == vertical_blank_height_);
}
}
assert(line_cycle_ < line_length_ * 4);
}
@ -1111,7 +1110,10 @@ void Chipset::Sprite::set_stop_and_control(uint16_t value) {
v_stop_ = uint16_t((value >> 8) | ((value & 0x02) << 7));
v_start_ = uint16_t((v_start_ & 0x00ff) | ((value & 0x04) << 6));
attached = value & 0x80;
visible = false; // 'Disarm' the sprite.
// Disarm the sprite, but expect graphics next from DMA.
visible = false;
dma_state_ = DMAState::FetchImage;
}
void Chipset::Sprite::set_image_data(int slot, uint16_t value) {
@ -1119,11 +1121,16 @@ void Chipset::Sprite::set_image_data(int slot, uint16_t value) {
visible |= slot == 0;
}
bool Chipset::Sprite::advance_dma(int y) {
visible |= (y == v_start_);
if(y == v_stop_ && dma_state_ > DMAState::FetchStopAndControl) {
dma_state_ = DMAState::FetchStart;
void Chipset::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 Chipset::Sprite::advance_dma(int offset) {
if(!visible) return false;
// Fetch another word.
@ -1135,37 +1142,21 @@ bool Chipset::Sprite::advance_dma(int y) {
// i.e. stopped.
default: return false;
// FetchStart: fetch the first control word and proceed to the second.
case DMAState::FetchStart:
set_start_position(next_word);
dma_state_ = DMAState::FetchStopAndControl;
case DMAState::FetchControl:
if(offset) {
set_stop_and_control(next_word);
} else {
set_start_position(next_word);
}
return true;
// FetchStopAndControl: fetch second control word, which will automatically disable visibility.
case DMAState::FetchStopAndControl:
set_stop_and_control(next_word);
dma_state_ = DMAState::FetchData1;
return true;
// FetchData1: Just fetch a word and proceed to FetchData0.
case DMAState::FetchData1:
set_image_data(1, next_word);
dma_state_ = DMAState::FetchData0;
return true;
// FetchData0: fetch a word and return to FetchData1.
case DMAState::FetchData0:
set_image_data(0, next_word);
dma_state_ = DMAState::FetchData1;
case DMAState::FetchImage:
set_image_data(1 - bool(offset), next_word);
return true;
}
return false;
}
void Chipset::Sprite::reset_dma() {
dma_state_ = DMAState::FetchStart;
}
template <int sprite> void Chipset::TwoSpriteShifter::load(
uint16_t lsb,
uint16_t msb,

View File

@ -150,8 +150,8 @@ class Chipset: private ClockingHint::Observer {
void set_stop_and_control(uint16_t value);
void set_image_data(int slot, uint16_t value);
bool advance_dma(int y);
void reset_dma();
void advance_line(int y, bool is_end_of_blank);
bool advance_dma(int offset);
uint16_t data[2]{};
bool attached = false;
@ -162,12 +162,9 @@ class Chipset: private ClockingHint::Observer {
uint16_t v_start_ = 0, v_stop_ = 0;
enum class DMAState {
FetchStart,
FetchStopAndControl,
FetchData1,
FetchData0,
} dma_state_ = DMAState::FetchStart;
FetchControl,
FetchImage
} dma_state_ = DMAState::FetchControl;
} sprites_[8];
class TwoSpriteShifter {
@ -206,7 +203,7 @@ class Chipset: private ClockingHint::Observer {
// (Default values are PAL).
int line_length_ = 227;
int short_field_height_ = 312;
int vertical_blank_height_ = 29;
int vertical_blank_height_ = 25; // PAL = 25, NTSC = 20
// Current raster position.
int line_cycle_ = 0, y_ = 0;