diff --git a/Components/SAA5050/SAA5050.cpp b/Components/SAA5050/SAA5050.cpp index 829b688d6..1f3550c9d 100644 --- a/Components/SAA5050/SAA5050.cpp +++ b/Components/SAA5050/SAA5050.cpp @@ -7,3 +7,157 @@ // #include "SAA5050.hpp" +#include + +namespace { +// SAA5050 font, padded out to one byte per row. The least-significant five bits of each byte +// are the meaningful pixels for that row, with the LSB being on the right. +constexpr uint8_t font[][10] = { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, // Character 32. + {0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x00, 0x04, 0x00, 0x00, }, + {0x00, 0x0a, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, + {0x00, 0x06, 0x09, 0x08, 0x1c, 0x08, 0x08, 0x1f, 0x00, 0x00, }, + {0x00, 0x0e, 0x15, 0x14, 0x0e, 0x05, 0x15, 0x0e, 0x00, 0x00, }, + {0x00, 0x18, 0x19, 0x02, 0x04, 0x08, 0x13, 0x03, 0x00, 0x00, }, + {0x00, 0x08, 0x14, 0x14, 0x08, 0x15, 0x12, 0x0d, 0x00, 0x00, }, + {0x00, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, + {0x00, 0x02, 0x04, 0x08, 0x08, 0x08, 0x04, 0x02, 0x00, 0x00, }, + {0x00, 0x08, 0x04, 0x02, 0x02, 0x02, 0x04, 0x08, 0x00, 0x00, }, + {0x00, 0x04, 0x15, 0x0e, 0x04, 0x0e, 0x15, 0x04, 0x00, 0x00, }, + {0x00, 0x00, 0x04, 0x04, 0x1f, 0x04, 0x04, 0x00, 0x00, 0x00, }, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x08, 0x00, }, + {0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, }, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, }, + {0x00, 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x00, 0x00, 0x00, }, + {0x00, 0x04, 0x0a, 0x11, 0x11, 0x11, 0x0a, 0x04, 0x00, 0x00, }, + {0x00, 0x04, 0x0c, 0x04, 0x04, 0x04, 0x04, 0x0e, 0x00, 0x00, }, + {0x00, 0x0e, 0x11, 0x01, 0x06, 0x08, 0x10, 0x1f, 0x00, 0x00, }, + {0x00, 0x1f, 0x01, 0x02, 0x06, 0x01, 0x11, 0x0e, 0x00, 0x00, }, + {0x00, 0x02, 0x06, 0x0a, 0x12, 0x1f, 0x02, 0x02, 0x00, 0x00, }, + {0x00, 0x1f, 0x10, 0x1e, 0x01, 0x01, 0x11, 0x0e, 0x00, 0x00, }, + {0x00, 0x06, 0x08, 0x10, 0x1e, 0x11, 0x11, 0x0e, 0x00, 0x00, }, + {0x00, 0x1f, 0x01, 0x02, 0x04, 0x08, 0x08, 0x08, 0x00, 0x00, }, + {0x00, 0x0e, 0x11, 0x11, 0x0e, 0x11, 0x11, 0x0e, 0x00, 0x00, }, + {0x00, 0x0e, 0x11, 0x11, 0x0f, 0x01, 0x02, 0x0c, 0x00, 0x00, }, + {0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, }, + {0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x04, 0x08, 0x00, }, + {0x00, 0x02, 0x04, 0x08, 0x10, 0x08, 0x04, 0x02, 0x00, 0x00, }, + {0x00, 0x00, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, }, + {0x00, 0x08, 0x04, 0x02, 0x01, 0x02, 0x04, 0x08, 0x00, 0x00, }, + {0x00, 0x0e, 0x11, 0x02, 0x04, 0x04, 0x00, 0x04, 0x00, 0x00, }, + {0x00, 0x0e, 0x11, 0x17, 0x15, 0x17, 0x10, 0x0e, 0x00, 0x00, }, + {0x00, 0x04, 0x0a, 0x11, 0x11, 0x1f, 0x11, 0x11, 0x00, 0x00, }, + {0x00, 0x1e, 0x11, 0x11, 0x1e, 0x11, 0x11, 0x1e, 0x00, 0x00, }, + {0x00, 0x0e, 0x11, 0x10, 0x10, 0x10, 0x11, 0x0e, 0x00, 0x00, }, + {0x00, 0x1e, 0x11, 0x11, 0x11, 0x11, 0x11, 0x1e, 0x00, 0x00, }, + {0x00, 0x1f, 0x10, 0x10, 0x1e, 0x10, 0x10, 0x1f, 0x00, 0x00, }, + {0x00, 0x1f, 0x10, 0x10, 0x1e, 0x10, 0x10, 0x10, 0x00, 0x00, }, + {0x00, 0x0e, 0x11, 0x10, 0x10, 0x13, 0x11, 0x0f, 0x00, 0x00, }, + {0x00, 0x11, 0x11, 0x11, 0x1f, 0x11, 0x11, 0x11, 0x00, 0x00, }, + {0x00, 0x0e, 0x04, 0x04, 0x04, 0x04, 0x04, 0x0e, 0x00, 0x00, }, + {0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x11, 0x0e, 0x00, 0x00, }, + {0x00, 0x11, 0x12, 0x14, 0x18, 0x14, 0x12, 0x11, 0x00, 0x00, }, + {0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1f, 0x00, 0x00, }, + {0x00, 0x11, 0x1b, 0x15, 0x15, 0x11, 0x11, 0x11, 0x00, 0x00, }, + {0x00, 0x11, 0x11, 0x19, 0x15, 0x13, 0x11, 0x11, 0x00, 0x00, }, + {0x00, 0x0e, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0e, 0x00, 0x00, }, + {0x00, 0x1e, 0x11, 0x11, 0x1e, 0x10, 0x10, 0x10, 0x00, 0x00, }, + {0x00, 0x0e, 0x11, 0x11, 0x11, 0x15, 0x12, 0x0d, 0x00, 0x00, }, + {0x00, 0x1e, 0x11, 0x11, 0x1e, 0x14, 0x12, 0x11, 0x00, 0x00, }, + {0x00, 0x0e, 0x11, 0x10, 0x0e, 0x01, 0x11, 0x0e, 0x00, 0x00, }, + {0x00, 0x1f, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, }, + {0x00, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0e, 0x00, 0x00, }, + {0x00, 0x11, 0x11, 0x11, 0x0a, 0x0a, 0x04, 0x04, 0x00, 0x00, }, + {0x00, 0x11, 0x11, 0x11, 0x15, 0x15, 0x15, 0x0a, 0x00, 0x00, }, + {0x00, 0x11, 0x11, 0x0a, 0x04, 0x0a, 0x11, 0x11, 0x00, 0x00, }, + {0x00, 0x11, 0x11, 0x0a, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, }, + {0x00, 0x1f, 0x01, 0x02, 0x04, 0x08, 0x10, 0x1f, 0x00, 0x00, }, + {0x00, 0x00, 0x04, 0x08, 0x1f, 0x08, 0x04, 0x00, 0x00, 0x00, }, + {0x00, 0x10, 0x10, 0x10, 0x10, 0x16, 0x01, 0x02, 0x04, 0x07, }, + {0x00, 0x00, 0x04, 0x02, 0x1f, 0x02, 0x04, 0x00, 0x00, 0x00, }, + {0x00, 0x00, 0x04, 0x0e, 0x15, 0x04, 0x04, 0x00, 0x00, 0x00, }, + {0x00, 0x0a, 0x0a, 0x1f, 0x0a, 0x1f, 0x0a, 0x0a, 0x00, 0x00, }, + {0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, }, + {0x00, 0x00, 0x00, 0x0e, 0x01, 0x0f, 0x11, 0x0f, 0x00, 0x00, }, + {0x00, 0x10, 0x10, 0x1e, 0x11, 0x11, 0x11, 0x1e, 0x00, 0x00, }, + {0x00, 0x00, 0x00, 0x0f, 0x10, 0x10, 0x10, 0x0f, 0x00, 0x00, }, + {0x00, 0x01, 0x01, 0x0f, 0x11, 0x11, 0x11, 0x0f, 0x00, 0x00, }, + {0x00, 0x00, 0x00, 0x0e, 0x11, 0x1f, 0x10, 0x0e, 0x00, 0x00, }, + {0x00, 0x02, 0x04, 0x04, 0x0e, 0x04, 0x04, 0x04, 0x00, 0x00, }, + {0x00, 0x00, 0x00, 0x0f, 0x11, 0x11, 0x11, 0x0f, 0x01, 0x0e, }, + {0x00, 0x10, 0x10, 0x1e, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, }, + {0x00, 0x04, 0x00, 0x0c, 0x04, 0x04, 0x04, 0x0e, 0x00, 0x00, }, + {0x00, 0x04, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08, }, + {0x00, 0x08, 0x08, 0x09, 0x0a, 0x0c, 0x0a, 0x09, 0x00, 0x00, }, + {0x00, 0x0c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x0e, 0x00, 0x00, }, + {0x00, 0x00, 0x00, 0x1a, 0x15, 0x15, 0x15, 0x15, 0x00, 0x00, }, + {0x00, 0x00, 0x00, 0x1e, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, }, + {0x00, 0x00, 0x00, 0x0e, 0x11, 0x11, 0x11, 0x0e, 0x00, 0x00, }, + {0x00, 0x00, 0x00, 0x1e, 0x11, 0x11, 0x11, 0x1e, 0x10, 0x10, }, + {0x00, 0x00, 0x00, 0x0f, 0x11, 0x11, 0x11, 0x0f, 0x01, 0x01, }, + {0x00, 0x00, 0x00, 0x0b, 0x0c, 0x08, 0x08, 0x08, 0x00, 0x00, }, + {0x00, 0x00, 0x00, 0x0f, 0x10, 0x0e, 0x01, 0x1e, 0x00, 0x00, }, + {0x00, 0x04, 0x04, 0x0e, 0x04, 0x04, 0x04, 0x02, 0x00, 0x00, }, + {0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x0f, 0x00, 0x00, }, + {0x00, 0x00, 0x00, 0x11, 0x11, 0x0a, 0x0a, 0x04, 0x00, 0x00, }, + {0x00, 0x00, 0x00, 0x11, 0x11, 0x15, 0x15, 0x0a, 0x00, 0x00, }, + {0x00, 0x00, 0x00, 0x11, 0x0a, 0x04, 0x0a, 0x11, 0x00, 0x00, }, + {0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x0f, 0x01, 0x0e, }, + {0x00, 0x00, 0x00, 0x1f, 0x02, 0x04, 0x08, 0x1f, 0x00, 0x00, }, + {0x00, 0x10, 0x10, 0x10, 0x10, 0x11, 0x03, 0x05, 0x07, 0x01, }, + {0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x00, 0x00, }, + {0x00, 0x18, 0x04, 0x18, 0x04, 0x19, 0x03, 0x05, 0x07, 0x01, }, + {0x00, 0x00, 0x04, 0x00, 0x1f, 0x00, 0x04, 0x00, 0x00, 0x00, }, + {0x00, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x00, 0x00, }, +}; +} + +using namespace Mullard; + +void SAA5050Serialiser::begin_frame() { + line_ = -1; + row_ = 0; +} + +void SAA5050Serialiser::begin_line() { + ++line_; + if(line_ == 20) { + line_ = 0; + ++row_; + } + + output_.alpha = 0x7; + output_.background = 0x0; + has_output_ = false; +} + +bool SAA5050Serialiser::has_output() const { + return has_output_; +} + +SAA5050Serialiser::Output SAA5050Serialiser::output() { + has_output_ = false; + return output_; +} + +void SAA5050Serialiser::add(const uint8_t c) { + has_output_ = true; + + const uint8_t masked_c = c & 0x7f; + if(masked_c < 32) { + // TODO: all control characters! + output_.pixels = 0; + return; + } + + // TODO: proper scaling! + const uint8_t source = font[c - 32][line_ >> 1]; + output_.pixels = uint16_t( + ((source & 0x01) ? 0xb0000'0000'0011 : 0) | + ((source & 0x02) ? 0xb0000'0000'1100 : 0) | + ((source & 0x04) ? 0xb0000'0011'0000 : 0) | + ((source & 0x08) ? 0xb0000'1100'0000 : 0) | + ((source & 0x10) ? 0xb0011'0000'0000 : 0) | + ((source & 0x20) ? 0xb1100'0000'0000 : 0) + ); +} diff --git a/Components/SAA5050/SAA5050.hpp b/Components/SAA5050/SAA5050.hpp index d791188f8..551387ab7 100644 --- a/Components/SAA5050/SAA5050.hpp +++ b/Components/SAA5050/SAA5050.hpp @@ -7,3 +7,35 @@ // #pragma once + +#include + +namespace Mullard { + +struct SAA5050Serialiser { +public: + void begin_frame(); + void begin_line(); + + void add(uint8_t); + + struct Output { + // The low twelve bits of this word provide 1bpp pixels. + uint16_t pixels; + + // Colours for set and background pixels. + uint8_t alpha; + uint8_t background; + }; + bool has_output() const; + Output output(); + +private: + int row_, line_; + Output output_; + bool has_output_ = false; + + // TODO: more state. Graphics mode only, probably? +}; + +}