459 lines
16 KiB
C++
459 lines
16 KiB
C++
//
|
|
// 6847.cpp
|
|
// Clock Signal
|
|
//
|
|
// Created by Thomas Harte on 04/05/2026.
|
|
// Copyright © 2026 Thomas Harte. All rights reserved.
|
|
//
|
|
|
|
#include "6847.hpp"
|
|
|
|
#include <cstdint>
|
|
|
|
namespace {
|
|
static constexpr uint8_t font[64][12] = {
|
|
{ 0x00, 0x00, 0x00, 0x1c, 0x22, 0x02, 0x1a, 0x2a, 0x2a, 0x1c, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x08, 0x14, 0x22, 0x22, 0x3e, 0x22, 0x22, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x3c, 0x12, 0x12, 0x1c, 0x12, 0x12, 0x3c, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x1c, 0x22, 0x20, 0x20, 0x20, 0x22, 0x1c, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x3c, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3c, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x3e, 0x20, 0x20, 0x3c, 0x20, 0x20, 0x3e, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x3e, 0x20, 0x20, 0x3c, 0x20, 0x20, 0x20, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x1e, 0x20, 0x20, 0x26, 0x22, 0x22, 0x1e, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x3e, 0x22, 0x22, 0x22, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x1c, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1c, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x22, 0x22, 0x1c, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x22, 0x24, 0x28, 0x30, 0x28, 0x24, 0x22, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3e, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x22, 0x36, 0x2a, 0x2a, 0x22, 0x22, 0x22, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x22, 0x32, 0x2a, 0x26, 0x22, 0x22, 0x22, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x3e, 0x22, 0x22, 0x22, 0x22, 0x22, 0x3e, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x3c, 0x22, 0x22, 0x3c, 0x20, 0x20, 0x20, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x1c, 0x22, 0x22, 0x22, 0x2a, 0x24, 0x1a, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x3c, 0x22, 0x22, 0x3c, 0x28, 0x24, 0x22, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x1c, 0x22, 0x10, 0x08, 0x04, 0x22, 0x1c, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1c, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x14, 0x14, 0x08, 0x08, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x2a, 0x2a, 0x36, 0x22, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x22, 0x22, 0x14, 0x08, 0x14, 0x22, 0x22, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x22, 0x22, 0x14, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x3e, 0x02, 0x04, 0x08, 0x10, 0x20, 0x3e, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x38, 0x20, 0x20, 0x20, 0x20, 0x20, 0x38, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x20, 0x20, 0x10, 0x08, 0x04, 0x02, 0x02, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x0e, 0x02, 0x02, 0x02, 0x02, 0x02, 0x0e, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x08, 0x1c, 0x2a, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x3e, 0x10, 0x08, 0x00, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x08, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x14, 0x14, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x14, 0x14, 0x36, 0x00, 0x36, 0x14, 0x14, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x08, 0x1e, 0x20, 0x1c, 0x02, 0x3c, 0x08, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x32, 0x32, 0x04, 0x08, 0x10, 0x26, 0x26, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x10, 0x28, 0x28, 0x10, 0x2a, 0x24, 0x1a, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x08, 0x10, 0x20, 0x20, 0x20, 0x10, 0x08, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x08, 0x04, 0x02, 0x02, 0x02, 0x04, 0x08, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x00, 0x08, 0x1c, 0x3e, 0x1c, 0x08, 0x00, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x3e, 0x08, 0x08, 0x00, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x10, 0x20, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x02, 0x02, 0x04, 0x08, 0x10, 0x20, 0x20, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x18, 0x24, 0x24, 0x24, 0x24, 0x24, 0x18, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x08, 0x18, 0x08, 0x08, 0x08, 0x08, 0x1c, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x1c, 0x22, 0x02, 0x1c, 0x20, 0x20, 0x3e, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x1c, 0x22, 0x02, 0x0c, 0x02, 0x22, 0x1c, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x04, 0x0c, 0x14, 0x3e, 0x04, 0x04, 0x04, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x3e, 0x20, 0x3c, 0x02, 0x02, 0x22, 0x1c, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x1c, 0x20, 0x20, 0x3c, 0x22, 0x22, 0x1c, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x3e, 0x02, 0x04, 0x08, 0x10, 0x20, 0x20, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x1c, 0x22, 0x22, 0x1c, 0x22, 0x22, 0x1c, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x1c, 0x22, 0x22, 0x1e, 0x02, 0x02, 0x1c, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x08, 0x10, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x00, 0x00, },
|
|
{ 0x00, 0x00, 0x00, 0x18, 0x24, 0x04, 0x08, 0x08, 0x00, 0x08, 0x00, 0x00, },
|
|
};
|
|
|
|
|
|
namespace Colours {
|
|
constexpr uint32_t rgb(const uint8_t r, const uint8_t g, const uint8_t b) {
|
|
uint8_t value[] = {
|
|
r, g, b, 0
|
|
};
|
|
return std::bit_cast<uint32_t>(value);
|
|
}
|
|
|
|
//
|
|
// RGB values below sourced from http://www.hcvgm.org/VDG_Colours.html
|
|
//
|
|
constexpr uint32_t text0[] = { rgb(0x10, 0x60, 0x10), rgb(0x28, 0xe0, 0x28) };
|
|
constexpr uint32_t text1[] = { rgb(0xf0, 0xb0, 0x40), rgb(0x80, 0x30, 0x10) };
|
|
|
|
constexpr uint32_t resolution0[] = { rgb(0x10, 0x60, 0x10), rgb(0x28, 0xe0, 0x28) };
|
|
constexpr uint32_t resolution1[] = { rgb(0x00, 0x00, 0x00), rgb(0xf0, 0xf0, 0xf0) };
|
|
|
|
constexpr uint32_t colour0[] = {
|
|
rgb(0x28, 0xe0, 0x28),
|
|
rgb(0xf0, 0xf0, 0x70),
|
|
rgb(0x20, 0x20, 0xd8),
|
|
rgb(0xa8, 0x20, 0x20),
|
|
};
|
|
constexpr uint32_t colour1[] = {
|
|
rgb(0xf0, 0xf0, 0xf0),
|
|
rgb(0x28, 0xa8, 0xa8),
|
|
rgb(0xd3, 0x61, 0xfa),
|
|
rgb(0xf0, 0x88, 0x28),
|
|
};
|
|
|
|
constexpr uint32_t semigraphics[][2] = {
|
|
{ rgb(0x00, 0x00, 0x00), rgb(0x28, 0xe0, 0x28), },
|
|
{ rgb(0x00, 0x00, 0x00), rgb(0xf0, 0xf0, 0x70), },
|
|
{ rgb(0x00, 0x00, 0x00), rgb(0x20, 0x20, 0xd8), },
|
|
{ rgb(0x00, 0x00, 0x00), rgb(0xa8, 0x20, 0x20), },
|
|
{ rgb(0x00, 0x00, 0x00), rgb(0xf0, 0xf0, 0xf0), },
|
|
{ rgb(0x00, 0x00, 0x00), rgb(0x28, 0xa8, 0xa8), },
|
|
{ rgb(0x00, 0x00, 0x00), rgb(0xd3, 0x61, 0xfa), },
|
|
{ rgb(0x00, 0x00, 0x00), rgb(0xf0, 0x88, 0x28), },
|
|
};
|
|
}
|
|
|
|
}
|
|
|
|
using namespace Motorola::MC6847;
|
|
|
|
MC6847Base::MC6847Base(const Outputs::Display::Type display_type) :
|
|
crt_(
|
|
455,
|
|
1,
|
|
display_type,
|
|
Outputs::Display::InputDataType::Red8Green8Blue8
|
|
),
|
|
display_type_(display_type)
|
|
{
|
|
crt_.set_display_type(Outputs::Display::DisplayType::CompositeColour);
|
|
}
|
|
|
|
void MC6847Base::toggle_colour_phase() {
|
|
colour_burst_phase_ ^= 0x80;
|
|
}
|
|
|
|
void MC6847Base::sync_and_burst(const int line_begin, const int line_end) {
|
|
Numeric::if_includes<LineLayout::EndOfColourBurst>(
|
|
line_begin,
|
|
line_end,
|
|
[&] {
|
|
crt_.output_sync(LineLayout::EndOfSync);
|
|
if(display_type_ == Outputs::Display::Type::NTSC60) {
|
|
crt_.output_colour_burst(LineLayout::EndOfColourBurst - LineLayout::EndOfSync, colour_burst_phase_);
|
|
} else {
|
|
crt_.output_default_colour_burst(LineLayout::EndOfColourBurst - LineLayout::EndOfSync);
|
|
}
|
|
}
|
|
);
|
|
}
|
|
|
|
void MC6847Base::pixel_line(const int line_begin, const int line_end) {
|
|
sync_and_burst(line_begin, line_end);
|
|
Numeric::ActionRange<LineLayout::EndOfColourBurst>(line_begin, line_end)
|
|
.until<LineLayout::EndOfLeftBorder>(
|
|
[&](const int begin, const int end) {
|
|
crt_.output_level<uint32_t>(end - begin, border_colour_);
|
|
}
|
|
)
|
|
.then(
|
|
[&] {
|
|
pixels_ = reinterpret_cast<uint32_t *>(crt_.begin_data(256));
|
|
}
|
|
)
|
|
.until<LineLayout::EndOfPixels>(
|
|
[&](const int begin, const int end) {
|
|
if(!pixels_) [[unlikely]] {
|
|
return;
|
|
}
|
|
|
|
const int row = address_.row();
|
|
const int column_begin = (begin - LineLayout::EndOfLeftBorder) >> 3;
|
|
const int column_end = (end - LineLayout::EndOfLeftBorder) >> 3;
|
|
|
|
for(int c = column_begin; c < column_end; c++) {
|
|
const auto mode = line_.columns[c].mode;
|
|
const auto data = line_.columns[c & ~(mode & Mode::Columns16)].data;
|
|
|
|
if(mode & Mode::Graphics) {
|
|
switch(mode & (Mode::BPP2 | Mode::Columns16)) {
|
|
case 0: { // 1bpp, 32-column.
|
|
const uint32_t *const palette =
|
|
mode & Mode::ColourSelect ? Colours::resolution1 : Colours::resolution0;
|
|
|
|
pixels_[0] = palette[(data >> 7) & 1];
|
|
pixels_[1] = palette[(data >> 6) & 1];
|
|
pixels_[2] = palette[(data >> 5) & 1];
|
|
pixels_[3] = palette[(data >> 4) & 1];
|
|
pixels_[4] = palette[(data >> 3) & 1];
|
|
pixels_[5] = palette[(data >> 2) & 1];
|
|
pixels_[6] = palette[(data >> 1) & 1];
|
|
pixels_[7] = palette[(data >> 0) & 1];
|
|
} break;
|
|
|
|
case Mode::Columns16: { // 1bpp, 16-column.
|
|
const uint32_t *const palette =
|
|
mode & Mode::ColourSelect ? Colours::resolution1 : Colours::resolution0;
|
|
|
|
if(c & 1) {
|
|
pixels_[0] =
|
|
pixels_[1] = palette[(data >> 3) & 1];
|
|
pixels_[2] =
|
|
pixels_[3] = palette[(data >> 2) & 1];
|
|
pixels_[4] =
|
|
pixels_[5] = palette[(data >> 1) & 1];
|
|
pixels_[6] =
|
|
pixels_[7] = palette[(data >> 0) & 1];
|
|
} else {
|
|
pixels_[0] =
|
|
pixels_[1] = palette[(data >> 7) & 1];
|
|
pixels_[2] =
|
|
pixels_[3] = palette[(data >> 6) & 1];
|
|
pixels_[4] =
|
|
pixels_[5] = palette[(data >> 5) & 1];
|
|
pixels_[6] =
|
|
pixels_[7] = palette[(data >> 4) & 1];
|
|
}
|
|
} break;
|
|
|
|
case Mode::BPP2: { // 2bpp, 32-column.
|
|
const uint32_t *const palette =
|
|
mode & Mode::ColourSelect ? Colours::colour1 : Colours::colour0;
|
|
|
|
pixels_[0] =
|
|
pixels_[1] = palette[(data >> 6) & 3];
|
|
pixels_[2] =
|
|
pixels_[3] = palette[(data >> 4) & 3];
|
|
pixels_[4] =
|
|
pixels_[5] = palette[(data >> 2) & 3];
|
|
pixels_[6] =
|
|
pixels_[7] = palette[(data >> 0) & 3];
|
|
} break;
|
|
|
|
case Mode::BPP2 | Mode::Columns16: { // 2bpp, 16-column.
|
|
const uint32_t *const palette =
|
|
mode & Mode::ColourSelect ? Colours::colour1 : Colours::colour0;
|
|
|
|
if(c & 1) {
|
|
pixels_[0] =
|
|
pixels_[1] =
|
|
pixels_[2] =
|
|
pixels_[3] = palette[(data >> 2) & 3];
|
|
pixels_[4] =
|
|
pixels_[5] =
|
|
pixels_[6] =
|
|
pixels_[7] = palette[(data >> 0) & 3];
|
|
} else {
|
|
pixels_[0] =
|
|
pixels_[1] =
|
|
pixels_[2] =
|
|
pixels_[3] = palette[(data >> 6) & 3];
|
|
pixels_[4] =
|
|
pixels_[5] =
|
|
pixels_[6] =
|
|
pixels_[7] = palette[(data >> 4) & 3];
|
|
}
|
|
} break;
|
|
|
|
default: __builtin_unreachable();
|
|
}
|
|
} else {
|
|
if(mode & Mode::Semigraphics) {
|
|
const uint32_t *palette;
|
|
uint8_t pixels;
|
|
|
|
if(mode & Mode::ExternalROM) {
|
|
palette = Colours::semigraphics[data >> 6];
|
|
pixels = [&]() -> uint8_t {
|
|
if(row < 4) return data >> 4;
|
|
if(row < 8) return data >> 2;
|
|
return data;
|
|
} ();
|
|
} else {
|
|
palette = Colours::semigraphics[(data >> 4) & 7];
|
|
pixels = row < 6 ? data >> 2 : data;
|
|
}
|
|
|
|
pixels_[0] =
|
|
pixels_[1] =
|
|
pixels_[2] =
|
|
pixels_[3] = palette[(pixels >> 1) & 1];
|
|
pixels_[4] =
|
|
pixels_[5] =
|
|
pixels_[6] =
|
|
pixels_[7] = palette[(pixels >> 0) & 1];
|
|
} else {
|
|
const uint32_t *const palette = mode & Mode::ColourSelect ? Colours::text1 : Colours::text0;
|
|
uint8_t pixels = mode & Mode::Invert ? 0xff : 0x00;
|
|
|
|
if(mode & Mode::ExternalROM) {
|
|
// TODO: external ROM.
|
|
} else {
|
|
pixels ^= font[data & 63][row] ^ (data & 64 ? 0xff : 0x00);
|
|
}
|
|
|
|
pixels_[0] = palette[(pixels >> 7) & 1];
|
|
pixels_[1] = palette[(pixels >> 6) & 1];
|
|
pixels_[2] = palette[(pixels >> 5) & 1];
|
|
pixels_[3] = palette[(pixels >> 4) & 1];
|
|
pixels_[4] = palette[(pixels >> 3) & 1];
|
|
pixels_[5] = palette[(pixels >> 2) & 1];
|
|
pixels_[6] = palette[(pixels >> 1) & 1];
|
|
pixels_[7] = palette[(pixels >> 0) & 1];
|
|
}
|
|
}
|
|
pixels_ += 8;
|
|
}
|
|
}
|
|
)
|
|
.then(
|
|
[&] {
|
|
crt_.output_data(256);
|
|
}
|
|
)
|
|
.until<LineLayout::EndOfLine>(
|
|
[&](const int begin, const int end) {
|
|
crt_.output_level<uint32_t>(end - begin, border_colour_);
|
|
}
|
|
)
|
|
.finally(
|
|
[&] {
|
|
address_.apply_hsync();
|
|
}
|
|
);
|
|
}
|
|
|
|
void MC6847Base::border_line(const int line_begin, const int line_end) {
|
|
sync_and_burst(line_begin, line_end);
|
|
Numeric::clamp<LineLayout::EndOfColourBurst, LineLayout::EndOfLine>(
|
|
line_begin,
|
|
line_end,
|
|
[&](const int begin, const int end) {
|
|
crt_.output_level<uint32_t>(end - begin, border_colour_);
|
|
}
|
|
);
|
|
}
|
|
|
|
void MC6847Base::porch_line(const int, const int end) {
|
|
if(end == LineLayout::EndOfLine) {
|
|
crt_.output_sync(LineLayout::EndOfSync);
|
|
crt_.output_blank(LineLayout::EndOfLine - LineLayout::EndOfSync);
|
|
}
|
|
}
|
|
|
|
void MC6847Base::sync_line(const int, const int end) {
|
|
if(end == LineLayout::EndOfLine) {
|
|
crt_.output_sync(LineLayout::EndOfLine);
|
|
}
|
|
}
|
|
|
|
namespace {
|
|
constexpr auto EndOfHSyncPinOutput = MC6847Base::LineLayout::EndOfBackPorch;
|
|
}
|
|
|
|
bool MC6847Base::hsync(const int column) const {
|
|
return column <= EndOfHSyncPinOutput;
|
|
}
|
|
|
|
Cycles MC6847Base::next_sequence_point(const int column) const {
|
|
if(column < EndOfHSyncPinOutput) return EndOfHSyncPinOutput - column;
|
|
return LineLayout::EndOfLine - column;
|
|
}
|
|
|
|
void MC6847Base::reset() {
|
|
address_.apply_vertical_preload();
|
|
}
|
|
|
|
void MC6847Base::Address::apply_vertical_preload() {
|
|
row_ = 0;
|
|
address_ = 0;
|
|
}
|
|
|
|
void MC6847Base::Address::advance(const int column) {
|
|
address_ += (column & 1) | increment_mask_;
|
|
}
|
|
|
|
void MC6847Base::Address::apply_hsync() {
|
|
++row_;
|
|
if(row_ == target_row_) {
|
|
row_ = 0;
|
|
} else {
|
|
--address_;
|
|
}
|
|
address_ &= line_mask_;
|
|
}
|
|
|
|
void MC6847Base::Address::reset_row() {
|
|
row_ = 0;
|
|
}
|
|
|
|
void MC6847Base::set_mode(
|
|
const bool graphics,
|
|
const bool semigraphics,
|
|
const bool external_rom,
|
|
const bool invert,
|
|
const uint8_t graphics_mode,
|
|
const bool colour_select
|
|
) {
|
|
// "the font row is reset each time the VDG is switched from graphics to text mode".
|
|
if((mode_ & Mode::Graphics) && !graphics) {
|
|
address_.reset_row();
|
|
}
|
|
|
|
mode_ =
|
|
(graphics ? Mode::Graphics : 0) |
|
|
(semigraphics ? Mode::Semigraphics : 0) |
|
|
(external_rom ? Mode::ExternalROM : 0) |
|
|
(invert ? Mode::Invert : 0) |
|
|
(colour_select ? Mode::ColourSelect : 0);;
|
|
|
|
const auto set_32bytes = [&] {
|
|
address_.increment_mask_ = 1;
|
|
address_.line_mask_ = uint16_t(~31);
|
|
};
|
|
const auto set_16bytes = [&] {
|
|
address_.increment_mask_ = 0;
|
|
address_.line_mask_ = uint16_t(~15);
|
|
mode_ |= Mode::Columns16;
|
|
};
|
|
|
|
if(graphics) {
|
|
const auto mode = Mode::GraphicsMode(graphics_mode);
|
|
|
|
if(Mode::is_16column(mode)) {
|
|
set_16bytes();
|
|
} else {
|
|
set_32bytes();
|
|
}
|
|
address_.target_row_ = repeated_rows(mode);
|
|
if(is_2bpp(mode)) {
|
|
mode_ |= Mode::BPP2;
|
|
border_colour_ = colour_select ? Colours::colour1[0] : Colours::colour0[0];
|
|
} else {
|
|
border_colour_ = colour_select ? Colours::resolution1[1] : Colours::resolution0[1];
|
|
}
|
|
} else {
|
|
set_32bytes();
|
|
address_.target_row_ = 12;
|
|
border_colour_ = 0;
|
|
}
|
|
|
|
// TODO: apply my net understanding, which is now this:
|
|
//
|
|
// Alphanumeric modes works pretty much as already implemented with an access to the character ROM,
|
|
// though it obeys the top two bits;
|
|
//
|
|
// Semigraphic modes fetch much like the alphanumeric modes but use the fetched
|
|
// byte as colour + telectext-style pixel data;
|
|
//
|
|
// The graphics modes break down into either 1bpp or 2bpp output, at either 16 or 32 bytes per row.
|
|
}
|