1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-26 23:52:26 +00:00

Merge pull request #182 from TomHarte/BetterFDC

Continues building up the 8272
This commit is contained in:
Thomas Harte 2017-08-10 11:14:08 -04:00 committed by GitHub
commit 78138261c2
3 changed files with 52 additions and 33 deletions

View File

@ -13,10 +13,10 @@
using namespace Intel; using namespace Intel;
namespace { namespace {
const uint8_t StatusRQM = 0x80; // Set: ready to send or receive from processor. const uint8_t StatusRequest = 0x80; // Set: ready to send or receive from processor.
const uint8_t StatusDIO = 0x40; // Set: data is expected to be taken from the 8272 by the processor. const uint8_t StatusDirection = 0x40; // Set: data is expected to be taken from the 8272 by the processor.
const uint8_t StatusNDM = 0x20; // Set: the execution phase of a data transfer command is ongoing and DMA mode is disabled. const uint8_t StatusNonDMAExecuting = 0x20; // Set: the execution phase of a data transfer command is ongoing and DMA mode is disabled.
const uint8_t StatusCB = 0x10; // Set: the FDC is busy. const uint8_t StatusBusy = 0x10; // Set: the FDC is busy.
//const uint8_t StatusD3B = 0x08; // Set: drive 3 is seeking. //const uint8_t StatusD3B = 0x08; // Set: drive 3 is seeking.
//const uint8_t StatusD2B = 0x04; // Set: drive 2 is seeking. //const uint8_t StatusD2B = 0x04; // Set: drive 2 is seeking.
//const uint8_t StatusD1B = 0x02; // Set: drive 1 is seeking. //const uint8_t StatusD1B = 0x02; // Set: drive 1 is seeking.
@ -25,7 +25,7 @@ const uint8_t StatusCB = 0x10; // Set: the FDC is busy.
i8272::i8272(Cycles clock_rate, int clock_rate_multiplier, int revolutions_per_minute) : i8272::i8272(Cycles clock_rate, int clock_rate_multiplier, int revolutions_per_minute) :
Storage::Disk::MFMController(clock_rate, clock_rate_multiplier, revolutions_per_minute), Storage::Disk::MFMController(clock_rate, clock_rate_multiplier, revolutions_per_minute),
main_status_(StatusRQM), main_status_(0),
interesting_event_mask_((int)Event8272::CommandByte), interesting_event_mask_((int)Event8272::CommandByte),
resume_point_(0), resume_point_(0),
delay_time_(0), delay_time_(0),
@ -76,7 +76,7 @@ void i8272::set_register(int address, uint8_t value) {
if(!address) return; if(!address) return;
// if not ready for commands, do nothing // if not ready for commands, do nothing
if(!(main_status_ & StatusRQM)) return; if(!(main_status_ & StatusRequest)) return;
// accumulate latest byte in the command byte sequence // accumulate latest byte in the command byte sequence
command_.push_back(value); command_.push_back(value);
@ -135,7 +135,7 @@ void i8272::set_disk(std::shared_ptr<Storage::Disk::Disk> disk, int drive) {
set_data_mode(Scanning); set_data_mode(Scanning);
#define SET_DRIVE_HEAD_MFM() \ #define SET_DRIVE_HEAD_MFM() \
if(!dma_mode_) main_status_ |= StatusNDM; \ if(!dma_mode_) main_status_ |= StatusNonDMAExecuting; \
set_drive(drives_[command_[1]&3].drive); \ set_drive(drives_[command_[1]&3].drive); \
set_is_double_density(command_[0] & 0x40); \ set_is_double_density(command_[0] & 0x40); \
invalidate_track(); invalidate_track();
@ -150,94 +150,94 @@ void i8272::posit_event(int event_type) {
// into wait_for_complete_command_sequence. // into wait_for_complete_command_sequence.
wait_for_command: wait_for_command:
set_data_mode(Storage::Disk::MFMController::DataMode::Scanning); set_data_mode(Storage::Disk::MFMController::DataMode::Scanning);
main_status_ &= ~(StatusCB | StatusNDM); main_status_ &= ~(StatusBusy | StatusNonDMAExecuting);
command_.clear(); command_.clear();
// Sets the data request bit, and waits for a byte. Then sets the busy bit. Continues accepting bytes // Sets the data request bit, and waits for a byte. Then sets the busy bit. Continues accepting bytes
// until it has a quantity that make up an entire command, then resets the data request bit and // until it has a quantity that make up an entire command, then resets the data request bit and
// branches to that command. // branches to that command.
wait_for_complete_command_sequence: wait_for_complete_command_sequence:
main_status_ |= StatusRQM; main_status_ |= StatusRequest;
WAIT_FOR_EVENT(Event8272::CommandByte) WAIT_FOR_EVENT(Event8272::CommandByte)
main_status_ |= StatusCB; main_status_ |= StatusBusy;
switch(command_[0] & 0x1f) { switch(command_[0] & 0x1f) {
case 0x06: // read data case 0x06: // read data
if(command_.size() < 9) goto wait_for_complete_command_sequence; if(command_.size() < 9) goto wait_for_complete_command_sequence;
main_status_ &= ~StatusRQM; main_status_ &= ~StatusRequest;
goto read_data; goto read_data;
case 0x0b: // read deleted data case 0x0b: // read deleted data
if(command_.size() < 9) goto wait_for_complete_command_sequence; if(command_.size() < 9) goto wait_for_complete_command_sequence;
main_status_ &= ~StatusRQM; main_status_ &= ~StatusRequest;
goto read_deleted_data; goto read_deleted_data;
case 0x05: // write data case 0x05: // write data
if(command_.size() < 9) goto wait_for_complete_command_sequence; if(command_.size() < 9) goto wait_for_complete_command_sequence;
main_status_ &= ~StatusRQM; main_status_ &= ~StatusRequest;
goto write_data; goto write_data;
case 0x09: // write deleted data case 0x09: // write deleted data
if(command_.size() < 9) goto wait_for_complete_command_sequence; if(command_.size() < 9) goto wait_for_complete_command_sequence;
main_status_ &= ~StatusRQM; main_status_ &= ~StatusRequest;
goto write_deleted_data; goto write_deleted_data;
case 0x02: // read track case 0x02: // read track
if(command_.size() < 9) goto wait_for_complete_command_sequence; if(command_.size() < 9) goto wait_for_complete_command_sequence;
main_status_ &= ~StatusRQM; main_status_ &= ~StatusRequest;
goto read_track; goto read_track;
case 0x0a: // read ID case 0x0a: // read ID
if(command_.size() < 2) goto wait_for_complete_command_sequence; if(command_.size() < 2) goto wait_for_complete_command_sequence;
main_status_ &= ~StatusRQM; main_status_ &= ~StatusRequest;
goto read_id; goto read_id;
case 0x0d: // format track case 0x0d: // format track
if(command_.size() < 6) goto wait_for_complete_command_sequence; if(command_.size() < 6) goto wait_for_complete_command_sequence;
main_status_ &= ~StatusRQM; main_status_ &= ~StatusRequest;
goto format_track; goto format_track;
case 0x11: // scan low case 0x11: // scan low
if(command_.size() < 9) goto wait_for_complete_command_sequence; if(command_.size() < 9) goto wait_for_complete_command_sequence;
main_status_ &= ~StatusRQM; main_status_ &= ~StatusRequest;
goto scan_low; goto scan_low;
case 0x19: // scan low or equal case 0x19: // scan low or equal
if(command_.size() < 9) goto wait_for_complete_command_sequence; if(command_.size() < 9) goto wait_for_complete_command_sequence;
main_status_ &= ~StatusRQM; main_status_ &= ~StatusRequest;
goto scan_low_or_equal; goto scan_low_or_equal;
case 0x1d: // scan high or equal case 0x1d: // scan high or equal
if(command_.size() < 9) goto wait_for_complete_command_sequence; if(command_.size() < 9) goto wait_for_complete_command_sequence;
main_status_ &= ~StatusRQM; main_status_ &= ~StatusRequest;
goto scan_high_or_equal; goto scan_high_or_equal;
case 0x07: // recalibrate case 0x07: // recalibrate
if(command_.size() < 2) goto wait_for_complete_command_sequence; if(command_.size() < 2) goto wait_for_complete_command_sequence;
main_status_ &= ~StatusRQM; main_status_ &= ~StatusRequest;
goto recalibrate; goto recalibrate;
case 0x08: // sense interrupt status case 0x08: // sense interrupt status
main_status_ &= ~StatusRQM; main_status_ &= ~StatusRequest;
goto sense_interrupt_status; goto sense_interrupt_status;
case 0x03: // specify case 0x03: // specify
if(command_.size() < 3) goto wait_for_complete_command_sequence; if(command_.size() < 3) goto wait_for_complete_command_sequence;
main_status_ &= ~StatusRQM; main_status_ &= ~StatusRequest;
goto specify; goto specify;
case 0x04: // sense drive status case 0x04: // sense drive status
if(command_.size() < 2) goto wait_for_complete_command_sequence; if(command_.size() < 2) goto wait_for_complete_command_sequence;
main_status_ &= ~StatusRQM; main_status_ &= ~StatusRequest;
goto sense_drive_status; goto sense_drive_status;
case 0x0f: // seek case 0x0f: // seek
if(command_.size() < 3) goto wait_for_complete_command_sequence; if(command_.size() < 3) goto wait_for_complete_command_sequence;
main_status_ &= ~StatusRQM; main_status_ &= ~StatusRequest;
goto seek; goto seek;
default: // invalid default: // invalid
main_status_ &= ~StatusRQM; main_status_ &= ~StatusRequest;
goto invalid; goto invalid;
} }
@ -277,9 +277,9 @@ void i8272::posit_event(int event_type) {
WAIT_FOR_EVENT(Event::Token); WAIT_FOR_EVENT(Event::Token);
result_stack_.push_back(get_latest_token().byte_value); result_stack_.push_back(get_latest_token().byte_value);
distance_into_section_++; distance_into_section_++;
main_status_ |= StatusRQM | StatusDIO; main_status_ |= StatusRequest | StatusDirection;
WAIT_FOR_EVENT(Event8272::ResultEmpty); WAIT_FOR_EVENT(Event8272::ResultEmpty);
main_status_ &= ~StatusRQM; main_status_ &= ~StatusRequest;
if(distance_into_section_ < (128 << size_)) goto get_byte; if(distance_into_section_ < (128 << size_)) goto get_byte;
// read CRC, without transferring it // read CRC, without transferring it
@ -416,8 +416,17 @@ void i8272::posit_event(int event_type) {
goto wait_for_command; goto wait_for_command;
sense_drive_status: sense_drive_status:
printf("Sense drive status unimplemented!!\n"); {
goto wait_for_command; int drive = command_[1] & 3;
result_stack_.push_back(
(command_[1] & 7) | // drive and head number
0x08 | // single sided
(drives_[drive].drive->get_is_track_zero() ? 0x10 : 0x00) |
(drives_[drive].drive->has_disk() ? 0x20 : 0x00) | // ready, approximately (TODO)
0x40 // write protected
);
}
goto post_result;
// Performs any invalid command. // Performs any invalid command.
invalid: invalid:
@ -442,15 +451,15 @@ void i8272::posit_event(int event_type) {
// last thing in it will be returned first. // last thing in it will be returned first.
post_result: post_result:
// Set ready to send data to the processor, no longer in non-DMA execution phase. // Set ready to send data to the processor, no longer in non-DMA execution phase.
main_status_ |= StatusRQM | StatusDIO; main_status_ |= StatusRequest | StatusDirection;
main_status_ &= ~StatusNDM; main_status_ &= ~StatusNonDMAExecuting;
// The actual stuff of unwinding result_stack_ is handled by ::get_register; wait // The actual stuff of unwinding result_stack_ is handled by ::get_register; wait
// until the processor has read all result bytes. // until the processor has read all result bytes.
WAIT_FOR_EVENT(Event8272::ResultEmpty); WAIT_FOR_EVENT(Event8272::ResultEmpty);
// Reset data direction and end the command. // Reset data direction and end the command.
main_status_ &= ~StatusDIO; main_status_ &= ~StatusDirection;
goto wait_for_command; goto wait_for_command;
END_SECTION() END_SECTION()

View File

@ -46,6 +46,11 @@ bool Drive::get_is_read_only() {
return false; return false;
} }
bool Drive::get_is_ready() {
// TODO: a real test for this.
return disk_ != nullptr;
}
std::shared_ptr<Track> Drive::get_track() { std::shared_ptr<Track> Drive::get_track() {
if(disk_) return disk_->get_track_at_position(head_, (unsigned int)head_position_); if(disk_) return disk_->get_track_at_position(head_, (unsigned int)head_position_);
if(track_) return track_; if(track_) return track_;

View File

@ -65,6 +65,11 @@ class Drive {
*/ */
void set_track(const std::shared_ptr<Track> &track); void set_track(const std::shared_ptr<Track> &track);
/*!
@returns @c true if the drive is ready; @c false otherwise.
*/
bool get_is_ready();
private: private:
std::shared_ptr<Track> track_; std::shared_ptr<Track> track_;
std::shared_ptr<Disk> disk_; std::shared_ptr<Disk> disk_;