1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-03 11:30:02 +00:00

Edges to within millimetres of CRAM dots.

... but all the way up to bedtime.
This commit is contained in:
Thomas Harte 2018-10-25 23:12:03 -04:00
parent 9621ba59ae
commit 0587b9f257
2 changed files with 43 additions and 15 deletions

View File

@ -326,6 +326,10 @@ void TMS9918::run_for(const HalfCycles cycles) {
LineBuffer &line_buffer = line_buffers_[read_pointer_.row];
// TODO: actually perform these dots, at least in part by further subdividing
// the period to run for.
upcoming_cram_dots_.clear();
// --------------------
// Output video stream.
@ -340,6 +344,8 @@ void TMS9918::run_for(const HalfCycles cycles) {
}\
}
#define border(left, right) intersect(left, right, output_border(end - start))
if(line_buffer.line_mode == LineMode::Refresh || read_pointer_.row > mode_timing_.pixel_lines) {
if(read_pointer_.row >= mode_timing_.first_vsync_line && read_pointer_.row < mode_timing_.first_vsync_line+4) {
// Vertical sync.
@ -348,7 +354,7 @@ void TMS9918::run_for(const HalfCycles cycles) {
}
} else {
// Right border.
intersect(0, 15, output_border(end - start));
border(0, 15);
// Blanking region; total length is 58 cycles,
// and 58+15 = 73. So output the lot when the
@ -362,11 +368,11 @@ void TMS9918::run_for(const HalfCycles cycles) {
}
// Border colour for the rest of the line.
intersect(73, 342, output_border(end - start));
border(73, 342);
}
} else {
// Right border.
intersect(0, 15, output_border(end - start));
border(0, 15);
// Blanking region.
if(read_pointer_.column < 73 && end_column >= 73) {
@ -378,7 +384,7 @@ void TMS9918::run_for(const HalfCycles cycles) {
}
// Left border.
intersect(73, line_buffer.first_pixel_output_column, output_border(end - start));
border(73, line_buffer.first_pixel_output_column);
// Pixel region.
intersect(
@ -395,7 +401,7 @@ void TMS9918::run_for(const HalfCycles cycles) {
const int relative_start = start - line_buffer.first_pixel_output_column;
const int relative_end = end - line_buffer.first_pixel_output_column;
switch(line_buffer.line_mode) {
case LineMode::SMS: draw_sms(relative_start, relative_end); break;
case LineMode::SMS: draw_sms(relative_start, relative_end, 0); break;
case LineMode::Character: draw_tms_character(relative_start, relative_end); break;
case LineMode::Text: draw_tms_text(relative_start, relative_end); break;
@ -413,11 +419,12 @@ void TMS9918::run_for(const HalfCycles cycles) {
// Additional right border, if called for.
if(line_buffer.next_border_column != 342) {
intersect(line_buffer.next_border_column, 342, output_border(end - start));
border(line_buffer.next_border_column, 342);
}
}
#undef intersect
#undef border
#undef intersect
@ -841,7 +848,7 @@ void Base::draw_tms_text(int start, int end) {
}
}
void Base::draw_sms(int start, int end) {
void Base::draw_sms(int start, int end, uint32_t cram_dot) {
LineBuffer &line_buffer = line_buffers_[read_pointer_.row];
int colour_buffer[256];
@ -974,8 +981,9 @@ void Base::draw_sms(int start, int end) {
status_ |= StatusSpriteCollision;
}
// Map from the 32-colour buffer to real output pixels.
for(int c = start; c < end; ++c) {
// Map from the 32-colour buffer to real output pixels, applying the specific CRAM dot if any.
pixel_target_[start] = master_system_.colour_ram[colour_buffer[start] & 0x1f] | cram_dot;
for(int c = start+1; c < end; ++c) {
pixel_target_[c] = master_system_.colour_ram[colour_buffer[c] & 0x1f];
}

View File

@ -253,6 +253,16 @@ class Base {
int row, column;
} read_pointer_, write_pointer_;
// The SMS VDP has a programmer-set colour palette, with a dedicated patch of RAM. But the RAM is only exactly
// fast enough for the pixel clock. So when the programmer writes to it, that causes a one-pixel glitch; there
// isn't the bandwidth for the read both write to occur simultaneously. The following buffer therefore keeps
// track of pending collisions, for visual reproduction.
struct CRAMDot {
LineBufferPointer location;
uint32_t value;
};
std::vector<CRAMDot> upcoming_cram_dots_;
// Extra information that affects the Master System output mode.
struct {
// Programmer-set flags.
@ -314,17 +324,27 @@ class Base {
screen_mode_ = ScreenMode::Blank;
}
void do_external_slot() {
void do_external_slot(int access_column) {
// TODO: is queued access ready yet?
switch(queued_access_) {
default: return;
case MemoryAccess::Write:
if(master_system_.cram_is_selected) {
// Adjust the palette.
master_system_.colour_ram[ram_pointer_ & 0x1f] = palette_pack(
static_cast<uint8_t>(((read_ahead_buffer_ >> 0) & 3) * 255 / 3),
static_cast<uint8_t>(((read_ahead_buffer_ >> 2) & 3) * 255 / 3),
static_cast<uint8_t>(((read_ahead_buffer_ >> 4) & 3) * 255 / 3)
);
// Schedule a CRAM dot.
upcoming_cram_dots_.emplace_back();
auto dot = upcoming_cram_dots_.back();
dot.location.row = write_pointer_.row;
dot.location.column = access_column;
dot.value = master_system_.colour_ram[ram_pointer_ & 0x1f];
} else {
ram_[ram_pointer_ & 16383] = read_ahead_buffer_;
}
@ -374,7 +394,7 @@ class Base {
case n
#define external_slot(n) \
slot(n): do_external_slot();
slot(n): do_external_slot((n)*2);
#define external_slots_2(n) \
external_slot(n); \
@ -606,7 +626,7 @@ class Base {
slot(31):
sprite_selection_buffer.reset_sprite_collection();
do_external_slot();
do_external_slot(31*2);
external_slots_2(32);
external_slot(34);
@ -758,7 +778,7 @@ class Base {
slot(29):
sprite_selection_buffer.reset_sprite_collection();
do_external_slot();
do_external_slot(29*2);
external_slot(30);
sprite_y_read(31, 0);
@ -799,7 +819,7 @@ class Base {
bool asked_for_write_area_ = false;
void draw_tms_character(int start, int end);
void draw_tms_text(int start, int end);
void draw_sms(int start, int end);
void draw_sms(int start, int end, uint32_t cram_dot);
};
}