mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-18 01:07:58 +00:00
Merge pull request #720 from TomHarte/Jasmin
Adds emulation of the Oric's Jasmin disk interface.
This commit is contained in:
commit
45afb13a54
@ -100,6 +100,34 @@ static bool IsMicrodisc(Storage::Encodings::MFM::Parser &parser) {
|
||||
return !std::memcmp(signature, first_sample.data(), sizeof(signature));
|
||||
}
|
||||
|
||||
static bool IsJasmin(Storage::Encodings::MFM::Parser &parser) {
|
||||
/*
|
||||
The Jasmin boot sector is sector 1 of track 0 and is loaded at $400;
|
||||
disassemble it to test it for validity.
|
||||
*/
|
||||
Storage::Encodings::MFM::Sector *sector = parser.get_sector(0, 0, 1);
|
||||
if(!sector) return false;
|
||||
if(sector->samples.empty()) return false;
|
||||
|
||||
const std::vector<uint8_t> &first_sample = sector->samples[0];
|
||||
if(first_sample.size() != 256) return false;
|
||||
|
||||
// Grab a disassembly.
|
||||
const auto disassembly =
|
||||
Analyser::Static::MOS6502::Disassemble(first_sample, Analyser::Static::Disassembler::OffsetMapper(0x400), {0x400});
|
||||
|
||||
// Check for references to the Jasmin registers.
|
||||
int register_hits = 0;
|
||||
for(auto list : {disassembly.external_stores, disassembly.external_loads, disassembly.external_modifies}) {
|
||||
for(auto address : list) {
|
||||
register_hits += (address >= 0x3f4 && address <= 0x3ff);
|
||||
}
|
||||
}
|
||||
|
||||
// Arbitrary, sure, but as long as at least two accesses to Jasmin registers are found, accept this.
|
||||
return register_hits >= 2;
|
||||
}
|
||||
|
||||
Analyser::Static::TargetList Analyser::Static::Oric::GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms) {
|
||||
auto target = std::make_unique<Target>();
|
||||
target->machine = Machine::Oric;
|
||||
@ -115,7 +143,7 @@ Analyser::Static::TargetList Analyser::Static::Oric::GetTargets(const Media &med
|
||||
for(const auto &file : tape_files) {
|
||||
if(file.data_type == File::MachineCode) {
|
||||
std::vector<uint16_t> entry_points = {file.starting_address};
|
||||
Analyser::Static::MOS6502::Disassembly disassembly =
|
||||
const Analyser::Static::MOS6502::Disassembly disassembly =
|
||||
Analyser::Static::MOS6502::Disassemble(file.data, Analyser::Static::Disassembler::OffsetMapper(file.starting_address), entry_points);
|
||||
|
||||
int basic10_score = Basic10Score(disassembly);
|
||||
@ -130,12 +158,17 @@ Analyser::Static::TargetList Analyser::Static::Oric::GetTargets(const Media &med
|
||||
}
|
||||
|
||||
if(!media.disks.empty()) {
|
||||
// Only the Microdisc is emulated right now, so accept only disks that it can boot from.
|
||||
// 8-DOS is recognised by a dedicated Disk II analyser, so check only for Microdisc and
|
||||
// Jasmin formats here.
|
||||
for(auto &disk: media.disks) {
|
||||
Storage::Encodings::MFM::Parser parser(true, disk);
|
||||
if(IsMicrodisc(parser)) {
|
||||
target->disk_interface = Target::DiskInterface::Microdisc;
|
||||
target->media.disks.push_back(disk);
|
||||
} else if(IsJasmin(parser)) {
|
||||
target->disk_interface = Target::DiskInterface::Jasmin;
|
||||
target->should_start_jasmin = true;
|
||||
target->media.disks.push_back(disk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,12 +26,14 @@ struct Target: public ::Analyser::Static::Target {
|
||||
enum class DiskInterface {
|
||||
Microdisc,
|
||||
Pravetz,
|
||||
Jasmin,
|
||||
None
|
||||
};
|
||||
|
||||
ROM rom = ROM::BASIC11;
|
||||
DiskInterface disk_interface = DiskInterface::None;
|
||||
std::string loading_command;
|
||||
bool should_start_jasmin = false;
|
||||
};
|
||||
|
||||
}
|
||||
|
70
Machines/Oric/Jasmin.cpp
Normal file
70
Machines/Oric/Jasmin.cpp
Normal file
@ -0,0 +1,70 @@
|
||||
//
|
||||
// Jasmin.cpp
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 05/01/2020.
|
||||
// Copyright © 2020 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#include "Jasmin.hpp"
|
||||
|
||||
using namespace Oric;
|
||||
|
||||
// NB: there's some controversy here on WD1770 versus WD1772, but between those two I think
|
||||
// the only difference is stepping rates, and it says 1770 on the schematic I'm looking at.
|
||||
Jasmin::Jasmin() : WD1770(P1770) {
|
||||
set_is_double_density(true);
|
||||
}
|
||||
|
||||
void Jasmin::set_disk(std::shared_ptr<Storage::Disk::Disk> disk, int d) {
|
||||
const size_t drive = size_t(d);
|
||||
if(!drives_[drive]) {
|
||||
drives_[drive] = std::make_unique<Storage::Disk::Drive>(8000000, 300, 2);
|
||||
if(drive == selected_drive_) set_drive(drives_[drive]);
|
||||
}
|
||||
drives_[drive]->set_disk(disk);
|
||||
}
|
||||
|
||||
void Jasmin::write(int address, uint8_t value) {
|
||||
switch(address) {
|
||||
// Set side.
|
||||
case 0x3f8:
|
||||
for(auto &drive : drives_) {
|
||||
if(drive) drive->set_head(value & 1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x3f9:
|
||||
/* TODO: reset. */
|
||||
break;
|
||||
|
||||
case 0x3fa: {
|
||||
// If b0, enable overlay RAM.
|
||||
posit_paging_flags((paging_flags_ & BASICDisable) | ((value & 1) ? OverlayRAMEnable : 0));
|
||||
} break;
|
||||
|
||||
case 0x3fb:
|
||||
// If b0, disable BASIC ROM.
|
||||
posit_paging_flags((paging_flags_ & OverlayRAMEnable) | ((value & 1) ? BASICDisable : 0));
|
||||
break;
|
||||
|
||||
case 0x3fc: case 0x3fd: case 0x3fe: case 0x3ff: {
|
||||
const size_t new_selected_drive = size_t(address - 0x3fc);
|
||||
|
||||
if(new_selected_drive != selected_drive_) {
|
||||
if(drives_[selected_drive_]) drives_[selected_drive_]->set_motor_on(false);
|
||||
selected_drive_ = new_selected_drive;
|
||||
set_drive(drives_[selected_drive_]);
|
||||
if(drives_[selected_drive_]) drives_[selected_drive_]->set_motor_on(motor_on_);
|
||||
}
|
||||
} break;
|
||||
|
||||
default:
|
||||
return WD::WD1770::write(address, value);
|
||||
}
|
||||
}
|
||||
|
||||
void Jasmin::set_motor_on(bool on) {
|
||||
motor_on_ = on;
|
||||
if(drives_[selected_drive_]) drives_[selected_drive_]->set_motor_on(motor_on_);
|
||||
}
|
60
Machines/Oric/Jasmin.hpp
Normal file
60
Machines/Oric/Jasmin.hpp
Normal file
@ -0,0 +1,60 @@
|
||||
//
|
||||
// Jasmin.hpp
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 05/01/2020.
|
||||
// Copyright © 2020 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef Jasmin_hpp
|
||||
#define Jasmin_hpp
|
||||
|
||||
#include "../../Components/1770/1770.hpp"
|
||||
#include "../../Activity/Observer.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
|
||||
namespace Oric {
|
||||
|
||||
class Jasmin: public WD::WD1770 {
|
||||
public:
|
||||
Jasmin();
|
||||
|
||||
void set_disk(std::shared_ptr<Storage::Disk::Disk> disk, int drive);
|
||||
void write(int address, uint8_t value);
|
||||
|
||||
enum PagingFlags {
|
||||
/// Indicates that overlay RAM is enabled, implying no ROM is visible.
|
||||
OverlayRAMEnable = (1 << 0),
|
||||
|
||||
/// Indicates that the BASIC ROM is disabled, implying that the JASMIN ROM
|
||||
/// fills its space.
|
||||
BASICDisable = (1 << 1)
|
||||
};
|
||||
struct Delegate: public WD1770::Delegate {
|
||||
virtual void jasmin_did_change_paging_flags(Jasmin *jasmin) = 0;
|
||||
};
|
||||
inline void set_delegate(Delegate *delegate) { delegate_ = delegate; WD1770::set_delegate(delegate); }
|
||||
inline int get_paging_flags() { return paging_flags_; }
|
||||
|
||||
private:
|
||||
std::array<std::shared_ptr<Storage::Disk::Drive>, 4> drives_;
|
||||
size_t selected_drive_;
|
||||
int paging_flags_ = 0;
|
||||
Delegate *delegate_ = nullptr;
|
||||
|
||||
void posit_paging_flags(int new_flags) {
|
||||
if(new_flags != paging_flags_) {
|
||||
paging_flags_ = new_flags;
|
||||
if(delegate_) delegate_->jasmin_did_change_paging_flags(this);
|
||||
}
|
||||
}
|
||||
|
||||
void set_motor_on(bool on) final;
|
||||
bool motor_on_ = false;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif /* Jasmin_hpp */
|
@ -45,6 +45,9 @@ uint16_t KeyboardMapper::mapped_key_for_key(Inputs::Keyboard::Key key) {
|
||||
|
||||
BIND(Space, KeySpace);
|
||||
BIND(Enter, KeyReturn);
|
||||
|
||||
BIND(F12, KeyNMI);
|
||||
BIND(F1, KeyJasminReset);
|
||||
}
|
||||
#undef BIND
|
||||
|
||||
|
@ -33,6 +33,7 @@ enum Key: uint16_t {
|
||||
KeyForwardSlash = 0x0700 | 0x08, Key0 = 0x0700 | 0x04, KeyL = 0x0700 | 0x02, Key8 = 0x0700 | 0x01,
|
||||
|
||||
KeyNMI = 0xfffd,
|
||||
KeyJasminReset = 0xfffc,
|
||||
};
|
||||
|
||||
struct KeyboardMapper: public KeyboardMachine::MappedMachine::KeyboardMapper {
|
||||
|
@ -22,7 +22,8 @@ Microdisc::Microdisc() : WD1770(P1793) {
|
||||
set_control_register(last_control_, 0xff);
|
||||
}
|
||||
|
||||
void Microdisc::set_disk(std::shared_ptr<Storage::Disk::Disk> disk, size_t drive) {
|
||||
void Microdisc::set_disk(std::shared_ptr<Storage::Disk::Disk> disk, int d) {
|
||||
const size_t drive = size_t(d);
|
||||
if(!drives_[drive]) {
|
||||
drives_[drive] = std::make_unique<Storage::Disk::Drive>(8000000, 300, 2);
|
||||
if(drive == selected_drive_) set_drive(drives_[drive]);
|
||||
|
@ -20,7 +20,7 @@ class Microdisc: public WD::WD1770 {
|
||||
public:
|
||||
Microdisc();
|
||||
|
||||
void set_disk(std::shared_ptr<Storage::Disk::Disk> disk, size_t drive);
|
||||
void set_disk(std::shared_ptr<Storage::Disk::Disk> disk, int drive);
|
||||
void set_control_register(uint8_t control);
|
||||
uint8_t get_interrupt_request_register();
|
||||
uint8_t get_data_request_register();
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include "Oric.hpp"
|
||||
|
||||
#include "Jasmin.hpp"
|
||||
#include "Keyboard.hpp"
|
||||
#include "Microdisc.hpp"
|
||||
#include "Video.hpp"
|
||||
@ -40,6 +41,8 @@
|
||||
|
||||
namespace Oric {
|
||||
|
||||
using DiskInterface = Analyser::Static::Oric::Target::DiskInterface;
|
||||
|
||||
enum ROM {
|
||||
BASIC10 = 0, BASIC11, Microdisc, Colour
|
||||
};
|
||||
@ -63,17 +66,32 @@ std::vector<std::unique_ptr<Configurable::Option>> get_options() {
|
||||
*/
|
||||
class Keyboard {
|
||||
public:
|
||||
Keyboard() {
|
||||
struct SpecialKeyHandler {
|
||||
virtual void perform_special_key(Oric::Key key) = 0;
|
||||
};
|
||||
|
||||
Keyboard(SpecialKeyHandler *handler) : special_key_handler_(handler) {
|
||||
clear_all_keys();
|
||||
}
|
||||
|
||||
/// Sets whether @c key is or is not pressed, per @c is_pressed.
|
||||
void set_key_state(uint16_t key, bool is_pressed) {
|
||||
uint8_t mask = key & 0xff;
|
||||
int line = key >> 8;
|
||||
switch(key) {
|
||||
default: {
|
||||
const uint8_t mask = key & 0xff;
|
||||
const int line = key >> 8;
|
||||
|
||||
if(is_pressed) rows_[line] |= mask;
|
||||
else rows_[line] &= ~mask;
|
||||
if(is_pressed) rows_[line] |= mask;
|
||||
else rows_[line] &= ~mask;
|
||||
} break;
|
||||
|
||||
case KeyNMI:
|
||||
case KeyJasminReset:
|
||||
if(is_pressed) {
|
||||
special_key_handler_->perform_special_key(Oric::Key(key));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets all keys as unpressed.
|
||||
@ -94,6 +112,7 @@ class Keyboard {
|
||||
private:
|
||||
uint8_t row_ = 0;
|
||||
uint8_t rows_[8];
|
||||
SpecialKeyHandler *const special_key_handler_;
|
||||
};
|
||||
|
||||
/*!
|
||||
@ -205,9 +224,11 @@ template <Analyser::Static::Oric::Target::DiskInterface disk_interface> class Co
|
||||
public Utility::TypeRecipient,
|
||||
public Storage::Tape::BinaryTapePlayer::Delegate,
|
||||
public Microdisc::Delegate,
|
||||
public Jasmin::Delegate,
|
||||
public ClockingHint::Observer,
|
||||
public Activity::Source,
|
||||
public Machine {
|
||||
public Machine,
|
||||
public Keyboard::SpecialKeyHandler {
|
||||
|
||||
public:
|
||||
ConcreteMachine(const Analyser::Static::Oric::Target &target, const ROMMachine::ROMFetcher &rom_fetcher) :
|
||||
@ -217,6 +238,7 @@ template <Analyser::Static::Oric::Target::DiskInterface disk_interface> class Co
|
||||
speaker_(ay8910_),
|
||||
via_port_handler_(audio_queue_, ay8910_, speaker_, tape_player_, keyboard_),
|
||||
via_(via_port_handler_),
|
||||
keyboard_(this),
|
||||
diskii_(2000000) {
|
||||
set_clock_rate(1000000);
|
||||
speaker_.set_input_rate(1000000.0f);
|
||||
@ -224,7 +246,7 @@ template <Analyser::Static::Oric::Target::DiskInterface disk_interface> class Co
|
||||
tape_player_.set_delegate(this);
|
||||
Memory::Fuzz(ram_, sizeof(ram_));
|
||||
|
||||
if constexpr (disk_interface == Analyser::Static::Oric::Target::DiskInterface::Pravetz) {
|
||||
if constexpr (disk_interface == DiskInterface::Pravetz) {
|
||||
diskii_.set_clocking_hint_observer(this);
|
||||
}
|
||||
|
||||
@ -244,10 +266,13 @@ template <Analyser::Static::Oric::Target::DiskInterface disk_interface> class Co
|
||||
size_t diskii_state_machine_index = 0;
|
||||
switch(disk_interface) {
|
||||
default: break;
|
||||
case Analyser::Static::Oric::Target::DiskInterface::Microdisc:
|
||||
case DiskInterface::Jasmin:
|
||||
rom_names.emplace_back(machine_name, "the ORIC Jasmin ROM", "jasmin.rom", 2*1024, 0x37220e89);
|
||||
break;
|
||||
case DiskInterface::Microdisc:
|
||||
rom_names.emplace_back(machine_name, "the ORIC Microdisc ROM", "microdisc.rom", 8*1024, 0xa9664a9c);
|
||||
break;
|
||||
case Analyser::Static::Oric::Target::DiskInterface::Pravetz:
|
||||
case DiskInterface::Pravetz:
|
||||
rom_names.emplace_back(machine_name, "the 8DOS boot ROM", "8dos.rom", 512, 0x49a74c06);
|
||||
// These ROM details are coupled with those in the DiskIICard.
|
||||
diskii_state_machine_index = rom_names.size();
|
||||
@ -268,11 +293,15 @@ template <Analyser::Static::Oric::Target::DiskInterface disk_interface> class Co
|
||||
|
||||
switch(disk_interface) {
|
||||
default: break;
|
||||
case Analyser::Static::Oric::Target::DiskInterface::Microdisc:
|
||||
case DiskInterface::Jasmin:
|
||||
jasmin_rom_ = std::move(*roms[2]);
|
||||
jasmin_rom_.resize(2048);
|
||||
break;
|
||||
case DiskInterface::Microdisc:
|
||||
microdisc_rom_ = std::move(*roms[2]);
|
||||
microdisc_rom_.resize(8192);
|
||||
break;
|
||||
case Analyser::Static::Oric::Target::DiskInterface::Pravetz: {
|
||||
case DiskInterface::Pravetz: {
|
||||
pravetz_rom_ = std::move(*roms[2]);
|
||||
pravetz_rom_.resize(512);
|
||||
|
||||
@ -285,16 +314,26 @@ template <Analyser::Static::Oric::Target::DiskInterface disk_interface> class Co
|
||||
|
||||
switch(target.disk_interface) {
|
||||
default: break;
|
||||
case Analyser::Static::Oric::Target::DiskInterface::Microdisc:
|
||||
case DiskInterface::Microdisc:
|
||||
microdisc_did_change_paging_flags(µdisc_);
|
||||
microdisc_.set_delegate(this);
|
||||
break;
|
||||
case DiskInterface::Jasmin:
|
||||
jasmin_did_change_paging_flags(&jasmin_);
|
||||
jasmin_.set_delegate(this);
|
||||
break;
|
||||
}
|
||||
|
||||
if(!target.loading_command.empty()) {
|
||||
type_string(target.loading_command);
|
||||
}
|
||||
|
||||
if(target.should_start_jasmin) {
|
||||
// If Jasmin autostart is requested then plan to do so in 3 seconds; empirically long enough
|
||||
// for the Oric to boot normally, before the Jasmin intercedes.
|
||||
jasmin_reset_counter_ = 3000000;
|
||||
}
|
||||
|
||||
switch(target.rom) {
|
||||
case Analyser::Static::Oric::Target::ROM::BASIC10:
|
||||
tape_get_byte_address_ = 0xe630;
|
||||
@ -330,6 +369,17 @@ template <Analyser::Static::Oric::Target::DiskInterface disk_interface> class Co
|
||||
use_fast_tape_hack_ = activate;
|
||||
}
|
||||
|
||||
template <typename DiskInterface> bool insert_disks(const Analyser::Static::Media &media, DiskInterface &interface, int num_drives) {
|
||||
int drive_index = 0;
|
||||
for(auto &disk : media.disks) {
|
||||
interface.set_disk(disk, drive_index);
|
||||
++drive_index;
|
||||
if(drive_index == num_drives) break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool insert_media(const Analyser::Static::Media &media) override final {
|
||||
bool inserted = false;
|
||||
|
||||
@ -340,21 +390,14 @@ template <Analyser::Static::Oric::Target::DiskInterface disk_interface> class Co
|
||||
|
||||
if(!media.disks.empty()) {
|
||||
switch(disk_interface) {
|
||||
case Analyser::Static::Oric::Target::DiskInterface::Microdisc: {
|
||||
inserted = true;
|
||||
size_t drive_index = 0;
|
||||
for(auto &disk : media.disks) {
|
||||
if(drive_index < 4) microdisc_.set_disk(disk, drive_index);
|
||||
++drive_index;
|
||||
}
|
||||
case DiskInterface::Jasmin:
|
||||
inserted |= insert_disks(media, jasmin_, 4);
|
||||
break;
|
||||
case DiskInterface::Microdisc: {
|
||||
inserted |= insert_disks(media, microdisc_, 4);
|
||||
} 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;
|
||||
}
|
||||
case DiskInterface::Pravetz: {
|
||||
inserted |= insert_disks(media, diskii_, 2);
|
||||
} break;
|
||||
|
||||
default: break;
|
||||
@ -385,13 +428,19 @@ template <Analyser::Static::Oric::Target::DiskInterface disk_interface> class Co
|
||||
}
|
||||
} else {
|
||||
if((address & 0xff00) == 0x0300) {
|
||||
if(address < 0x0310 || (disk_interface == Analyser::Static::Oric::Target::DiskInterface::None)) {
|
||||
if(address < 0x0310 || (disk_interface == DiskInterface::None)) {
|
||||
if(isReadOperation(operation)) *value = via_.read(address);
|
||||
else via_.write(address, *value);
|
||||
} else {
|
||||
switch(disk_interface) {
|
||||
default: break;
|
||||
case Analyser::Static::Oric::Target::DiskInterface::Microdisc:
|
||||
case DiskInterface::Jasmin:
|
||||
if(address >= 0x3f4) {
|
||||
if(isReadOperation(operation)) *value = jasmin_.read(address);
|
||||
else jasmin_.write(address, *value);
|
||||
}
|
||||
break;
|
||||
case DiskInterface::Microdisc:
|
||||
switch(address) {
|
||||
case 0x0310: case 0x0311: case 0x0312: case 0x0313:
|
||||
if(isReadOperation(operation)) *value = microdisc_.read(address);
|
||||
@ -406,7 +455,7 @@ template <Analyser::Static::Oric::Target::DiskInterface disk_interface> class Co
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case Analyser::Static::Oric::Target::DiskInterface::Pravetz:
|
||||
case DiskInterface::Pravetz:
|
||||
if(address >= 0x0320) {
|
||||
if(isReadOperation(operation)) *value = pravetz_rom_[pravetz_rom_base_pointer_ + (address & 0xff)];
|
||||
else {
|
||||
@ -448,10 +497,23 @@ template <Analyser::Static::Oric::Target::DiskInterface disk_interface> class Co
|
||||
tape_player_.run_for(Cycles(1));
|
||||
switch(disk_interface) {
|
||||
default: break;
|
||||
case Analyser::Static::Oric::Target::DiskInterface::Microdisc:
|
||||
case DiskInterface::Jasmin:
|
||||
jasmin_.run_for(Cycles(8));
|
||||
|
||||
// Jasmin autostart hack: wait for a period, then trigger a reset, having forced
|
||||
// the Jasmin to page its ROM in first. I assume the latter being what the Jasmin's
|
||||
// hardware boot button did.
|
||||
if(jasmin_reset_counter_) {
|
||||
--jasmin_reset_counter_;
|
||||
if(!jasmin_reset_counter_) {
|
||||
perform_special_key(KeyJasminReset);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DiskInterface::Microdisc:
|
||||
microdisc_.run_for(Cycles(8));
|
||||
break;
|
||||
case Analyser::Static::Oric::Target::DiskInterface::Pravetz:
|
||||
case DiskInterface::Pravetz:
|
||||
if(diskii_clocking_preference_ == ClockingHint::Preference::RealTime) {
|
||||
diskii_.set_data_input(*value);
|
||||
diskii_.run_for(Cycles(2));
|
||||
@ -461,6 +523,7 @@ template <Analyser::Static::Oric::Target::DiskInterface disk_interface> class Co
|
||||
break;
|
||||
}
|
||||
cycles_since_video_update_++;
|
||||
|
||||
return Cycles(1);
|
||||
}
|
||||
|
||||
@ -505,7 +568,7 @@ template <Analyser::Static::Oric::Target::DiskInterface disk_interface> class Co
|
||||
|
||||
// for Microdisc::Delegate
|
||||
void microdisc_did_change_paging_flags(class Microdisc *microdisc) override final {
|
||||
int flags = microdisc->get_paging_flags();
|
||||
const int flags = microdisc->get_paging_flags();
|
||||
if(!(flags&Microdisc::PagingFlags::BASICDisable)) {
|
||||
ram_top_ = basic_visible_ram_top_;
|
||||
paged_rom_ = rom_.data();
|
||||
@ -519,6 +582,31 @@ template <Analyser::Static::Oric::Target::DiskInterface disk_interface> class Co
|
||||
}
|
||||
}
|
||||
|
||||
// Jasmin::Delegate
|
||||
void jasmin_did_change_paging_flags(Jasmin *jasmin) override final {
|
||||
const int flags = jasmin->get_paging_flags();
|
||||
switch(flags) {
|
||||
// BASIC enabled, overlay disabled.
|
||||
default:
|
||||
ram_top_ = basic_visible_ram_top_;
|
||||
paged_rom_ = rom_.data();
|
||||
break;
|
||||
|
||||
// Overlay RAM enabled, with or without BASIC.
|
||||
case Jasmin::OverlayRAMEnable:
|
||||
case Jasmin::OverlayRAMEnable | Jasmin::BASICDisable:
|
||||
ram_top_ = basic_invisible_ram_top_;
|
||||
break;
|
||||
|
||||
// BASIC disabled, overlay disabled.
|
||||
case Jasmin::BASICDisable:
|
||||
ram_top_ = 0xf7ff;
|
||||
paged_rom_ = jasmin_rom_.data();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// WD::WD1770::Delegate
|
||||
void wd1770_did_change_output(WD::WD1770 *wd1770) override final {
|
||||
set_interrupt_line();
|
||||
}
|
||||
@ -561,10 +649,10 @@ template <Analyser::Static::Oric::Target::DiskInterface disk_interface> class Co
|
||||
void set_activity_observer(Activity::Observer *observer) override {
|
||||
switch(disk_interface) {
|
||||
default: break;
|
||||
case Analyser::Static::Oric::Target::DiskInterface::Microdisc:
|
||||
case DiskInterface::Microdisc:
|
||||
microdisc_.set_activity_observer(observer);
|
||||
break;
|
||||
case Analyser::Static::Oric::Target::DiskInterface::Pravetz:
|
||||
case DiskInterface::Pravetz:
|
||||
diskii_.set_activity_observer(observer);
|
||||
break;
|
||||
}
|
||||
@ -581,7 +669,7 @@ template <Analyser::Static::Oric::Target::DiskInterface disk_interface> class Co
|
||||
CPU::MOS6502::Processor<CPU::MOS6502::Personality::P6502, ConcreteMachine, false> m6502_;
|
||||
|
||||
// RAM and ROM
|
||||
std::vector<uint8_t> rom_, microdisc_rom_;
|
||||
std::vector<uint8_t> rom_, microdisc_rom_, jasmin_rom_;
|
||||
uint8_t ram_[65536];
|
||||
Cycles cycles_since_video_update_;
|
||||
inline void update_video() {
|
||||
@ -610,10 +698,14 @@ template <Analyser::Static::Oric::Target::DiskInterface disk_interface> class Co
|
||||
MOS::MOS6522::MOS6522<VIAPortHandler> via_;
|
||||
Keyboard keyboard_;
|
||||
|
||||
// the Microdisc, if in use
|
||||
// the Microdisc, if in use.
|
||||
class Microdisc microdisc_;
|
||||
|
||||
// the Pravetz/Disk II, if in use
|
||||
// the Jasmin, if in use.
|
||||
Jasmin jasmin_;
|
||||
int jasmin_reset_counter_ = 0;
|
||||
|
||||
// the Pravetz/Disk II, if in use.
|
||||
Apple::DiskII diskii_;
|
||||
Cycles cycles_since_diskii_update_;
|
||||
void flush_diskii() {
|
||||
@ -630,11 +722,40 @@ template <Analyser::Static::Oric::Target::DiskInterface disk_interface> class Co
|
||||
// Helper to discern current IRQ state
|
||||
inline void set_interrupt_line() {
|
||||
bool irq_line = via_.get_interrupt_line();
|
||||
if constexpr (disk_interface == Analyser::Static::Oric::Target::DiskInterface::Microdisc)
|
||||
|
||||
// The Microdisc directly provides an interrupt line.
|
||||
if constexpr (disk_interface == DiskInterface::Microdisc) {
|
||||
irq_line |= microdisc_.get_interrupt_request_line();
|
||||
}
|
||||
|
||||
// The Jasmin reroutes its data request line to the processor's interrupt line.
|
||||
if constexpr (disk_interface == DiskInterface::Jasmin) {
|
||||
irq_line |= jasmin_.get_data_request_line();
|
||||
}
|
||||
|
||||
m6502_.set_irq_line(irq_line);
|
||||
}
|
||||
|
||||
// Keys that aren't read by polling.
|
||||
void perform_special_key(Oric::Key key) override {
|
||||
switch(key) {
|
||||
default: break;
|
||||
|
||||
case KeyJasminReset:
|
||||
jasmin_.write(0x3fa, 0);
|
||||
jasmin_.write(0x3fb, 1);
|
||||
m6502_.set_power_on(true);
|
||||
break;
|
||||
|
||||
case KeyNMI:
|
||||
// As luck would have it, the 6502's NMI line is edge triggered.
|
||||
// So just forcing through an edge will work here.
|
||||
m6502_.set_nmi_line(true);
|
||||
m6502_.set_nmi_line(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// MARK - typing
|
||||
std::unique_ptr<Utility::StringSerialiser> string_serialiser_;
|
||||
};
|
||||
@ -645,11 +766,11 @@ using namespace Oric;
|
||||
|
||||
Machine *Machine::Oric(const Analyser::Static::Target *target_hint, const ROMMachine::ROMFetcher &rom_fetcher) {
|
||||
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, rom_fetcher);
|
||||
case DiskInterface::Microdisc: return new ConcreteMachine<DiskInterface::Microdisc>(*oric_target, rom_fetcher);
|
||||
case DiskInterface::Pravetz: return new ConcreteMachine<DiskInterface::Pravetz>(*oric_target, rom_fetcher);
|
||||
case DiskInterface::Jasmin: return new ConcreteMachine<DiskInterface::Jasmin>(*oric_target, rom_fetcher);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -369,6 +369,8 @@
|
||||
4B79E4461E3AF38600141F11 /* floppy525.png in Resources */ = {isa = PBXBuildFile; fileRef = 4B79E4431E3AF38600141F11 /* floppy525.png */; };
|
||||
4B7A90E52041097C008514A2 /* ColecoVision.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B7A90E42041097C008514A2 /* ColecoVision.cpp */; };
|
||||
4B7A90ED20410A85008514A2 /* StaticAnalyser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B7A90EC20410A85008514A2 /* StaticAnalyser.cpp */; };
|
||||
4B7BA03023C2B19C00B98D9E /* Jasmin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B7BA02E23C2B19B00B98D9E /* Jasmin.cpp */; };
|
||||
4B7BA03123C2B19C00B98D9E /* Jasmin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B7BA02E23C2B19B00B98D9E /* Jasmin.cpp */; };
|
||||
4B7BC7F51F58F27800D1B1B4 /* 6502AllRAM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B6A4C911F58F09E00E3F787 /* 6502AllRAM.cpp */; };
|
||||
4B7F188E2154825E00388727 /* MasterSystem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B7F188C2154825D00388727 /* MasterSystem.cpp */; };
|
||||
4B7F188F2154825E00388727 /* MasterSystem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B7F188C2154825D00388727 /* MasterSystem.cpp */; };
|
||||
@ -1178,6 +1180,8 @@
|
||||
4B7A90E42041097C008514A2 /* ColecoVision.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ColecoVision.cpp; sourceTree = "<group>"; };
|
||||
4B7A90EB20410A85008514A2 /* StaticAnalyser.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = StaticAnalyser.hpp; sourceTree = "<group>"; };
|
||||
4B7A90EC20410A85008514A2 /* StaticAnalyser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StaticAnalyser.cpp; sourceTree = "<group>"; };
|
||||
4B7BA02E23C2B19B00B98D9E /* Jasmin.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Jasmin.cpp; path = Oric/Jasmin.cpp; sourceTree = "<group>"; };
|
||||
4B7BA02F23C2B19B00B98D9E /* Jasmin.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Jasmin.hpp; path = Oric/Jasmin.hpp; sourceTree = "<group>"; };
|
||||
4B7F188C2154825D00388727 /* MasterSystem.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MasterSystem.cpp; sourceTree = "<group>"; };
|
||||
4B7F188D2154825D00388727 /* MasterSystem.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = MasterSystem.hpp; sourceTree = "<group>"; };
|
||||
4B7F1895215486A100388727 /* StaticAnalyser.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = StaticAnalyser.hpp; sourceTree = "<group>"; };
|
||||
@ -3529,10 +3533,12 @@
|
||||
4BCF1FA51DADC3E10039D2E7 /* Oric */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4B7BA02E23C2B19B00B98D9E /* Jasmin.cpp */,
|
||||
4B54C0BD1F8D8F450050900F /* Keyboard.cpp */,
|
||||
4B5FADBE1DE3BF2B00AEC565 /* Microdisc.cpp */,
|
||||
4BCF1FA21DADC3DD0039D2E7 /* Oric.cpp */,
|
||||
4B2BFDB01DAEF5FF001A68B8 /* Video.cpp */,
|
||||
4B7BA02F23C2B19B00B98D9E /* Jasmin.hpp */,
|
||||
4B54C0BE1F8D8F450050900F /* Keyboard.hpp */,
|
||||
4B5FADBF1DE3BF2B00AEC565 /* Microdisc.hpp */,
|
||||
4BCF1FA31DADC3DD0039D2E7 /* Oric.hpp */,
|
||||
@ -4215,6 +4221,7 @@
|
||||
4B055AD51FAE9B0B0060FFFF /* Video.cpp in Sources */,
|
||||
4B894521201967B4007DE474 /* StaticAnalyser.cpp in Sources */,
|
||||
4B8318B522D3E548006DB630 /* Macintosh.cpp in Sources */,
|
||||
4B7BA03123C2B19C00B98D9E /* Jasmin.cpp in Sources */,
|
||||
4B7F188F2154825E00388727 /* MasterSystem.cpp in Sources */,
|
||||
4B055AA51FAE85EF0060FFFF /* Encoder.cpp in Sources */,
|
||||
4BD5D2692199148100DDF17D /* ScanTargetGLSLFragments.cpp in Sources */,
|
||||
@ -4472,6 +4479,7 @@
|
||||
4B4518831F75E91A00926311 /* PCMTrack.cpp in Sources */,
|
||||
4B0ACC3223775819008902D0 /* Atari2600.cpp in Sources */,
|
||||
4B45189F1F75FD1C00926311 /* AcornADF.cpp in Sources */,
|
||||
4B7BA03023C2B19C00B98D9E /* Jasmin.cpp in Sources */,
|
||||
4B7136911F789C93008B8ED9 /* SegmentParser.cpp in Sources */,
|
||||
4B4518A21F75FD1C00926311 /* G64.cpp in Sources */,
|
||||
4B89452C201967B4007DE474 /* Tape.cpp in Sources */,
|
||||
|
@ -49,7 +49,8 @@ typedef NS_ENUM(NSInteger, CSMachineOricModel) {
|
||||
typedef NS_ENUM(NSInteger, CSMachineOricDiskInterface) {
|
||||
CSMachineOricDiskInterfaceNone,
|
||||
CSMachineOricDiskInterfaceMicrodisc,
|
||||
CSMachineOricDiskInterfacePravetz
|
||||
CSMachineOricDiskInterfacePravetz,
|
||||
CSMachineOricDiskInterfaceJasmin
|
||||
};
|
||||
|
||||
typedef NS_ENUM(NSInteger, CSMachineVic20Region) {
|
||||
|
@ -102,6 +102,7 @@
|
||||
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;
|
||||
case CSMachineOricDiskInterfaceJasmin: target->disk_interface = Target::DiskInterface::Jasmin; break;
|
||||
}
|
||||
_targets.push_back(std::move(target));
|
||||
}
|
||||
|
@ -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="720" height="205"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="1440" height="900"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="3840" height="2137"/>
|
||||
<view key="contentView" wantsLayer="YES" id="EiT-Mj-1SZ">
|
||||
<rect key="frame" x="0.0" y="0.0" width="720" height="205"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
@ -64,7 +64,7 @@ Gw
|
||||
<tabViewItems>
|
||||
<tabViewItem label="Apple II" identifier="appleii" id="P59-QG-LOa">
|
||||
<view key="view" id="dHz-Yv-GNq">
|
||||
<rect key="frame" x="10" y="33" width="604" height="94"/>
|
||||
<rect key="frame" x="10" y="33" width="674" height="94"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="V5Z-dX-Ns4">
|
||||
@ -305,7 +305,7 @@ 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="604" height="94"/>
|
||||
<rect key="frame" x="10" y="33" width="674" height="94"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="0ct-tf-uRH">
|
||||
@ -339,6 +339,7 @@ Gw
|
||||
<items>
|
||||
<menuItem title="None" state="on" id="XhK-Jh-oTW"/>
|
||||
<menuItem title="Microdisc" tag="1" id="1jS-Lz-FRj"/>
|
||||
<menuItem title="Jasmin" tag="3" id="CGU-gd-xov"/>
|
||||
<menuItem title="8DOS" tag="2" id="edb-fl-C8Y"/>
|
||||
</items>
|
||||
</menu>
|
||||
@ -370,7 +371,7 @@ Gw
|
||||
</tabViewItem>
|
||||
<tabViewItem label="Vic-20" identifier="vic20" id="cyO-PU-hSU">
|
||||
<view key="view" id="fLI-XB-QCr">
|
||||
<rect key="frame" x="10" y="33" width="604" height="94"/>
|
||||
<rect key="frame" x="10" y="33" width="674" height="94"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="ueK-gq-gaF">
|
||||
|
@ -195,6 +195,7 @@ class MachinePicker: NSObject {
|
||||
switch oricDiskInterfaceButton!.selectedTag() {
|
||||
case 1: diskInterface = .microdisc
|
||||
case 2: diskInterface = .pravetz
|
||||
case 3: diskInterface = .jasmin
|
||||
default: break;
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user