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:
commit
78138261c2
@ -13,10 +13,10 @@
|
||||
using namespace Intel;
|
||||
|
||||
namespace {
|
||||
const uint8_t StatusRQM = 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 StatusNDM = 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 StatusRequest = 0x80; // Set: ready to send or receive from processor.
|
||||
const uint8_t StatusDirection = 0x40; // Set: data is expected to be taken from the 8272 by the processor.
|
||||
const uint8_t StatusNonDMAExecuting = 0x20; // Set: the execution phase of a data transfer command is ongoing and DMA mode is disabled.
|
||||
const uint8_t StatusBusy = 0x10; // Set: the FDC is busy.
|
||||
//const uint8_t StatusD3B = 0x08; // Set: drive 3 is seeking.
|
||||
//const uint8_t StatusD2B = 0x04; // Set: drive 2 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) :
|
||||
Storage::Disk::MFMController(clock_rate, clock_rate_multiplier, revolutions_per_minute),
|
||||
main_status_(StatusRQM),
|
||||
main_status_(0),
|
||||
interesting_event_mask_((int)Event8272::CommandByte),
|
||||
resume_point_(0),
|
||||
delay_time_(0),
|
||||
@ -76,7 +76,7 @@ void i8272::set_register(int address, uint8_t value) {
|
||||
if(!address) return;
|
||||
|
||||
// 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
|
||||
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);
|
||||
|
||||
#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_is_double_density(command_[0] & 0x40); \
|
||||
invalidate_track();
|
||||
@ -150,94 +150,94 @@ void i8272::posit_event(int event_type) {
|
||||
// into wait_for_complete_command_sequence.
|
||||
wait_for_command:
|
||||
set_data_mode(Storage::Disk::MFMController::DataMode::Scanning);
|
||||
main_status_ &= ~(StatusCB | StatusNDM);
|
||||
main_status_ &= ~(StatusBusy | StatusNonDMAExecuting);
|
||||
command_.clear();
|
||||
|
||||
// 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
|
||||
// branches to that command.
|
||||
wait_for_complete_command_sequence:
|
||||
main_status_ |= StatusRQM;
|
||||
main_status_ |= StatusRequest;
|
||||
WAIT_FOR_EVENT(Event8272::CommandByte)
|
||||
main_status_ |= StatusCB;
|
||||
main_status_ |= StatusBusy;
|
||||
|
||||
switch(command_[0] & 0x1f) {
|
||||
case 0x06: // read data
|
||||
if(command_.size() < 9) goto wait_for_complete_command_sequence;
|
||||
main_status_ &= ~StatusRQM;
|
||||
main_status_ &= ~StatusRequest;
|
||||
goto read_data;
|
||||
|
||||
case 0x0b: // read deleted data
|
||||
if(command_.size() < 9) goto wait_for_complete_command_sequence;
|
||||
main_status_ &= ~StatusRQM;
|
||||
main_status_ &= ~StatusRequest;
|
||||
goto read_deleted_data;
|
||||
|
||||
case 0x05: // write data
|
||||
if(command_.size() < 9) goto wait_for_complete_command_sequence;
|
||||
main_status_ &= ~StatusRQM;
|
||||
main_status_ &= ~StatusRequest;
|
||||
goto write_data;
|
||||
|
||||
case 0x09: // write deleted data
|
||||
if(command_.size() < 9) goto wait_for_complete_command_sequence;
|
||||
main_status_ &= ~StatusRQM;
|
||||
main_status_ &= ~StatusRequest;
|
||||
goto write_deleted_data;
|
||||
|
||||
case 0x02: // read track
|
||||
if(command_.size() < 9) goto wait_for_complete_command_sequence;
|
||||
main_status_ &= ~StatusRQM;
|
||||
main_status_ &= ~StatusRequest;
|
||||
goto read_track;
|
||||
|
||||
case 0x0a: // read ID
|
||||
if(command_.size() < 2) goto wait_for_complete_command_sequence;
|
||||
main_status_ &= ~StatusRQM;
|
||||
main_status_ &= ~StatusRequest;
|
||||
goto read_id;
|
||||
|
||||
case 0x0d: // format track
|
||||
if(command_.size() < 6) goto wait_for_complete_command_sequence;
|
||||
main_status_ &= ~StatusRQM;
|
||||
main_status_ &= ~StatusRequest;
|
||||
goto format_track;
|
||||
|
||||
case 0x11: // scan low
|
||||
if(command_.size() < 9) goto wait_for_complete_command_sequence;
|
||||
main_status_ &= ~StatusRQM;
|
||||
main_status_ &= ~StatusRequest;
|
||||
goto scan_low;
|
||||
|
||||
case 0x19: // scan low or equal
|
||||
if(command_.size() < 9) goto wait_for_complete_command_sequence;
|
||||
main_status_ &= ~StatusRQM;
|
||||
main_status_ &= ~StatusRequest;
|
||||
goto scan_low_or_equal;
|
||||
|
||||
case 0x1d: // scan high or equal
|
||||
if(command_.size() < 9) goto wait_for_complete_command_sequence;
|
||||
main_status_ &= ~StatusRQM;
|
||||
main_status_ &= ~StatusRequest;
|
||||
goto scan_high_or_equal;
|
||||
|
||||
case 0x07: // recalibrate
|
||||
if(command_.size() < 2) goto wait_for_complete_command_sequence;
|
||||
main_status_ &= ~StatusRQM;
|
||||
main_status_ &= ~StatusRequest;
|
||||
goto recalibrate;
|
||||
|
||||
case 0x08: // sense interrupt status
|
||||
main_status_ &= ~StatusRQM;
|
||||
main_status_ &= ~StatusRequest;
|
||||
goto sense_interrupt_status;
|
||||
|
||||
case 0x03: // specify
|
||||
if(command_.size() < 3) goto wait_for_complete_command_sequence;
|
||||
main_status_ &= ~StatusRQM;
|
||||
main_status_ &= ~StatusRequest;
|
||||
goto specify;
|
||||
|
||||
case 0x04: // sense drive status
|
||||
if(command_.size() < 2) goto wait_for_complete_command_sequence;
|
||||
main_status_ &= ~StatusRQM;
|
||||
main_status_ &= ~StatusRequest;
|
||||
goto sense_drive_status;
|
||||
|
||||
case 0x0f: // seek
|
||||
if(command_.size() < 3) goto wait_for_complete_command_sequence;
|
||||
main_status_ &= ~StatusRQM;
|
||||
main_status_ &= ~StatusRequest;
|
||||
goto seek;
|
||||
|
||||
default: // invalid
|
||||
main_status_ &= ~StatusRQM;
|
||||
main_status_ &= ~StatusRequest;
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
@ -277,9 +277,9 @@ void i8272::posit_event(int event_type) {
|
||||
WAIT_FOR_EVENT(Event::Token);
|
||||
result_stack_.push_back(get_latest_token().byte_value);
|
||||
distance_into_section_++;
|
||||
main_status_ |= StatusRQM | StatusDIO;
|
||||
main_status_ |= StatusRequest | StatusDirection;
|
||||
WAIT_FOR_EVENT(Event8272::ResultEmpty);
|
||||
main_status_ &= ~StatusRQM;
|
||||
main_status_ &= ~StatusRequest;
|
||||
if(distance_into_section_ < (128 << size_)) goto get_byte;
|
||||
|
||||
// read CRC, without transferring it
|
||||
@ -416,8 +416,17 @@ void i8272::posit_event(int event_type) {
|
||||
goto wait_for_command;
|
||||
|
||||
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.
|
||||
invalid:
|
||||
@ -442,15 +451,15 @@ void i8272::posit_event(int event_type) {
|
||||
// last thing in it will be returned first.
|
||||
post_result:
|
||||
// Set ready to send data to the processor, no longer in non-DMA execution phase.
|
||||
main_status_ |= StatusRQM | StatusDIO;
|
||||
main_status_ &= ~StatusNDM;
|
||||
main_status_ |= StatusRequest | StatusDirection;
|
||||
main_status_ &= ~StatusNonDMAExecuting;
|
||||
|
||||
// The actual stuff of unwinding result_stack_ is handled by ::get_register; wait
|
||||
// until the processor has read all result bytes.
|
||||
WAIT_FOR_EVENT(Event8272::ResultEmpty);
|
||||
|
||||
// Reset data direction and end the command.
|
||||
main_status_ &= ~StatusDIO;
|
||||
main_status_ &= ~StatusDirection;
|
||||
goto wait_for_command;
|
||||
|
||||
END_SECTION()
|
||||
|
@ -46,6 +46,11 @@ bool Drive::get_is_read_only() {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Drive::get_is_ready() {
|
||||
// TODO: a real test for this.
|
||||
return disk_ != nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<Track> Drive::get_track() {
|
||||
if(disk_) return disk_->get_track_at_position(head_, (unsigned int)head_position_);
|
||||
if(track_) return track_;
|
||||
|
@ -65,6 +65,11 @@ class Drive {
|
||||
*/
|
||||
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:
|
||||
std::shared_ptr<Track> track_;
|
||||
std::shared_ptr<Disk> disk_;
|
||||
|
Loading…
Reference in New Issue
Block a user