diff --git a/devices/common/dbdma.cpp b/devices/common/dbdma.cpp index 04bc5ea..9ebd897 100644 --- a/devices/common/dbdma.cpp +++ b/devices/common/dbdma.cpp @@ -102,6 +102,7 @@ uint8_t DMAChannel::interpret_cmd() { break; case DBDMA_Cmd::INPUT_MORE: case DBDMA_Cmd::INPUT_LAST: + this->xfer_from_device(); if (this->in_cb) this->in_cb(); break; @@ -406,6 +407,20 @@ void DMAChannel::reg_write(uint32_t offset, uint32_t value, int size) { } } +void DMAChannel::xfer_from_device() { + if (this->dev_obj == nullptr) + return; + + this->xfer_dir = DMA_DIR_FROM_DEV; + + if (!this->dev_obj->xfer_from(this->queue_data, this->queue_len)) { + this->queue_len = 0; + this->finish_cmd(); + } + + this->interpret_cmd(); +} + DmaPullResult DMAChannel::pull_data(uint32_t req_len, uint32_t *avail_len, uint8_t **p_data) { *avail_len = 0; diff --git a/devices/common/dbdma.h b/devices/common/dbdma.h index 0fccc1c..4b73d14 100644 --- a/devices/common/dbdma.h +++ b/devices/common/dbdma.h @@ -103,7 +103,7 @@ namespace DBDMA_Cmd { typedef std::function DbdmaCallback; -class DMAChannel : public DmaBidirChannel { +class DMAChannel : public DmaBidirChannel, public DmaChannel { public: DMAChannel(std::string name) : DmaBidirChannel(name) {} ~DMAChannel() = default; @@ -134,6 +134,7 @@ protected: void finish_cmd(); void xfer_quad(const DMACmd *cmd_desc, DMACmd *cmd_host); void update_irq(); + void xfer_from_device(); void start(void); void resume(void); diff --git a/devices/common/dmacore.h b/devices/common/dmacore.h index 247e877..28186e9 100644 --- a/devices/common/dmacore.h +++ b/devices/common/dmacore.h @@ -1,6 +1,6 @@ /* DingusPPC - The Experimental PowerPC Macintosh emulator -Copyright (C) 2018-22 divingkatae and maximum +Copyright (C) 2018-24 divingkatae and maximum (theweirdo) spatium (Contact divingkatae#1017 or powermax#2286 on Discord for more info) @@ -25,6 +25,7 @@ along with this program. If not, see . #define DMA_CORE_H #include +#include #include enum DmaPullResult : int { @@ -75,4 +76,52 @@ private: std::string name; }; +// ---------------------- New DMA API ------------------------- +enum DmaMsg : unsigned { + CH_START = 1, + CH_STOP, + DATA_AVAIL, +}; + +enum XferDir : unsigned { + DMA_DIR_UNDEF = 0, + DMA_DIR_TO_DEV, + DMA_DIR_FROM_DEV, +}; + +class DmaChannel; + +class DmaDevice { +public: + DmaDevice() = default; + ~DmaDevice() = default; + + void connect(DmaChannel *ch_obj) { this->channel_obj = ch_obj; }; + void notify(DmaMsg msg) {}; + virtual int xfer_from(uint8_t *buf, int len) { return len; }; + +protected: + DmaChannel* channel_obj = nullptr; +}; + +class DmaChannel { +public: + DmaChannel() = default; + ~DmaChannel() = default; + + void connect(DmaDevice *dev_obj) { this->dev_obj = dev_obj; }; + void notify(DmaMsg msg) {}; + +protected: + DmaDevice* dev_obj = nullptr; + XferDir xfer_dir = DMA_DIR_UNDEF; +}; + +/* + TODO: write CONNECT macro that + - constructs both DmaChannel and DmaDevice objects + - calls connect() method on both objects + - initializes DMA interrupts +*/ + #endif // DMA_CORE_H