2016-11-22 00:12:53 +00:00
|
|
|
//
|
|
|
|
// Microdisc.cpp
|
|
|
|
// Clock Signal
|
|
|
|
//
|
|
|
|
// Created by Thomas Harte on 22/11/2016.
|
2018-05-13 19:19:52 +00:00
|
|
|
// Copyright 2016 Thomas Harte. All rights reserved.
|
2016-11-22 00:12:53 +00:00
|
|
|
//
|
|
|
|
|
|
|
|
#include "Microdisc.hpp"
|
|
|
|
|
|
|
|
using namespace Oric;
|
|
|
|
|
2016-12-02 02:13:16 +00:00
|
|
|
namespace {
|
2016-12-02 23:36:47 +00:00
|
|
|
// The number below, in cycles against an 8Mhz clock, was arrived at fairly unscientifically,
|
|
|
|
// by comparing the amount of time this emulator took to show a directory versus a video of
|
|
|
|
// a real Oric. It therefore assumes all other timing measurements were correct on the day
|
|
|
|
// of the test. More work to do, I think.
|
2019-10-30 02:36:29 +00:00
|
|
|
const Cycles::IntType head_load_request_counter_target = 7653333;
|
2016-12-02 02:13:16 +00:00
|
|
|
}
|
|
|
|
|
2020-01-17 02:34:57 +00:00
|
|
|
Microdisc::Microdisc() : DiskController(P1793, 8000000, Storage::Disk::Drive::ReadyType::ShugartRDY) {
|
2016-12-28 23:49:32 +00:00
|
|
|
set_control_register(last_control_, 0xff);
|
|
|
|
}
|
2016-11-22 00:12:53 +00:00
|
|
|
|
2017-03-26 18:34:47 +00:00
|
|
|
void Microdisc::set_control_register(uint8_t control) {
|
2019-10-29 01:13:42 +00:00
|
|
|
const uint8_t changes = last_control_ ^ control;
|
2016-12-28 23:29:37 +00:00
|
|
|
last_control_ = control;
|
2016-12-28 23:49:32 +00:00
|
|
|
set_control_register(control, changes);
|
|
|
|
}
|
2016-12-02 23:36:47 +00:00
|
|
|
|
2017-03-26 18:34:47 +00:00
|
|
|
void Microdisc::set_control_register(uint8_t control, uint8_t changes) {
|
2016-11-22 14:09:52 +00:00
|
|
|
// b2: data separator clock rate select (1 = double) [TODO]
|
2016-11-22 00:12:53 +00:00
|
|
|
|
|
|
|
// b65: drive select
|
2017-03-26 18:34:47 +00:00
|
|
|
if((changes >> 5)&3) {
|
2016-12-28 23:29:37 +00:00
|
|
|
selected_drive_ = (control >> 5)&3;
|
|
|
|
set_drive(drives_[selected_drive_]);
|
|
|
|
}
|
2016-11-22 00:12:53 +00:00
|
|
|
|
|
|
|
// b4: side select
|
2017-03-26 18:34:47 +00:00
|
|
|
if(changes & 0x10) {
|
2019-10-29 01:13:42 +00:00
|
|
|
const int head = (control & 0x10) ? 1 : 0;
|
2018-05-12 03:05:36 +00:00
|
|
|
for(auto &drive : drives_) {
|
|
|
|
if(drive) drive->set_head(head);
|
2016-12-28 23:29:37 +00:00
|
|
|
}
|
2016-11-22 00:12:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// b3: double density select (0 = double)
|
2017-03-26 18:34:47 +00:00
|
|
|
if(changes & 0x08) {
|
2016-12-28 23:29:37 +00:00
|
|
|
set_is_double_density(!(control & 0x08));
|
|
|
|
}
|
2016-11-22 00:12:53 +00:00
|
|
|
|
|
|
|
// b0: IRQ enable
|
2017-03-26 18:34:47 +00:00
|
|
|
if(changes & 0x01) {
|
2019-10-29 01:13:42 +00:00
|
|
|
const bool had_irq = get_interrupt_request_line();
|
2016-12-28 23:29:37 +00:00
|
|
|
irq_enable_ = !!(control & 0x01);
|
2019-10-29 01:13:42 +00:00
|
|
|
const bool has_irq = get_interrupt_request_line();
|
2017-03-26 18:34:47 +00:00
|
|
|
if(has_irq != had_irq && delegate_) {
|
2016-12-28 23:29:37 +00:00
|
|
|
delegate_->wd1770_did_change_output(this);
|
|
|
|
}
|
2016-11-26 01:35:44 +00:00
|
|
|
}
|
2016-11-22 14:09:52 +00:00
|
|
|
|
|
|
|
// b7: EPROM select (0 = select)
|
|
|
|
// b1: ROM disable (0 = disable)
|
2017-03-26 18:34:47 +00:00
|
|
|
if(changes & 0x82) {
|
2020-01-16 04:15:39 +00:00
|
|
|
enable_overlay_ram_ = control & 0x80;
|
|
|
|
disable_basic_rom_ = !(control & 0x02);
|
|
|
|
select_paged_item();
|
2016-11-22 14:09:52 +00:00
|
|
|
}
|
2016-11-22 00:12:53 +00:00
|
|
|
}
|
|
|
|
|
2017-03-26 18:34:47 +00:00
|
|
|
bool Microdisc::get_interrupt_request_line() {
|
2016-11-22 00:12:53 +00:00
|
|
|
return irq_enable_ && WD1770::get_interrupt_request_line();
|
|
|
|
}
|
|
|
|
|
2017-03-26 18:34:47 +00:00
|
|
|
uint8_t Microdisc::get_interrupt_request_register() {
|
2016-12-07 02:16:29 +00:00
|
|
|
return 0x7f | (WD1770::get_interrupt_request_line() ? 0x00 : 0x80);
|
2016-11-22 00:12:53 +00:00
|
|
|
}
|
|
|
|
|
2017-03-26 18:34:47 +00:00
|
|
|
uint8_t Microdisc::get_data_request_register() {
|
2016-11-25 13:24:59 +00:00
|
|
|
return 0x7f | (get_data_request_line() ? 0x00 : 0x80);
|
2016-11-22 00:12:53 +00:00
|
|
|
}
|
2016-12-02 01:12:22 +00:00
|
|
|
|
2017-03-26 18:34:47 +00:00
|
|
|
void Microdisc::set_head_load_request(bool head_load) {
|
2018-05-12 03:05:36 +00:00
|
|
|
head_load_request_ = head_load;
|
|
|
|
|
2017-09-12 02:15:54 +00:00
|
|
|
// The drive motors (at present: I believe **all drive motors** regardless of the selected drive) receive
|
|
|
|
// the current head load request state.
|
2018-05-12 03:05:36 +00:00
|
|
|
for(auto &drive : drives_) {
|
|
|
|
if(drive) drive->set_motor_on(head_load);
|
2017-09-12 02:15:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// A request to load the head results in a delay until the head is confirmed loaded. This delay is handled
|
|
|
|
// in ::run_for. A request to unload the head results in an instant answer that the head is unloaded.
|
2017-03-26 18:34:47 +00:00
|
|
|
if(head_load) {
|
2016-12-02 02:13:16 +00:00
|
|
|
head_load_request_counter_ = 0;
|
2017-03-26 18:34:47 +00:00
|
|
|
} else {
|
2016-12-02 02:13:16 +00:00
|
|
|
head_load_request_counter_ = head_load_request_counter_target;
|
|
|
|
set_head_loaded(head_load);
|
|
|
|
}
|
2018-05-12 03:05:36 +00:00
|
|
|
|
|
|
|
if(observer_) {
|
|
|
|
observer_->set_led_status("Microdisc", head_load);
|
|
|
|
}
|
2016-12-02 02:13:16 +00:00
|
|
|
}
|
|
|
|
|
2017-07-28 02:05:29 +00:00
|
|
|
void Microdisc::run_for(const Cycles cycles) {
|
2017-03-26 18:34:47 +00:00
|
|
|
if(head_load_request_counter_ < head_load_request_counter_target) {
|
2019-10-30 02:36:29 +00:00
|
|
|
head_load_request_counter_ += cycles.as_integral();
|
2016-12-02 02:13:16 +00:00
|
|
|
if(head_load_request_counter_ >= head_load_request_counter_target) set_head_loaded(true);
|
|
|
|
}
|
2017-07-25 01:51:13 +00:00
|
|
|
WD::WD1770::run_for(cycles);
|
2016-12-02 02:13:16 +00:00
|
|
|
}
|
|
|
|
|
2018-05-12 03:05:36 +00:00
|
|
|
void Microdisc::set_activity_observer(Activity::Observer *observer) {
|
|
|
|
observer_ = observer;
|
|
|
|
if(observer) {
|
|
|
|
observer->register_led("Microdisc");
|
|
|
|
observer_->set_led_status("Microdisc", head_load_request_);
|
|
|
|
}
|
2018-05-12 21:32:53 +00:00
|
|
|
}
|