mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-29 12:50:28 +00:00
Attempt proper EOP semantics; multisector reads.
This commit is contained in:
parent
c31ee968df
commit
208846a166
@ -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:
|
||||||
|
@ -119,8 +119,11 @@ 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;
|
||||||
|
|
||||||
|
bool complete = false;
|
||||||
|
while(!complete) {
|
||||||
for(auto &pair: drives_[decoder_.target().drive].sectors(decoder_.target().head)) {
|
for(auto &pair: drives_[decoder_.target().drive].sectors(decoder_.target().head)) {
|
||||||
if(
|
if(
|
||||||
(pair.second.address.track == target.cylinder) &&
|
(pair.second.address.track == target.cylinder) &&
|
||||||
@ -128,49 +131,63 @@ class FloppyController {
|
|||||||
(pair.second.address.side == target.head) &&
|
(pair.second.address.side == target.head) &&
|
||||||
(pair.second.size == target.size)
|
(pair.second.size == target.size)
|
||||||
) {
|
) {
|
||||||
found_sector = true;
|
// found_sector = true;
|
||||||
bool wrote_in_full = true;
|
// bool wrote_in_full = true;
|
||||||
|
|
||||||
printf("Writing data beginning: ");
|
printf("Writing data beginning: ");
|
||||||
for(int c = 0; c < 128 << target.size; c++) {
|
for(int c = 0; c < 128 << target.size; c++) {
|
||||||
if(c < 8) printf("%02x ", pair.second.samples[0].data()[c]);
|
if(c < 8) printf("%02x ", pair.second.samples[0].data()[c]);
|
||||||
|
|
||||||
if(!dma_.write(2, 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");
|
printf("FDC: DMA not permitted\n");
|
||||||
wrote_in_full = false;
|
// wrote_in_full = false;
|
||||||
|
break;
|
||||||
|
case AccessResult::AcceptedWithEOP:
|
||||||
|
complete = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(access_result != AccessResult::Accepted) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
++target.sector; // TODO: multitrack?
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
if(wrote_in_full) {
|
// if(wrote_in_full) {
|
||||||
results_.serialise(
|
// } else {
|
||||||
status_,
|
// printf("FDC: didn't write in full\n");
|
||||||
decoder_.geometry().cylinder,
|
// // TODO: Overrun, presumably?
|
||||||
decoder_.geometry().head,
|
// }
|
||||||
decoder_.geometry().sector,
|
|
||||||
decoder_.geometry().size);
|
|
||||||
} else {
|
|
||||||
printf("FDC: didn't write in full\n");
|
|
||||||
// TODO: Overrun, presumably?
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
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(
|
results_.serialise(
|
||||||
status_,
|
status_,
|
||||||
decoder_.geometry().cylinder,
|
decoder_.geometry().cylinder,
|
||||||
decoder_.geometry().head,
|
decoder_.geometry().head,
|
||||||
decoder_.geometry().sector,
|
decoder_.geometry().sector,
|
||||||
decoder_.geometry().size);
|
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);
|
||||||
|
Loading…
Reference in New Issue
Block a user