1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-12-23 20:29:42 +00:00

Adds bus req/ack to the DMA controller; hacks support into the ST.

This commit is contained in:
Thomas Harte 2019-11-03 21:11:25 -05:00
parent 07582cee4a
commit 48b0d8c329
3 changed files with 99 additions and 20 deletions

View File

@ -46,7 +46,7 @@ class ConcreteMachine:
public ClockingHint::Observer,
public Motorola::ACIA::ACIA::InterruptDelegate,
public Motorola::MFP68901::MFP68901::InterruptDelegate,
public DMAController::InterruptDelegate,
public DMAController::Delegate,
public MouseMachine::Machine,
public KeyboardMachine::MappedMachine,
public MediaTarget::Machine,
@ -101,7 +101,7 @@ class ConcreteMachine:
dma_->set_clocking_hint_observer(this);
mfp_->set_interrupt_delegate(this);
dma_->set_interrupt_delegate(this);
dma_->set_delegate(this);
ay_.set_port_handler(this);
set_gpip_input();
@ -436,8 +436,15 @@ class ConcreteMachine:
void acia6850_did_change_interrupt_status(Motorola::ACIA::ACIA *) final {
set_gpip_input();
}
void dma_controller_did_change_interrupt_status(DMAController *) final {
void dma_controller_did_change_output(DMAController *) final {
set_gpip_input();
// Filty hack, here! Should: set the 68000's bus request line. But until
// that's implemented, just offers magical zero-cost DMA insertion and
// extrication.
if(dma_->get_bus_request_line()) {
dma_->bus_grant(ram_.data(), ram_.size());
}
}
void set_gpip_input() {
/*
@ -512,7 +519,7 @@ class ConcreteMachine:
b1: select floppy drive 0
b0: "page choice signal for double-sided floppy drive"
*/
dma_->set_floppy_drive_selection(!(value & 2), !(value & 4), value & 1);
dma_->set_floppy_drive_selection(!(value & 2), !(value & 4), !(value & 1));
}
}

View File

@ -126,39 +126,98 @@ void DMAController::wd1770_did_change_output(WD::WD1770 *) {
// Check for a change in interrupt state.
const bool old_interrupt_line = interrupt_line_;
interrupt_line_ = fdc_.get_interrupt_request_line();
if(interrupt_delegate_ && interrupt_line_ != old_interrupt_line) {
interrupt_delegate_->dma_controller_did_change_interrupt_status(this);
if(delegate_ && interrupt_line_ != old_interrupt_line) {
delegate_->dma_controller_did_change_output(this);
}
// Check for a change in DRQ state, if it's the FDC that is currently being watched.
if(fdc_.get_data_request_line()) {
if(!(control_ & Control::DRQSource)) return;
if(byte_count_ && fdc_.get_data_request_line() && (control_ & Control::DRQSource)) {
--byte_count_;
if(control_ & Control::Direction) {
// TODO: DMA is supposed to be helping with a write.
} else {
// DMA is enabling a read.
// Read from the data register into the active buffer.
buffer_[active_buffer_][bytes_received_] = fdc_.get_register(3);
++bytes_received_;
if(bytes_received_ < 16) {
buffer_[active_buffer_].contents[bytes_received_] = fdc_.get_register(3);
++bytes_received_;
}
if(bytes_received_ == 16) {
// TODO: BusReq and eventual deposit into RAM?
// Mark buffer as full.
buffer_[active_buffer_].is_full = true;
active_buffer_ ^= 1;
bytes_received_ = 0;
// Move to the next if it is empty; if it isn't, note a DMA error.
const auto next_buffer = active_buffer_ ^ 1;
error_ |= buffer_[next_buffer].is_full;
if(!buffer_[next_buffer].is_full) {
bytes_received_ = 0;
active_buffer_ = next_buffer;
}
// Set bus request.
if(!bus_request_line_) {
bus_request_line_ = true;
if(delegate_) delegate_->dma_controller_did_change_output(this);
}
}
}
}
}
void DMAController::set_interrupt_delegate(InterruptDelegate *delegate) {
interrupt_delegate_ = delegate;
int DMAController::bus_grant(uint16_t *ram, size_t size) {
// Being granted the bus negates the request.
bus_request_line_ = false;
if(delegate_) delegate_->dma_controller_did_change_output(this);
if(control_ & Control::Direction) {
// TODO: writes.
return 0;
} else {
// Check that the older buffer is full; stop if not.
if(!buffer_[active_buffer_ ^ 1].is_full) return 0;
for(int c = 0; c < 8; ++c) {
ram[address_ >> 1] = uint16_t(
(buffer_[active_buffer_ ^ 1].contents[(c << 1) + 0] << 8) |
(buffer_[active_buffer_ ^ 1].contents[(c << 1) + 1] << 0)
);
address_ += 2;
}
buffer_[active_buffer_ ^ 1].is_full = false;
// Check that the newer buffer is full; stop if not.
if(!buffer_[active_buffer_ ].is_full) return 8;
for(int c = 0; c < 8; ++c) {
ram[address_ >> 1] = uint16_t(
(buffer_[active_buffer_].contents[(c << 1) + 0] << 8) |
(buffer_[active_buffer_].contents[(c << 1) + 1] << 0)
);
address_ += 2;
}
buffer_[active_buffer_].is_full = false;
// Both buffers were full, so unblock reading.
bytes_received_ = 0;
return 16;
}
}
void DMAController::set_delegate(Delegate *delegate) {
delegate_ = delegate;
}
bool DMAController::get_interrupt_line() {
return interrupt_line_;
}
bool DMAController::get_bus_request_line() {
return bus_request_line_;
}
void DMAController::set_component_prefers_clocking(ClockingHint::Source *, ClockingHint::Preference) {
update_clocking_observer();
}

View File

@ -28,14 +28,23 @@ class DMAController: public WD::WD1770::Delegate, public ClockingHint::Source, p
void run_for(HalfCycles duration);
bool get_interrupt_line();
bool get_bus_request_line();
/*!
Indicates that the DMA controller has been granted bus access to the block of memory at @c ram, which
is of size @c size.
@returns The number of words read or written.
*/
int bus_grant(uint16_t *ram, size_t size);
void set_floppy_drive_selection(bool drive1, bool drive2, bool side2);
void set_floppy_disk(std::shared_ptr<Storage::Disk::Disk> disk, size_t drive);
struct InterruptDelegate {
virtual void dma_controller_did_change_interrupt_status(DMAController *) = 0;
struct Delegate {
virtual void dma_controller_did_change_output(DMAController *) = 0;
};
void set_interrupt_delegate(InterruptDelegate *delegate);
void set_delegate(Delegate *delegate);
// ClockingHint::Source.
ClockingHint::Preference preferred_clocking() final;
@ -74,13 +83,17 @@ class DMAController: public WD::WD1770::Delegate, public ClockingHint::Source, p
uint16_t control_ = 0;
InterruptDelegate *interrupt_delegate_ = nullptr;
Delegate *delegate_ = nullptr;
bool interrupt_line_ = false;
bool bus_request_line_ = false;
void set_component_prefers_clocking(ClockingHint::Source *, ClockingHint::Preference) final;
// MARK: - DMA State.
uint8_t buffer_[2][16];
struct Buffer {
uint8_t contents[16];
bool is_full = false;
} buffer_[2];
int active_buffer_ = 0;
int bytes_received_ = 0;
bool error_ = false;