1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-08 10:07:25 +00:00
CLK/Machines/Oric/BD500.cpp
2024-02-15 13:41:35 -05:00

111 lines
2.9 KiB
C++

//
// BD500.cpp
// Clock Signal
//
// Created by Thomas Harte on 14/01/2020.
// Copyright © 2020 Thomas Harte. All rights reserved.
//
#include "BD500.hpp"
using namespace Oric;
/*
Notes on the code below: the Byte Drive 500 isn't well documented; this implementation is based on
experimentation without access to real hardware as documented in http://forum.defence-force.org/viewtopic.php?f=25&t=2055
and with additional guidance from iss of Oricutron (amongst other things) elsewhere,
e.g. http://forum.defence-force.org/viewtopic.php?f=22&t=1698&start=105#p21468
*/
BD500::BD500() : DiskController(P1793, 9000000, Storage::Disk::Drive::ReadyType::ShugartModifiedRDY) {
disable_basic_rom_ = true;
select_paged_item();
set_is_double_density(true);
set_drive(1);
}
void BD500::write(int address, uint8_t value) {
access(address);
if(address >= 0x0320 && address <= 0x0323) {
WD::WD1770::write(address, value);
}
if(address == 0x031a) {
// Drive select; kudos to iss of Oricutron for figuring this one out;
// cf. http://forum.defence-force.org/viewtopic.php?f=25&p=21409#p21393
switch(value & 0xe0) {
default: set_drive(0); break;
case 0x20: set_drive(1); break;
case 0x40: set_drive(2); break;
case 0x80: set_drive(4); break;
case 0xc0: set_drive(8); break;
}
}
}
uint8_t BD500::read(int address) {
access(address);
switch(address) {
default: return 0xff;
case 0x0320: case 0x0321: case 0x0322: case 0x0323:
return WD::WD1770::read(address);
case 0x312: return (get_data_request_line() ? 0x80 : 0x00) | (get_interrupt_request_line() ? 0x40 : 0x00);
}
}
void BD500::access(int address) {
// Determine whether to perform a command.
switch(address) {
case 0x0320: case 0x0321: case 0x0322: case 0x0323: case 0x0312:
return;
case 0x311: disable_basic_rom_ = true; break;
case 0x313: enable_overlay_ram_ = false; break;
case 0x314: enable_overlay_ram_ = true; break;
case 0x317: disable_basic_rom_ = false; break;
default: break;
}
select_paged_item();
}
void BD500::set_head_load_request(bool head_load) {
// Turn all motors on or off; if off then unload the head instantly.
is_loading_head_ |= head_load;
for_all_drives([head_load] (Storage::Disk::Drive &drive, size_t) {
drive.set_motor_on(head_load);
});
if(!head_load) set_head_loaded(false);
}
void BD500::run_for(const Cycles cycles) {
// If a head load is in progress and the selected drive is now ready,
// declare head loaded.
if(is_loading_head_ && get_drive().get_is_ready()) {
set_head_loaded(true);
is_loading_head_ = false;
}
WD::WD1770::run_for(cycles);
}
void BD500::set_activity_observer(Activity::Observer *observer) {
observer_ = observer;
if(observer) {
observer->register_led("BD-500");
observer_->set_led_status("BD-500", get_head_loaded());
}
}
void BD500::set_head_loaded(bool loaded) {
WD::WD1770::set_head_loaded(loaded);
if(observer_) {
observer_->set_led_status("BD-500", loaded);
}
}