1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-25 16:31:42 +00:00

Start mangling towards pixel output.

This commit is contained in:
Thomas Harte 2023-12-06 10:30:30 -05:00
parent d88c7ae148
commit c5aa3fc75c

View File

@ -97,12 +97,17 @@ class CGA {
control_ = control;
if(control & 0x2) {
mode_ = Mode::Pixels;
clock_divider = 1 + !(control & 0x10);
mode_ = (control & 0x10) ? Mode::Pixels640 : Mode::Pixels320;
} else {
mode_ = Mode::Text;
clock_divider = 1 + !(control & 0x01);
}
// TODO: I think I need a separate clock divider, which affects the input to the CRTC,
// and an output multiplier, to set how many pixels are generated per CRTC tick.
//
// 640px mode generates 16 pixels per tick, all the other modes generate 8.
// The clock is divided by 1 in all 80-column text mode, 2 in all other modes.
clock_divider = 1 + !(control & 0x01);
}
uint8_t control() {
@ -150,6 +155,54 @@ class CGA {
pixel_pointer[4] = pixel_pointer[5] = pixel_pointer[6] = pixel_pointer[7] =
pixel_pointer[8] = 0x3f; // i.e. white.
} else {
if(mode_ == Mode::Text) {
serialise_text(state);
} else {
serialise_pixels(state);
}
}
pixel_pointer += 8;
}
}
// Advance.
count += 8;
// Output pixel row prematurely if storage is exhausted.
if(output_state == OutputState::Pixels && pixel_pointer == pixels + DefaultAllocationSize) {
flush_pixels();
count = 0;
}
}
void perform_bus_cycle_phase2(const Motorola::CRTC::BusState &) {}
void flush_pixels() {
crt.output_data(count * pixels_divider, size_t(count));
pixels = pixel_pointer = nullptr;
}
void serialise_pixels(const Motorola::CRTC::BusState &state) {
// This is what I think is happenings:
//
// Refresh address is still shifted left one and two bytes are fetched, just as if it were
// character code + attributes except that these are two bytes worth of graphics.
//
// Meanwhile, row address is used to invent a 15th address line.
const uint8_t bitmap = ram[((state.refresh_address << 1) + (state.row_address << 13)) & 0x3fff];
// const uint8_t bitmap = ram[(state.refresh_address + (state.row_address << 13)) & 0x3fff];
// Better than nothing...
pixel_pointer[0] =
pixel_pointer[1] = (bitmap & 0xc0) >> 6;
pixel_pointer[2] =
pixel_pointer[3] = (bitmap & 0x30) >> 4;
pixel_pointer[4] =
pixel_pointer[5] = (bitmap & 0x0c) >> 2;
pixel_pointer[6] =
pixel_pointer[7] = (bitmap & 0x03) >> 0;
}
void serialise_text(const Motorola::CRTC::BusState &state) {
const uint8_t attributes = ram[((state.refresh_address << 1) + 1) & 0xfff];
const uint8_t glyph = ram[((state.refresh_address << 1) + 0) & 0xfff];
const uint8_t row = font[(glyph * 8) + state.row_address];
@ -185,25 +238,6 @@ class CGA {
pixel_pointer[6] = (row & 0x02) ? colours[1] : colours[0];
pixel_pointer[7] = (row & 0x01) ? colours[1] : colours[0];
}
pixel_pointer += 8;
}
}
// Advance.
count += 8;
// Output pixel row prematurely if storage is exhausted.
if(output_state == OutputState::Pixels && pixel_pointer == pixels + DefaultAllocationSize) {
flush_pixels();
count = 0;
}
}
void perform_bus_cycle_phase2(const Motorola::CRTC::BusState &) {}
void flush_pixels() {
crt.output_data(count * pixels_divider, size_t(count));
pixels = pixel_pointer = nullptr;
}
Outputs::CRT::CRT crt;
@ -223,7 +257,7 @@ class CGA {
uint8_t control_ = 0;
enum class Mode {
Pixels, Text,
Pixels640, Pixels320, Text,
} mode_ = Mode::Text;
int clock_divider = 1;
} outputter_;