1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-25 16:31:42 +00:00

Attempt proper EOP semantics; multisector reads.

This commit is contained in:
Thomas Harte 2023-12-02 18:38:26 -05:00
parent c31ee968df
commit 208846a166
2 changed files with 87 additions and 59 deletions

View File

@ -15,6 +15,12 @@
namespace PCCompatible { namespace PCCompatible {
enum class AccessResult {
Accepted,
AcceptedWithEOP,
NotAccepted,
};
class i8237 { class i8237 {
public: public:
void flip_flop_reset() { void flip_flop_reset() {
@ -149,32 +155,38 @@ class i8237 {
// //
// Interface for reading/writing via DMA. // 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). /// 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. /// @returns A combined address and @c AccessResult.
uint32_t access(size_t channel, bool is_write) { std::pair<uint16_t, AccessResult> access(size_t channel, bool is_write) {
// if(channels_[channel].transfer_complete) {
// return NotAvailable;
// }
if(is_write && channels_[channel].transfer != Channel::Transfer::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) { 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; const auto address = channels_[channel].address.full;
channels_[channel].address.full += channels_[channel].address_decrement ? -1 : 1; channels_[channel].address.full += channels_[channel].address_decrement ? -1 : 1;
--channels_[channel].count.full; --channels_[channel].count.full;
const bool was_complete = channels_[channel].transfer_complete;
channels_[channel].transfer_complete = (channels_[channel].count.full == 0xffff); channels_[channel].transfer_complete = (channels_[channel].count.full == 0xffff);
if(channels_[channel].transfer_complete) { if(channels_[channel].transfer_complete) {
// TODO: _something_ with mode. // 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: private:
@ -257,16 +269,15 @@ class DMA {
} }
// TODO: this permits only 8-bit DMA. Fix that. // TODO: this permits only 8-bit DMA. Fix that.
bool write(size_t channel, uint8_t value) { AccessResult write(size_t channel, uint8_t value) {
auto address = controller.access(channel, true); auto access = controller.access(channel, true);
if(address == i8237::NotAvailable) { if(access.second == AccessResult::NotAccepted) {
return false; 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; *memory_->at(address) = value;
return access.second;
return true;
} }
private: private:

View File

@ -119,58 +119,75 @@ class FloppyController {
status_.begin(decoder_); status_.begin(decoder_);
// Search for a matching sector. // Search for a matching sector.
const auto target = decoder_.geometry(); auto target = decoder_.geometry();
bool found_sector = false; // 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;
printf("Writing data beginning: "); bool complete = false;
for(int c = 0; c < 128 << target.size; c++) { while(!complete) {
if(c < 8) printf("%02x ", pair.second.samples[0].data()[c]); 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("Writing data beginning: ");
printf("FDC: DMA not permitted\n"); for(int c = 0; c < 128 << target.size; c++) {
wrote_in_full = false; if(c < 8) printf("%02x ", pair.second.samples[0].data()[c]);
break;
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) { ++target.sector; // TODO: multitrack?
results_.serialise( printf("\n");
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?
}
break; // if(wrote_in_full) {
// } else {
// printf("FDC: didn't write in full\n");
// // TODO: Overrun, presumably?
// }
break;
}
} }
} }
if(!found_sector) { results_.serialise(
printf("FDC: sector not found\n"); status_,
// TODO: there's more than this, I think. decoder_.geometry().cylinder,
status_.set(Intel::i8272::Status0::AbnormalTermination); decoder_.geometry().head,
results_.serialise( decoder_.geometry().sector,
status_, decoder_.geometry().size);
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].status = decoder_.drive_head();
drives_[decoder_.target().drive].raised_interrupt = true; drives_[decoder_.target().drive].raised_interrupt = true;
pic_.apply_edge<6>(true); pic_.apply_edge<6>(true);