mirror of
https://github.com/TomHarte/CLK.git
synced 2024-12-28 07:29:45 +00:00
Give clearer names to the two pointers.
This commit is contained in:
parent
392b0acb58
commit
9b7a925816
@ -39,10 +39,10 @@ Base<personality>::Base() :
|
|||||||
|
|
||||||
// Establish that output is delayed after reading by `output_lag` cycles; start
|
// Establish that output is delayed after reading by `output_lag` cycles; start
|
||||||
// at a random position.
|
// at a random position.
|
||||||
read_pointer_.row = rand() % 262;
|
fetch_pointer_.row = rand() % 262;
|
||||||
read_pointer_.column = rand() % (Timing<personality>::CyclesPerLine - output_lag);
|
fetch_pointer_.column = rand() % (Timing<personality>::CyclesPerLine - output_lag);
|
||||||
write_pointer_.row = read_pointer_.row;
|
output_pointer_.row = output_pointer_.row;
|
||||||
write_pointer_.column = read_pointer_.column + output_lag;
|
output_pointer_.column = output_pointer_.column + output_lag;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <Personality personality>
|
template <Personality personality>
|
||||||
@ -155,20 +155,20 @@ void TMS9918<personality>::run_for(const HalfCycles cycles) {
|
|||||||
|
|
||||||
while(write_cycles_pool || read_cycles_pool) {
|
while(write_cycles_pool || read_cycles_pool) {
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
LineBufferPointer backup = this->read_pointer_;
|
LineBufferPointer backup = this->output_pointer_;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(write_cycles_pool) {
|
if(write_cycles_pool) {
|
||||||
// Determine how much writing to do.
|
// Determine how much writing to do.
|
||||||
const int write_cycles = std::min(
|
const int write_cycles = std::min(
|
||||||
Timing<personality>::CyclesPerLine - this->write_pointer_.column,
|
Timing<personality>::CyclesPerLine - this->fetch_pointer_.column,
|
||||||
write_cycles_pool
|
write_cycles_pool
|
||||||
);
|
);
|
||||||
const int end_column = this->write_pointer_.column + write_cycles;
|
const int end_column = this->fetch_pointer_.column + write_cycles;
|
||||||
LineBuffer &line_buffer = this->line_buffers_[this->write_pointer_.row];
|
LineBuffer &line_buffer = this->line_buffers_[this->fetch_pointer_.row];
|
||||||
|
|
||||||
// Determine what this does to any enqueued VRAM access.
|
// Determine what this does to any enqueued VRAM access.
|
||||||
this->minimum_access_column_ = this->write_pointer_.column + this->cycles_until_access_;
|
this->minimum_access_column_ = this->fetch_pointer_.column + this->cycles_until_access_;
|
||||||
this->cycles_until_access_ -= write_cycles;
|
this->cycles_until_access_ -= write_cycles;
|
||||||
|
|
||||||
|
|
||||||
@ -176,8 +176,8 @@ void TMS9918<personality>::run_for(const HalfCycles cycles) {
|
|||||||
// Latch scrolling position, if necessary.
|
// Latch scrolling position, if necessary.
|
||||||
// ---------------------------------------
|
// ---------------------------------------
|
||||||
if constexpr (is_sega_vdp(personality)) {
|
if constexpr (is_sega_vdp(personality)) {
|
||||||
if(this->write_pointer_.column < 61 && end_column >= 61) {
|
if(this->fetch_pointer_.column < 61 && end_column >= 61) {
|
||||||
if(!this->write_pointer_.row) {
|
if(!this->fetch_pointer_.row) {
|
||||||
Storage<personality>::latched_vertical_scroll_ = Storage<personality>::vertical_scroll_;
|
Storage<personality>::latched_vertical_scroll_ = Storage<personality>::vertical_scroll_;
|
||||||
|
|
||||||
if(Storage<personality>::mode4_enable_) {
|
if(Storage<personality>::mode4_enable_) {
|
||||||
@ -201,7 +201,7 @@ void TMS9918<personality>::run_for(const HalfCycles cycles) {
|
|||||||
// Perform memory accesses.
|
// Perform memory accesses.
|
||||||
// ------------------------
|
// ------------------------
|
||||||
#define fetch(function, clock) \
|
#define fetch(function, clock) \
|
||||||
const int first_window = from_internal<personality, clock>(this->write_pointer_.column);\
|
const int first_window = from_internal<personality, clock>(this->fetch_pointer_.column);\
|
||||||
const int final_window = from_internal<personality, clock>(end_column); \
|
const int final_window = from_internal<personality, clock>(end_column); \
|
||||||
if(first_window == final_window) break; \
|
if(first_window == final_window) break; \
|
||||||
if(final_window != clock_rate<personality, clock>()) { \
|
if(final_window != clock_rate<personality, clock>()) { \
|
||||||
@ -224,12 +224,12 @@ void TMS9918<personality>::run_for(const HalfCycles cycles) {
|
|||||||
// -------------------------------
|
// -------------------------------
|
||||||
// Check for interrupt conditions.
|
// Check for interrupt conditions.
|
||||||
// -------------------------------
|
// -------------------------------
|
||||||
if(this->write_pointer_.column < this->mode_timing_.line_interrupt_position && end_column >= this->mode_timing_.line_interrupt_position) {
|
if(this->fetch_pointer_.column < this->mode_timing_.line_interrupt_position && end_column >= this->mode_timing_.line_interrupt_position) {
|
||||||
// The Sega VDP offers a decrementing counter for triggering line interrupts;
|
// The Sega VDP offers a decrementing counter for triggering line interrupts;
|
||||||
// it is reloaded either when it overflows or upon every non-pixel line after the first.
|
// it is reloaded either when it overflows or upon every non-pixel line after the first.
|
||||||
// It is otherwise decremented.
|
// It is otherwise decremented.
|
||||||
if constexpr (is_sega_vdp(personality)) {
|
if constexpr (is_sega_vdp(personality)) {
|
||||||
if(this->write_pointer_.row >= 0 && this->write_pointer_.row <= this->mode_timing_.pixel_lines) {
|
if(this->fetch_pointer_.row >= 0 && this->fetch_pointer_.row <= this->mode_timing_.pixel_lines) {
|
||||||
--this->line_interrupt_counter_;
|
--this->line_interrupt_counter_;
|
||||||
if(this->line_interrupt_counter_ == 0xff) {
|
if(this->line_interrupt_counter_ == 0xff) {
|
||||||
this->line_interrupt_pending_ = true;
|
this->line_interrupt_pending_ = true;
|
||||||
@ -245,8 +245,8 @@ void TMS9918<personality>::run_for(const HalfCycles cycles) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(
|
if(
|
||||||
this->write_pointer_.row == this->mode_timing_.end_of_frame_interrupt_position.row &&
|
this->fetch_pointer_.row == this->mode_timing_.end_of_frame_interrupt_position.row &&
|
||||||
this->write_pointer_.column < this->mode_timing_.end_of_frame_interrupt_position.column &&
|
this->fetch_pointer_.column < this->mode_timing_.end_of_frame_interrupt_position.column &&
|
||||||
end_column >= this->mode_timing_.end_of_frame_interrupt_position.column
|
end_column >= this->mode_timing_.end_of_frame_interrupt_position.column
|
||||||
) {
|
) {
|
||||||
this->status_ |= StatusInterrupt;
|
this->status_ |= StatusInterrupt;
|
||||||
@ -257,13 +257,13 @@ void TMS9918<personality>::run_for(const HalfCycles cycles) {
|
|||||||
// -------------
|
// -------------
|
||||||
// Advance time.
|
// Advance time.
|
||||||
// -------------
|
// -------------
|
||||||
this->write_pointer_.column = end_column;
|
this->fetch_pointer_.column = end_column;
|
||||||
write_cycles_pool -= write_cycles;
|
write_cycles_pool -= write_cycles;
|
||||||
|
|
||||||
if(this->write_pointer_.column == Timing<personality>::CyclesPerLine) {
|
if(this->fetch_pointer_.column == Timing<personality>::CyclesPerLine) {
|
||||||
this->write_pointer_.column = 0;
|
this->fetch_pointer_.column = 0;
|
||||||
this->write_pointer_.row = (this->write_pointer_.row + 1) % this->mode_timing_.total_lines;
|
this->fetch_pointer_.row = (this->fetch_pointer_.row + 1) % this->mode_timing_.total_lines;
|
||||||
LineBuffer &next_line_buffer = this->line_buffers_[this->write_pointer_.row];
|
LineBuffer &next_line_buffer = this->line_buffers_[this->fetch_pointer_.row];
|
||||||
|
|
||||||
// Establish the current screen output mode, which will be captured as a
|
// Establish the current screen output mode, which will be captured as a
|
||||||
// line mode momentarily.
|
// line mode momentarily.
|
||||||
@ -292,22 +292,22 @@ void TMS9918<personality>::run_for(const HalfCycles cycles) {
|
|||||||
|
|
||||||
if(
|
if(
|
||||||
(this->screen_mode_ == ScreenMode::Blank) ||
|
(this->screen_mode_ == ScreenMode::Blank) ||
|
||||||
(this->write_pointer_.row >= this->mode_timing_.pixel_lines && this->write_pointer_.row != this->mode_timing_.total_lines-1))
|
(this->fetch_pointer_.row >= this->mode_timing_.pixel_lines && this->fetch_pointer_.row != this->mode_timing_.total_lines-1))
|
||||||
next_line_buffer.line_mode = LineMode::Refresh;
|
next_line_buffer.line_mode = LineMode::Refresh;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
assert(backup.row == this->read_pointer_.row && backup.column == this->read_pointer_.column);
|
assert(backup.row == this->output_pointer_.row && backup.column == this->output_pointer_.column);
|
||||||
backup = this->write_pointer_;
|
backup = this->fetch_pointer_;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
if(read_cycles_pool) {
|
if(read_cycles_pool) {
|
||||||
// Determine how much time has passed in the remainder of this line, and proceed.
|
// Determine how much time has passed in the remainder of this line, and proceed.
|
||||||
const int target_read_cycles = std::min(
|
const int target_read_cycles = std::min(
|
||||||
Timing<personality>::CyclesPerLine - this->read_pointer_.column,
|
Timing<personality>::CyclesPerLine - this->output_pointer_.column,
|
||||||
read_cycles_pool
|
read_cycles_pool
|
||||||
);
|
);
|
||||||
int read_cycles_performed = 0;
|
int read_cycles_performed = 0;
|
||||||
@ -322,8 +322,8 @@ void TMS9918<personality>::run_for(const HalfCycles cycles) {
|
|||||||
if constexpr (is_sega_vdp(personality)) {
|
if constexpr (is_sega_vdp(personality)) {
|
||||||
next_cram_value = 0;
|
next_cram_value = 0;
|
||||||
|
|
||||||
if(!this->upcoming_cram_dots_.empty() && this->upcoming_cram_dots_.front().location.row == this->read_pointer_.row) {
|
if(!this->upcoming_cram_dots_.empty() && this->upcoming_cram_dots_.front().location.row == this->output_pointer_.row) {
|
||||||
int time_until_dot = this->upcoming_cram_dots_.front().location.column - this->read_pointer_.column;
|
int time_until_dot = this->upcoming_cram_dots_.front().location.column - this->output_pointer_.column;
|
||||||
|
|
||||||
if(time_until_dot < read_cycles) {
|
if(time_until_dot < read_cycles) {
|
||||||
read_cycles = time_until_dot;
|
read_cycles = time_until_dot;
|
||||||
@ -335,8 +335,8 @@ void TMS9918<personality>::run_for(const HalfCycles cycles) {
|
|||||||
|
|
||||||
read_cycles_performed += read_cycles;
|
read_cycles_performed += read_cycles;
|
||||||
|
|
||||||
const int end_column = this->read_pointer_.column + read_cycles;
|
const int end_column = this->output_pointer_.column + read_cycles;
|
||||||
LineBuffer &line_buffer = this->line_buffers_[this->read_pointer_.row];
|
LineBuffer &line_buffer = this->line_buffers_[this->output_pointer_.row];
|
||||||
|
|
||||||
|
|
||||||
// --------------------
|
// --------------------
|
||||||
@ -349,7 +349,7 @@ void TMS9918<personality>::run_for(const HalfCycles cycles) {
|
|||||||
#define output_default_colour_burst(x) crt_convert(output_default_colour_burst, x)
|
#define output_default_colour_burst(x) crt_convert(output_default_colour_burst, x)
|
||||||
|
|
||||||
#define intersect(left, right, code) { \
|
#define intersect(left, right, code) { \
|
||||||
const int start = std::max(this->read_pointer_.column, left); \
|
const int start = std::max(this->output_pointer_.column, left); \
|
||||||
const int end = std::min(end_column, right); \
|
const int end = std::min(end_column, right); \
|
||||||
if(end > start) {\
|
if(end > start) {\
|
||||||
code;\
|
code;\
|
||||||
@ -358,10 +358,10 @@ void TMS9918<personality>::run_for(const HalfCycles cycles) {
|
|||||||
|
|
||||||
#define border(left, right) intersect(left, right, this->output_border(end - start, cram_value))
|
#define border(left, right) intersect(left, right, this->output_border(end - start, cram_value))
|
||||||
|
|
||||||
if(line_buffer.line_mode == LineMode::Refresh || this->read_pointer_.row > this->mode_timing_.pixel_lines) {
|
if(line_buffer.line_mode == LineMode::Refresh || this->output_pointer_.row > this->mode_timing_.pixel_lines) {
|
||||||
if(
|
if(
|
||||||
this->read_pointer_.row >= this->mode_timing_.first_vsync_line &&
|
this->output_pointer_.row >= this->mode_timing_.first_vsync_line &&
|
||||||
this->read_pointer_.row < this->mode_timing_.first_vsync_line + 4
|
this->output_pointer_.row < this->mode_timing_.first_vsync_line + 4
|
||||||
) {
|
) {
|
||||||
// Vertical sync.
|
// Vertical sync.
|
||||||
// TODO: the Mega Drive supports interlaced video, I think?
|
// TODO: the Mega Drive supports interlaced video, I think?
|
||||||
@ -375,7 +375,7 @@ void TMS9918<personality>::run_for(const HalfCycles cycles) {
|
|||||||
// Blanking region: output the entire sequence when the cursor
|
// Blanking region: output the entire sequence when the cursor
|
||||||
// crosses the start-of-border point.
|
// crosses the start-of-border point.
|
||||||
if(
|
if(
|
||||||
this->read_pointer_.column < Timing<personality>::StartOfLeftBorder &&
|
this->output_pointer_.column < Timing<personality>::StartOfLeftBorder &&
|
||||||
end_column >= Timing<personality>::StartOfLeftBorder
|
end_column >= Timing<personality>::StartOfLeftBorder
|
||||||
) {
|
) {
|
||||||
output_blank(Timing<personality>::StartOfSync - Timing<personality>::EndOfRightBorder);
|
output_blank(Timing<personality>::StartOfSync - Timing<personality>::EndOfRightBorder);
|
||||||
@ -394,7 +394,7 @@ void TMS9918<personality>::run_for(const HalfCycles cycles) {
|
|||||||
|
|
||||||
// Blanking region.
|
// Blanking region.
|
||||||
if(
|
if(
|
||||||
this->read_pointer_.column < Timing<personality>::StartOfLeftBorder &&
|
this->output_pointer_.column < Timing<personality>::StartOfLeftBorder &&
|
||||||
end_column >= Timing<personality>::StartOfLeftBorder
|
end_column >= Timing<personality>::StartOfLeftBorder
|
||||||
) {
|
) {
|
||||||
output_blank(Timing<personality>::StartOfSync - Timing<personality>::EndOfRightBorder);
|
output_blank(Timing<personality>::StartOfSync - Timing<personality>::EndOfRightBorder);
|
||||||
@ -464,17 +464,17 @@ void TMS9918<personality>::run_for(const HalfCycles cycles) {
|
|||||||
// -------------
|
// -------------
|
||||||
// Advance time.
|
// Advance time.
|
||||||
// -------------
|
// -------------
|
||||||
this->read_pointer_.column = end_column;
|
this->output_pointer_.column = end_column;
|
||||||
}
|
}
|
||||||
|
|
||||||
read_cycles_pool -= target_read_cycles;
|
read_cycles_pool -= target_read_cycles;
|
||||||
if(this->read_pointer_.column == Timing<personality>::CyclesPerLine) {
|
if(this->output_pointer_.column == Timing<personality>::CyclesPerLine) {
|
||||||
this->read_pointer_.column = 0;
|
this->output_pointer_.column = 0;
|
||||||
this->read_pointer_.row = (this->read_pointer_.row + 1) % this->mode_timing_.total_lines;
|
this->output_pointer_.row = (this->output_pointer_.row + 1) % this->mode_timing_.total_lines;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(backup.row == this->write_pointer_.row && backup.column == this->write_pointer_.column);
|
assert(backup.row == this->fetch_pointer_.row && backup.column == this->fetch_pointer_.column);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -776,9 +776,9 @@ uint8_t TMS9918<personality>::get_current_line() const {
|
|||||||
// Determine the row to return.
|
// Determine the row to return.
|
||||||
constexpr int row_change_position = 63; // This is the proper Master System value; substitute if any other VDPs turn out to have this functionality.
|
constexpr int row_change_position = 63; // This is the proper Master System value; substitute if any other VDPs turn out to have this functionality.
|
||||||
int source_row =
|
int source_row =
|
||||||
(this->write_pointer_.column < row_change_position)
|
(this->fetch_pointer_.column < row_change_position)
|
||||||
? (this->write_pointer_.row + this->mode_timing_.total_lines - 1) % this->mode_timing_.total_lines
|
? (this->fetch_pointer_.row + this->mode_timing_.total_lines - 1) % this->mode_timing_.total_lines
|
||||||
: this->write_pointer_.row;
|
: this->fetch_pointer_.row;
|
||||||
|
|
||||||
if(this->tv_standard_ == TVStandard::NTSC) {
|
if(this->tv_standard_ == TVStandard::NTSC) {
|
||||||
if(this->mode_timing_.pixel_lines == 240) {
|
if(this->mode_timing_.pixel_lines == 240) {
|
||||||
@ -815,7 +815,7 @@ HalfCycles TMS9918<personality>::get_next_sequence_point() const {
|
|||||||
int time_until_frame_interrupt =
|
int time_until_frame_interrupt =
|
||||||
(
|
(
|
||||||
((this->mode_timing_.end_of_frame_interrupt_position.row * Timing<personality>::CyclesPerLine) + this->mode_timing_.end_of_frame_interrupt_position.column + frame_length) -
|
((this->mode_timing_.end_of_frame_interrupt_position.row * Timing<personality>::CyclesPerLine) + this->mode_timing_.end_of_frame_interrupt_position.column + frame_length) -
|
||||||
((this->write_pointer_.row * Timing<personality>::CyclesPerLine) + this->write_pointer_.column)
|
((this->fetch_pointer_.row * Timing<personality>::CyclesPerLine) + this->fetch_pointer_.column)
|
||||||
) % frame_length;
|
) % frame_length;
|
||||||
if(!time_until_frame_interrupt) time_until_frame_interrupt = frame_length;
|
if(!time_until_frame_interrupt) time_until_frame_interrupt = frame_length;
|
||||||
|
|
||||||
@ -826,8 +826,8 @@ HalfCycles TMS9918<personality>::get_next_sequence_point() const {
|
|||||||
// Calculate when the next line interrupt will occur.
|
// Calculate when the next line interrupt will occur.
|
||||||
int next_line_interrupt_row = -1;
|
int next_line_interrupt_row = -1;
|
||||||
|
|
||||||
int cycles_to_next_interrupt_threshold = this->mode_timing_.line_interrupt_position - this->write_pointer_.column;
|
int cycles_to_next_interrupt_threshold = this->mode_timing_.line_interrupt_position - this->fetch_pointer_.column;
|
||||||
int line_of_next_interrupt_threshold = this->write_pointer_.row;
|
int line_of_next_interrupt_threshold = this->fetch_pointer_.row;
|
||||||
if(cycles_to_next_interrupt_threshold <= 0) {
|
if(cycles_to_next_interrupt_threshold <= 0) {
|
||||||
cycles_to_next_interrupt_threshold += Timing<personality>::CyclesPerLine;
|
cycles_to_next_interrupt_threshold += Timing<personality>::CyclesPerLine;
|
||||||
++line_of_next_interrupt_threshold;
|
++line_of_next_interrupt_threshold;
|
||||||
@ -866,8 +866,8 @@ template <Personality personality>
|
|||||||
HalfCycles TMS9918<personality>::get_time_until_line(int line) {
|
HalfCycles TMS9918<personality>::get_time_until_line(int line) {
|
||||||
if(line < 0) line += this->mode_timing_.total_lines;
|
if(line < 0) line += this->mode_timing_.total_lines;
|
||||||
|
|
||||||
int cycles_to_next_interrupt_threshold = this->mode_timing_.line_interrupt_position - this->write_pointer_.column;
|
int cycles_to_next_interrupt_threshold = this->mode_timing_.line_interrupt_position - this->fetch_pointer_.column;
|
||||||
int line_of_next_interrupt_threshold = this->write_pointer_.row;
|
int line_of_next_interrupt_threshold = this->fetch_pointer_.row;
|
||||||
if(cycles_to_next_interrupt_threshold <= 0) {
|
if(cycles_to_next_interrupt_threshold <= 0) {
|
||||||
cycles_to_next_interrupt_threshold += Timing<personality>::CyclesPerLine;
|
cycles_to_next_interrupt_threshold += Timing<personality>::CyclesPerLine;
|
||||||
++line_of_next_interrupt_threshold;
|
++line_of_next_interrupt_threshold;
|
||||||
@ -900,7 +900,7 @@ template <Personality personality>uint8_t TMS9918<personality>::get_latched_hori
|
|||||||
|
|
||||||
template <Personality personality>
|
template <Personality personality>
|
||||||
void TMS9918<personality>::latch_horizontal_counter() {
|
void TMS9918<personality>::latch_horizontal_counter() {
|
||||||
this->latched_column_ = this->write_pointer_.column;
|
this->latched_column_ = this->fetch_pointer_.column;
|
||||||
}
|
}
|
||||||
|
|
||||||
template class TI::TMS::TMS9918<Personality::TMS9918A>;
|
template class TI::TMS::TMS9918<Personality::TMS9918A>;
|
||||||
|
@ -300,7 +300,7 @@ template <Personality personality> struct Base: public Storage<personality> {
|
|||||||
// to update sprites and tiles, but writing time affects when the palette is used and when the collision flag
|
// to update sprites and tiles, but writing time affects when the palette is used and when the collision flag
|
||||||
// may end up being set. So the two processes are slightly decoupled. The end of reading one line may overlap
|
// may end up being set. So the two processes are slightly decoupled. The end of reading one line may overlap
|
||||||
// with the beginning of writing the next, hence the two separate line buffers.
|
// with the beginning of writing the next, hence the two separate line buffers.
|
||||||
LineBufferPointer read_pointer_, write_pointer_;
|
LineBufferPointer output_pointer_, fetch_pointer_;
|
||||||
|
|
||||||
int masked_address(int address);
|
int masked_address(int address);
|
||||||
void write_vram(uint8_t);
|
void write_vram(uint8_t);
|
||||||
@ -370,8 +370,8 @@ template <Personality personality> struct Base: public Storage<personality> {
|
|||||||
// on screen. So it's wherever the output stream would be now. Which
|
// on screen. So it's wherever the output stream would be now. Which
|
||||||
// is output_lag cycles ago from the point of view of the input stream.
|
// is output_lag cycles ago from the point of view of the input stream.
|
||||||
auto &dot = Storage<personality>::upcoming_cram_dots_.emplace_back();
|
auto &dot = Storage<personality>::upcoming_cram_dots_.emplace_back();
|
||||||
dot.location.column = write_pointer_.column - output_lag;
|
dot.location.column = fetch_pointer_.column - output_lag;
|
||||||
dot.location.row = write_pointer_.row;
|
dot.location.row = fetch_pointer_.row;
|
||||||
|
|
||||||
// Handle before this row conditionally; then handle after (or, more realistically,
|
// Handle before this row conditionally; then handle after (or, more realistically,
|
||||||
// exactly at the end of) naturally.
|
// exactly at the end of) naturally.
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
template <Personality personality>
|
template <Personality personality>
|
||||||
void Base<personality>::draw_tms_character(int start, int end) {
|
void Base<personality>::draw_tms_character(int start, int end) {
|
||||||
LineBuffer &line_buffer = line_buffers_[read_pointer_.row];
|
LineBuffer &line_buffer = line_buffers_[output_pointer_.row];
|
||||||
|
|
||||||
// Paint the background tiles.
|
// Paint the background tiles.
|
||||||
const int pixels_left = end - start;
|
const int pixels_left = end - start;
|
||||||
@ -106,7 +106,7 @@ void Base<personality>::draw_tms_character(int start, int end) {
|
|||||||
|
|
||||||
template <Personality personality>
|
template <Personality personality>
|
||||||
void Base<personality>::draw_tms_text(int start, int end) {
|
void Base<personality>::draw_tms_text(int start, int end) {
|
||||||
LineBuffer &line_buffer = line_buffers_[read_pointer_.row];
|
LineBuffer &line_buffer = line_buffers_[output_pointer_.row];
|
||||||
const uint32_t colours[2] = { palette[background_colour_], palette[text_colour_] };
|
const uint32_t colours[2] = { palette[background_colour_], palette[text_colour_] };
|
||||||
|
|
||||||
const int shift = start % 6;
|
const int shift = start % 6;
|
||||||
@ -135,7 +135,7 @@ template <Personality personality>
|
|||||||
void Base<personality>::draw_sms(int start, int end, uint32_t cram_dot) {
|
void Base<personality>::draw_sms(int start, int end, uint32_t cram_dot) {
|
||||||
if constexpr (is_sega_vdp(personality)) {
|
if constexpr (is_sega_vdp(personality)) {
|
||||||
|
|
||||||
LineBuffer &line_buffer = line_buffers_[read_pointer_.row];
|
LineBuffer &line_buffer = line_buffers_[output_pointer_.row];
|
||||||
int colour_buffer[256];
|
int colour_buffer[256];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -143,7 +143,7 @@ void Base<personality>::draw_sms(int start, int end, uint32_t cram_dot) {
|
|||||||
*/
|
*/
|
||||||
int tile_start = start, tile_end = end;
|
int tile_start = start, tile_end = end;
|
||||||
int tile_offset = start;
|
int tile_offset = start;
|
||||||
if(read_pointer_.row >= 16 || !Storage<personality>::horizontal_scroll_lock_) {
|
if(output_pointer_.row >= 16 || !Storage<personality>::horizontal_scroll_lock_) {
|
||||||
for(int c = start; c < (line_buffer.latched_horizontal_scroll & 7); ++c) {
|
for(int c = start; c < (line_buffer.latched_horizontal_scroll & 7); ++c) {
|
||||||
colour_buffer[c] = 16 + background_colour_;
|
colour_buffer[c] = 16 + background_colour_;
|
||||||
++tile_offset;
|
++tile_offset;
|
||||||
|
@ -139,9 +139,9 @@ template<bool use_end> void Base<personality>::fetch_tms_text(int start, int end
|
|||||||
fetch_columns_4(location, column); \
|
fetch_columns_4(location, column); \
|
||||||
fetch_columns_4(location+12, column+4);
|
fetch_columns_4(location+12, column+4);
|
||||||
|
|
||||||
LineBuffer &line_buffer = line_buffers_[write_pointer_.row];
|
LineBuffer &line_buffer = line_buffers_[fetch_pointer_.row];
|
||||||
const size_t row_base = pattern_name_address_ & (0x3c00 | size_t(write_pointer_.row >> 3) * 40);
|
const size_t row_base = pattern_name_address_ & (0x3c00 | size_t(fetch_pointer_.row >> 3) * 40);
|
||||||
const size_t row_offset = pattern_generator_table_address_ & (0x3800 | (write_pointer_.row & 7));
|
const size_t row_offset = pattern_generator_table_address_ & (0x3800 | (fetch_pointer_.row & 7));
|
||||||
|
|
||||||
switch(start) {
|
switch(start) {
|
||||||
default: assert(false);
|
default: assert(false);
|
||||||
@ -210,7 +210,7 @@ template<bool use_end> void Base<personality>::fetch_tms_character(int start, in
|
|||||||
sprite_fetch_graphics(location+2, sprite)
|
sprite_fetch_graphics(location+2, sprite)
|
||||||
|
|
||||||
#define sprite_y_read(location, sprite) \
|
#define sprite_y_read(location, sprite) \
|
||||||
slot(location): posit_sprite(sprite_selection_buffer, sprite, ram_[sprite_attribute_table_address_ & (((sprite) << 2) | 0x3f80)], write_pointer_.row);
|
slot(location): posit_sprite(sprite_selection_buffer, sprite, ram_[sprite_attribute_table_address_ & (((sprite) << 2) | 0x3f80)], fetch_pointer_.row);
|
||||||
|
|
||||||
#define fetch_tile_name(column) line_buffer.names[column].offset = ram_[(row_base + column) & 0x3fff];
|
#define fetch_tile_name(column) line_buffer.names[column].offset = ram_[(row_base + column) & 0x3fff];
|
||||||
|
|
||||||
@ -237,9 +237,9 @@ template<bool use_end> void Base<personality>::fetch_tms_character(int start, in
|
|||||||
slot(location+14): \
|
slot(location+14): \
|
||||||
slot(location+15): fetch_tile(column+3)
|
slot(location+15): fetch_tile(column+3)
|
||||||
|
|
||||||
LineBuffer &line_buffer = line_buffers_[write_pointer_.row];
|
LineBuffer &line_buffer = line_buffers_[fetch_pointer_.row];
|
||||||
LineBuffer &sprite_selection_buffer = line_buffers_[(write_pointer_.row + 1) % mode_timing_.total_lines];
|
LineBuffer &sprite_selection_buffer = line_buffers_[(fetch_pointer_.row + 1) % mode_timing_.total_lines];
|
||||||
const size_t row_base = pattern_name_address_ & (size_t((write_pointer_.row << 2)&~31) | 0x3c00);
|
const size_t row_base = pattern_name_address_ & (size_t((fetch_pointer_.row << 2)&~31) | 0x3c00);
|
||||||
|
|
||||||
size_t pattern_base = pattern_generator_table_address_;
|
size_t pattern_base = pattern_generator_table_address_;
|
||||||
size_t colour_base = colour_table_address_;
|
size_t colour_base = colour_table_address_;
|
||||||
@ -247,10 +247,10 @@ template<bool use_end> void Base<personality>::fetch_tms_character(int start, in
|
|||||||
|
|
||||||
if(screen_mode_ == ScreenMode::Graphics) {
|
if(screen_mode_ == ScreenMode::Graphics) {
|
||||||
// If this is high resolution mode, allow the row number to affect the pattern and colour addresses.
|
// If this is high resolution mode, allow the row number to affect the pattern and colour addresses.
|
||||||
pattern_base &= size_t(0x2000 | ((write_pointer_.row & 0xc0) << 5));
|
pattern_base &= size_t(0x2000 | ((fetch_pointer_.row & 0xc0) << 5));
|
||||||
colour_base &= size_t(0x2000 | ((write_pointer_.row & 0xc0) << 5));
|
colour_base &= size_t(0x2000 | ((fetch_pointer_.row & 0xc0) << 5));
|
||||||
|
|
||||||
colour_base += size_t(write_pointer_.row & 7);
|
colour_base += size_t(fetch_pointer_.row & 7);
|
||||||
colour_name_shift = 0;
|
colour_name_shift = 0;
|
||||||
} else {
|
} else {
|
||||||
colour_base &= size_t(0xffc0);
|
colour_base &= size_t(0xffc0);
|
||||||
@ -258,9 +258,9 @@ template<bool use_end> void Base<personality>::fetch_tms_character(int start, in
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(screen_mode_ == ScreenMode::MultiColour) {
|
if(screen_mode_ == ScreenMode::MultiColour) {
|
||||||
pattern_base += size_t((write_pointer_.row >> 2) & 7);
|
pattern_base += size_t((fetch_pointer_.row >> 2) & 7);
|
||||||
} else {
|
} else {
|
||||||
pattern_base += size_t(write_pointer_.row & 7);
|
pattern_base += size_t(fetch_pointer_.row & 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(start) {
|
switch(start) {
|
||||||
@ -348,8 +348,8 @@ template<bool use_end> void Base<personality>::fetch_sms(int start, int end) {
|
|||||||
|
|
||||||
#define sprite_y_read(location, sprite) \
|
#define sprite_y_read(location, sprite) \
|
||||||
slot(location): \
|
slot(location): \
|
||||||
posit_sprite(sprite_selection_buffer, sprite, ram_[Storage<personality>::sprite_attribute_table_address_ & ((sprite) | 0x3f00)], write_pointer_.row); \
|
posit_sprite(sprite_selection_buffer, sprite, ram_[Storage<personality>::sprite_attribute_table_address_ & ((sprite) | 0x3f00)], fetch_pointer_.row); \
|
||||||
posit_sprite(sprite_selection_buffer, sprite+1, ram_[Storage<personality>::sprite_attribute_table_address_ & ((sprite + 1) | 0x3f00)], write_pointer_.row); \
|
posit_sprite(sprite_selection_buffer, sprite+1, ram_[Storage<personality>::sprite_attribute_table_address_ & ((sprite + 1) | 0x3f00)], fetch_pointer_.row); \
|
||||||
|
|
||||||
#define fetch_tile_name(column, row_info) {\
|
#define fetch_tile_name(column, row_info) {\
|
||||||
const size_t scrolled_column = (column - horizontal_offset) & 0x1f;\
|
const size_t scrolled_column = (column - horizontal_offset) & 0x1f;\
|
||||||
@ -391,9 +391,9 @@ template<bool use_end> void Base<personality>::fetch_sms(int start, int end) {
|
|||||||
slot(location+15): fetch_tile(column+3)
|
slot(location+15): fetch_tile(column+3)
|
||||||
|
|
||||||
// Determine the coarse horizontal scrolling offset; this isn't applied on the first two lines if the programmer has requested it.
|
// Determine the coarse horizontal scrolling offset; this isn't applied on the first two lines if the programmer has requested it.
|
||||||
LineBuffer &line_buffer = line_buffers_[write_pointer_.row];
|
LineBuffer &line_buffer = line_buffers_[fetch_pointer_.row];
|
||||||
LineBuffer &sprite_selection_buffer = line_buffers_[(write_pointer_.row + 1) % mode_timing_.total_lines];
|
LineBuffer &sprite_selection_buffer = line_buffers_[(fetch_pointer_.row + 1) % mode_timing_.total_lines];
|
||||||
const int horizontal_offset = (write_pointer_.row >= 16 || !Storage<personality>::horizontal_scroll_lock_) ? (line_buffer.latched_horizontal_scroll >> 3) : 0;
|
const int horizontal_offset = (fetch_pointer_.row >= 16 || !Storage<personality>::horizontal_scroll_lock_) ? (line_buffer.latched_horizontal_scroll >> 3) : 0;
|
||||||
|
|
||||||
// Limit address bits in use if this is a SMS2 mode.
|
// Limit address bits in use if this is a SMS2 mode.
|
||||||
const bool is_tall_mode = mode_timing_.pixel_lines != 192;
|
const bool is_tall_mode = mode_timing_.pixel_lines != 192;
|
||||||
@ -402,7 +402,7 @@ template<bool use_end> void Base<personality>::fetch_sms(int start, int end) {
|
|||||||
|
|
||||||
// Determine row info for the screen both (i) if vertical scrolling is applied; and (ii) if it isn't.
|
// Determine row info for the screen both (i) if vertical scrolling is applied; and (ii) if it isn't.
|
||||||
// The programmer can opt out of applying vertical scrolling to the right-hand portion of the display.
|
// The programmer can opt out of applying vertical scrolling to the right-hand portion of the display.
|
||||||
const int scrolled_row = (write_pointer_.row + Storage<personality>::latched_vertical_scroll_) % (is_tall_mode ? 256 : 224);
|
const int scrolled_row = (fetch_pointer_.row + Storage<personality>::latched_vertical_scroll_) % (is_tall_mode ? 256 : 224);
|
||||||
struct RowInfo {
|
struct RowInfo {
|
||||||
size_t pattern_address_base;
|
size_t pattern_address_base;
|
||||||
size_t sub_row[2];
|
size_t sub_row[2];
|
||||||
@ -413,9 +413,9 @@ template<bool use_end> void Base<personality>::fetch_sms(int start, int end) {
|
|||||||
};
|
};
|
||||||
RowInfo row_info;
|
RowInfo row_info;
|
||||||
if(Storage<personality>::vertical_scroll_lock_) {
|
if(Storage<personality>::vertical_scroll_lock_) {
|
||||||
row_info.pattern_address_base = (pattern_name_address & size_t(((write_pointer_.row & ~7) << 3) | 0x3800)) - pattern_name_offset;
|
row_info.pattern_address_base = (pattern_name_address & size_t(((fetch_pointer_.row & ~7) << 3) | 0x3800)) - pattern_name_offset;
|
||||||
row_info.sub_row[0] = size_t((write_pointer_.row & 7) << 2);
|
row_info.sub_row[0] = size_t((fetch_pointer_.row & 7) << 2);
|
||||||
row_info.sub_row[1] = 28 ^ size_t((write_pointer_.row & 7) << 2);
|
row_info.sub_row[1] = 28 ^ size_t((fetch_pointer_.row & 7) << 2);
|
||||||
} else row_info = scrolled_row_info;
|
} else row_info = scrolled_row_info;
|
||||||
|
|
||||||
// ... and do the actual fetching, which follows this routine:
|
// ... and do the actual fetching, which follows this routine:
|
||||||
|
Loading…
Reference in New Issue
Block a user