mirror of
https://github.com/TomHarte/CLK.git
synced 2025-02-16 18:30:32 +00:00
Advances IWM/drive emulation very close to the point of 'Welcome to Macintosh'.
This commit is contained in:
parent
cc7226ae9f
commit
877b46d2c1
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#include "IWM.hpp"
|
#include "IWM.hpp"
|
||||||
|
|
||||||
|
#define NDEBUG
|
||||||
#include "../../Outputs/Log.hpp"
|
#include "../../Outputs/Log.hpp"
|
||||||
|
|
||||||
using namespace Apple;
|
using namespace Apple;
|
||||||
@ -84,7 +85,7 @@ uint8_t IWM::read(int address) {
|
|||||||
LOGNBR("Reading status (including [" << active_drive_ << "][" << ((state_ & CA2) ? '2' : '-') << ((state_ & CA1) ? '1' : '-') << ((state_ & CA0) ? '0' : '-') << ((state_ & SEL) ? 'S' : '-') << "] ");
|
LOGNBR("Reading status (including [" << active_drive_ << "][" << ((state_ & CA2) ? '2' : '-') << ((state_ & CA1) ? '1' : '-') << ((state_ & CA0) ? '0' : '-') << ((state_ & SEL) ? 'S' : '-') << "] ");
|
||||||
|
|
||||||
// Determine the SENSE input.
|
// Determine the SENSE input.
|
||||||
uint8_t sense = 0x00;
|
uint8_t sense = 0;
|
||||||
switch(state_ & (CA2 | CA1 | CA0 | SEL)) {
|
switch(state_ & (CA2 | CA1 | CA0 | SEL)) {
|
||||||
default:
|
default:
|
||||||
LOG("unknown)");
|
LOG("unknown)");
|
||||||
@ -96,7 +97,8 @@ uint8_t IWM::read(int address) {
|
|||||||
//
|
//
|
||||||
// {CA1,CA0,SEL,CA2}
|
// {CA1,CA0,SEL,CA2}
|
||||||
|
|
||||||
// case 0: // Head step direction. (0 = inward)
|
// case 0: // Head step direction.
|
||||||
|
// (0 = inward)
|
||||||
// printf("head step direction)\n");
|
// printf("head step direction)\n");
|
||||||
// break;
|
// break;
|
||||||
|
|
||||||
@ -106,11 +108,12 @@ uint8_t IWM::read(int address) {
|
|||||||
sense = drives_[active_drive_] && drives_[active_drive_]->has_disk() ? 0 : 1;
|
sense = drives_[active_drive_] && drives_[active_drive_]->has_disk() ? 0 : 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// case CA0: // Disk head step completed.
|
case CA0: // Disk head step completed.
|
||||||
// (0 = still stepping)
|
// (0 = still stepping)
|
||||||
// printf("head stepping)\n");
|
LOG("head stepping)");
|
||||||
// break;
|
sense = 1;
|
||||||
//
|
break;
|
||||||
|
|
||||||
case CA0|SEL: // Disk locked.
|
case CA0|SEL: // Disk locked.
|
||||||
// (0 = write protected)
|
// (0 = write protected)
|
||||||
LOG("disk locked)");
|
LOG("disk locked)");
|
||||||
@ -135,14 +138,18 @@ uint8_t IWM::read(int address) {
|
|||||||
LOG("tachometer " << PADHEX(2) << int(sense) << ")");
|
LOG("tachometer " << PADHEX(2) << int(sense) << ")");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// case CA2: // Read data, lower head.
|
case CA2: // Read data, lower head.
|
||||||
// printf("data, lower head)\n");
|
LOG("data, lower head)\n");
|
||||||
// break;
|
if(drives_[0]) drives_[0]->set_head(0);
|
||||||
//
|
if(drives_[1]) drives_[1]->set_head(0);
|
||||||
// case CA2|SEL: // Read data, upper head.
|
break;
|
||||||
// printf("data, upper head)\n");
|
|
||||||
// break;
|
case CA2|SEL: // Read data, upper head.
|
||||||
//
|
LOG("data, upper head)\n");
|
||||||
|
if(drives_[0]) drives_[0]->set_head(1);
|
||||||
|
if(drives_[1]) drives_[1]->set_head(1);
|
||||||
|
break;
|
||||||
|
|
||||||
case CA2|CA1: // Single- or double-sided drive.
|
case CA2|CA1: // Single- or double-sided drive.
|
||||||
// (0 = single sided)
|
// (0 = single sided)
|
||||||
LOG("single- or double-sided drive)");
|
LOG("single- or double-sided drive)");
|
||||||
@ -152,13 +159,13 @@ uint8_t IWM::read(int address) {
|
|||||||
case CA2|CA1|CA0: // "Present/HD" (per the Mac Plus ROM)
|
case CA2|CA1|CA0: // "Present/HD" (per the Mac Plus ROM)
|
||||||
// (0 = ??HD??)
|
// (0 = ??HD??)
|
||||||
LOG("present/HD)");
|
LOG("present/HD)");
|
||||||
sense = drives_[active_drive_] ? 1 : 0;
|
sense = drives_[active_drive_] ? 0 : 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CA2|CA1|CA0|SEL: // Drive installed.
|
case CA2|CA1|CA0|SEL: // Drive installed.
|
||||||
// (0 = present, 1 = missing)
|
// (0 = present, 1 = missing)
|
||||||
LOG("drive installed)");
|
LOG("drive installed)");
|
||||||
sense = drives_[active_drive_] ? 0 : 1;
|
sense = drives_[active_drive_] ? 1 : 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -245,8 +252,8 @@ void IWM::access(int address) {
|
|||||||
default: break;
|
default: break;
|
||||||
|
|
||||||
case LSTRB:
|
case LSTRB:
|
||||||
// Catch high-to-low LSTRB transitions.
|
// Catch low-to-high LSTRB transitions.
|
||||||
if(!(address & 1)) {
|
if(address & 1) {
|
||||||
switch(state_ & (CA1 | CA0 | SEL)) {
|
switch(state_ & (CA1 | CA0 | SEL)) {
|
||||||
default:
|
default:
|
||||||
LOG("Unhandled LSTRB");
|
LOG("Unhandled LSTRB");
|
||||||
@ -254,10 +261,13 @@ void IWM::access(int address) {
|
|||||||
|
|
||||||
case 0:
|
case 0:
|
||||||
LOG("LSTRB Set stepping direction: " << int(state_ & CA2));
|
LOG("LSTRB Set stepping direction: " << int(state_ & CA2));
|
||||||
|
step_direction_ = (state_ & CA2) ? -1 : 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CA0:
|
case CA0:
|
||||||
LOG("LSTRB Step");
|
LOG("LSTRB Step");
|
||||||
|
if(drives_[0]) drives_[0]->step(Storage::Disk::HeadPosition(step_direction_));
|
||||||
|
if(drives_[1]) drives_[1]->step(Storage::Disk::HeadPosition(step_direction_));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CA1:
|
case CA1:
|
||||||
|
@ -67,6 +67,8 @@ class IWM:
|
|||||||
void propose_shift(uint8_t bit);
|
void propose_shift(uint8_t bit);
|
||||||
Cycles cycles_since_shift_;
|
Cycles cycles_since_shift_;
|
||||||
Cycles bit_length_;
|
Cycles bit_length_;
|
||||||
|
|
||||||
|
int step_direction_ = 0; // TODO: this should live on the drive.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -217,7 +217,9 @@ template <Analyser::Static::Macintosh::Target::Model model> class ConcreteMachin
|
|||||||
|
|
||||||
case 0x68f000:
|
case 0x68f000:
|
||||||
// The IWM; this is a purely polled device, so can be run on demand.
|
// The IWM; this is a purely polled device, so can be run on demand.
|
||||||
printf("[%06x]: ", mc68000_.get_state().program_counter);
|
#ifndef NDEBUG
|
||||||
|
// printf("[%06x]: ", mc68000_.get_state().program_counter);
|
||||||
|
#endif
|
||||||
iwm_.flush();
|
iwm_.flush();
|
||||||
if(cycle.operation & Microcycle::Read) {
|
if(cycle.operation & Microcycle::Read) {
|
||||||
cycle.value->halves.low = iwm_.iwm.read(register_address);
|
cycle.value->halves.low = iwm_.iwm.read(register_address);
|
||||||
@ -295,9 +297,9 @@ template <Analyser::Static::Macintosh::Target::Model model> class ConcreteMachin
|
|||||||
if(!(operation & Microcycle::Read) || word_address >= 0x300000) operation = 0;
|
if(!(operation & Microcycle::Read) || word_address >= 0x300000) operation = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!(operation & Microcycle::Read) && (word_address == (0x0000182e >> 1))) {
|
// if(!(operation & Microcycle::Read) && (word_address == (0x0000182e >> 1))) {
|
||||||
printf("Write to 0000182e: %04x from %08x\n", cycle.value->full, mc68000_.get_state().program_counter);
|
// printf("Write to 0000182e: %04x from %08x\n", cycle.value->full, mc68000_.get_state().program_counter);
|
||||||
}
|
// }
|
||||||
|
|
||||||
const auto masked_operation = operation & (Microcycle::SelectWord | Microcycle::SelectByte | Microcycle::Read | Microcycle::InterruptAcknowledge);
|
const auto masked_operation = operation & (Microcycle::SelectWord | Microcycle::SelectByte | Microcycle::Read | Microcycle::InterruptAcknowledge);
|
||||||
switch(masked_operation) {
|
switch(masked_operation) {
|
||||||
|
@ -291,7 +291,15 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
|||||||
#ifdef LOG_TRACE
|
#ifdef LOG_TRACE
|
||||||
const uint32_t fetched_pc = (program_counter_.full - 4)&0xffffff;
|
const uint32_t fetched_pc = (program_counter_.full - 4)&0xffffff;
|
||||||
|
|
||||||
should_log |= fetched_pc >= 0x417E66;
|
should_log |= (fetched_pc == 0x400BF8);
|
||||||
|
// should_log = (fetched_pc >= 0x40A284 && fetched_pc <= 0x40A732);
|
||||||
|
// should_log |= fetched_pc == 0x400A30;
|
||||||
|
// should_log =
|
||||||
|
// (fetched_pc >= 0x402DF8 && fetched_pc <= 0x403412) ||
|
||||||
|
// (fetched_pc >= 0x4077B6 && fetched_pc <= 0x40799A);
|
||||||
|
// should_log = fetched_pc >= 0x418C22 && fetched_pc <= 0x418CD8;
|
||||||
|
// should_log |= fetched_pc == 0x4009ce; // Here rests a call to _MountVol, which fails.
|
||||||
|
// should_log &= fetched_pc != 0x400b82;
|
||||||
//1300
|
//1300
|
||||||
// should_log = (fetched_pc >= 0x400D9A) && (fetched_pc <= 0x400EAA);
|
// should_log = (fetched_pc >= 0x400D9A) && (fetched_pc <= 0x400EAA);
|
||||||
// == 0x0003ea);
|
// == 0x0003ea);
|
||||||
|
@ -39,11 +39,20 @@ std::shared_ptr<Track> PlusTooBIN::get_track_at_position(Track::Address address)
|
|||||||
if(address.head >= get_head_count()) return nullptr;
|
if(address.head >= get_head_count()) return nullptr;
|
||||||
|
|
||||||
const auto start_position = Encodings::AppleGCR::Macintosh::sectors_in_track(address.position.as_int());
|
const auto start_position = Encodings::AppleGCR::Macintosh::sectors_in_track(address.position.as_int());
|
||||||
const long file_offset = long(start_position.start * 2 + address.head * start_position.start) * sector_size;
|
const long file_offset = long(start_position.start * 2 + address.head * start_position.length) * sector_size;
|
||||||
file_.seek(file_offset, SEEK_SET);
|
file_.seek(file_offset, SEEK_SET);
|
||||||
|
|
||||||
const auto track_contents = file_.read(std::size_t(sector_size * start_position.length));
|
const auto track_contents = file_.read(std::size_t(sector_size * start_position.length));
|
||||||
const std::size_t number_of_bits = std::size_t(sector_size * start_position.length * 8);
|
|
||||||
|
|
||||||
return std::shared_ptr<PCMTrack>(new PCMTrack(PCMSegment(number_of_bits, track_contents)));
|
// Split up the data that comes out per encoded sector, prefixing proper sync bits.
|
||||||
|
Storage::Disk::PCMSegment segment;
|
||||||
|
for(size_t c = 0; c < size_t(start_position.length); ++c) {
|
||||||
|
segment += Storage::Encodings::AppleGCR::six_and_two_sync(5);
|
||||||
|
|
||||||
|
size_t data_start = 0;
|
||||||
|
while(track_contents[c*1024 + data_start] == 0xff) ++data_start;
|
||||||
|
segment += PCMSegment((1024 - data_start) * 8, &track_contents[c*1024 + data_start]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_shared<PCMTrack>(segment);
|
||||||
}
|
}
|
||||||
|
@ -247,8 +247,8 @@ void Drive::get_next_event(const Time &duration_already_passed) {
|
|||||||
|
|
||||||
// divide interval, which is in terms of a single rotation of the disk, by rotation speed to
|
// divide interval, which is in terms of a single rotation of the disk, by rotation speed to
|
||||||
// convert it into revolutions per second; this is achieved by multiplying by rotational_multiplier_
|
// convert it into revolutions per second; this is achieved by multiplying by rotational_multiplier_
|
||||||
assert(current_event_.length <= Time(1) && current_event_.length >= Time(0));
|
// assert(current_event_.length <= Time(1) && current_event_.length >= Time(0));
|
||||||
assert(current_event_.length > duration_already_passed);
|
// assert(current_event_.length > duration_already_passed);
|
||||||
Time interval = (current_event_.length - duration_already_passed) * rotational_multiplier_;
|
Time interval = (current_event_.length - duration_already_passed) * rotational_multiplier_;
|
||||||
|
|
||||||
// An interval greater than 15ms => adjust gain up the point where noise starts happening.
|
// An interval greater than 15ms => adjust gain up the point where noise starts happening.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user