mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-19 23:32:28 +00:00
Implements multicolour mode on the TMS.
This commit is contained in:
parent
fdfd72a42c
commit
ea13c7dd32
@ -72,6 +72,15 @@ struct ReverseTable {
|
|||||||
}
|
}
|
||||||
} reverse_table;
|
} reverse_table;
|
||||||
|
|
||||||
|
// Bits are reversed in the internal mode value; they're stored
|
||||||
|
// in the order M1 M2 M3. Hence the definitions below.
|
||||||
|
enum ScreenMode {
|
||||||
|
Text = 4,
|
||||||
|
MultiColour = 2,
|
||||||
|
ColouredText = 0,
|
||||||
|
Graphics = 1
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TMS9918Base::TMS9918Base() :
|
TMS9918Base::TMS9918Base() :
|
||||||
@ -293,7 +302,8 @@ void TMS9918::run_for(const HalfCycles cycles) {
|
|||||||
int row_base = pattern_name_address_;
|
int row_base = pattern_name_address_;
|
||||||
int pattern_base = pattern_generator_table_address_;
|
int pattern_base = pattern_generator_table_address_;
|
||||||
int colour_base = colour_table_address_;
|
int colour_base = colour_table_address_;
|
||||||
if(screen_mode_ == 1) {
|
if(screen_mode_ == ScreenMode::Graphics) {
|
||||||
|
// If this is high resolution mode, allow the row number to affect the pattern and colour addresses.
|
||||||
pattern_base &= 0x2000 | ((row_ & 0xc0) << 5);
|
pattern_base &= 0x2000 | ((row_ & 0xc0) << 5);
|
||||||
colour_base &= 0x2000 | ((row_ & 0xc0) << 5);
|
colour_base &= 0x2000 | ((row_ & 0xc0) << 5);
|
||||||
}
|
}
|
||||||
@ -304,7 +314,7 @@ void TMS9918::run_for(const HalfCycles cycles) {
|
|||||||
const int pattern_names_end = (end - 27 + 3) >> 2;
|
const int pattern_names_end = (end - 27 + 3) >> 2;
|
||||||
std::memcpy(&pattern_names_[pattern_names_start], &ram_[row_base + pattern_names_start], static_cast<size_t>(pattern_names_end - pattern_names_start));
|
std::memcpy(&pattern_names_[pattern_names_start], &ram_[row_base + pattern_names_start], static_cast<size_t>(pattern_names_end - pattern_names_start));
|
||||||
|
|
||||||
// Colours are collected ever fourth window starting from window 29.
|
// Colours are collected every fourth window starting from window 29.
|
||||||
const int colours_start = (access_pointer_ - 29 + 3) >> 2;
|
const int colours_start = (access_pointer_ - 29 + 3) >> 2;
|
||||||
const int colours_end = (end - 29 + 3) >> 2;
|
const int colours_end = (end - 29 + 3) >> 2;
|
||||||
if(screen_mode_ != 1) {
|
if(screen_mode_ != 1) {
|
||||||
@ -320,8 +330,11 @@ void TMS9918::run_for(const HalfCycles cycles) {
|
|||||||
// Patterns are collected ever fourth window starting from window 30.
|
// Patterns are collected ever fourth window starting from window 30.
|
||||||
const int pattern_buffer_start = (access_pointer_ - 30 + 3) >> 2;
|
const int pattern_buffer_start = (access_pointer_ - 30 + 3) >> 2;
|
||||||
const int pattern_buffer_end = (end - 30 + 3) >> 2;
|
const int pattern_buffer_end = (end - 30 + 3) >> 2;
|
||||||
|
|
||||||
|
// Multicolour mode uss a different function of row to pick bytes
|
||||||
|
const int row = (screen_mode_ != 2) ? (row_ & 7) : ((row_ >> 2) & 7);
|
||||||
for(int column = pattern_buffer_start; column < pattern_buffer_end; ++column) {
|
for(int column = pattern_buffer_start; column < pattern_buffer_end; ++column) {
|
||||||
pattern_buffer_[column] = ram_[pattern_base + (pattern_names_[column] << 3) + (row_ & 7)];
|
pattern_buffer_[column] = ram_[pattern_base + (pattern_names_[column] << 3) + row];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sprite slots occur in three quarters of ever fourth window starting from window 28.
|
// Sprite slots occur in three quarters of ever fourth window starting from window 28.
|
||||||
@ -421,7 +434,7 @@ void TMS9918::run_for(const HalfCycles cycles) {
|
|||||||
case LineMode::Character: {
|
case LineMode::Character: {
|
||||||
// If this is the start of the visible area, seed sprite shifter positions.
|
// If this is the start of the visible area, seed sprite shifter positions.
|
||||||
SpriteSet &sprite_set = sprite_sets_[active_sprite_set_ ^ 1];
|
SpriteSet &sprite_set = sprite_sets_[active_sprite_set_ ^ 1];
|
||||||
if(line_mode_ == LineMode::Character && output_column_ == first_pixel_column_) {
|
if(output_column_ == first_pixel_column_) {
|
||||||
int c = sprite_set.active_sprite_slot;
|
int c = sprite_set.active_sprite_slot;
|
||||||
while(c--) {
|
while(c--) {
|
||||||
SpriteSet::ActiveSprite &sprite = sprite_set.active_sprites[c];
|
SpriteSet::ActiveSprite &sprite = sprite_set.active_sprites[c];
|
||||||
@ -435,36 +448,46 @@ void TMS9918::run_for(const HalfCycles cycles) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Paint the background tiles.
|
// Paint the background tiles.
|
||||||
const int shift = (output_column_ - first_pixel_column_) & 7;
|
|
||||||
int byte_column = (output_column_ - first_pixel_column_) >> 3;
|
|
||||||
|
|
||||||
const int pixels_left = pixels_end - output_column_;
|
const int pixels_left = pixels_end - output_column_;
|
||||||
int length = std::min(pixels_left, 8 - shift);
|
if(screen_mode_ == ScreenMode::MultiColour) {
|
||||||
|
int pixel_location = output_column_ - first_pixel_column_;
|
||||||
int pattern = reverse_table.map[pattern_buffer_[byte_column]] >> shift;
|
for(int c = 0; c < pixels_left; ++c) {
|
||||||
uint8_t colour = colour_buffer_[byte_column];
|
pixel_target_[c] = palette[
|
||||||
uint32_t colours[2] = {
|
(pattern_buffer_[(pixel_location + c) >> 3] >> (((pixel_location + c) & 4)^4)) & 15
|
||||||
palette[(colour & 15) ? (colour & 15) : background_colour_],
|
];
|
||||||
palette[(colour >> 4) ? (colour >> 4) : background_colour_]
|
|
||||||
};
|
|
||||||
|
|
||||||
int background_pixels_left = pixels_left;
|
|
||||||
while(true) {
|
|
||||||
background_pixels_left -= length;
|
|
||||||
for(int c = 0; c < length; ++c) {
|
|
||||||
pixel_target_[c] = colours[pattern&0x01];
|
|
||||||
pattern >>= 1;
|
|
||||||
}
|
}
|
||||||
pixel_target_ += length;
|
pixel_target_ += pixels_left;
|
||||||
|
} else {
|
||||||
|
const int shift = (output_column_ - first_pixel_column_) & 7;
|
||||||
|
int byte_column = (output_column_ - first_pixel_column_) >> 3;
|
||||||
|
|
||||||
if(!background_pixels_left) break;
|
int length = std::min(pixels_left, 8 - shift);
|
||||||
length = std::min(8, background_pixels_left);
|
|
||||||
byte_column++;
|
|
||||||
|
|
||||||
pattern = reverse_table.map[pattern_buffer_[byte_column]];
|
int pattern = reverse_table.map[pattern_buffer_[byte_column]] >> shift;
|
||||||
colour = colour_buffer_[byte_column];
|
uint8_t colour = colour_buffer_[byte_column];
|
||||||
colours[0] = palette[(colour & 15) ? (colour & 15) : background_colour_];
|
uint32_t colours[2] = {
|
||||||
colours[1] = palette[(colour >> 4) ? (colour >> 4) : background_colour_];
|
palette[(colour & 15) ? (colour & 15) : background_colour_],
|
||||||
|
palette[(colour >> 4) ? (colour >> 4) : background_colour_]
|
||||||
|
};
|
||||||
|
|
||||||
|
int background_pixels_left = pixels_left;
|
||||||
|
while(true) {
|
||||||
|
background_pixels_left -= length;
|
||||||
|
for(int c = 0; c < length; ++c) {
|
||||||
|
pixel_target_[c] = colours[pattern&0x01];
|
||||||
|
pattern >>= 1;
|
||||||
|
}
|
||||||
|
pixel_target_ += length;
|
||||||
|
|
||||||
|
if(!background_pixels_left) break;
|
||||||
|
length = std::min(8, background_pixels_left);
|
||||||
|
byte_column++;
|
||||||
|
|
||||||
|
pattern = reverse_table.map[pattern_buffer_[byte_column]];
|
||||||
|
colour = colour_buffer_[byte_column];
|
||||||
|
colours[0] = palette[(colour & 15) ? (colour & 15) : background_colour_];
|
||||||
|
colours[1] = palette[(colour >> 4) ? (colour >> 4) : background_colour_];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Paint sprites and check for collisions.
|
// Paint sprites and check for collisions.
|
||||||
@ -554,7 +577,7 @@ void TMS9918::run_for(const HalfCycles cycles) {
|
|||||||
screen_mode_ = next_screen_mode_;
|
screen_mode_ = next_screen_mode_;
|
||||||
blank_screen_ = next_blank_screen_;
|
blank_screen_ = next_blank_screen_;
|
||||||
switch(screen_mode_) {
|
switch(screen_mode_) {
|
||||||
case 2:
|
case ScreenMode::Text:
|
||||||
line_mode_ = LineMode::Text;
|
line_mode_ = LineMode::Text;
|
||||||
first_pixel_column_ = 69;
|
first_pixel_column_ = 69;
|
||||||
first_right_border_column_ = 309;
|
first_right_border_column_ = 309;
|
||||||
@ -608,7 +631,7 @@ void TMS9918::set_register(int address, uint8_t value) {
|
|||||||
case 1:
|
case 1:
|
||||||
next_blank_screen_ = !(low_write_ & 0x40);
|
next_blank_screen_ = !(low_write_ & 0x40);
|
||||||
generate_interrupts_ = !!(low_write_ & 0x20);
|
generate_interrupts_ = !!(low_write_ & 0x20);
|
||||||
next_screen_mode_ = (next_screen_mode_ & 1) | ((low_write_ & 0x18) >> 3);
|
next_screen_mode_ = (next_screen_mode_ & 1) | ((low_write_ & 0x18) >> 2);
|
||||||
sprites_16x16_ = !!(low_write_ & 0x02);
|
sprites_16x16_ = !!(low_write_ & 0x02);
|
||||||
sprites_magnified_ = !!(low_write_ & 0x01);
|
sprites_magnified_ = !!(low_write_ & 0x01);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user