1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-12-27 01:31:42 +00:00

Merge pull request #520 from TomHarte/EnhancedIIe

Adds Enhanced IIe emulation.
This commit is contained in:
Thomas Harte 2018-08-11 19:42:47 -04:00 committed by GitHub
commit 10c930a59d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 72 additions and 60 deletions

View File

@ -19,7 +19,8 @@ struct Target: public ::Analyser::Static::Target {
enum class Model {
II,
IIplus,
IIe
IIe,
EnhancedIIe
};
enum class DiskController {
None,

View File

@ -34,7 +34,9 @@
namespace {
template <bool is_iie> class ConcreteMachine:
#define is_iie() ((model == Analyser::Static::AppleII::Target::Model::IIe) || (model == Analyser::Static::AppleII::Target::Model::EnhancedIIe))
template <Analyser::Static::AppleII::Target::Model model> class ConcreteMachine:
public CRTMachine::Machine,
public MediaTarget::Machine,
public KeyboardMachine::Machine,
@ -62,7 +64,7 @@ template <bool is_iie> class ConcreteMachine:
CPU::MOS6502::Processor<ConcreteMachine, false> m6502_;
VideoBusHandler video_bus_handler_;
std::unique_ptr<AppleII::Video::Video<VideoBusHandler, is_iie>> video_;
std::unique_ptr<AppleII::Video::Video<VideoBusHandler, is_iie()>> video_;
int cycles_into_current_line_ = 0;
Cycles cycles_since_video_update_;
@ -179,7 +181,7 @@ template <bool is_iie> class ConcreteMachine:
bool has_language_card_ = true;
void set_language_card_paging() {
uint8_t *const ram = alternative_zero_page_ ? aux_ram_ : ram_;
uint8_t *const rom = is_iie ? &rom_[3840] : rom_.data();
uint8_t *const rom = is_iie() ? &rom_[3840] : rom_.data();
page(0xd0, 0xe0,
language_card_.read ? &ram[language_card_.bank1 ? 0xd000 : 0xc000] : rom,
@ -298,7 +300,7 @@ template <bool is_iie> class ConcreteMachine:
public:
ConcreteMachine(const Analyser::Static::AppleII::Target &target, const ROMMachine::ROMFetcher &rom_fetcher):
m6502_(CPU::MOS6502::Personality::P6502, *this),
m6502_((model == Analyser::Static::AppleII::Target::Model::EnhancedIIe) ? CPU::MOS6502::Personality::P65C02 : CPU::MOS6502::Personality::P6502, *this),
video_bus_handler_(ram_, aux_ram_),
audio_toggle_(audio_queue_),
speaker_(audio_toggle_) {
@ -345,6 +347,11 @@ template <bool is_iie> class ConcreteMachine:
rom_names.push_back("apple2eu-character.rom");
rom_names.push_back("apple2eu.rom");
break;
case Target::Model::EnhancedIIe:
rom_size += 3840;
rom_names.push_back("apple2e-character.rom");
rom_names.push_back("apple2e.rom");
break;
}
const auto roms = rom_fetcher("AppleII", rom_names);
@ -383,7 +390,7 @@ template <bool is_iie> class ConcreteMachine:
}
void setup_output(float aspect_ratio) override {
video_.reset(new AppleII::Video::Video<VideoBusHandler, is_iie>(video_bus_handler_));
video_.reset(new AppleII::Video::Video<VideoBusHandler, is_iie()>(video_bus_handler_));
video_->set_character_rom(character_rom_);
}
@ -422,7 +429,7 @@ template <bool is_iie> class ConcreteMachine:
if(isReadOperation(operation)) *value = read_pages_[address >> 8][address & 0xff];
else if(write_pages_[address >> 8]) write_pages_[address >> 8][address & 0xff] = *value;
if(is_iie && address >= 0xc300 && address < 0xd000) {
if(is_iie() && address >= 0xc300 && address < 0xd000) {
bool internal_c8_rom = internal_c8_rom_;
internal_c8_rom |= ((address >> 8) == 0xc3) && !slot_C3_rom_;
internal_c8_rom &= (address != 0xcfff);
@ -468,7 +475,7 @@ template <bool is_iie> class ConcreteMachine:
*value &= 0x7f;
if(
static_cast<Joystick *>(joysticks_[0].get())->buttons[0] || static_cast<Joystick *>(joysticks_[1].get())->buttons[2] ||
(is_iie && open_apple_is_pressed_)
(is_iie() && open_apple_is_pressed_)
)
*value |= 0x80;
break;
@ -476,7 +483,7 @@ template <bool is_iie> class ConcreteMachine:
*value &= 0x7f;
if(
static_cast<Joystick *>(joysticks_[0].get())->buttons[1] || static_cast<Joystick *>(joysticks_[1].get())->buttons[1] ||
(is_iie && closed_apple_is_pressed_)
(is_iie() && closed_apple_is_pressed_)
)
*value |= 0x80;
break;
@ -498,26 +505,26 @@ template <bool is_iie> class ConcreteMachine:
} break;
// The IIe-only state reads follow...
case 0xc011: if(is_iie) *value = (*value & 0x7f) | (language_card_.bank1 ? 0x80 : 0x00); break;
case 0xc012: if(is_iie) *value = (*value & 0x7f) | (language_card_.read ? 0x80 : 0x00); break;
case 0xc013: if(is_iie) *value = (*value & 0x7f) | (read_auxiliary_memory_ ? 0x80 : 0x00); break;
case 0xc014: if(is_iie) *value = (*value & 0x7f) | (write_auxiliary_memory_ ? 0x80 : 0x00); break;
case 0xc015: if(is_iie) *value = (*value & 0x7f) | (internal_CX_rom_ ? 0x80 : 0x00); break;
case 0xc016: if(is_iie) *value = (*value & 0x7f) | (alternative_zero_page_ ? 0x80 : 0x00); break;
case 0xc017: if(is_iie) *value = (*value & 0x7f) | (slot_C3_rom_ ? 0x80 : 0x00); break;
case 0xc018: if(is_iie) *value = (*value & 0x7f) | (video_->get_80_store() ? 0x80 : 0x00); break;
case 0xc019: if(is_iie) *value = (*value & 0x7f) | (video_->get_is_vertical_blank(cycles_since_video_update_) ? 0x00 : 0x80); break;
case 0xc01a: if(is_iie) *value = (*value & 0x7f) | (video_->get_text() ? 0x80 : 0x00); break;
case 0xc01b: if(is_iie) *value = (*value & 0x7f) | (video_->get_mixed() ? 0x80 : 0x00); break;
case 0xc01c: if(is_iie) *value = (*value & 0x7f) | (video_->get_page2() ? 0x80 : 0x00); break;
case 0xc01d: if(is_iie) *value = (*value & 0x7f) | (video_->get_high_resolution() ? 0x80 : 0x00); break;
case 0xc01e: if(is_iie) *value = (*value & 0x7f) | (video_->get_alternative_character_set() ? 0x80 : 0x00); break;
case 0xc01f: if(is_iie) *value = (*value & 0x7f) | (video_->get_80_columns() ? 0x80 : 0x00); break;
case 0xc07f: if(is_iie) *value = (*value & 0x7f) | (video_->get_double_high_resolution() ? 0x80 : 0x00); break;
case 0xc011: if(is_iie()) *value = (*value & 0x7f) | (language_card_.bank1 ? 0x80 : 0x00); break;
case 0xc012: if(is_iie()) *value = (*value & 0x7f) | (language_card_.read ? 0x80 : 0x00); break;
case 0xc013: if(is_iie()) *value = (*value & 0x7f) | (read_auxiliary_memory_ ? 0x80 : 0x00); break;
case 0xc014: if(is_iie()) *value = (*value & 0x7f) | (write_auxiliary_memory_ ? 0x80 : 0x00); break;
case 0xc015: if(is_iie()) *value = (*value & 0x7f) | (internal_CX_rom_ ? 0x80 : 0x00); break;
case 0xc016: if(is_iie()) *value = (*value & 0x7f) | (alternative_zero_page_ ? 0x80 : 0x00); break;
case 0xc017: if(is_iie()) *value = (*value & 0x7f) | (slot_C3_rom_ ? 0x80 : 0x00); break;
case 0xc018: if(is_iie()) *value = (*value & 0x7f) | (video_->get_80_store() ? 0x80 : 0x00); break;
case 0xc019: if(is_iie()) *value = (*value & 0x7f) | (video_->get_is_vertical_blank(cycles_since_video_update_) ? 0x00 : 0x80); break;
case 0xc01a: if(is_iie()) *value = (*value & 0x7f) | (video_->get_text() ? 0x80 : 0x00); break;
case 0xc01b: if(is_iie()) *value = (*value & 0x7f) | (video_->get_mixed() ? 0x80 : 0x00); break;
case 0xc01c: if(is_iie()) *value = (*value & 0x7f) | (video_->get_page2() ? 0x80 : 0x00); break;
case 0xc01d: if(is_iie()) *value = (*value & 0x7f) | (video_->get_high_resolution() ? 0x80 : 0x00); break;
case 0xc01e: if(is_iie()) *value = (*value & 0x7f) | (video_->get_alternative_character_set() ? 0x80 : 0x00); break;
case 0xc01f: if(is_iie()) *value = (*value & 0x7f) | (video_->get_80_columns() ? 0x80 : 0x00); break;
case 0xc07f: if(is_iie()) *value = (*value & 0x7f) | (video_->get_double_high_resolution() ? 0x80 : 0x00); break;
}
} else {
// Write-only switches. All IIe as currently implemented.
if(is_iie) {
if(is_iie()) {
switch(address) {
default: printf("Write %04x?\n", address); break;
@ -612,7 +619,7 @@ template <bool is_iie> class ConcreteMachine:
case 0xc05e:
case 0xc05f:
if(is_iie) {
if(is_iie()) {
update_video();
video_->set_double_high_resolution(!(address&1));
}
@ -626,7 +633,7 @@ template <bool is_iie> class ConcreteMachine:
}
// On the IIe, reading C010 returns additional key info.
if(is_iie && isReadOperation(operation)) {
if(is_iie() && isReadOperation(operation)) {
*value = (key_is_down_ ? 0x80 : 0x00) | (keyboard_input_ & 0x7f);
}
break;
@ -769,7 +776,7 @@ template <bool is_iie> class ConcreteMachine:
}
// Prior to the IIe, the keyboard could produce uppercase only.
if(!is_iie) value = static_cast<char>(toupper(value));
if(!is_iie()) value = static_cast<char>(toupper(value));
if(is_pressed) {
keyboard_input_ = static_cast<uint8_t>(value | 0x80);
@ -818,10 +825,12 @@ using namespace AppleII;
Machine *Machine::AppleII(const Analyser::Static::Target *target, const ROMMachine::ROMFetcher &rom_fetcher) {
using Target = Analyser::Static::AppleII::Target;
const Target *const appleii_target = dynamic_cast<const Target *>(target);
if(appleii_target->model == Target::Model::IIe) {
return new ConcreteMachine<true>(*appleii_target, rom_fetcher);
} else {
return new ConcreteMachine<false>(*appleii_target, rom_fetcher);
switch(appleii_target->model) {
default: return nullptr;
case Target::Model::II: return new ConcreteMachine<Target::Model::II>(*appleii_target, rom_fetcher);
case Target::Model::IIplus: return new ConcreteMachine<Target::Model::IIplus>(*appleii_target, rom_fetcher);
case Target::Model::IIe: return new ConcreteMachine<Target::Model::IIe>(*appleii_target, rom_fetcher);
case Target::Model::EnhancedIIe: return new ConcreteMachine<Target::Model::EnhancedIIe>(*appleii_target, rom_fetcher);
}
}

View File

@ -262,18 +262,20 @@ template <class BusHandler, bool is_iie> class Video: public VideoBase {
case GraphicsMode::Text: {
const uint8_t inverses[] = {
0xff,
alternative_character_set_ ? static_cast<uint8_t>(0xff) : static_cast<uint8_t>((flash_ / flash_length) * 0xff),
static_cast<uint8_t>((flash_ / flash_length) * 0xff),
0x00,
0x00
};
const uint8_t masks[] = {
alternative_character_set_ ? static_cast<uint8_t>(0x7f) : static_cast<uint8_t>(0x3f),
is_iie ? 0x7f : 0x3f,
};
for(int c = column_; c < pixel_end; ++c) {
const uint8_t character = bus_handler_.perform_read(static_cast<uint16_t>(text_address + c));
const uint8_t xor_mask = inverses[character >> 6];
const std::size_t character_address = static_cast<std::size_t>(((character & masks[character >> 7]) << 3) + pixel_row);
int character = bus_handler_.perform_read(static_cast<uint16_t>(text_address + c));
if(is_iie) {
character |= alternative_character_set_ ? 0x100 : 0;
} else {
character &= 0x3f;
}
const uint8_t xor_mask = is_iie ? 0xff : inverses[character >> 6];
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;
// The character ROM is output MSB to LSB rather than LSB to MSB.
@ -290,26 +292,21 @@ template <class BusHandler, bool is_iie> class Video: public VideoBase {
} break;
case GraphicsMode::DoubleText: {
const uint8_t inverses[] = {
0xff,
alternative_character_set_ ? static_cast<uint8_t>(0xff) : static_cast<uint8_t>((flash_ / flash_length) * 0xff),
0x00,
0x00
};
const uint8_t masks[] = {
alternative_character_set_ ? static_cast<uint8_t>(0x7f) : static_cast<uint8_t>(0x3f),
is_iie ? 0x7f : 0x3f,
};
for(int c = column_; c < pixel_end; ++c) {
const uint16_t characters = bus_handler_.perform_aux_read(static_cast<uint16_t>(text_address + c));
const std::size_t character_addresses[2] = {
static_cast<std::size_t>((((characters >> 8) & masks[characters >> 15]) << 3) + pixel_row),
static_cast<std::size_t>(((characters & masks[(characters >> 7)&1]) << 3) + pixel_row),
static_cast<std::size_t>(
(((characters >> 8)) << 3) + pixel_row
),
static_cast<std::size_t>(
(characters << 3) + pixel_row
),
};
const size_t pattern_offset = alternative_character_set_ ? (256*8) : 0;
const uint8_t character_patterns[2] = {
static_cast<uint8_t>(character_rom_[character_addresses[0]] ^ inverses[(characters >> 14) & 3]),
static_cast<uint8_t>(character_rom_[character_addresses[1]] ^ inverses[(characters >> 6) & 3]),
character_rom_[character_addresses[0] + pattern_offset],
character_rom_[character_addresses[1] + pattern_offset],
};
// The character ROM is output MSB to LSB rather than LSB to MSB.

View File

@ -13,7 +13,8 @@
typedef NS_ENUM(NSInteger, CSMachineAppleIIModel) {
CSMachineAppleIIModelAppleII,
CSMachineAppleIIModelAppleIIPlus,
CSMachineAppleIIModelAppleIIe
CSMachineAppleIIModelAppleIIe,
CSMachineAppleIIModelAppleEnhancedIIe
};
typedef NS_ENUM(NSInteger, CSMachineAppleIIDiskController) {

View File

@ -169,9 +169,10 @@ static Analyser::Static::ZX8081::Target::MemoryModel ZX8081MemoryModelFromSize(K
std::unique_ptr<Target> target(new Target);
target->machine = Analyser::Machine::AppleII;
switch(model) {
default: target->model = Target::Model::II; break;
case CSMachineAppleIIModelAppleIIPlus: target->model = Target::Model::IIplus; break;
case CSMachineAppleIIModelAppleIIe: target->model = Target::Model::IIe; break;
default: target->model = Target::Model::II; break;
case CSMachineAppleIIModelAppleIIPlus: target->model = Target::Model::IIplus; break;
case CSMachineAppleIIModelAppleIIe: target->model = Target::Model::IIe; break;
case CSMachineAppleIIModelAppleEnhancedIIe: target->model = Target::Model::EnhancedIIe; break;
}
switch(diskController) {
default:

View File

@ -84,7 +84,7 @@ Gw
</textFieldCell>
</textField>
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="jli-ac-Sij">
<rect key="frame" x="65" y="67" width="91" height="26"/>
<rect key="frame" x="65" y="67" width="115" height="26"/>
<popUpButtonCell key="cell" type="push" title="Apple II" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="VBQ-JG-AeM" id="U6V-us-O2F">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/>
@ -93,6 +93,7 @@ Gw
<menuItem title="Apple II" state="on" id="VBQ-JG-AeM"/>
<menuItem title="Apple II+" tag="1" id="Yme-Wn-Obh"/>
<menuItem title="Apple IIe" tag="2" id="AMt-WU-a0H"/>
<menuItem title="Enhanced IIe" tag="3" id="kUz-FG-lqW"/>
</items>
</menu>
</popUpButtonCell>

View File

@ -131,6 +131,7 @@ class MachinePicker: NSObject {
switch appleIIModelButton!.selectedTag() {
case 1: model = .appleIIPlus
case 2: model = .appleIIe
case 3: model = .appleEnhancedIIe
case 0: fallthrough
default: model = .appleII
}

View File

@ -9,5 +9,6 @@ apple2eu.rom — as per apple2e.rom, but for the Unenhanced Apple II.
apple2-character.rom — a 2kb image of the Apple IIe's character ROM.
apple2eu-character.rom — a 4kb image of the Unenhanced IIe's character ROM.
apple2e-character.rom — a 4kb image of the Enhanced IIe's character ROM.
Apologies for the wackiness around "at least xkb big", it's to allow for use of files such as those on ftp.apple.asimov.net, which tend to be a bunch of other things, then the system ROM.