1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-06-08 10:52:58 +00:00

Makes attempt to implement support for the Pravetz 8D + 8DOS.

i.e. the Disk II wired up to the Oric, with some ROM swaps.
This commit is contained in:
Thomas Harte 2018-05-08 22:05:43 -04:00
parent d1b889aa61
commit c3a2f7717b
14 changed files with 327 additions and 169 deletions

View File

@ -36,9 +36,9 @@ Analyser::Static::Target *OricTarget(const Storage::Encodings::AppleGCR::Sector
using Target = Analyser::Static::Oric::Target;
auto *target = new Target;
target->machine = Analyser::Machine::Oric;
// TODO: configure the Oric as a Pravetz 8D with 8DOS.
target->rom = Target::ROM::Pravetz;
target->disk_interface = Target::DiskInterface::Pravetz;
target->loading_command = "call 800\n";
return target;
}

View File

@ -134,17 +134,19 @@ Analyser::Static::TargetList Analyser::Static::Oric::GetTargets(const Media &med
for(auto &disk: media.disks) {
Storage::Encodings::MFM::Parser parser(true, disk);
if(IsMicrodisc(parser)) {
target->has_microdrive = true;
target->disk_interface = Target::DiskInterface::Microdisc;
target->media.disks.push_back(disk);
}
}
} else {
target->has_microdrive = false;
}
else
target->disk_interface = Target::DiskInterface::None;
// TODO: really this should add two targets if not all votes agree
target->use_atmos_rom = basic11_votes >= basic10_votes;
if(target->has_microdrive) target->use_atmos_rom = true;
if(basic11_votes >= basic10_votes || target->disk_interface == Target::DiskInterface::Microdisc)
target->rom = Target::ROM::BASIC11;
else
target->rom = Target::ROM::BASIC10;
TargetList targets;
if(target->media.tapes.size() || target->media.disks.size() || target->media.cartridges.size())

View File

@ -17,8 +17,20 @@ namespace Static {
namespace Oric {
struct Target: public ::Analyser::Static::Target {
bool use_atmos_rom = false;
bool has_microdrive = false;
enum class ROM {
BASIC10,
BASIC11,
Pravetz
};
enum class DiskInterface {
Microdisc,
Pravetz,
None
};
ROM rom = ROM::BASIC11;
DiskInterface disk_interface = DiskInterface::None;
std::string loading_command;
};

View File

@ -184,3 +184,39 @@ void DiskII::set_component_is_sleeping(Sleeper *component, bool is_sleeping) {
bool DiskII::is_sleeping() {
return controller_can_sleep_ && drive_is_sleeping_[0] && drive_is_sleeping_[1];
}
void DiskII::set_register(int address, uint8_t value) {
trigger_address(address, value);
}
uint8_t DiskII::get_register(int address) {
return trigger_address(address, 0xff);
}
uint8_t DiskII::trigger_address(int address, uint8_t value) {
switch(address & 0xf) {
default:
case 0x0: set_control(Control::P0, false); break;
case 0x1: set_control(Control::P0, true); break;
case 0x2: set_control(Control::P1, false); break;
case 0x3: set_control(Control::P1, true); break;
case 0x4: set_control(Control::P2, false); break;
case 0x5: set_control(Control::P2, true); break;
case 0x6: set_control(Control::P3, false); break;
case 0x7: set_control(Control::P3, true); break;
case 0x8: set_control(Control::Motor, false); break;
case 0x9: set_control(Control::Motor, true); break;
case 0xa: select_drive(0); break;
case 0xb: select_drive(1); break;
case 0xc: return get_shift_register();
case 0xd: set_data_register(value); break;
case 0xe: set_mode(Mode::Read); break;
case 0xf: set_mode(Mode::Write); break;
}
return 0xff;
}

View File

@ -30,6 +30,16 @@ class DiskII:
public:
DiskII();
void set_register(int address, uint8_t value);
uint8_t get_register(int address);
void run_for(const Cycles cycles);
void set_state_machine(const std::vector<uint8_t> &);
void set_disk(const std::shared_ptr<Storage::Disk::Disk> &disk, int drive);
bool is_sleeping() override;
private:
enum class Control {
P0, P1, P2, P3,
Motor,
@ -43,13 +53,7 @@ class DiskII:
void set_data_register(uint8_t value);
uint8_t get_shift_register();
void run_for(const Cycles cycles);
void set_state_machine(const std::vector<uint8_t> &);
void set_disk(const std::shared_ptr<Storage::Disk::Disk> &disk, int drive);
bool is_sleeping() override;
private:
uint8_t trigger_address(int address, uint8_t value);
void process_event(const Storage::Disk::Track::Event &event) override;
void set_component_is_sleeping(Sleeper *component, bool is_sleeping) override;

View File

@ -22,40 +22,13 @@ DiskIICard::DiskIICard(const ROMMachine::ROMFetcher &rom_fetcher, bool is_16_sec
}
void DiskIICard::perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
if(isReadOperation(operation) && address < 0x100) {
*value &= boot_[address];
if(address < 0x100) {
if(isReadOperation(operation)) *value &= boot_[address];
} else {
using Control = Apple::DiskII::Control;
using Mode = Apple::DiskII::Mode;
switch(address & 0xf) {
case 0x0: diskii_.set_control(Control::P0, false); break;
case 0x1: diskii_.set_control(Control::P0, true); break;
case 0x2: diskii_.set_control(Control::P1, false); break;
case 0x3: diskii_.set_control(Control::P1, true); break;
case 0x4: diskii_.set_control(Control::P2, false); break;
case 0x5: diskii_.set_control(Control::P2, true); break;
case 0x6: diskii_.set_control(Control::P3, false); break;
case 0x7: diskii_.set_control(Control::P3, true); break;
case 0x8: diskii_.set_control(Control::Motor, false); break;
case 0x9: diskii_.set_control(Control::Motor, true); break;
case 0xa: diskii_.select_drive(0); break;
case 0xb: diskii_.select_drive(1); break;
case 0xc: {
/* shift register? */
const uint8_t shift_value = diskii_.get_shift_register();
if(isReadOperation(operation))
*value = shift_value;
} break;
case 0xd:
/* data register? */
diskii_.set_data_register(*value);
break;
case 0xe: diskii_.set_mode(Mode::Read); break;
case 0xf: diskii_.set_mode(Mode::Write); break;
if(isReadOperation(operation)) {
*value = diskii_.get_register(address);
} else {
diskii_.set_register(address, *value);
}
}
}

View File

@ -22,6 +22,7 @@
#include "../../Processors/6502/6502.hpp"
#include "../../Components/6522/6522.hpp"
#include "../../Components/AY38910/AY38910.hpp"
#include "../../Components/DiskII/DiskII.hpp"
#include "../../Storage/Tape/Tape.hpp"
#include "../../Storage/Tape/Parsers/Oric.hpp"
@ -189,7 +190,7 @@ class VIAPortHandler: public MOS::MOS6522::IRQDelegatePortHandler {
Keyboard &keyboard_;
};
class ConcreteMachine:
template <Analyser::Static::Oric::Target::DiskInterface disk_interface> class ConcreteMachine:
public CRTMachine::Machine,
public ConfigurationTarget::Machine,
public KeyboardMachine::Machine,
@ -202,13 +203,13 @@ class ConcreteMachine:
public Machine {
public:
ConcreteMachine() :
ConcreteMachine(const Analyser::Static::Oric::Target *target) :
m6502_(*this),
rom_type_(target ? target->rom : Analyser::Static::Oric::Target::ROM::BASIC10),
ay8910_(audio_queue_),
speaker_(ay8910_),
via_port_handler_(audio_queue_, ay8910_, speaker_, tape_player_, keyboard_),
via_(via_port_handler_),
paged_rom_(rom_) {
via_(via_port_handler_) {
set_clock_rate(1000000);
via_port_handler_.set_interrupt_delegate(this);
tape_player_.set_delegate(this);
@ -221,26 +222,46 @@ class ConcreteMachine:
// Obtains the system ROMs.
bool set_rom_fetcher(const ROMMachine::ROMFetcher &roms_with_names) override {
auto roms = roms_with_names(
"Oric",
{
"basic10.rom", "basic11.rom",
"microdisc.rom", "colour.rom"
});
std::vector<std::string> rom_names = {"colour.rom"};
switch(rom_type_) {
case Analyser::Static::Oric::Target::ROM::BASIC10: rom_names.push_back("basic10.rom"); break;
case Analyser::Static::Oric::Target::ROM::BASIC11: rom_names.push_back("basic11.rom"); break;
case Analyser::Static::Oric::Target::ROM::Pravetz: rom_names.push_back("pravetz.rom"); break;
}
switch(disk_interface) {
default: break;
case Analyser::Static::Oric::Target::DiskInterface::Microdisc: rom_names.push_back("microdisc.rom"); break;
case Analyser::Static::Oric::Target::DiskInterface::Pravetz: rom_names.push_back("8dos.rom"); break;
}
auto roms = roms_with_names("Oric", rom_names);
for(std::size_t index = 0; index < roms.size(); ++index) {
if(!roms[index]) return false;
}
basic10_rom_ = std::move(*roms[0]);
basic11_rom_ = std::move(*roms[1]);
microdisc_rom_ = std::move(*roms[2]);
colour_rom_ = std::move(*roms[3]);
colour_rom_ = std::move(*roms[0]);
rom_ = std::move(*roms[1]);
switch(disk_interface) {
default: break;
case Analyser::Static::Oric::Target::DiskInterface::Microdisc:
microdisc_rom_ = std::move(*roms[2]);
microdisc_rom_.resize(8192);
break;
case Analyser::Static::Oric::Target::DiskInterface::Pravetz: {
pravetz_rom_ = std::move(*roms[2]);
pravetz_rom_.resize(512);
auto state_machine_rom = roms_with_names("DiskII", {"state-machine-16.rom"});
if(!state_machine_rom[0]) return false;
diskii_.set_state_machine(*state_machine_rom[0]);
} break;
}
basic10_rom_.resize(16384);
basic11_rom_.resize(16384);
microdisc_rom_.resize(8192);
colour_rom_.resize(128);
rom_.resize(16384);
paged_rom_ = rom_.data();
if(video_output_) video_output_->set_colour_rom(colour_rom_);
@ -267,47 +288,67 @@ class ConcreteMachine:
void configure_as_target(const Analyser::Static::Target *target) override final {
auto *const oric_target = dynamic_cast<const Analyser::Static::Oric::Target *>(target);
if(oric_target->has_microdrive) {
microdisc_is_enabled_ = true;
microdisc_did_change_paging_flags(&microdisc_);
microdisc_.set_delegate(this);
switch(oric_target->disk_interface) {
default: break;
case Analyser::Static::Oric::Target::DiskInterface::Microdisc:
microdisc_did_change_paging_flags(&microdisc_);
microdisc_.set_delegate(this);
break;
}
if(!oric_target->loading_command.empty()) {
type_string(oric_target->loading_command);
}
if(oric_target->use_atmos_rom) {
std::memcpy(rom_, basic11_rom_.data(), std::min(basic11_rom_.size(), sizeof(rom_)));
is_using_basic11_ = true;
tape_get_byte_address_ = 0xe6c9;
scan_keyboard_address_ = 0xf495;
tape_speed_address_ = 0x024d;
} else {
std::memcpy(rom_, basic10_rom_.data(), std::min(basic10_rom_.size(), sizeof(rom_)));
is_using_basic11_ = false;
tape_get_byte_address_ = 0xe630;
scan_keyboard_address_ = 0xf43c;
tape_speed_address_ = 0x67;
switch(rom_type_) {
case Analyser::Static::Oric::Target::ROM::BASIC10:
tape_get_byte_address_ = 0xe630;
scan_keyboard_address_ = 0xf43c;
tape_speed_address_ = 0x67;
break;
case Analyser::Static::Oric::Target::ROM::BASIC11:
case Analyser::Static::Oric::Target::ROM::Pravetz:
tape_get_byte_address_ = 0xe6c9;
scan_keyboard_address_ = 0xf495;
tape_speed_address_ = 0x024d;
break;
}
insert_media(target->media);
}
bool insert_media(const Analyser::Static::Media &media) override final {
bool inserted = false;
if(media.tapes.size()) {
tape_player_.set_tape(media.tapes.front());
inserted = true;
}
int drive_index = 0;
for(auto &disk : media.disks) {
if(drive_index < 4) microdisc_.set_disk(disk, drive_index);
drive_index++;
if(!media.disks.empty()) {
switch(disk_interface) {
case Analyser::Static::Oric::Target::DiskInterface::Microdisc: {
inserted = true;
int drive_index = 0;
for(auto &disk : media.disks) {
if(drive_index < 4) microdisc_.set_disk(disk, drive_index);
drive_index++;
}
} break;
case Analyser::Static::Oric::Target::DiskInterface::Pravetz: {
inserted = true;
int drive_index = 0;
for(auto &disk : media.disks) {
if(drive_index < 2) diskii_.set_disk(disk, drive_index);
drive_index++;
}
} break;
default: break;
}
}
return !media.tapes.empty() || (!media.disks.empty() && microdisc_is_enabled_);
return inserted;
}
// to satisfy CPU::MOS6502::BusHandler
@ -318,7 +359,7 @@ class ConcreteMachine:
// 024D = 0 => fast; otherwise slow
// E6C9 = read byte: return byte in A
if( address == tape_get_byte_address_ &&
paged_rom_ == rom_ &&
paged_rom_ == rom_.data() &&
use_fast_tape_hack_ &&
operation == CPU::MOS6502::BusOperation::ReadOpcode &&
tape_player_.has_tape() &&
@ -331,23 +372,45 @@ class ConcreteMachine:
}
} else {
if((address & 0xff00) == 0x0300) {
if(microdisc_is_enabled_ && address >= 0x0310) {
switch(address) {
case 0x0310: case 0x0311: case 0x0312: case 0x0313:
if(isReadOperation(operation)) *value = microdisc_.get_register(address);
else microdisc_.set_register(address, *value);
break;
case 0x314: case 0x315: case 0x316: case 0x317:
if(isReadOperation(operation)) *value = microdisc_.get_interrupt_request_register();
else microdisc_.set_control_register(*value);
break;
case 0x318: case 0x319: case 0x31a: case 0x31b:
if(isReadOperation(operation)) *value = microdisc_.get_data_request_register();
break;
}
} else {
if(address < 0x0310 || (disk_interface == Analyser::Static::Oric::Target::DiskInterface::None)) {
if(isReadOperation(operation)) *value = via_.get_register(address);
else via_.set_register(address, *value);
} else {
switch(disk_interface) {
default: break;
case Analyser::Static::Oric::Target::DiskInterface::Microdisc:
switch(address) {
case 0x0310: case 0x0311: case 0x0312: case 0x0313:
if(isReadOperation(operation)) *value = microdisc_.get_register(address);
else microdisc_.set_register(address, *value);
break;
case 0x314: case 0x315: case 0x316: case 0x317:
if(isReadOperation(operation)) *value = microdisc_.get_interrupt_request_register();
else microdisc_.set_control_register(*value);
break;
case 0x318: case 0x319: case 0x31a: case 0x31b:
if(isReadOperation(operation)) *value = microdisc_.get_data_request_register();
break;
}
break;
case Analyser::Static::Oric::Target::DiskInterface::Pravetz:
if(address >= 0x0320) {
if(isReadOperation(operation)) *value = pravetz_rom_[pravetz_rom_base_pointer_ + (address & 0xff)];
else {
switch(address) {
case 0x380: case 0x381: case 0x382: case 0x383:
ram_top_ = (address&1) ? 0xffff : 0xbfff;
pravetz_rom_base_pointer_ = (address&2) ? 0x100 : 0x000;
break;
}
}
} else {
update_diskii();
if(isReadOperation(operation)) *value = diskii_.get_register(address);
else diskii_.set_register(address, *value);
}
break;
}
}
} else {
if(isReadOperation(operation))
@ -372,7 +435,11 @@ class ConcreteMachine:
via_.run_for(Cycles(1));
via_port_handler_.run_for(Cycles(1));
tape_player_.run_for(Cycles(1));
if(microdisc_is_enabled_) microdisc_.run_for(Cycles(8));
switch(disk_interface) {
default: break;
case Analyser::Static::Oric::Target::DiskInterface::Microdisc: microdisc_.run_for(Cycles(8)); break;
case Analyser::Static::Oric::Target::DiskInterface::Pravetz: cycles_since_diskii_update_ += 2; break;
}
cycles_since_video_update_++;
return Cycles(1);
}
@ -380,6 +447,7 @@ class ConcreteMachine:
forceinline void flush() {
update_video();
via_port_handler_.flush();
if(disk_interface == Analyser::Static::Oric::Target::DiskInterface::Pravetz) update_diskii();
}
// to satisfy CRTMachine::Machine
@ -429,7 +497,7 @@ class ConcreteMachine:
int flags = microdisc->get_paging_flags();
if(!(flags&Microdisc::PagingFlags::BASICDisable)) {
ram_top_ = 0xbfff;
paged_rom_ = rom_;
paged_rom_ = rom_.data();
} else {
if(flags&Microdisc::PagingFlags::MicrodscDisable) {
ram_top_ = 0xffff;
@ -487,15 +555,15 @@ class ConcreteMachine:
CPU::MOS6502::Processor<ConcreteMachine, false> m6502_;
// RAM and ROM
std::vector<uint8_t> basic11_rom_, basic10_rom_, microdisc_rom_, colour_rom_;
uint8_t ram_[65536], rom_[16384];
Analyser::Static::Oric::Target::ROM rom_type_;
std::vector<uint8_t> rom_, microdisc_rom_, colour_rom_;
uint8_t ram_[65536];
Cycles cycles_since_video_update_;
inline void update_video() {
video_output_->run_for(cycles_since_video_update_.flush());
}
// ROM bookkeeping
bool is_using_basic11_ = false;
uint16_t tape_get_byte_address_ = 0, scan_keyboard_address_ = 0, tape_speed_address_ = 0;
int keyboard_read_count_ = 0;
@ -519,14 +587,26 @@ class ConcreteMachine:
// the Microdisc, if in use
class Microdisc microdisc_;
bool microdisc_is_enabled_ = false;
uint16_t ram_top_ = 0xbfff;
uint8_t *paged_rom_;
// the Pravetz/Disk II, if in use
Apple::DiskII diskii_;
std::vector<uint8_t> pravetz_rom_;
std::size_t pravetz_rom_base_pointer_ = 0;
Cycles cycles_since_diskii_update_;
void update_diskii() {
diskii_.run_for(cycles_since_diskii_update_.flush());
}
// Overlay RAM
uint16_t ram_top_ = 0xbfff;
uint8_t *paged_rom_ = nullptr;
// Helper to discern current IRQ state
inline void set_interrupt_line() {
m6502_.set_irq_line(
via_.get_interrupt_line() ||
(microdisc_is_enabled_ && microdisc_.get_interrupt_request_line()));
bool irq_line = via_.get_interrupt_line();
if(disk_interface == Analyser::Static::Oric::Target::DiskInterface::Microdisc)
irq_line |= microdisc_.get_interrupt_request_line();
m6502_.set_irq_line(irq_line);
}
};
@ -534,8 +614,14 @@ class ConcreteMachine:
using namespace Oric;
Machine *Machine::Oric() {
return new ConcreteMachine;
Machine *Machine::Oric(const Analyser::Static::Target *target_hint) {
auto *const oric_target = dynamic_cast<const Analyser::Static::Oric::Target *>(target_hint);
using DiskInterface = Analyser::Static::Oric::Target::DiskInterface;
switch(oric_target->disk_interface) {
default: return new ConcreteMachine<DiskInterface::None>(oric_target);
case DiskInterface::Microdisc: return new ConcreteMachine<DiskInterface::Microdisc>(oric_target);
case DiskInterface::Pravetz: return new ConcreteMachine<DiskInterface::Pravetz>(oric_target);
}
}
Machine::~Machine() {}

View File

@ -10,6 +10,7 @@
#define Oric_hpp
#include "../../Configurable/Configurable.hpp"
#include "../../Analyser/Static/StaticAnalyser.hpp"
namespace Oric {
@ -24,7 +25,7 @@ class Machine {
virtual ~Machine();
/// Creates and returns an Oric.
static Machine *Oric();
static Machine *Oric(const Analyser::Static::Target *target_hint);
};
}

View File

@ -33,7 +33,7 @@ namespace {
case Analyser::Machine::ColecoVision: machine = new Machine::TypedDynamicMachine<Coleco::Vision::Machine>(Coleco::Vision::Machine::ColecoVision()); break;
case Analyser::Machine::Electron: machine = new Machine::TypedDynamicMachine<Electron::Machine>(Electron::Machine::Electron()); break;
case Analyser::Machine::MSX: machine = new Machine::TypedDynamicMachine<MSX::Machine>(MSX::Machine::MSX()); break;
case Analyser::Machine::Oric: machine = new Machine::TypedDynamicMachine<Oric::Machine>(Oric::Machine::Oric()); break;
case Analyser::Machine::Oric: machine = new Machine::TypedDynamicMachine<Oric::Machine>(Oric::Machine::Oric(target)); break;
case Analyser::Machine::Vic20: machine = new Machine::TypedDynamicMachine<Commodore::Vic20::Machine>(Commodore::Vic20::Machine::Vic20()); break;
case Analyser::Machine::ZX8081: machine = new Machine::TypedDynamicMachine<ZX8081::Machine>(ZX8081::Machine::ZX8081(target)); break;

View File

@ -29,7 +29,14 @@ typedef NS_ENUM(NSInteger, CSMachineCPCModel) {
typedef NS_ENUM(NSInteger, CSMachineOricModel) {
CSMachineOricModelOric1,
CSMachineOricModelOricAtmos
CSMachineOricModelOricAtmos,
CSMachineOricModelPravetz
};
typedef NS_ENUM(NSInteger, CSMachineOricDiskInterface) {
CSMachineOricDiskInterfaceNone,
CSMachineOricDiskInterfaceMicrodisc,
CSMachineOricDiskInterfacePravetz
};
typedef NS_ENUM(NSInteger, CSMachineVic20Region) {
@ -49,7 +56,7 @@ typedef int Kilobytes;
- (instancetype)initWithElectronDFS:(BOOL)dfs adfs:(BOOL)adfs;
- (instancetype)initWithAmstradCPCModel:(CSMachineCPCModel)model;
- (instancetype)initWithMSXHasDiskDrive:(BOOL)hasDiskDrive;
- (instancetype)initWithOricModel:(CSMachineOricModel)model hasMicrodrive:(BOOL)hasMicrodrive;
- (instancetype)initWithOricModel:(CSMachineOricModel)model diskInterface:(CSMachineOricDiskInterface)diskInterface;
- (instancetype)initWithVic20Region:(CSMachineVic20Region)region memorySize:(Kilobytes)memorySize hasC1540:(BOOL)hasC1540;
- (instancetype)initWithZX80MemorySize:(Kilobytes)memorySize useZX81ROM:(BOOL)useZX81ROM;
- (instancetype)initWithZX81MemorySize:(Kilobytes)memorySize;

View File

@ -81,14 +81,22 @@
return self;
}
- (instancetype)initWithOricModel:(CSMachineOricModel)model hasMicrodrive:(BOOL)hasMicrodrive {
- (instancetype)initWithOricModel:(CSMachineOricModel)model diskInterface:(CSMachineOricDiskInterface)diskInterface {
self = [super init];
if(self) {
using Target = Analyser::Static::Oric::Target;
std::unique_ptr<Target> target(new Target);
target->machine = Analyser::Machine::Oric;
target->use_atmos_rom = (model == CSMachineOricModelOricAtmos);
target->has_microdrive = !!hasMicrodrive;
switch(model) {
case CSMachineOricModelOric1: target->rom = Target::ROM::BASIC10; break;
case CSMachineOricModelOricAtmos: target->rom = Target::ROM::BASIC11; break;
case CSMachineOricModelPravetz: target->rom = Target::ROM::Pravetz; break;
}
switch(diskInterface) {
case CSMachineOricDiskInterfaceNone: target->disk_interface = Target::DiskInterface::None; break;
case CSMachineOricDiskInterfaceMicrodisc: target->disk_interface = Target::DiskInterface::Microdisc; break;
case CSMachineOricDiskInterfacePravetz: target->disk_interface = Target::DiskInterface::Pravetz; break;
}
_targets.push_back(std::move(target));
}
return self;

View File

@ -18,7 +18,7 @@
<windowStyleMask key="styleMask" titled="YES" documentModal="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="196" y="240" width="600" height="204"/>
<rect key="screenRect" x="0.0" y="0.0" width="1366" height="768"/>
<rect key="screenRect" x="0.0" y="0.0" width="1440" height="900"/>
<view key="contentView" wantsLayer="YES" id="EiT-Mj-1SZ">
<rect key="frame" x="0.0" y="0.0" width="600" height="204"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
@ -132,7 +132,7 @@ Gw
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="00d-sg-Krh">
<rect key="frame" x="54" y="66" width="94" height="26"/>
<rect key="frame" x="58" y="66" width="94" height="26"/>
<popUpButtonCell key="cell" type="push" title="CPC6128" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" tag="6128" imageScaling="proportionallyDown" inset="2" selectedItem="klh-ZE-Agp" id="hVJ-h6-iea">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/>
@ -146,8 +146,8 @@ Gw
</popUpButtonCell>
</popUpButton>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="q9q-sl-J0q">
<rect key="frame" x="8" y="71" width="42" height="17"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Model" id="Cw3-q5-1bC">
<rect key="frame" x="8" y="71" width="46" height="17"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Model:" id="Cw3-q5-1bC">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
@ -197,11 +197,11 @@ Gw
</tabViewItem>
<tabViewItem label="MSX" identifier="msx" id="6SR-DY-zdI">
<view key="view" id="mWD-An-tR7">
<rect key="frame" x="10" y="33" width="554" height="54"/>
<rect key="frame" x="10" y="33" width="554" height="93"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="8xT-Pr-8SE">
<rect key="frame" x="15" y="35" width="124" height="18"/>
<rect key="frame" x="15" y="74" width="124" height="18"/>
<buttonCell key="cell" type="check" title="Attach disk drive" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="CB3-nA-VTM">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
@ -218,26 +218,19 @@ Gw
</tabViewItem>
<tabViewItem label="Oric" identifier="oric" id="NSx-DC-p4M">
<view key="view" id="sOR-e0-8iZ">
<rect key="frame" x="10" y="33" width="554" height="89"/>
<rect key="frame" x="10" y="33" width="554" height="93"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="mZw-PY-0Yv">
<rect key="frame" x="15" y="43" width="129" height="18"/>
<buttonCell key="cell" type="check" title="Attach Microdrive" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="Wl2-KO-smb">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
</button>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="0ct-tf-uRH">
<rect key="frame" x="17" y="69" width="42" height="17"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Model" id="Xm1-7x-YVl">
<rect key="frame" x="17" y="73" width="46" height="17"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Model:" id="Xm1-7x-YVl">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="ENP-hI-BVZ">
<rect key="frame" x="63" y="64" width="105" height="26"/>
<rect key="frame" x="67" y="68" width="105" height="26"/>
<popUpButtonCell key="cell" type="push" title="Oric-1" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" tag="1" imageScaling="proportionallyDown" inset="2" selectedItem="jGN-1a-biF" id="Jll-EJ-cMr">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/>
@ -245,21 +238,46 @@ Gw
<items>
<menuItem title="Oric-1" state="on" tag="1" id="jGN-1a-biF"/>
<menuItem title="Oric Atmos" tag="2" id="p5O-Jq-Tft"/>
<menuItem title="Pravetz 8D" tag="2" id="u6z-2t-ly9"/>
</items>
</menu>
</popUpButtonCell>
</popUpButton>
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="fYL-p6-wyn">
<rect key="frame" x="111" y="37" width="96" height="26"/>
<popUpButtonCell key="cell" type="push" title="None" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" tag="1" imageScaling="proportionallyDown" inset="2" selectedItem="XhK-Jh-oTW" id="aYb-m1-H9X">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/>
<menu key="menu" id="hy3-Li-nlW">
<items>
<menuItem title="None" state="on" tag="1" id="XhK-Jh-oTW"/>
<menuItem title="Microdisc" tag="2" id="1jS-Lz-FRj"/>
<menuItem title="8DOS" tag="2" id="edb-fl-C8Y"/>
</items>
</menu>
</popUpButtonCell>
</popUpButton>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="okM-ZI-NbF">
<rect key="frame" x="15" y="42" width="92" height="17"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Disk interface:" id="SFK-hS-tFC">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<constraints>
<constraint firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="mZw-PY-0Yv" secondAttribute="bottom" constant="17" id="74q-Nf-cCV"/>
<constraint firstItem="ENP-hI-BVZ" firstAttribute="top" secondItem="sOR-e0-8iZ" secondAttribute="top" constant="1" id="Bgq-8R-8I4"/>
<constraint firstItem="mZw-PY-0Yv" firstAttribute="top" secondItem="ENP-hI-BVZ" secondAttribute="bottom" constant="8" id="Mjq-84-vdN"/>
<constraint firstItem="fYL-p6-wyn" firstAttribute="leading" secondItem="okM-ZI-NbF" secondAttribute="trailing" constant="8" id="Pra-lC-JPB"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="ENP-hI-BVZ" secondAttribute="trailing" constant="17" id="Sr5-QZ-xU3"/>
<constraint firstItem="ENP-hI-BVZ" firstAttribute="leading" secondItem="0ct-tf-uRH" secondAttribute="trailing" constant="8" id="Wcg-1P-z6l"/>
<constraint firstItem="okM-ZI-NbF" firstAttribute="leading" secondItem="sOR-e0-8iZ" secondAttribute="leading" constant="17" id="Xhq-0O-N2R"/>
<constraint firstItem="okM-ZI-NbF" firstAttribute="centerY" secondItem="fYL-p6-wyn" secondAttribute="centerY" id="dyC-ab-DKU"/>
<constraint firstItem="0ct-tf-uRH" firstAttribute="centerY" secondItem="ENP-hI-BVZ" secondAttribute="centerY" id="e8Q-nY-gIr"/>
<constraint firstItem="mZw-PY-0Yv" firstAttribute="leading" secondItem="sOR-e0-8iZ" secondAttribute="leading" constant="17" id="equ-PG-WAg"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="mZw-PY-0Yv" secondAttribute="trailing" constant="17" id="erm-Kw-icY"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="fYL-p6-wyn" secondAttribute="trailing" constant="17" id="ewV-Dw-zj2"/>
<constraint firstItem="0ct-tf-uRH" firstAttribute="leading" secondItem="sOR-e0-8iZ" secondAttribute="leading" constant="19" id="huH-9L-97Y"/>
<constraint firstItem="fYL-p6-wyn" firstAttribute="top" secondItem="ENP-hI-BVZ" secondAttribute="bottom" constant="10" id="l3T-Ve-0Jw"/>
<constraint firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="fYL-p6-wyn" secondAttribute="bottom" constant="10" id="mN9-AZ-wSn"/>
</constraints>
</view>
</tabViewItem>
@ -269,7 +287,7 @@ Gw
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="ueK-gq-gaF">
<rect key="frame" x="67" y="67" width="144" height="26"/>
<rect key="frame" x="71" y="67" width="144" height="26"/>
<popUpButtonCell key="cell" type="push" title="European (PAL)" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="45i-0n-gau" id="yi7-eo-I0q">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/>
@ -285,7 +303,7 @@ Gw
</popUpButtonCell>
</popUpButton>
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="2eV-Us-eEv">
<rect key="frame" x="102" y="36" width="114" height="26"/>
<rect key="frame" x="106" y="36" width="114" height="26"/>
<popUpButtonCell key="cell" type="push" title="Unexpanded" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="fOl-8Q-fsA" id="rH0-7T-pJE">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/>
@ -299,16 +317,16 @@ Gw
</popUpButtonCell>
</popUpButton>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="MTh-9p-FqC">
<rect key="frame" x="17" y="72" width="46" height="17"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Region" id="F3g-Ya-ypU">
<rect key="frame" x="17" y="72" width="50" height="17"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Region:" id="F3g-Ya-ypU">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="gRS-DK-rIy">
<rect key="frame" x="15" y="41" width="83" height="17"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Memory Size" id="a4I-vG-yCp">
<rect key="frame" x="15" y="41" width="87" height="17"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Memory Size:" id="a4I-vG-yCp">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
@ -346,7 +364,7 @@ Gw
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="I1a-Eu-5UB">
<rect key="frame" x="102" y="66" width="114" height="26"/>
<rect key="frame" x="106" y="66" width="114" height="26"/>
<popUpButtonCell key="cell" type="push" title="Unexpanded" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="4Sa-jR-xOd" id="B8M-do-Yod">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/>
@ -360,8 +378,8 @@ Gw
</popUpButtonCell>
</popUpButton>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="NCX-4e-lSu">
<rect key="frame" x="15" y="71" width="83" height="17"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Memory Size" id="e6x-TE-OC5">
<rect key="frame" x="15" y="71" width="87" height="17"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Memory Size:" id="e6x-TE-OC5">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
@ -390,11 +408,11 @@ Gw
</tabViewItem>
<tabViewItem label="ZX81" identifier="zx81" id="Wnn-nQ-gZ6">
<view key="view" id="bmd-gL-gzT">
<rect key="frame" x="10" y="33" width="554" height="54"/>
<rect key="frame" x="10" y="33" width="554" height="93"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="5aO-UX-HnX">
<rect key="frame" x="102" y="27" width="114" height="26"/>
<rect key="frame" x="106" y="66" width="114" height="26"/>
<popUpButtonCell key="cell" type="push" title="Unexpanded" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="7QC-Ij-hES" id="d3W-Gl-3Mf">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/>
@ -408,8 +426,8 @@ Gw
</popUpButtonCell>
</popUpButton>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="8tU-73-XEE">
<rect key="frame" x="15" y="32" width="83" height="17"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Memory Size" id="z4b-oR-Yl2">
<rect key="frame" x="15" y="71" width="87" height="17"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Memory Size:" id="z4b-oR-Yl2">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
@ -455,7 +473,7 @@ Gw
<outlet property="electronDFSButton" destination="JqM-IK-FMP" id="C80-1k-TdQ"/>
<outlet property="machineSelector" destination="VUb-QG-x7c" id="crR-hB-jGd"/>
<outlet property="msxHasDiskDriveButton" destination="8xT-Pr-8SE" id="zGH-GA-9QF"/>
<outlet property="oricHasMicrodriveButton" destination="mZw-PY-0Yv" id="EuA-uL-PNR"/>
<outlet property="oricDiskInterfaceButton" destination="fYL-p6-wyn" id="aAt-wM-hRZ"/>
<outlet property="oricModelTypeButton" destination="ENP-hI-BVZ" id="n9i-Ym-miE"/>
<outlet property="vic20HasC1540Button" destination="Lrf-gL-6EI" id="21g-dJ-mOo"/>
<outlet property="vic20MemorySizeButton" destination="2eV-Us-eEv" id="5j4-jw-89d"/>

View File

@ -27,7 +27,7 @@ class MachinePicker: NSObject {
// MARK: - Oric properties
@IBOutlet var oricModelTypeButton: NSPopUpButton?
@IBOutlet var oricHasMicrodriveButton: NSButton?
@IBOutlet var oricDiskInterfaceButton: NSPopUpButton?
// MARK: - Vic-20 properties
@IBOutlet var vic20RegionButton: NSPopUpButton?
@ -65,7 +65,7 @@ class MachinePicker: NSObject {
msxHasDiskDriveButton?.state = standardUserDefaults.bool(forKey: "new.msxDiskDrive") ? .on : .off
// Oric settings
oricHasMicrodriveButton?.state = standardUserDefaults.bool(forKey: "new.oricMicrodrive") ? .on : .off
oricDiskInterfaceButton?.selectItem(withTag: standardUserDefaults.integer(forKey: "new.oricDiskInterface"))
oricModelTypeButton?.selectItem(withTag: standardUserDefaults.integer(forKey: "new.oricModel"))
// Vic-20 settings
@ -102,7 +102,7 @@ class MachinePicker: NSObject {
standardUserDefaults.set(msxHasDiskDriveButton?.state == .on, forKey: "new.msxDiskDrive")
// Oric settings
standardUserDefaults.set(oricHasMicrodriveButton?.state == .on, forKey: "new.oricMicrodrive")
standardUserDefaults.set(oricDiskInterfaceButton!.selectedTag(), forKey: "new.oricDiskInterface")
standardUserDefaults.set(oricModelTypeButton!.selectedTag(), forKey: "new.oricModel")
// Vic-20 settings
@ -156,11 +156,21 @@ class MachinePicker: NSObject {
return CSStaticAnalyser(msxHasDiskDrive: msxHasDiskDriveButton!.state == .on)
case "oric":
let hasMicrodrive = oricHasMicrodriveButton!.state == .on
switch oricModelTypeButton!.selectedItem!.tag {
case 1: return CSStaticAnalyser(oricModel: .oric1, hasMicrodrive: hasMicrodrive)
default: return CSStaticAnalyser(oricModel: .oricAtmos, hasMicrodrive: hasMicrodrive)
var diskInterface: CSMachineOricDiskInterface = .none
switch oricDiskInterfaceButton!.selectedTag() {
case 1: diskInterface = .microdisc
case 2: diskInterface = .pravetz
default: break;
}
var model: CSMachineOricModel = .oric1
switch oricModelTypeButton!.selectedItem!.tag {
case 1: model = .oricAtmos
case 2: model = .pravetz
default: break;
}
return CSStaticAnalyser(oricModel: model, diskInterface: diskInterface)
case "vic20":
let memorySize = Kilobytes(vic20MemorySizeButton!.selectedItem!.tag)

View File

@ -6,4 +6,5 @@ basic10.rom
basic11.rom
colour.rom
microdisc.rom
8dos.rom
8dos.rom
pravetz.rom