1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-04 18:29:40 +00:00

Merge pull request #195 from TomHarte/8272Tidying

Brings the 1770 into usage of those parts factored out of it for the 8272
This commit is contained in:
Thomas Harte 2017-08-14 16:34:15 -04:00 committed by GitHub
commit 113da93796
6 changed files with 180 additions and 344 deletions

View File

@ -25,29 +25,16 @@ WD1770::Status::Status() :
busy(false) {}
WD1770::WD1770(Personality p) :
Storage::Disk::Controller(8000000, 16, 300),
crc_generator_(0x1021, 0xffff),
interesting_event_mask_(Event::Command),
Storage::Disk::MFMController(8000000, 16, 300),
interesting_event_mask_((int)Event1770::Command),
resume_point_(0),
delay_time_(0),
index_hole_count_target_(-1),
is_awaiting_marker_value_(false),
data_mode_(DataMode::Scanning),
delegate_(nullptr),
personality_(p),
head_is_loaded_(false) {
set_is_double_density(false);
posit_event(Event::Command);
}
void WD1770::set_is_double_density(bool is_double_density) {
is_double_density_ = is_double_density;
Storage::Time bit_length;
bit_length.length = 1;
bit_length.clock_rate = is_double_density ? 500000 : 250000;
set_expected_bit_length(bit_length);
if(!is_double_density) is_awaiting_marker_value_ = false;
posit_event((int)Event1770::Command);
}
void WD1770::set_register(int address, uint8_t value) {
@ -60,7 +47,7 @@ void WD1770::set_register(int address, uint8_t value) {
});
} else {
command_ = value;
posit_event(Event::Command);
posit_event((int)Event1770::Command);
}
}
break;
@ -131,148 +118,24 @@ void WD1770::run_for(const Cycles cycles) {
unsigned int number_of_cycles = (unsigned int)cycles.as_int();
if(delay_time_ <= number_of_cycles) {
delay_time_ = 0;
posit_event(Event::Timer);
posit_event((int)Event1770::Timer);
} else {
delay_time_ -= number_of_cycles;
}
}
}
void WD1770::process_input_bit(int value, unsigned int cycles_since_index_hole) {
if(data_mode_ == DataMode::Writing) return;
shift_register_ = (shift_register_ << 1) | value;
bits_since_token_++;
if(data_mode_ == DataMode::Scanning) {
Token::Type token_type = Token::Byte;
if(!is_double_density_) {
switch(shift_register_ & 0xffff) {
case Storage::Encodings::MFM::FMIndexAddressMark:
token_type = Token::Index;
crc_generator_.reset();
crc_generator_.add(latest_token_.byte_value = Storage::Encodings::MFM::IndexAddressByte);
break;
case Storage::Encodings::MFM::FMIDAddressMark:
token_type = Token::ID;
crc_generator_.reset();
crc_generator_.add(latest_token_.byte_value = Storage::Encodings::MFM::IDAddressByte);
break;
case Storage::Encodings::MFM::FMDataAddressMark:
token_type = Token::Data;
crc_generator_.reset();
crc_generator_.add(latest_token_.byte_value = Storage::Encodings::MFM::DataAddressByte);
break;
case Storage::Encodings::MFM::FMDeletedDataAddressMark:
token_type = Token::DeletedData;
crc_generator_.reset();
crc_generator_.add(latest_token_.byte_value = Storage::Encodings::MFM::DeletedDataAddressByte);
break;
default:
break;
}
} else {
switch(shift_register_ & 0xffff) {
case Storage::Encodings::MFM::MFMIndexSync:
bits_since_token_ = 0;
is_awaiting_marker_value_ = true;
token_type = Token::Sync;
latest_token_.byte_value = Storage::Encodings::MFM::MFMIndexSyncByteValue;
break;
case Storage::Encodings::MFM::MFMSync:
bits_since_token_ = 0;
is_awaiting_marker_value_ = true;
crc_generator_.set_value(Storage::Encodings::MFM::MFMPostSyncCRCValue);
token_type = Token::Sync;
latest_token_.byte_value = Storage::Encodings::MFM::MFMSyncByteValue;
break;
default:
break;
}
}
if(token_type != Token::Byte) {
latest_token_.type = token_type;
bits_since_token_ = 0;
posit_event(Event::Token);
return;
}
}
if(bits_since_token_ == 16) {
latest_token_.type = Token::Byte;
latest_token_.byte_value = (uint8_t)(
((shift_register_ & 0x0001) >> 0) |
((shift_register_ & 0x0004) >> 1) |
((shift_register_ & 0x0010) >> 2) |
((shift_register_ & 0x0040) >> 3) |
((shift_register_ & 0x0100) >> 4) |
((shift_register_ & 0x0400) >> 5) |
((shift_register_ & 0x1000) >> 6) |
((shift_register_ & 0x4000) >> 7));
bits_since_token_ = 0;
if(is_awaiting_marker_value_ && is_double_density_) {
is_awaiting_marker_value_ = false;
switch(latest_token_.byte_value) {
case Storage::Encodings::MFM::IndexAddressByte:
latest_token_.type = Token::Index;
break;
case Storage::Encodings::MFM::IDAddressByte:
latest_token_.type = Token::ID;
break;
case Storage::Encodings::MFM::DataAddressByte:
latest_token_.type = Token::Data;
break;
case Storage::Encodings::MFM::DeletedDataAddressByte:
latest_token_.type = Token::DeletedData;
break;
default: break;
}
}
crc_generator_.add(latest_token_.byte_value);
posit_event(Event::Token);
return;
}
}
void WD1770::process_index_hole() {
index_hole_count_++;
posit_event(Event::IndexHole);
if(index_hole_count_target_ == index_hole_count_) {
posit_event(Event::IndexHoleTarget);
index_hole_count_target_ = -1;
}
// motor power-down
if(index_hole_count_ == 9 && !status_.busy && has_motor_on_line()) {
set_motor_on(false);
}
// head unload
if(index_hole_count_ == 15 && !status_.busy && has_head_load_line()) {
set_head_load_request(false);
}
}
void WD1770::process_write_completed() {
posit_event(Event::DataWritten);
}
#define WAIT_FOR_EVENT(mask) resume_point_ = __LINE__; interesting_event_mask_ = mask; return; case __LINE__:
#define WAIT_FOR_TIME(ms) resume_point_ = __LINE__; interesting_event_mask_ = Event::Timer; delay_time_ = ms * 8000; case __LINE__: if(delay_time_) return;
#define WAIT_FOR_BYTES(count) resume_point_ = __LINE__; interesting_event_mask_ = Event::Token; distance_into_section_ = 0; return; case __LINE__: if(latest_token_.type == Token::Byte) distance_into_section_++; if(distance_into_section_ < count) { interesting_event_mask_ = Event::Token; return; }
#define WAIT_FOR_EVENT(mask) resume_point_ = __LINE__; interesting_event_mask_ = (int)mask; return; case __LINE__:
#define WAIT_FOR_TIME(ms) resume_point_ = __LINE__; delay_time_ = ms * 8000; WAIT_FOR_EVENT(Event1770::Timer);
#define WAIT_FOR_BYTES(count) resume_point_ = __LINE__; distance_into_section_ = 0; WAIT_FOR_EVENT(Event::Token); if(get_latest_token().type == Token::Byte) distance_into_section_++; if(distance_into_section_ < count) { interesting_event_mask_ = (int)Event::Token; return; }
#define BEGIN_SECTION() switch(resume_point_) { default:
#define END_SECTION() 0; }
#define READ_ID() \
if(new_event_type == Event::Token) { \
if(!distance_into_section_ && latest_token_.type == Token::ID) {data_mode_ = DataMode::Reading; distance_into_section_++; } \
else if(distance_into_section_ && distance_into_section_ < 7 && latest_token_.type == Token::Byte) { \
header_[distance_into_section_ - 1] = latest_token_.byte_value; \
if(new_event_type == (int)Event::Token) { \
if(!distance_into_section_ && get_latest_token().type == Token::ID) {set_data_mode(DataMode::Reading); distance_into_section_++; } \
else if(distance_into_section_ && distance_into_section_ < 7 && get_latest_token().type == Token::Byte) { \
header_[distance_into_section_ - 1] = get_latest_token().byte_value; \
distance_into_section_++; \
} \
}
@ -285,7 +148,7 @@ void WD1770::process_write_completed() {
set_motor_on(true); \
index_hole_count_ = 0; \
index_hole_count_target_ = 6; \
WAIT_FOR_EVENT(Event::IndexHoleTarget); \
WAIT_FOR_EVENT(Event1770::IndexHoleTarget); \
status_.spin_up = true;
// +--------+----------+-------------------------+
@ -305,7 +168,25 @@ void WD1770::process_write_completed() {
// ! 4 ! Forc int ! 1 1 0 1 i3 i2 i1 i0 !
// +--------+----------+-------------------------+
void WD1770::posit_event(Event new_event_type) {
void WD1770::posit_event(int new_event_type) {
if(new_event_type == (int)Event::IndexHole) {
index_hole_count_++;
if(index_hole_count_target_ == index_hole_count_) {
posit_event((int)Event1770::IndexHoleTarget);
index_hole_count_target_ = -1;
}
// motor power-down
if(index_hole_count_ == 9 && !status_.busy && has_motor_on_line()) {
set_motor_on(false);
}
// head unload
if(index_hole_count_ == 15 && !status_.busy && has_head_load_line()) {
set_head_load_request(false);
}
}
if(!(interesting_event_mask_ & (int)new_event_type)) return;
interesting_event_mask_ &= ~new_event_type;
@ -315,7 +196,7 @@ void WD1770::posit_event(Event new_event_type) {
// Wait for a new command, branch to the appropriate handler.
wait_for_command:
printf("Idle...\n");
data_mode_ = DataMode::Scanning;
set_data_mode(DataMode::Scanning);
index_hole_count_ = 0;
update_status([] (Status &status) {
@ -323,7 +204,7 @@ void WD1770::posit_event(Event new_event_type) {
status.interrupt_request = true;
});
WAIT_FOR_EVENT(Event::Command);
WAIT_FOR_EVENT(Event1770::Command);
update_status([] (Status &status) {
status.busy = true;
@ -372,7 +253,7 @@ void WD1770::posit_event(Event new_event_type) {
}
set_head_load_request(true);
if(head_is_loaded_) goto test_type1_type;
WAIT_FOR_EVENT(Event::HeadLoad);
WAIT_FOR_EVENT(Event1770::HeadLoad);
goto test_type1_type;
begin_type1_spin_up:
@ -429,7 +310,7 @@ void WD1770::posit_event(Event new_event_type) {
distance_into_section_ = 0;
verify_read_data:
WAIT_FOR_EVENT(Event::IndexHole | Event::Token);
WAIT_FOR_EVENT((int)Event::IndexHole | (int)Event::Token);
READ_ID();
if(index_hole_count_ == 6) {
@ -439,8 +320,8 @@ void WD1770::posit_event(Event new_event_type) {
goto wait_for_command;
}
if(distance_into_section_ == 7) {
data_mode_ = DataMode::Scanning;
if(crc_generator_.get_value()) {
set_data_mode(DataMode::Scanning);
if(get_crc_generator().get_value()) {
update_status([] (Status &status) {
status.crc_error = true;
});
@ -491,7 +372,7 @@ void WD1770::posit_event(Event new_event_type) {
begin_type2_load_head:
set_head_load_request(true);
if(head_is_loaded_) goto test_type2_delay;
WAIT_FOR_EVENT(Event::HeadLoad);
WAIT_FOR_EVENT(Event1770::HeadLoad);
goto test_type2_delay;
begin_type2_spin_up:
@ -513,7 +394,7 @@ void WD1770::posit_event(Event new_event_type) {
}
type2_get_header:
WAIT_FOR_EVENT(Event::IndexHole | Event::Token);
WAIT_FOR_EVENT((int)Event::IndexHole | (int)Event::Token);
READ_ID();
if(index_hole_count_ == 5) {
@ -525,11 +406,11 @@ void WD1770::posit_event(Event new_event_type) {
}
if(distance_into_section_ == 7) {
printf("Considering %d/%d\n", header_[0], header_[2]);
data_mode_ = DataMode::Scanning;
set_data_mode(DataMode::Scanning);
if( header_[0] == track_ && header_[2] == sector_ &&
(has_motor_on_line() || !(command_&0x02) || ((command_&0x08) >> 3) == header_[1])) {
printf("Found %d/%d\n", header_[0], header_[2]);
if(crc_generator_.get_value()) {
if(get_crc_generator().get_value()) {
printf("CRC error; back to searching\n");
update_status([] (Status &status) {
status.crc_error = true;
@ -554,20 +435,20 @@ void WD1770::posit_event(Event new_event_type) {
type2_read_data:
WAIT_FOR_EVENT(Event::Token);
// TODO: timeout
if(latest_token_.type == Token::Data || latest_token_.type == Token::DeletedData) {
if(get_latest_token().type == Token::Data || get_latest_token().type == Token::DeletedData) {
update_status([this] (Status &status) {
status.record_type = (latest_token_.type == Token::DeletedData);
status.record_type = (get_latest_token().type == Token::DeletedData);
});
distance_into_section_ = 0;
data_mode_ = DataMode::Reading;
set_data_mode(DataMode::Reading);
goto type2_read_byte;
}
goto type2_read_data;
type2_read_byte:
WAIT_FOR_EVENT(Event::Token);
if(latest_token_.type != Token::Byte) goto type2_read_byte;
data_ = latest_token_.byte_value;
if(get_latest_token().type != Token::Byte) goto type2_read_byte;
data_ = get_latest_token().byte_value;
update_status([] (Status &status) {
status.lost_data |= status.data_request;
status.data_request = true;
@ -581,11 +462,11 @@ void WD1770::posit_event(Event new_event_type) {
type2_check_crc:
WAIT_FOR_EVENT(Event::Token);
if(latest_token_.type != Token::Byte) goto type2_read_byte;
header_[distance_into_section_] = latest_token_.byte_value;
if(get_latest_token().type != Token::Byte) goto type2_read_byte;
header_[distance_into_section_] = get_latest_token().byte_value;
distance_into_section_++;
if(distance_into_section_ == 2) {
if(crc_generator_.get_value()) {
if(get_crc_generator().get_value()) {
printf("CRC error; terminating\n");
update_status([this] (Status &status) {
status.crc_error = true;
@ -616,24 +497,24 @@ void WD1770::posit_event(Event new_event_type) {
goto wait_for_command;
}
WAIT_FOR_BYTES(1);
if(is_double_density_) {
if(get_is_double_density()) {
WAIT_FOR_BYTES(11);
}
data_mode_ = DataMode::Writing;
set_data_mode(DataMode::Writing);
begin_writing();
for(int c = 0; c < (is_double_density_ ? 12 : 6); c++) {
for(int c = 0; c < (get_is_double_density() ? 12 : 6); c++) {
write_byte(0);
}
WAIT_FOR_EVENT(Event::DataWritten);
if(is_double_density_) {
crc_generator_.set_value(Storage::Encodings::MFM::MFMPostSyncCRCValue);
if(get_is_double_density()) {
get_crc_generator().set_value(Storage::Encodings::MFM::MFMPostSyncCRCValue);
for(int c = 0; c < 3; c++) write_raw_short(Storage::Encodings::MFM::MFMSync);
write_byte((command_&0x01) ? Storage::Encodings::MFM::DeletedDataAddressByte : Storage::Encodings::MFM::DataAddressByte);
} else {
crc_generator_.reset();
crc_generator_.add((command_&0x01) ? Storage::Encodings::MFM::DeletedDataAddressByte : Storage::Encodings::MFM::DataAddressByte);
get_crc_generator().reset();
get_crc_generator().add((command_&0x01) ? Storage::Encodings::MFM::DeletedDataAddressByte : Storage::Encodings::MFM::DataAddressByte);
write_raw_short((command_&0x01) ? Storage::Encodings::MFM::FMDeletedDataAddressMark : Storage::Encodings::MFM::FMDataAddressMark);
}
@ -669,11 +550,8 @@ void WD1770::posit_event(Event new_event_type) {
goto type2_write_loop;
type2_write_crc: {
uint16_t crc = crc_generator_.get_value();
write_byte(crc >> 8);
write_byte(crc & 0xff);
}
type2_write_crc:
write_crc();
write_byte(0xff);
WAIT_FOR_EVENT(Event::DataWritten);
end_writing();
@ -712,7 +590,7 @@ void WD1770::posit_event(Event new_event_type) {
begin_type3_load_head:
set_head_load_request(true);
if(head_is_loaded_) goto type3_test_delay;
WAIT_FOR_EVENT(Event::HeadLoad);
WAIT_FOR_EVENT(Event1770::HeadLoad);
goto type3_test_delay;
begin_type3_spin_up:
@ -733,17 +611,17 @@ void WD1770::posit_event(Event new_event_type) {
distance_into_section_ = 0;
read_address_get_header:
WAIT_FOR_EVENT(Event::IndexHole | Event::Token);
if(new_event_type == Event::Token) {
if(!distance_into_section_ && latest_token_.type == Token::ID) {data_mode_ = DataMode::Reading; distance_into_section_++; }
else if(distance_into_section_ && distance_into_section_ < 7 && latest_token_.type == Token::Byte) {
WAIT_FOR_EVENT((int)Event::IndexHole | (int)Event::Token);
if(new_event_type == (int)Event::Token) {
if(!distance_into_section_ && get_latest_token().type == Token::ID) {set_data_mode(DataMode::Reading); distance_into_section_++; }
else if(distance_into_section_ && distance_into_section_ < 7 && get_latest_token().type == Token::Byte) {
if(status_.data_request) {
update_status([] (Status &status) {
status.lost_data = true;
});
goto wait_for_command;
}
header_[distance_into_section_ - 1] = data_ = latest_token_.byte_value;
header_[distance_into_section_ - 1] = data_ = get_latest_token().byte_value;
track_ = header_[0];
update_status([] (Status &status) {
status.data_request = true;
@ -751,7 +629,7 @@ void WD1770::posit_event(Event new_event_type) {
distance_into_section_++;
if(distance_into_section_ == 7) {
if(crc_generator_.get_value()) {
if(get_crc_generator().get_value()) {
update_status([] (Status &status) {
status.crc_error = true;
});
@ -774,7 +652,7 @@ void WD1770::posit_event(Event new_event_type) {
index_hole_count_ = 0;
read_track_read_byte:
WAIT_FOR_EVENT(Event::Token | Event::IndexHole);
WAIT_FOR_EVENT((int)Event::Token | (int)Event::IndexHole);
if(index_hole_count_) {
goto wait_for_command;
}
@ -784,7 +662,7 @@ void WD1770::posit_event(Event new_event_type) {
});
goto wait_for_command;
}
data_ = latest_token_.byte_value;
data_ = get_latest_token().byte_value;
update_status([] (Status &status) {
status.data_request = true;
});
@ -815,25 +693,23 @@ void WD1770::posit_event(Event new_event_type) {
goto wait_for_command;
}
WAIT_FOR_EVENT(Event::IndexHoleTarget);
WAIT_FOR_EVENT(Event1770::IndexHoleTarget);
begin_writing();
index_hole_count_ = 0;
write_track_write_loop:
if(is_double_density_) {
if(get_is_double_density()) {
switch(data_) {
case 0xf5:
write_raw_short(Storage::Encodings::MFM::MFMSync);
crc_generator_.set_value(Storage::Encodings::MFM::MFMPostSyncCRCValue);
get_crc_generator().set_value(Storage::Encodings::MFM::MFMPostSyncCRCValue);
break;
case 0xf6:
write_raw_short(Storage::Encodings::MFM::MFMIndexSync);
break;
case 0xff: {
uint16_t crc = crc_generator_.get_value();
write_byte(crc >> 8);
write_byte(crc & 0xff);
} break;
case 0xff:
write_crc();
break;
default:
write_byte(data_);
break;
@ -856,17 +732,15 @@ void WD1770::posit_event(Event new_event_type) {
(data_ & 0x01)
)
);
crc_generator_.reset();
crc_generator_.add(data_);
get_crc_generator().reset();
get_crc_generator().add(data_);
break;
case 0xfc:
write_raw_short(Storage::Encodings::MFM::FMIndexAddressMark);
break;
case 0xf7: {
uint16_t crc = crc_generator_.get_value();
write_byte(crc >> 8);
write_byte(crc & 0xff);
} break;
case 0xf7:
write_crc();
break;
default:
write_byte(data_);
break;
@ -910,27 +784,5 @@ void WD1770::set_head_load_request(bool head_load) {}
void WD1770::set_head_loaded(bool head_loaded) {
head_is_loaded_ = head_loaded;
if(head_loaded) posit_event(Event::HeadLoad);
}
void WD1770::write_bit(int bit) {
if(is_double_density_) {
Controller::write_bit(!bit && !last_bit_);
Controller::write_bit(!!bit);
last_bit_ = bit;
} else {
Controller::write_bit(true);
Controller::write_bit(!!bit);
}
}
void WD1770::write_byte(uint8_t byte) {
for(int c = 0; c < 8; c++) write_bit((byte << c)&0x80);
crc_generator_.add(byte);
}
void WD1770::write_raw_short(uint16_t value) {
for(int c = 0; c < 16; c++) {
Controller::write_bit(!!((value << c)&0x8000));
}
if(head_loaded) posit_event((int)Event1770::HeadLoad);
}

View File

@ -9,8 +9,7 @@
#ifndef _770_hpp
#define _770_hpp
#include "../../Storage/Disk/DiskController.hpp"
#include "../../NumberTheory/CRC.hpp"
#include "../../Storage/Disk/MFMDiskController.hpp"
namespace WD {
@ -18,7 +17,7 @@ namespace WD {
Provides an emulation of various Western Digital drive controllers, including the
WD1770, WD1772, FDC1773 and FDC1793.
*/
class WD1770: public Storage::Disk::Controller {
class WD1770: public Storage::Disk::MFMController {
public:
enum Personality {
P1770, // implies automatic motor-on management, with Type 2 commands offering a spin-up disable
@ -34,7 +33,7 @@ class WD1770: public Storage::Disk::Controller {
WD1770(Personality p);
/// Sets the value of the double-density input; when @c is_double_density is @c true, reads and writes double-density format data.
void set_is_double_density(bool is_double_density);
using Storage::Disk::MFMController::set_is_double_density;
/// Writes @c value to the register at @c address. Only the low two bits of the address are decoded.
void set_register(int address, uint8_t value);
@ -107,66 +106,31 @@ class WD1770: public Storage::Disk::Controller {
int index_hole_count_;
int index_hole_count_target_;
int bits_since_token_;
int distance_into_section_;
bool is_awaiting_marker_value_;
int step_direction_;
void update_status(std::function<void(Status &)> updater);
// Tokeniser
enum DataMode {
Scanning,
Reading,
Writing
} data_mode_;
bool is_double_density_;
int shift_register_;
struct Token {
enum Type {
Index, ID, Data, DeletedData, Sync, Byte
} type;
uint8_t byte_value;
} latest_token_;
// Events
enum Event: int {
Command = (1 << 0), // Indicates receipt of a new command.
Token = (1 << 1), // Indicates recognition of a new token in the flux stream. Interrogate latest_token_ for details.
IndexHole = (1 << 2), // Indicates the passing of a physical index hole.
HeadLoad = (1 << 3), // Indicates the head has been loaded (1973 only).
DataWritten = (1 << 4), // Indicates that all queued bits have been written
enum Event1770: int {
Command = (1 << 3), // Indicates receipt of a new command.
HeadLoad = (1 << 4), // Indicates the head has been loaded (1973 only).
Timer = (1 << 5), // Indicates that the delay_time_-powered timer has timed out.
IndexHoleTarget = (1 << 6) // Indicates that index_hole_count_ has reached index_hole_count_target_.
};
void posit_event(Event type);
void posit_event(int type);
int interesting_event_mask_;
int resume_point_;
unsigned int delay_time_;
// Output
int last_bit_;
void write_bit(int bit);
void write_byte(uint8_t byte);
void write_raw_short(uint16_t value);
// ID buffer
uint8_t header_[6];
// CRC generator
NumberTheory::CRC16 crc_generator_;
// 1793 head-loading logic
bool head_is_loaded_;
// delegate
Delegate *delegate_;
// Storage::Disk::Controller
virtual void process_input_bit(int value, unsigned int cycles_since_index_hole);
virtual void process_index_hole();
virtual void process_write_completed();
};
}

View File

@ -427,39 +427,11 @@ void i8272::posit_event(int event_type) {
write_data_found_header:
begin_writing();
if(get_is_double_density()) {
for(int c = 0; c < 50; c++) {
write_byte(0x4e);
}
for(int c = 0; c < 12; c++) {
write_byte(0x00);
}
} else {
for(int c = 0; c < 11; c++) {
write_byte(0xff);
}
for(int c = 0; c < 6; c++) {
write_byte(0x00);
}
}
WAIT_FOR_EVENT(Event::DataWritten);
{
bool is_deleted = (command_[0] & 0x1f) == 0x09;
if(get_is_double_density()) {
get_crc_generator().set_value(Storage::Encodings::MFM::MFMPostSyncCRCValue);
for(int c = 0; c < 3; c++) write_raw_short(Storage::Encodings::MFM::MFMSync);
write_byte(is_deleted ? Storage::Encodings::MFM::DeletedDataAddressByte : Storage::Encodings::MFM::DataAddressByte);
} else {
get_crc_generator().reset();
get_crc_generator().add(is_deleted ? Storage::Encodings::MFM::DeletedDataAddressByte : Storage::Encodings::MFM::DataAddressByte);
write_raw_short(is_deleted ? Storage::Encodings::MFM::FMDeletedDataAddressMark : Storage::Encodings::MFM::FMDataAddressMark);
}
}
write_id_data_joiner((command_[0] & 0x1f) == 0x09);
SetDataDirectionFromProcessor();
SetDataRequest();
WAIT_FOR_EVENT(Event::DataWritten);
expects_input_ = true;
distance_into_section_ = 0;
@ -571,32 +543,12 @@ void i8272::posit_event(int event_type) {
begin_writing();
// Write start-of-track.
if(get_is_double_density()) {
for(int c = 0; c < 80; c++) write_byte(0x4e);
for(int c = 0; c < 12; c++) write_byte(0x00);
for(int c = 0; c < 3; c++) write_raw_short(Storage::Encodings::MFM::MFMIndexSync);
write_byte(Storage::Encodings::MFM::IndexAddressByte);
for(int c = 0; c < 50; c++) write_byte(0x4e);
} else {
for(int c = 0; c < 40; c++) write_byte(0xff);
for(int c = 0; c < 6; c++) write_byte(0x00);
write_raw_short(Storage::Encodings::MFM::FMIndexAddressMark);
for(int c = 0; c < 26; c++) write_byte(0xff);
}
write_start_of_track();
WAIT_FOR_EVENT(Event::DataWritten);
sector_ = 0;
format_track_write_sector:
if(get_is_double_density()) {
for(int c = 0; c < 12; c++) write_byte(0x00);
for(int c = 0; c < 3; c++) write_raw_short(Storage::Encodings::MFM::MFMSync);
get_crc_generator().set_value(Storage::Encodings::MFM::MFMPostSyncCRCValue);
write_byte(Storage::Encodings::MFM::IDAddressByte);
} else {
for(int c = 0; c < 6; c++) write_byte(0x00);
get_crc_generator().reset();
write_raw_short(Storage::Encodings::MFM::FMIDAddressMark);
}
write_id_joiner();
// Write the sector header, obtaining its contents
// from the processor.
@ -618,29 +570,12 @@ void i8272::posit_event(int event_type) {
write_crc();
// Write the sector body.
if(get_is_double_density()) {
for(int c = 0; c < 22; c++) write_byte(0x4e);
for(int c = 0; c < 12; c++) write_byte(0x00);
for(int c = 0; c < 3; c++) write_raw_short(Storage::Encodings::MFM::MFMSync);
get_crc_generator().set_value(Storage::Encodings::MFM::MFMPostSyncCRCValue);
write_byte(Storage::Encodings::MFM::DataAddressByte);
} else {
for(int c = 0; c < 11; c++) write_byte(0xff);
for(int c = 0; c < 6; c++) write_byte(0x00);
get_crc_generator().reset();
write_raw_short(Storage::Encodings::MFM::FMDataAddressMark);
}
for(int c = 0; c < (128 << command_[2]); c++) {
write_byte(command_[5]);
}
write_id_data_joiner(false);
write_n_bytes(128 << command_[2], command_[5]);
write_crc();
// Write the prescribed gap.
if(get_is_double_density()) {
for(int c = 0; c < command_[4]; c++) write_byte(0x4e);
} else {
for(int c = 0; c < command_[4]; c++) write_byte(0xff);
}
write_n_bytes(command_[4], get_is_double_density() ? 0x4e : 0xff);
// Consider repeating.
sector_++;

View File

@ -10,7 +10,6 @@
#define i8272_hpp
#include "../../Storage/Disk/MFMDiskController.hpp"
#include "../../Storage/Disk/Drive.hpp"
#include <cstdint>
#include <memory>

View File

@ -181,3 +181,59 @@ void MFMController::write_crc() {
write_byte(crc >> 8);
write_byte(crc & 0xff);
}
void MFMController::write_n_bytes(int quantity, uint8_t value) {
while(quantity--) write_byte(value);
}
void MFMController::write_id_joiner() {
if(get_is_double_density()) {
write_n_bytes(12, 0x00);
for(int c = 0; c < 3; c++) write_raw_short(Storage::Encodings::MFM::MFMSync);
get_crc_generator().set_value(Storage::Encodings::MFM::MFMPostSyncCRCValue);
write_byte(Storage::Encodings::MFM::IDAddressByte);
} else {
write_n_bytes(6, 0x00);
get_crc_generator().reset();
write_raw_short(Storage::Encodings::MFM::FMIDAddressMark);
}
}
void MFMController::write_id_data_joiner(bool is_deleted) {
if(get_is_double_density()) {
write_n_bytes(22, 0x4e);
write_n_bytes(12, 0x00);
for(int c = 0; c < 3; c++) write_raw_short(Storage::Encodings::MFM::MFMSync);
get_crc_generator().set_value(Storage::Encodings::MFM::MFMPostSyncCRCValue);
write_byte(is_deleted ? Storage::Encodings::MFM::DeletedDataAddressByte : Storage::Encodings::MFM::DataAddressByte);
} else {
write_n_bytes(11, 0xff);
write_n_bytes(6, 0x00);
get_crc_generator().reset();
get_crc_generator().add(is_deleted ? Storage::Encodings::MFM::DeletedDataAddressByte : Storage::Encodings::MFM::DataAddressByte);
write_raw_short(is_deleted ? Storage::Encodings::MFM::FMDeletedDataAddressMark : Storage::Encodings::MFM::FMDataAddressMark);
}
}
void MFMController::write_post_data_gap() {
if(get_is_double_density()) {
write_n_bytes(54, 0x4e);
} else {
write_n_bytes(27, 0xff);
}
}
void MFMController::write_start_of_track() {
if(get_is_double_density()) {
write_n_bytes(80, 0x4e);
write_n_bytes(12, 0x00);
for(int c = 0; c < 3; c++) write_raw_short(Storage::Encodings::MFM::MFMIndexSync);
write_byte(Storage::Encodings::MFM::IndexAddressByte);
write_n_bytes(50, 0x4e);
} else {
write_n_bytes(40, 0xff);
write_n_bytes(6, 0x00);
write_raw_short(Storage::Encodings::MFM::FMIndexAddressMark);
write_n_bytes(26, 0xff);
}
}

View File

@ -113,6 +113,36 @@ class MFMController: public Controller {
*/
void write_crc();
/*!
Calls @c write_byte with @c value, @c quantity times.
*/
void write_n_bytes(int quantity, uint8_t value);
/*!
Writes everything that should, per the spec, appear prior to the address contained
in an ID mark proper gaps and the ID mark and appropriate seeds the CRC generator.
*/
void write_id_joiner();
/*!
Writes everything that should, per the spec, appear after the ID's CRC, up to and
including the mark that indicates the beginning of data, appropriately seeding
the CRC generator.
*/
void write_id_data_joiner(bool is_deleted);
/*!
Writes the gap expected after a sector's data CRC and before the beginning of the
next ID joiner.
*/
void write_post_data_gap();
/*!
Writes everything that should, per the spec, following the index hole and prior
to any sectors.
*/
void write_start_of_track();
private:
// Storage::Disk::Controller
virtual void process_input_bit(int value, unsigned int cycles_since_index_hole);