diff --git a/Machines/PCCompatible/DMA.hpp b/Machines/PCCompatible/DMA.hpp index 670286457..73a4ff487 100644 --- a/Machines/PCCompatible/DMA.hpp +++ b/Machines/PCCompatible/DMA.hpp @@ -15,6 +15,12 @@ namespace PCCompatible { +enum class AccessResult { + Accepted, + AcceptedWithEOP, + NotAccepted, +}; + class i8237 { public: void flip_flop_reset() { @@ -149,32 +155,38 @@ class i8237 { // // Interface for reading/writing via DMA. // - static constexpr auto NotAvailable = uint32_t(~0); /// Provides the next target address for @c channel if performing either a write (if @c is_write is @c true) or read (otherwise). /// - /// @returns Either a 16-bit address or @c NotAvailable if the requested channel isn't set up to perform a read or write at present. - uint32_t access(size_t channel, bool is_write) { -// if(channels_[channel].transfer_complete) { -// return NotAvailable; -// } + /// @returns A combined address and @c AccessResult. + std::pair access(size_t channel, bool is_write) { if(is_write && channels_[channel].transfer != Channel::Transfer::Write) { - return NotAvailable; + return std::make_pair(0, AccessResult::NotAccepted); } if(!is_write && channels_[channel].transfer != Channel::Transfer::Read) { - return NotAvailable; + return std::make_pair(0, AccessResult::NotAccepted); } const auto address = channels_[channel].address.full; channels_[channel].address.full += channels_[channel].address_decrement ? -1 : 1; --channels_[channel].count.full; + + const bool was_complete = channels_[channel].transfer_complete; channels_[channel].transfer_complete = (channels_[channel].count.full == 0xffff); if(channels_[channel].transfer_complete) { // TODO: _something_ with mode. } - return address; + auto result = AccessResult::Accepted; + if(!was_complete && channels_[channel].transfer_complete) { + result = AccessResult::AcceptedWithEOP; + } + return std::make_pair(address, result); + } + + void set_complete(size_t channel) { + channels_[channel].transfer_complete = true; } private: @@ -257,16 +269,15 @@ class DMA { } // TODO: this permits only 8-bit DMA. Fix that. - bool write(size_t channel, uint8_t value) { - auto address = controller.access(channel, true); - if(address == i8237::NotAvailable) { - return false; + AccessResult write(size_t channel, uint8_t value) { + auto access = controller.access(channel, true); + if(access.second == AccessResult::NotAccepted) { + return access.second; } - address |= uint32_t(pages.channel_page(channel) << 16); + const uint32_t address = uint32_t(pages.channel_page(channel) << 16) | access.first; *memory_->at(address) = value; - - return true; + return access.second; } private: diff --git a/Machines/PCCompatible/PCCompatible.cpp b/Machines/PCCompatible/PCCompatible.cpp index d05701f7d..0a71e7a5f 100644 --- a/Machines/PCCompatible/PCCompatible.cpp +++ b/Machines/PCCompatible/PCCompatible.cpp @@ -119,58 +119,75 @@ class FloppyController { status_.begin(decoder_); // Search for a matching sector. - const auto target = decoder_.geometry(); - bool found_sector = false; - for(auto &pair: drives_[decoder_.target().drive].sectors(decoder_.target().head)) { - if( - (pair.second.address.track == target.cylinder) && - (pair.second.address.sector == target.sector) && - (pair.second.address.side == target.head) && - (pair.second.size == target.size) - ) { - found_sector = true; - bool wrote_in_full = true; + auto target = decoder_.geometry(); +// bool found_sector = false; - printf("Writing data beginning: "); - for(int c = 0; c < 128 << target.size; c++) { - if(c < 8) printf("%02x ", pair.second.samples[0].data()[c]); + bool complete = false; + while(!complete) { + for(auto &pair: drives_[decoder_.target().drive].sectors(decoder_.target().head)) { + if( + (pair.second.address.track == target.cylinder) && + (pair.second.address.sector == target.sector) && + (pair.second.address.side == target.head) && + (pair.second.size == target.size) + ) { +// found_sector = true; +// bool wrote_in_full = true; - if(!dma_.write(2, pair.second.samples[0].data()[c])) { - printf("FDC: DMA not permitted\n"); - wrote_in_full = false; - break; + printf("Writing data beginning: "); + for(int c = 0; c < 128 << target.size; c++) { + if(c < 8) printf("%02x ", pair.second.samples[0].data()[c]); + + const auto access_result = dma_.write(2, pair.second.samples[0].data()[c]); + switch(access_result) { + default: break; + case AccessResult::NotAccepted: + printf("FDC: DMA not permitted\n"); +// wrote_in_full = false; + break; + case AccessResult::AcceptedWithEOP: + complete = true; + break; + } + if(access_result != AccessResult::Accepted) { + break; + } } - } - printf("\n"); - if(wrote_in_full) { - results_.serialise( - status_, - decoder_.geometry().cylinder, - decoder_.geometry().head, - decoder_.geometry().sector, - decoder_.geometry().size); - } else { - printf("FDC: didn't write in full\n"); - // TODO: Overrun, presumably? - } + ++target.sector; // TODO: multitrack? + printf("\n"); - break; +// if(wrote_in_full) { +// } else { +// printf("FDC: didn't write in full\n"); +// // TODO: Overrun, presumably? +// } + + break; + } } } - if(!found_sector) { - printf("FDC: sector not found\n"); - // TODO: there's more than this, I think. - status_.set(Intel::i8272::Status0::AbnormalTermination); - results_.serialise( - status_, - decoder_.geometry().cylinder, - decoder_.geometry().head, - decoder_.geometry().sector, - decoder_.geometry().size); - } + results_.serialise( + status_, + decoder_.geometry().cylinder, + decoder_.geometry().head, + decoder_.geometry().sector, + decoder_.geometry().size); +// if(!found_sector) { +// printf("FDC: sector not found\n"); +// // TODO: there's more than this, I think. +// status_.set(Intel::i8272::Status0::AbnormalTermination); +// results_.serialise( +// status_, +// decoder_.geometry().cylinder, +// decoder_.geometry().head, +// decoder_.geometry().sector, +// decoder_.geometry().size); +// } + + // TODO: what if head has changed? drives_[decoder_.target().drive].status = decoder_.drive_head(); drives_[decoder_.target().drive].raised_interrupt = true; pic_.apply_edge<6>(true);