1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-06-25 18:30:07 +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:
Thomas Harte 2020-01-05 20:05:55 -05:00
parent 09289f383d
commit 9f30be1c13
6 changed files with 215 additions and 19 deletions

66
Machines/Oric/Jasmin.cpp Normal file
View 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
View 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 */

View File

@ -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]);

View File

@ -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();

View File

@ -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(&microdisc_);
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);
}
}

View File

@ -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 */,