mirror of
https://github.com/TomHarte/CLK.git
synced 2025-01-26 15:32:04 +00:00
Attempts to implement most of a Jasmin disk interface.
With one obvious omission: there's no way to start it? The real interface had a dedicated button, but I don't yet know what that button did. Research needed.
This commit is contained in:
parent
09289f383d
commit
9f30be1c13
66
Machines/Oric/Jasmin.cpp
Normal file
66
Machines/Oric/Jasmin.cpp
Normal file
@ -0,0 +1,66 @@
|
||||
//
|
||||
// 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_]);
|
||||
|
||||
// TODO: establish motor status for new drive.
|
||||
}
|
||||
} break;
|
||||
|
||||
default:
|
||||
return WD::WD1770::write(address, value);
|
||||
}
|
||||
}
|
58
Machines/Oric/Jasmin.hpp
Normal file
58
Machines/Oric/Jasmin.hpp
Normal file
@ -0,0 +1,58 @@
|
||||
//
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif /* Jasmin_hpp */
|
@ -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"
|
||||
@ -205,6 +206,7 @@ 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 {
|
||||
@ -244,6 +246,9 @@ 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::Jasmin:
|
||||
rom_names.emplace_back(machine_name, "the ORIC Jasmin ROM", "jasmin.rom", 2*1024, 0x37220e89);
|
||||
break;
|
||||
case Analyser::Static::Oric::Target::DiskInterface::Microdisc:
|
||||
rom_names.emplace_back(machine_name, "the ORIC Microdisc ROM", "microdisc.rom", 8*1024, 0xa9664a9c);
|
||||
break;
|
||||
@ -268,6 +273,10 @@ template <Analyser::Static::Oric::Target::DiskInterface disk_interface> class Co
|
||||
|
||||
switch(disk_interface) {
|
||||
default: break;
|
||||
case Analyser::Static::Oric::Target::DiskInterface::Jasmin:
|
||||
jasmin_rom_ = std::move(*roms[2]);
|
||||
jasmin_rom_.resize(2048);
|
||||
break;
|
||||
case Analyser::Static::Oric::Target::DiskInterface::Microdisc:
|
||||
microdisc_rom_ = std::move(*roms[2]);
|
||||
microdisc_rom_.resize(8192);
|
||||
@ -289,6 +298,9 @@ template <Analyser::Static::Oric::Target::DiskInterface disk_interface> class Co
|
||||
microdisc_did_change_paging_flags(µdisc_);
|
||||
microdisc_.set_delegate(this);
|
||||
break;
|
||||
case Analyser::Static::Oric::Target::DiskInterface::Jasmin:
|
||||
jasmin_.set_delegate(this);
|
||||
break;
|
||||
}
|
||||
|
||||
if(!target.loading_command.empty()) {
|
||||
@ -330,6 +342,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 +363,14 @@ template <Analyser::Static::Oric::Target::DiskInterface disk_interface> class Co
|
||||
|
||||
if(!media.disks.empty()) {
|
||||
switch(disk_interface) {
|
||||
case Analyser::Static::Oric::Target::DiskInterface::Jasmin:
|
||||
inserted |= insert_disks(media, jasmin_, 4);
|
||||
break;
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
inserted |= insert_disks(media, diskii_, 2);
|
||||
} break;
|
||||
|
||||
default: break;
|
||||
@ -391,6 +407,12 @@ template <Analyser::Static::Oric::Target::DiskInterface disk_interface> class Co
|
||||
} else {
|
||||
switch(disk_interface) {
|
||||
default: break;
|
||||
case Analyser::Static::Oric::Target::DiskInterface::Jasmin:
|
||||
if(address >= 0x3f4) {
|
||||
if(isReadOperation(operation)) *value = jasmin_.read(address);
|
||||
else jasmin_.write(address, *value);
|
||||
}
|
||||
break;
|
||||
case Analyser::Static::Oric::Target::DiskInterface::Microdisc:
|
||||
switch(address) {
|
||||
case 0x0310: case 0x0311: case 0x0312: case 0x0313:
|
||||
@ -448,6 +470,9 @@ 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::Jasmin:
|
||||
jasmin_.run_for(Cycles(8));
|
||||
break;
|
||||
case Analyser::Static::Oric::Target::DiskInterface::Microdisc:
|
||||
microdisc_.run_for(Cycles(8));
|
||||
break;
|
||||
@ -505,7 +530,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 +544,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();
|
||||
}
|
||||
@ -581,7 +631,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 +660,13 @@ 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_;
|
||||
|
||||
// the Pravetz/Disk II, if in use.
|
||||
Apple::DiskII diskii_;
|
||||
Cycles cycles_since_diskii_update_;
|
||||
void flush_diskii() {
|
||||
@ -630,8 +683,17 @@ 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 == Analyser::Static::Oric::Target::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 == Analyser::Static::Oric::Target::DiskInterface::Jasmin) {
|
||||
irq_line |= jasmin_.get_data_request_line();
|
||||
}
|
||||
|
||||
m6502_.set_irq_line(irq_line);
|
||||
}
|
||||
|
||||
@ -650,6 +712,7 @@ Machine *Machine::Oric(const Analyser::Static::Target *target_hint, const ROMMac
|
||||
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 */,
|
||||
|
Loading…
x
Reference in New Issue
Block a user