1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-06-26 10:29:31 +00:00

Consolidate text output and support blinking; add sprites-enabled flag.

This commit is contained in:
Thomas Harte 2023-02-15 20:18:56 -05:00
parent 9b71f42375
commit 3f2a5929a3
5 changed files with 67 additions and 50 deletions

View File

@ -292,6 +292,16 @@ void TMS9918<personality>::run_for(const HalfCycles cycles) {
if(this->fetch_pointer_.column == Timing<personality>::CyclesPerLine) {
this->fetch_pointer_.column = 0;
this->fetch_pointer_.row = (this->fetch_pointer_.row + 1) % this->mode_timing_.total_lines;
if constexpr (is_yamaha_vdp(personality)) {
if(!this->fetch_pointer_.row && Storage<personality>::blink_periods_) {
--Storage<personality>::blink_counter_;
while(!Storage<personality>::blink_counter_) {
Storage<personality>::in_blink_ ^= 1;
Storage<personality>::blink_counter_ = (Storage<personality>::blink_periods_ >> (Storage<personality>::in_blink_ << 2)) & 0xf;
}
}
}
LineBuffer &next_line_buffer = this->line_buffers_[this->fetch_pointer_.row];
// Progress towards any delayed events.
@ -366,8 +376,7 @@ void TMS9918<personality>::run_for(const HalfCycles cycles) {
this->vertical_state();
const bool is_refresh = next_line_buffer.vertical_state == VerticalState::Blank;
// TODO: an actual sprites-enabled flag.
Storage<personality>::begin_line(this->screen_mode_, is_refresh, false);
Storage<personality>::begin_line(this->screen_mode_, is_refresh);
if(is_refresh) {
// The Yamaha handles refresh lines via its own microprogram; other VDPs
@ -491,10 +500,10 @@ void TMS9918<personality>::run_for(const HalfCycles cycles) {
// Left border.
border(Timing<personality>::StartOfLeftBorder, line_buffer.first_pixel_output_column);
#define draw(function, clock) { \
#define draw(function, clock) { \
const int relative_start = from_internal<personality, clock>(start - line_buffer.first_pixel_output_column); \
const int relative_end = from_internal<personality, clock>(end - line_buffer.first_pixel_output_column); \
if(relative_start == relative_end) break; \
if(relative_start == relative_end) break; \
this->function; }
// Pixel region.
@ -515,7 +524,7 @@ void TMS9918<personality>::run_for(const HalfCycles cycles) {
switch(line_buffer.fetch_mode) {
case FetchMode::SMS: draw(draw_sms(relative_start, relative_end, cram_value), Clock::TMSPixel); break;
case FetchMode::Character: draw(draw_tms_character(relative_start, relative_end), Clock::TMSPixel); break;
case FetchMode::Text: draw(draw_tms_text(relative_start, relative_end), Clock::TMSPixel); break;
case FetchMode::Text: draw(template draw_tms_text<false>(relative_start, relative_end), Clock::TMSPixel); break;
case FetchMode::Yamaha: draw(draw_yamaha(relative_start, relative_end), Clock::Internal); break;
case FetchMode::Refresh: break; /* Dealt with elsewhere. */
@ -752,6 +761,7 @@ void Base<personality>::commit_register(int reg, uint8_t value) {
case 8:
LOG("TODO: Yamaha VRAM organisation, sprite disable, etc; " << PADHEX(2) << +value);
Storage<personality>::sprites_enabled_ = !(value & 0x02);
// b7: "1 = input on colour bus, enable mouse; 1 = output on colour bus, disable mouse" [documentation clearly in error]
// b6: 1 = enable light pen
// b5: sets the colour of code 0 to the colour of the palette (???)
@ -778,12 +788,17 @@ void Base<personality>::commit_register(int reg, uint8_t value) {
case 11: install_field<15>(sprite_attribute_table_address_, value); break;
case 12:
LOG("TODO: Yamaha text and background blink colour; " << PADHEX(2) << +value);
Storage<personality>::blink_text_colour_ = value >> 4;
Storage<personality>::blink_background_colour_ = value & 0xf;
// as per register 7, but in blink mode.
break;
case 13:
LOG("TODO: Yamaha blink display times; " << PADHEX(2) << +value);
Storage<personality>::blink_periods_ = value;
if(!value) {
Storage<personality>::in_blink_ = 0;
}
// b0b3: display time for odd page;
// b4b7: display time for even page.
break;

View File

@ -527,7 +527,7 @@ template <Personality personality> struct Base: public Storage<personality> {
// Output serialisers.
void draw_tms_character(int start, int end);
void draw_tms_text(int start, int end);
template <bool apply_blink> void draw_tms_text(int start, int end);
void draw_sms(int start, int end, uint32_t cram_dot);
template<ScreenMode mode> void draw_yamaha(LineBuffer &, int start, int end);

View File

@ -105,19 +105,32 @@ void Base<personality>::draw_tms_character(int start, int end) {
}
template <Personality personality>
template <bool apply_blink>
void Base<personality>::draw_tms_text(int start, int end) {
LineBuffer &line_buffer = line_buffers_[output_pointer_.row];
const uint32_t colours[2] = { palette()[background_colour_], palette()[text_colour_] };
uint32_t colours[2][2] = {
{palette()[background_colour_], palette()[text_colour_]},
{0, 0}
};
if constexpr (apply_blink) {
colours[1][0] = palette()[Storage<personality>::blink_background_colour_];
colours[1][1] = palette()[Storage<personality>::blink_text_colour_];
}
const int shift = start % 6;
int byte_column = start / 6;
int pattern = Numeric::bit_reverse(line_buffer.characters.shapes[byte_column]) >> shift;
int pixels_left = end - start;
int length = std::min(pixels_left, 6 - shift);
int flag = 0;
if constexpr (apply_blink) {
flag = (line_buffer.characters.flags[byte_column >> 3] >> ((byte_column & 7) ^ 7)) & Storage<personality>::in_blink_;
}
while(true) {
pixels_left -= length;
for(int c = 0; c < length; ++c) {
pixel_target_[c] = colours[pattern&0x01];
pixel_target_[c] = colours[flag][(pattern&0x01)];
pattern >>= 1;
}
pixel_target_ += length;
@ -126,6 +139,9 @@ void Base<personality>::draw_tms_text(int start, int end) {
length = std::min(6, pixels_left);
byte_column++;
pattern = Numeric::bit_reverse(line_buffer.characters.shapes[byte_column]);
if constexpr (apply_blink) {
flag = (line_buffer.characters.flags[byte_column >> 3] >> ((byte_column & 7) ^ 7)) & Storage<personality>::in_blink_;
}
}
}
@ -170,14 +186,14 @@ void Base<personality>::draw_sms(int start, int end, uint32_t cram_dot) {
int length = std::min(pixels_left, 8 - shift);
pattern = *reinterpret_cast<const uint32_t *>(line_buffer.tiles.patterns[byte_column]);
if(line_buffer.characters.flags[byte_column]&2)
if(line_buffer.tiles.flags[byte_column]&2)
pattern >>= shift;
else
pattern <<= shift;
while(true) {
const int palette_offset = (line_buffer.characters.flags[byte_column]&0x18) << 1;
if(line_buffer.characters.flags[byte_column]&2) {
const int palette_offset = (line_buffer.tiles.flags[byte_column]&0x18) << 1;
if(line_buffer.tiles.flags[byte_column]&2) {
for(int c = 0; c < length; ++c) {
colour_buffer[tile_offset] =
((pattern_index[3] & 0x01) << 3) |
@ -313,33 +329,6 @@ void Base<personality>::draw_yamaha(LineBuffer &buffer, int start, int end) {
return;
}
if constexpr (mode == ScreenMode::YamahaText80) {
const uint32_t primary_colours[2] = { palette()[background_colour_], palette()[text_colour_] };
// const uint32_t inverse_colours[2] = { palette()[background_colour_], palette()[text_colour_] }; // TODO.
start >>= 1;
end >>= 1;
const int shift = start % 6;
int byte_column = start / 6;
int pattern = Numeric::bit_reverse(buffer.characters.shapes[byte_column]) >> shift;
int pixels_left = end - start;
int length = std::min(pixels_left, 6 - shift);
while(true) {
pixels_left -= length;
for(int c = 0; c < length; ++c) {
pixel_target_[c] = primary_colours[pattern&0x01]; // TODO.
pattern >>= 1;
}
pixel_target_ += length;
if(!pixels_left) break;
length = std::min(6, pixels_left);
byte_column++;
pattern = Numeric::bit_reverse(buffer.characters.shapes[byte_column]);
}
}
}
template <Personality personality>
@ -350,9 +339,9 @@ void Base<personality>::draw_yamaha(int start, int end) {
if constexpr (is_yamaha_vdp(personality)) {
switch(line_buffer.screen_mode) {
// These modes look the same as on the TMS.
case ScreenMode::Text: draw_tms_text(start >> 2, end >> 2); break;
case ScreenMode::Text: draw_tms_text<false>(start >> 2, end >> 2); break;
case ScreenMode::YamahaText80: draw_tms_text<true>(start >> 1, end >> 1); break;
Dispatch(YamahaText80);
Dispatch(YamahaGraphics3);
Dispatch(YamahaGraphics4);
Dispatch(YamahaGraphics5);

View File

@ -504,7 +504,7 @@ template<ScreenMode mode> void Base<personality>::fetch_yamaha(LineBuffer &line_
case ScreenMode::YamahaText80: {
const auto column = AddressT(Storage<personality>::data_block_ >> 3);
const AddressT address = colour_table_address_ & (0x1fe00 | size_t(y >> 3) * 10);
line_buffer.characters.flags[column] = ram_[address];
line_buffer.characters.flags[column] = ram_[address + column];
} break;
default: break;

View File

@ -25,7 +25,7 @@ template <Personality personality, typename Enable = void> struct Storage {
template <> struct Storage<Personality::TMS9918A> {
using AddressT = uint16_t;
void begin_line(ScreenMode, bool, bool) {}
void begin_line(ScreenMode, bool) {}
};
// Yamaha-specific storage.
@ -91,8 +91,20 @@ template <Personality personality> struct Storage<personality, std::enable_if_t<
int data_block_ = 0;
int sprite_block_ = 0;
// Text blink colours.
uint8_t blink_text_colour_ = 0;
uint8_t blink_background_colour_ = 0;
// Blink state (which is also affects even/odd page display in applicable modes).
int in_blink_ = 1;
uint8_t blink_periods_ = 0;
uint8_t blink_counter_ = 0;
// Sprite collection state.
bool sprites_enabled_ = true;
/// Resets line-ephemeral state for a new line.
void begin_line(ScreenMode mode, bool is_refresh, bool sprites_enabled) {
void begin_line(ScreenMode mode, bool is_refresh) {
// TODO: reinstate upon completion of the Yamaha pipeline.
// assert(mode < ScreenMode::YamahaText80 || next_event_ == nullptr || next_event_->offset == 1368);
@ -408,15 +420,16 @@ template <Personality personality> struct Storage<personality, std::enable_if_t<
return StandardGenerators::external_every_eight(grauw_index - 166);
}
if(grauw_index >= 182 && grauw_index < 1236) {
if(grauw_index >= 182 && grauw_index < 1238) {
const int offset = grauw_index - 182;
const int block = offset / 32;
const int sub_block = offset & 31;
switch(sub_block) {
case 0: if(block > 0) return Event::Type::Name;
case 6: if((sub_block & 3) != 3) return Event::Type::External;;
case 12: if(block > 0) return Event::Type::Pattern;
case 18: if(block > 0) return Event::Type::Colour;
case 6: if((sub_block & 3) != 3) return Event::Type::External;
case 12: if(block < 32) return Event::Type::SpriteY;
case 18: if(block > 0) return Event::Type::Pattern;
case 24: if(block > 0) return Event::Type::Colour;
}
}
@ -463,7 +476,7 @@ template <Personality personality> struct Storage<personality, std::enable_if_t<
AddressT sprite_attribute_table_address_;
AddressT sprite_generator_table_address_;
void begin_line(ScreenMode, bool, bool) {}
void begin_line(ScreenMode, bool) {}
};
}