sc53c94: Add DBDMA support.

- For pdm/amic, real_dma_xfer is called when SCSI_DMA_Ctrl has the run bit set.
- For tnt/grandcentral, dma_wait is called when the DBDMA is started (run bit is set). It will call real_dma_xfer when the phase and sequence are DATA_IN/RCV_DATA or DATA_OUT/SEND_DATA.
- dma_wait and real_dma_xfer uses a one shot timer instead of a loop to continue doing DMA while also giving time to the CPU. This and the above changes handles the case where the DBDMA is started before setting up the transfer phase and sequence.
- dma_stop will stop the one shot timer when the DBDMA channel is stopped.
This commit is contained in:
joevt 2024-03-10 22:10:28 -07:00 committed by dingusdev
parent ff766b10eb
commit 8a1055ed1b
2 changed files with 73 additions and 17 deletions

View File

@ -657,7 +657,7 @@ void Sc53C94::real_dma_xfer_out()
{
// transfer data from host's memory to target
while (this->xfer_count) {
if (this->xfer_count) {
uint32_t got_bytes;
uint8_t* src_ptr;
this->dma_ch->pull_data(std::min((int)this->xfer_count, DATA_FIFO_MAX),
@ -674,6 +674,16 @@ void Sc53C94::real_dma_xfer_out()
this->sequencer();
}
}
if (this->xfer_count) {
this->dma_timer_id = TimerManager::get_instance()->add_oneshot_timer(
10000,
[this]() {
// re-enter the sequencer with the state specified in next_state
this->dma_timer_id = 0;
this->real_dma_xfer_out();
});
}
}
void Sc53C94::real_dma_xfer_in()
@ -682,25 +692,60 @@ void Sc53C94::real_dma_xfer_in()
// transfer data from target to host's memory
while (this->xfer_count) {
if (this->data_fifo_pos) {
this->dma_ch->push_data((char*)this->data_fifo, this->data_fifo_pos);
if (this->xfer_count && this->data_fifo_pos) {
this->dma_ch->push_data((char*)this->data_fifo, this->data_fifo_pos);
this->xfer_count -= this->data_fifo_pos;
this->data_fifo_pos = 0;
if (!this->xfer_count) {
is_done = true;
this->status |= STAT_TC; // signal zero transfer count
this->cur_state = SeqState::XFER_END;
this->sequencer();
}
}
// see if we need to refill FIFO
if (!this->data_fifo_pos && !is_done) {
this->xfer_count -= this->data_fifo_pos;
this->data_fifo_pos = 0;
if (!this->xfer_count) {
is_done = true;
this->status |= STAT_TC; // signal zero transfer count
this->cur_state = SeqState::XFER_END;
this->sequencer();
}
}
// see if we need to refill FIFO
if (!this->data_fifo_pos && !is_done) {
this->sequencer();
this->dma_timer_id = TimerManager::get_instance()->add_oneshot_timer(
10000,
[this]() {
// re-enter the sequencer with the state specified in next_state
this->dma_timer_id = 0;
this->real_dma_xfer_in();
});
}
}
void Sc53C94::dma_wait() {
if (this->cur_bus_phase == ScsiPhase::DATA_IN && this->cur_state == SeqState::RCV_DATA) {
real_dma_xfer_in();
}
else if (this->cur_bus_phase == ScsiPhase::DATA_OUT && this->cur_state == SeqState::SEND_DATA) {
real_dma_xfer_out();
}
else {
this->dma_timer_id = TimerManager::get_instance()->add_oneshot_timer(
10000,
[this]() {
this->dma_timer_id = 0;
this->dma_wait();
});
}
}
void Sc53C94::dma_start()
{
dma_wait();
}
void Sc53C94::dma_stop()
{
if (this->dma_timer_id) {
TimerManager::get_instance()->cancel_timer(this->dma_timer_id);
this->dma_timer_id = 0;
}
}
static const PropMap Sc53C94_properties = {

View File

@ -30,12 +30,12 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#define SC_53C94_H
#include <devices/common/scsi/scsi.h>
#include <devices/common/dbdma.h>
#include <cinttypes>
#include <functional>
#include <memory>
class DmaBidirChannel;
class InterruptCtrl;
/** 53C94 read registers */
@ -209,8 +209,18 @@ public:
void real_dma_xfer_out();
void real_dma_xfer_in();
void dma_start();
void dma_wait();
void dma_stop();
void set_dma_channel(DmaBidirChannel *dma_ch) {
this->dma_ch = dma_ch;
auto dbdma_ch = dynamic_cast<DMAChannel*>(dma_ch);
if (dbdma_ch) {
dbdma_ch->set_callbacks(
std::bind(&Sc53C94::dma_start, this),
std::bind(&Sc53C94::dma_stop, this)
);
}
};
void set_drq_callback(DrqCb cb) {
@ -282,6 +292,7 @@ private:
// DMA related stuff
DmaBidirChannel* dma_ch = nullptr;
DrqCb drq_cb = nullptr;
uint32_t dma_timer_id = 0;
};
#endif // SC_53C94_H