mirror of
https://github.com/TomHarte/CLK.git
synced 2024-12-27 01:31:42 +00:00
Merge pull request #541 from TomHarte/Annunciator3
Implements the two undocumented annunciator 3 graphics modes
This commit is contained in:
commit
5a5fc1ae1a
@ -534,7 +534,7 @@ template <Analyser::Static::AppleII::Target::Model model> class ConcreteMachine:
|
||||
#undef IIeSwitchRead
|
||||
|
||||
case 0xc07f:
|
||||
if(is_iie()) *value = (*value & 0x7f) | (video_->get_double_high_resolution() ? 0x80 : 0x00);
|
||||
if(is_iie()) *value = (*value & 0x7f) | (video_->get_annunciator_3() ? 0x80 : 0x00);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
@ -611,7 +611,7 @@ template <Analyser::Static::AppleII::Target::Model model> class ConcreteMachine:
|
||||
analogue_charge_ = 0.0f;
|
||||
} break;
|
||||
|
||||
/* Read-write switches. */
|
||||
/* Switches triggered by reading or writing. */
|
||||
case 0xc050:
|
||||
case 0xc051:
|
||||
update_video();
|
||||
@ -636,7 +636,7 @@ template <Analyser::Static::AppleII::Target::Model model> class ConcreteMachine:
|
||||
case 0xc05f:
|
||||
if(is_iie()) {
|
||||
update_video();
|
||||
video_->set_double_high_resolution(!(address&1));
|
||||
video_->set_annunciator_3(!(address&1));
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -131,15 +131,16 @@ bool VideoBase::get_high_resolution() {
|
||||
return set_high_resolution_;
|
||||
}
|
||||
|
||||
void VideoBase::set_double_high_resolution(bool double_high_resolution) {
|
||||
set_double_high_resolution_ = double_high_resolution;
|
||||
void VideoBase::set_annunciator_3(bool annunciator_3) {
|
||||
set_annunciator_3_ = annunciator_3;
|
||||
deferrer_.defer(Cycles(2), [=] {
|
||||
double_high_resolution_ = double_high_resolution;
|
||||
annunciator_3_ = annunciator_3;
|
||||
high_resolution_mask_ = annunciator_3_ ? 0x7f : 0xff;
|
||||
});
|
||||
}
|
||||
|
||||
bool VideoBase::get_double_high_resolution() {
|
||||
return set_double_high_resolution_;
|
||||
bool VideoBase::get_annunciator_3() {
|
||||
return set_annunciator_3_;
|
||||
}
|
||||
|
||||
void VideoBase::set_character_rom(const std::vector<uint8_t> &character_rom) {
|
||||
@ -242,6 +243,20 @@ void VideoBase::output_low_resolution(uint8_t *target, const uint8_t *const sour
|
||||
}
|
||||
}
|
||||
|
||||
void VideoBase::output_fat_low_resolution(uint8_t *target, const uint8_t *const source, size_t length, int column, int row) const {
|
||||
const int row_shift = row&4;
|
||||
for(size_t c = 0; c < length; ++c) {
|
||||
// Fat low-resolution mode appears not to do anything to try to make odd and
|
||||
// even columns compatible.
|
||||
target[0] = target[1] = target[8] = target[9] = (source[c] >> row_shift) & 1;
|
||||
target[2] = target[3] = target[10] = target[11] = (source[c] >> row_shift) & 2;
|
||||
target[4] = target[5] = target[12] = target[13] = (source[c] >> row_shift) & 4;
|
||||
target[6] = target[7] = (source[c] >> row_shift) & 8;
|
||||
graphics_carry_ = (source[c] >> row_shift) & 4;
|
||||
target += 14;
|
||||
}
|
||||
}
|
||||
|
||||
void VideoBase::output_double_low_resolution(uint8_t *target, const uint8_t *const source, const uint8_t *const auxiliary_source, size_t length, int column, int row) const {
|
||||
const int row_shift = row&4;
|
||||
for(size_t c = 0; c < length; ++c) {
|
||||
@ -276,7 +291,9 @@ void VideoBase::output_high_resolution(uint8_t *target, const uint8_t *const sou
|
||||
for(size_t c = 0; c < length; ++c) {
|
||||
// High resolution graphics shift out LSB to MSB, optionally with a delay of half a pixel.
|
||||
// If there is a delay, the previous output level is held to bridge the gap.
|
||||
if(source[c] & 0x80) {
|
||||
// Delays may be ignored on a IIe if Annunciator 3 is set; that's the state that
|
||||
// high_resolution_mask_ models.
|
||||
if(source[c] & high_resolution_mask_ & 0x80) {
|
||||
target[0] = graphics_carry_;
|
||||
target[1] = target[2] = source[c] & 0x01;
|
||||
target[3] = target[4] = source[c] & 0x02;
|
||||
|
@ -128,18 +128,19 @@ class VideoBase {
|
||||
bool get_high_resolution();
|
||||
|
||||
/*!
|
||||
Setter for DHIRES ($C05E/$C05F; triggers on write only).
|
||||
Setter for annunciator 3.
|
||||
|
||||
* On: turn on double-high resolution.
|
||||
* Off: turn off double-high resolution.
|
||||
* On: turn on annunciator 3.
|
||||
* Off: turn off annunciator 3.
|
||||
|
||||
DHIRES doesn't exist on a II/II+. On the IIe there is another
|
||||
register usually grouped with the graphics setters called IOUDIS
|
||||
that affects visibility of this switch. But it has no effect on
|
||||
video, so it's not modelled by this class.
|
||||
This exists on both the II/II+ and the IIe, but has no effect on
|
||||
video on the older machines. It's intended to be used on the IIe
|
||||
to confirm double-high resolution mode but has side effects in
|
||||
selecting mixed mode output and discarding high-resolution
|
||||
delay bits.
|
||||
*/
|
||||
void set_double_high_resolution(bool);
|
||||
bool get_double_high_resolution();
|
||||
void set_annunciator_3(bool);
|
||||
bool get_annunciator_3();
|
||||
|
||||
// Setup for text mode.
|
||||
void set_character_rom(const std::vector<uint8_t> &);
|
||||
@ -158,14 +159,15 @@ class VideoBase {
|
||||
|
||||
// Enumerates all Apple II and IIe display modes.
|
||||
enum class GraphicsMode {
|
||||
LowRes = 0,
|
||||
DoubleLowRes,
|
||||
Text = 0,
|
||||
DoubleText,
|
||||
HighRes,
|
||||
DoubleHighRes,
|
||||
Text,
|
||||
DoubleText,
|
||||
LowRes,
|
||||
DoubleLowRes,
|
||||
FatLowRes
|
||||
};
|
||||
bool is_text_mode(GraphicsMode m) { return m >= GraphicsMode::Text; }
|
||||
bool is_text_mode(GraphicsMode m) { return m <= GraphicsMode::DoubleText; }
|
||||
bool is_double_mode(GraphicsMode m) { return !!(static_cast<int>(m)&1); }
|
||||
|
||||
// Various soft-switch values.
|
||||
@ -176,13 +178,14 @@ class VideoBase {
|
||||
bool text_ = true, set_text_ = true;
|
||||
bool mixed_ = false, set_mixed_ = false;
|
||||
bool high_resolution_ = false, set_high_resolution_ = false;
|
||||
bool double_high_resolution_ = false, set_double_high_resolution_ = false;
|
||||
bool annunciator_3_ = false, set_annunciator_3_ = false;
|
||||
|
||||
// Graphics carry is the final level output in a fetch window;
|
||||
// it carries on into the next if it's high resolution with
|
||||
// the delay bit set.
|
||||
mutable uint8_t graphics_carry_ = 0;
|
||||
bool was_double_ = false;
|
||||
uint8_t high_resolution_mask_ = 0xff;
|
||||
|
||||
// This holds a copy of the character ROM. The regular character
|
||||
// set is assumed to be in the first 64*8 bytes; the alternative
|
||||
@ -236,6 +239,14 @@ class VideoBase {
|
||||
*/
|
||||
void output_double_high_resolution(uint8_t *target, const uint8_t *source, const uint8_t *auxiliary_source, size_t length) const;
|
||||
|
||||
/*!
|
||||
Outputs 40-column "fat low resolution" graphics to @c target, drawing @c length columns from @c source.
|
||||
|
||||
Fat low-resolution mode is like regular low-resolution mode except that data is shifted out on the 7M
|
||||
clock rather than the 14M.
|
||||
*/
|
||||
void output_fat_low_resolution(uint8_t *target, const uint8_t *source, size_t length, int column, int row) const;
|
||||
|
||||
// Maintain a ClockDeferrer for delayed mode switches.
|
||||
ClockDeferrer<Cycles> deferrer_;
|
||||
};
|
||||
@ -366,6 +377,7 @@ template <class BusHandler, bool is_iie> class Video: public VideoBase {
|
||||
case GraphicsMode::Text:
|
||||
case GraphicsMode::DoubleText:
|
||||
case GraphicsMode::LowRes:
|
||||
case GraphicsMode::FatLowRes:
|
||||
case GraphicsMode::DoubleLowRes: {
|
||||
const uint16_t text_address = static_cast<uint16_t>(((video_page()+1) * 0x400) + row_address);
|
||||
fetch_address = static_cast<uint16_t>(text_address + column_);
|
||||
@ -439,6 +451,15 @@ template <class BusHandler, bool is_iie> class Video: public VideoBase {
|
||||
pixel_row);
|
||||
break;
|
||||
|
||||
case GraphicsMode::FatLowRes:
|
||||
output_fat_low_resolution(
|
||||
&pixel_pointer_[pixel_start * 14 + 7],
|
||||
&base_stream_[static_cast<size_t>(pixel_start)],
|
||||
static_cast<size_t>(pixel_end - pixel_start),
|
||||
pixel_start,
|
||||
pixel_row);
|
||||
break;
|
||||
|
||||
case GraphicsMode::DoubleLowRes:
|
||||
output_double_low_resolution(
|
||||
&pixel_pointer_[pixel_start * 14],
|
||||
@ -539,14 +560,16 @@ template <class BusHandler, bool is_iie> class Video: public VideoBase {
|
||||
}
|
||||
|
||||
GraphicsMode graphics_mode(int row) {
|
||||
if(text_) return columns_80_ ? GraphicsMode::DoubleText : GraphicsMode::Text;
|
||||
if(mixed_ && row >= 160 && row < 192) {
|
||||
return (columns_80_ || double_high_resolution_) ? GraphicsMode::DoubleText : GraphicsMode::Text;
|
||||
}
|
||||
if(
|
||||
text_ ||
|
||||
(mixed_ && row >= 160 && row < 192)
|
||||
) return columns_80_ ? GraphicsMode::DoubleText : GraphicsMode::Text;
|
||||
if(high_resolution_) {
|
||||
return double_high_resolution_ ? GraphicsMode::DoubleHighRes : GraphicsMode::HighRes;
|
||||
return (annunciator_3_ && columns_80_) ? GraphicsMode::DoubleHighRes : GraphicsMode::HighRes;
|
||||
} else {
|
||||
return double_high_resolution_ ? GraphicsMode::DoubleLowRes : GraphicsMode::LowRes;
|
||||
if(columns_80_) return GraphicsMode::DoubleLowRes;
|
||||
if(annunciator_3_) return GraphicsMode::FatLowRes;
|
||||
return GraphicsMode::LowRes;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user