diff --git a/Analyser/Static/AppleII/Target.hpp b/Analyser/Static/AppleII/Target.hpp index 25c4e78cf..3c97abfcb 100644 --- a/Analyser/Static/AppleII/Target.hpp +++ b/Analyser/Static/AppleII/Target.hpp @@ -19,7 +19,8 @@ struct Target: public ::Analyser::Static::Target { enum class Model { II, IIplus, - IIe + IIe, + EnhancedIIe }; enum class DiskController { None, diff --git a/Machines/AppleII/AppleII.cpp b/Machines/AppleII/AppleII.cpp index 2e876de93..25168b059 100644 --- a/Machines/AppleII/AppleII.cpp +++ b/Machines/AppleII/AppleII.cpp @@ -34,7 +34,9 @@ namespace { -template class ConcreteMachine: +#define is_iie() ((model == Analyser::Static::AppleII::Target::Model::IIe) || (model == Analyser::Static::AppleII::Target::Model::EnhancedIIe)) + +template class ConcreteMachine: public CRTMachine::Machine, public MediaTarget::Machine, public KeyboardMachine::Machine, @@ -62,7 +64,7 @@ template class ConcreteMachine: CPU::MOS6502::Processor m6502_; VideoBusHandler video_bus_handler_; - std::unique_ptr> video_; + std::unique_ptr> video_; int cycles_into_current_line_ = 0; Cycles cycles_since_video_update_; @@ -179,7 +181,7 @@ template 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 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 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 class ConcreteMachine: } void setup_output(float aspect_ratio) override { - video_.reset(new AppleII::Video::Video(video_bus_handler_)); + video_.reset(new AppleII::Video::Video(video_bus_handler_)); video_->set_character_rom(character_rom_); } @@ -422,7 +429,7 @@ template 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 class ConcreteMachine: *value &= 0x7f; if( static_cast(joysticks_[0].get())->buttons[0] || static_cast(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 class ConcreteMachine: *value &= 0x7f; if( static_cast(joysticks_[0].get())->buttons[1] || static_cast(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 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 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 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 class ConcreteMachine: } // Prior to the IIe, the keyboard could produce uppercase only. - if(!is_iie) value = static_cast(toupper(value)); + if(!is_iie()) value = static_cast(toupper(value)); if(is_pressed) { keyboard_input_ = static_cast(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(target); - if(appleii_target->model == Target::Model::IIe) { - return new ConcreteMachine(*appleii_target, rom_fetcher); - } else { - return new ConcreteMachine(*appleii_target, rom_fetcher); + switch(appleii_target->model) { + default: return nullptr; + case Target::Model::II: return new ConcreteMachine(*appleii_target, rom_fetcher); + case Target::Model::IIplus: return new ConcreteMachine(*appleii_target, rom_fetcher); + case Target::Model::IIe: return new ConcreteMachine(*appleii_target, rom_fetcher); + case Target::Model::EnhancedIIe: return new ConcreteMachine(*appleii_target, rom_fetcher); } } diff --git a/Machines/AppleII/Video.hpp b/Machines/AppleII/Video.hpp index ecf357905..f03bb721e 100644 --- a/Machines/AppleII/Video.hpp +++ b/Machines/AppleII/Video.hpp @@ -262,18 +262,20 @@ template class Video: public VideoBase { case GraphicsMode::Text: { const uint8_t inverses[] = { 0xff, - alternative_character_set_ ? static_cast(0xff) : static_cast((flash_ / flash_length) * 0xff), + static_cast((flash_ / flash_length) * 0xff), 0x00, 0x00 }; - const uint8_t masks[] = { - alternative_character_set_ ? static_cast(0x7f) : static_cast(0x3f), - is_iie ? 0x7f : 0x3f, - }; for(int c = column_; c < pixel_end; ++c) { - const uint8_t character = bus_handler_.perform_read(static_cast(text_address + c)); - const uint8_t xor_mask = inverses[character >> 6]; - const std::size_t character_address = static_cast(((character & masks[character >> 7]) << 3) + pixel_row); + int character = bus_handler_.perform_read(static_cast(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((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 Video: public VideoBase { } break; case GraphicsMode::DoubleText: { - const uint8_t inverses[] = { - 0xff, - alternative_character_set_ ? static_cast(0xff) : static_cast((flash_ / flash_length) * 0xff), - 0x00, - 0x00 - }; - const uint8_t masks[] = { - alternative_character_set_ ? static_cast(0x7f) : static_cast(0x3f), - is_iie ? 0x7f : 0x3f, - }; for(int c = column_; c < pixel_end; ++c) { const uint16_t characters = bus_handler_.perform_aux_read(static_cast(text_address + c)); const std::size_t character_addresses[2] = { - static_cast((((characters >> 8) & masks[characters >> 15]) << 3) + pixel_row), - static_cast(((characters & masks[(characters >> 7)&1]) << 3) + pixel_row), + static_cast( + (((characters >> 8)) << 3) + pixel_row + ), + static_cast( + (characters << 3) + pixel_row + ), }; + const size_t pattern_offset = alternative_character_set_ ? (256*8) : 0; const uint8_t character_patterns[2] = { - static_cast(character_rom_[character_addresses[0]] ^ inverses[(characters >> 14) & 3]), - static_cast(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. diff --git a/OSBindings/Mac/Clock Signal/Machine/StaticAnalyser/CSStaticAnalyser.h b/OSBindings/Mac/Clock Signal/Machine/StaticAnalyser/CSStaticAnalyser.h index 943656c6c..b8b5cc4b5 100644 --- a/OSBindings/Mac/Clock Signal/Machine/StaticAnalyser/CSStaticAnalyser.h +++ b/OSBindings/Mac/Clock Signal/Machine/StaticAnalyser/CSStaticAnalyser.h @@ -13,7 +13,8 @@ typedef NS_ENUM(NSInteger, CSMachineAppleIIModel) { CSMachineAppleIIModelAppleII, CSMachineAppleIIModelAppleIIPlus, - CSMachineAppleIIModelAppleIIe + CSMachineAppleIIModelAppleIIe, + CSMachineAppleIIModelAppleEnhancedIIe }; typedef NS_ENUM(NSInteger, CSMachineAppleIIDiskController) { diff --git a/OSBindings/Mac/Clock Signal/Machine/StaticAnalyser/CSStaticAnalyser.mm b/OSBindings/Mac/Clock Signal/Machine/StaticAnalyser/CSStaticAnalyser.mm index b804d2c59..f1933c417 100644 --- a/OSBindings/Mac/Clock Signal/Machine/StaticAnalyser/CSStaticAnalyser.mm +++ b/OSBindings/Mac/Clock Signal/Machine/StaticAnalyser/CSStaticAnalyser.mm @@ -169,9 +169,10 @@ static Analyser::Static::ZX8081::Target::MemoryModel ZX8081MemoryModelFromSize(K std::unique_ptr 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: diff --git a/OSBindings/Mac/Clock Signal/MachinePicker/Base.lproj/MachinePicker.xib b/OSBindings/Mac/Clock Signal/MachinePicker/Base.lproj/MachinePicker.xib index 52727ce02..1ab907199 100644 --- a/OSBindings/Mac/Clock Signal/MachinePicker/Base.lproj/MachinePicker.xib +++ b/OSBindings/Mac/Clock Signal/MachinePicker/Base.lproj/MachinePicker.xib @@ -84,7 +84,7 @@ Gw - + @@ -93,6 +93,7 @@ Gw + diff --git a/OSBindings/Mac/Clock Signal/MachinePicker/MachinePicker.swift b/OSBindings/Mac/Clock Signal/MachinePicker/MachinePicker.swift index da9a669e6..2292463ff 100644 --- a/OSBindings/Mac/Clock Signal/MachinePicker/MachinePicker.swift +++ b/OSBindings/Mac/Clock Signal/MachinePicker/MachinePicker.swift @@ -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 } diff --git a/ROMImages/AppleII/readme.txt b/ROMImages/AppleII/readme.txt index 0cb8c1131..75c375f24 100644 --- a/ROMImages/AppleII/readme.txt +++ b/ROMImages/AppleII/readme.txt @@ -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. \ No newline at end of file