1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-26 23:52:26 +00:00

Merge pull request #539 from TomHarte/40ColumnTextCorruption

Corrects 40-column alternative text mode corruption
This commit is contained in:
Thomas Harte 2018-09-05 10:27:09 -04:00 committed by GitHub
commit 6725ee2190
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 49 additions and 17 deletions

View File

@ -27,6 +27,23 @@ VideoBase::VideoBase(bool is_iie, std::function<void(Cycles)> &&target) :
crt_->set_video_signal(Outputs::CRT::VideoSignal::Composite);
crt_->set_visible_area(Outputs::CRT::Rect(0.118f, 0.122f, 0.77f, 0.77f));
crt_->set_immediate_default_phase(0.0f);
character_zones[0].xor_mask = 0;
character_zones[0].address_mask = 0x3f;
character_zones[1].xor_mask = 0;
character_zones[1].address_mask = 0x3f;
character_zones[2].xor_mask = 0;
character_zones[2].address_mask = 0x3f;
character_zones[3].xor_mask = 0;
character_zones[3].address_mask = 0x3f;
if(is_iie) {
character_zones[0].xor_mask =
character_zones[2].xor_mask =
character_zones[3].xor_mask = 0xff;
character_zones[2].address_mask =
character_zones[3].address_mask = 0xff;
}
}
Outputs::CRT::CRT *VideoBase::get_crt() {
@ -40,6 +57,13 @@ void VideoBase::set_alternative_character_set(bool alternative_character_set) {
set_alternative_character_set_ = alternative_character_set;
deferrer_.defer(Cycles(2), [=] {
alternative_character_set_ = alternative_character_set;
if(alternative_character_set) {
character_zones[1].address_mask = 0xff;
character_zones[1].xor_mask = 0;
} else {
character_zones[1].address_mask = 0x3f;
character_zones[1].xor_mask = flash_mask();
}
});
}
@ -137,18 +161,9 @@ void VideoBase::set_character_rom(const std::vector<uint8_t> &character_rom) {
}
void VideoBase::output_text(uint8_t *target, uint8_t *source, size_t length, size_t pixel_row) const {
const uint8_t inverses[] = {
0xff,
is_iie_ ? static_cast<uint8_t>(0xff) : static_cast<uint8_t>((flash_ / flash_length) * 0xff),
is_iie_ ? static_cast<uint8_t>(0xff) : static_cast<uint8_t>(0x00),
is_iie_ ? static_cast<uint8_t>(0xff) : static_cast<uint8_t>(0x00)
};
const int or_mask = alternative_character_set_ ? 0x100 : 0x000;
const int and_mask = is_iie_ ? ~0 : 0x3f;
for(size_t c = 0; c < length; ++c) {
const int character = (source[c] | or_mask) & and_mask;
const uint8_t xor_mask = inverses[character >> 6];
const int character = source[c] & character_zones[source[c] >> 6].address_mask;
const uint8_t xor_mask = character_zones[source[c] >> 6].xor_mask;
const std::size_t character_address = static_cast<std::size_t>(character << 3) + pixel_row;
const uint8_t character_pattern = character_rom_[character_address] ^ xor_mask;
@ -169,17 +184,20 @@ void VideoBase::output_double_text(uint8_t *target, uint8_t *source, uint8_t *au
for(size_t c = 0; c < length; ++c) {
const std::size_t character_addresses[2] = {
static_cast<std::size_t>(
auxiliary_source[c] << 3
(auxiliary_source[c] & character_zones[auxiliary_source[c] >> 6].address_mask) << 3
) + pixel_row,
static_cast<std::size_t>(
source[c] << 3
) + pixel_row,
(source[c] & character_zones[source[c] >> 6].address_mask) << 3
) + pixel_row
};
const size_t pattern_offset = alternative_character_set_ ? (256*8) : 0;
const uint8_t character_patterns[2] = {
character_rom_[character_addresses[0] + pattern_offset],
character_rom_[character_addresses[1] + pattern_offset],
static_cast<uint8_t>(
character_rom_[character_addresses[0]] ^ character_zones[auxiliary_source[c] >> 6].xor_mask
),
static_cast<uint8_t>(
character_rom_[character_addresses[1]] ^ character_zones[source[c] >> 6].xor_mask
)
};
// The character ROM is output MSB to LSB rather than LSB to MSB.

View File

@ -152,6 +152,9 @@ class VideoBase {
// State affecting logical state.
int row_ = 0, column_ = 0, flash_ = 0;
uint8_t flash_mask() {
return static_cast<uint8_t>((flash_ / flash_length) * 0xff);
}
// Enumerates all Apple II and IIe display modes.
enum class GraphicsMode {
@ -195,6 +198,14 @@ class VideoBase {
bool is_iie_ = false;
static const int flash_length = 8406;
// Describes the current text mode mapping from in-memory character index
// to output character.
struct CharacterMapping {
uint8_t address_mask;
uint8_t xor_mask;
};
CharacterMapping character_zones[4];
/*!
Outputs 40-column text to @c target, using @c length bytes from @c source.
*/
@ -516,6 +527,9 @@ template <class BusHandler, bool is_iie> class Video: public VideoBase {
if(!column_) {
row_ = (row_ + 1) % 262;
flash_ = (flash_ + 1) % (2 * flash_length);
if(!alternative_character_set_) {
character_zones[1].xor_mask = flash_mask();
}
// Add an extra half a colour cycle of blank; this isn't counted in the run_for
// count explicitly but is promised.