1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-01-11 08:30:55 +00:00

Strung together a very basic version of 8272 write [/deleted] data. Lots of cases as-yet unhandled.

This commit is contained in:
Thomas Harte 2017-08-13 12:50:07 -04:00
parent eec42aa7ae
commit b0a7208cc7
4 changed files with 145 additions and 28 deletions

View File

@ -7,6 +7,7 @@
//
#include "i8272.hpp"
#include "../../Storage/Disk/Encodings/MFM.hpp"
#include <cstdio>
@ -57,7 +58,8 @@ i8272::i8272(Cycles clock_rate, int clock_rate_multiplier, int revolutions_per_m
interesting_event_mask_((int)Event8272::CommandByte),
resume_point_(0),
delay_time_(0),
head_timers_running_(0) {
head_timers_running_(0),
expects_input_(false) {
posit_event((int)Event8272::CommandByte);
}
@ -124,9 +126,15 @@ void i8272::set_register(int address, uint8_t value) {
// if not ready for commands, do nothing
if(!DataRequest() || DataDirectionToProcessor()) return;
// accumulate latest byte in the command byte sequence
command_.push_back(value);
posit_event((int)Event8272::CommandByte);
if(expects_input_) {
input_ = value;
has_input_ = true;
ResetDataRequest();
} else {
// accumulate latest byte in the command byte sequence
command_.push_back(value);
posit_event((int)Event8272::CommandByte);
}
}
uint8_t i8272::get_register(int address) {
@ -218,6 +226,7 @@ void i8272::posit_event(int event_type) {
// Resets busy and non-DMA execution, clears the command buffer, sets the data mode to scanning and flows
// into wait_for_complete_command_sequence.
wait_for_command:
expects_input_ = false;
set_data_mode(Storage::Disk::MFMController::DataMode::Scanning);
ResetBusy();
ResetNonDMAExecution();
@ -240,14 +249,10 @@ void i8272::posit_event(int event_type) {
goto read_data;
case 0x05: // write data
if(command_.size() < 9) goto wait_for_complete_command_sequence;
ResetDataRequest();
goto write_data;
case 0x09: // write deleted data
if(command_.size() < 9) goto wait_for_complete_command_sequence;
ResetDataRequest();
goto write_deleted_data;
goto write_data;
case 0x02: // read track
if(command_.size() < 9) goto wait_for_complete_command_sequence;
@ -308,10 +313,10 @@ void i8272::posit_event(int event_type) {
goto invalid;
}
// Performs the read data or read deleted data command.
read_data:
printf("Read [deleted?] data, sector %02x %02x %02x %02x\n", command_[2], command_[3], command_[4], command_[5]);
// Decodes drive, head and density, loads the head, loads the internal cylinder, head, sector and size registers,
// and searches for a sector that meets those criteria. If one is found, inspects the instruction in use and
// jumps to an appropriate handler.
read_write_find_header:
// Establishes the drive and head being addressed, and whether in double density mode; populates the internal
// cylinder, head, sector and size registers from the command stream.
if(!dma_mode_) SetNonDMAExecution();
@ -323,8 +328,6 @@ void i8272::posit_event(int event_type) {
sector_ = command_[4];
size_ = command_[5];
read_next_data:
// Sets a maximum index hole limit of 2 then performs a find header/read header loop, continuing either until
// the index hole limit is breached or a sector is found with a cylinder, head, sector and size equal to the
// values in the internal registers.
@ -334,7 +337,7 @@ void i8272::posit_event(int event_type) {
if(!index_hole_limit_) {
// Two index holes have passed wihout finding the header sought.
SetNoData();
goto abort_read;
goto abort_read_write;
}
READ_HEADER();
if(get_crc_generator().get_value()) {
@ -343,8 +346,30 @@ void i8272::posit_event(int event_type) {
}
if(header_[0] != cylinder_ || header_[1] != head_ || header_[2] != sector_ || header_[3] != size_) goto find_next_sector;
// Branch to whatever is supposed to happen next
switch(command_[0] & 0x1f) {
case 0x06: // read data
case 0x0b: // read deleted data
goto read_data_found_header;
case 0x05: // write data
case 0x09: // write deleted data
goto write_data_found_header;
}
// Sets abnormal termination of the current command and proceeds to an ST0, ST1, ST2, C, H, R, N result phase.
abort_read_write:
SetAbnormalTermination();
goto post_st012chrn;
// Performs the read data or read deleted data command.
read_data:
read_next_data:
goto read_write_find_header;
// Finds the next data block and sets data mode to reading, setting an error flag if the on-disk deleted
// flag doesn't match the sort the command was looking for.
read_data_found_header:
FIND_DATA();
distance_into_section_ = 0;
if((get_latest_token().type == Token::Data) != ((command_[0]&0xf) == 0x6)) {
@ -377,7 +402,7 @@ void i8272::posit_event(int event_type) {
break;
case (int)Event::Token: // The caller hasn't read the old byte yet and a new one has arrived
SetOverrun();
goto abort_read;
goto abort_read_write;
break;
case (int)Event::IndexHole:
break;
@ -390,7 +415,7 @@ void i8272::posit_event(int event_type) {
// This implies a CRC error in the sector; mark as such and temrinate.
SetDataError();
SetDataFieldDataError();
goto abort_read;
goto abort_read_write;
}
// check whether that's it: either the final requested sector has been read, or because
@ -403,17 +428,64 @@ void i8272::posit_event(int event_type) {
// For a final result phase, post the standard ST0, ST1, ST2, C, H, R, N
goto post_st012chrn;
abort_read:
SetAbnormalTermination();
goto post_st012chrn;
write_data:
printf("Write data unimplemented!!\n");
goto wait_for_command;
printf("Write [deleted] data\n");
write_deleted_data:
printf("Write deleted data unimplemented!!\n");
goto wait_for_command;
write_next_data:
goto read_write_find_header;
write_data_found_header:
begin_writing();
// Write out the requested gap between ID and data.
for(int c = 0; c < command_[7]; c++) {
write_byte(0x4e);
}
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);
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);
}
}
SetDataDirectionFromProcessor();
SetDataRequest();
expects_input_ = true;
distance_into_section_ = 0;
write_loop:
WAIT_FOR_EVENT(Event::DataWritten);
if(!has_input_) {
SetOverrun();
end_writing();
goto abort_read_write;
}
write_byte(input_);
has_input_ = false;
distance_into_section_++;
if(distance_into_section_ < (128 << size_)) {
SetDataRequest();
goto write_loop;
}
{
uint16_t crc = get_crc_generator().get_value();
write_byte(crc >> 8);
write_byte(crc & 0xff);
}
expects_input_ = false;
WAIT_FOR_EVENT(Event::DataWritten);
end_writing();
goto post_st012chrn;
read_track:
printf("Read track unimplemented!!\n");
@ -433,7 +505,7 @@ void i8272::posit_event(int event_type) {
FIND_HEADER();
if(!index_hole_limit_) {
SetNoData();
goto abort_read;
goto abort_read_write;
}
READ_HEADER();

View File

@ -36,6 +36,9 @@ class i8272: public Storage::Disk::MFMController {
// A buffer for accumulating the incoming command, and one for accumulating the result.
std::vector<uint8_t> command_;
std::vector<uint8_t> result_stack_;
uint8_t input_;
bool has_input_;
bool expects_input_;
// Event stream: the 8272-specific events, plus the current event state.
enum class Event8272: int {

View File

@ -153,3 +153,25 @@ void MFMController::process_input_bit(int value, unsigned int cycles_since_index
return;
}
}
void MFMController::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 MFMController::write_byte(uint8_t byte) {
for(int c = 0; c < 8; c++) write_bit((byte << c)&0x80);
crc_generator_.add(byte);
}
void MFMController::write_raw_short(uint16_t value) {
for(int c = 0; c < 16; c++) {
Controller::write_bit(!!((value << c)&0x8000));
}
}

View File

@ -90,6 +90,23 @@ class MFMController: public Controller {
*/
virtual void posit_event(int type) = 0;
/*!
Encodes @c bit according to the current single/double density mode and adds it
to the controller's write buffer.
*/
void write_bit(int bit);
/*!
Encodes @c byte according to the current single/double density mode and adds it
to the controller's write buffer.
*/
void write_byte(uint8_t byte);
/*!
Serialises @c value into the controller's write buffer without adjustment.
*/
void write_raw_short(uint16_t value);
private:
// Storage::Disk::Controller
virtual void process_input_bit(int value, unsigned int cycles_since_index_hole);
@ -108,6 +125,9 @@ class MFMController: public Controller {
// output
Token latest_token_;
// writing
int last_bit_;
// CRC generator
NumberTheory::CRC16 crc_generator_;
};