mirror of
https://github.com/TomHarte/CLK.git
synced 2025-02-03 22:33:29 +00:00
Consolidate text output and support blinking; add sprites-enabled flag.
This commit is contained in:
parent
9b71f42375
commit
3f2a5929a3
@ -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;
|
||||
}
|
||||
|
||||
// b0–b3: display time for odd page;
|
||||
// b4–b7: display time for even page.
|
||||
break;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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) {}
|
||||
};
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user