diff --git a/devices/dbdma.cpp b/devices/dbdma.cpp
new file mode 100644
index 0000000..439c779
--- /dev/null
+++ b/devices/dbdma.cpp
@@ -0,0 +1,139 @@
+/*
+DingusPPC - The Experimental PowerPC Macintosh emulator
+Copyright (C) 2018-20 divingkatae and maximum
+ (theweirdo) spatium
+
+(Contact divingkatae#1017 or powermax#2286 on Discord for more info)
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+
+/** @file Descriptor-based direct memory access emulation. */
+
+#include
+#include
+#include "dbdma.h"
+#include "endianswap.h"
+
+uint32_t DMAChannel::reg_read(uint32_t offset, int size)
+{
+ uint32_t res = 0;
+
+ if (size != 4) {
+ LOG_F(WARNING, "Unsupported non-DWORD read from DMA channel");
+ return 0;
+ }
+
+ switch(offset) {
+ case DMAReg::CH_CTRL:
+ res = 0; /* ChannelControl reads as 0 (DBDMA spec 5.5.1, table 74) */
+ break;
+ case DMAReg::CH_STAT:
+ res = BYTESWAP_32(this->ch_stat);
+ break;
+ default:
+ LOG_F(WARNING, "Unsupported DMA channel register 0x%X", offset);
+ }
+
+ return res;
+}
+
+void DMAChannel::reg_write(uint32_t offset, uint32_t value, int size)
+{
+ uint16_t mask, old_stat, new_stat;
+
+ if (size != 4) {
+ LOG_F(WARNING, "Unsupported non-DWORD write to DMA channel");
+ return;
+ }
+
+ value = BYTESWAP_32(value);
+ old_stat = this->ch_stat;
+
+ switch(offset) {
+ case DMAReg::CH_CTRL:
+ mask = value >> 16;
+ new_stat = (value & mask & 0xF0FFU) | (old_stat & ~mask);
+ LOG_F(INFO, "New ChannelStatus value = 0x%X", new_stat);
+
+ if ((new_stat & CH_STAT_RUN) != (old_stat & CH_STAT_RUN)) {
+ if (new_stat & CH_STAT_RUN) {
+ new_stat |= CH_STAT_ACTIVE;
+ this->ch_stat = new_stat;
+ this->start();
+ } else {
+ new_stat &= ~CH_STAT_ACTIVE;
+ new_stat &= ~CH_STAT_DEAD;
+ this->ch_stat = new_stat;
+ this->abort();
+ }
+ } else if ((new_stat & CH_STAT_WAKE) != (old_stat & CH_STAT_WAKE)) {
+ new_stat |= CH_STAT_ACTIVE;
+ this->ch_stat = new_stat;
+ this->resume();
+ } else if ((new_stat & CH_STAT_PAUSE) != (old_stat & CH_STAT_PAUSE)) {
+ if (new_stat & CH_STAT_PAUSE) {
+ new_stat &= ~CH_STAT_ACTIVE;
+ this->ch_stat = new_stat;
+ this->pause();
+ }
+ }
+ if (new_stat & CH_STAT_FLUSH) {
+ LOG_F(WARNING, "DMA flush not implemented!");
+ new_stat &= ~CH_STAT_FLUSH;
+ this->ch_stat = new_stat;
+ }
+ break;
+ case DMAReg::CH_STAT:
+ break; /* ingore writes to ChannelStatus */
+ case DMAReg::CMD_PTR_LO:
+ if (!(this->ch_stat & CH_STAT_RUN) && !(this->ch_stat & CH_STAT_ACTIVE)) {
+ this->cmd_ptr = BYTESWAP_32(value);
+ LOG_F(INFO, "CommandPtrLo set to 0x%X", this->cmd_ptr);
+ }
+ break;
+ default:
+ LOG_F(WARNING, "Unsupported DMA channel register 0x%X", offset);
+ }
+}
+
+void DMAChannel::start()
+{
+ if (this->ch_stat & CH_STAT_PAUSE) {
+ LOG_F(WARNING, "Cannot start DMA channel, PAUSE bit is set");
+ return;
+ }
+
+ LOG_F(INFO, "Starting DMA channel, stat = 0x%X", this->ch_stat);
+}
+
+void DMAChannel::resume()
+{
+ if (this->ch_stat & CH_STAT_PAUSE) {
+ LOG_F(WARNING, "Cannot resume DMA channel, PAUSE bit is set");
+ return;
+ }
+
+ LOG_F(INFO, "Resuming DMA channel");
+}
+
+void DMAChannel::abort()
+{
+ LOG_F(INFO, "Aborting DMA channel");
+}
+
+void DMAChannel::pause()
+{
+ LOG_F(INFO, "Pausing DMA channel");
+}
diff --git a/devices/dbdma.h b/devices/dbdma.h
new file mode 100644
index 0000000..1016559
--- /dev/null
+++ b/devices/dbdma.h
@@ -0,0 +1,70 @@
+/*
+DingusPPC - The Experimental PowerPC Macintosh emulator
+Copyright (C) 2018-20 divingkatae and maximum
+ (theweirdo) spatium
+
+(Contact divingkatae#1017 or powermax#2286 on Discord for more info)
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+
+/** @file Descriptor-based direct memory access emulation.
+
+ Official documentation can be found in the fifth chapter of the book
+ "Macintosh Technology in the Common Hardware Reference Platform"
+ by Apple Computer, Inc.
+ */
+
+#ifndef DB_DMA_H
+#define DB_DMA_H
+
+#include
+
+/** DBDMA Channel registers offsets */
+enum DMAReg : uint32_t {
+ CH_CTRL = 0,
+ CH_STAT = 4,
+ CMD_PTR_LO = 12,
+};
+
+/** Channel Status bits (DBDMA spec, 5.5.3) */
+enum {
+ CH_STAT_ACTIVE = 0x400,
+ CH_STAT_DEAD = 0x800,
+ CH_STAT_WAKE = 0x1000,
+ CH_STAT_FLUSH = 0x2000,
+ CH_STAT_PAUSE = 0x4000,
+ CH_STAT_RUN = 0x8000
+};
+
+class DMAChannel {
+public:
+ DMAChannel() = default;
+ ~DMAChannel() = default;
+
+ uint32_t reg_read(uint32_t offset, int size);
+ void reg_write(uint32_t offset, uint32_t value, int size);
+
+protected:
+ void start(void);
+ void resume(void);
+ void abort(void);
+ void pause(void);
+
+private:
+ uint16_t ch_stat = 0;
+ uint32_t cmd_ptr = 0;
+};
+
+#endif /* DB_DMA_H */
diff --git a/devices/heathrow.cpp b/devices/heathrow.cpp
index 796a274..4c1a14a 100644
--- a/devices/heathrow.cpp
+++ b/devices/heathrow.cpp
@@ -25,6 +25,7 @@ along with this program. If not, see .
#include "macio.h"
#include "viacuda.h"
#include "awacs.h"
+#include "dbdma.h"
#include "machines/machinebase.h"
/** Heathrow Mac I/O device emulation.
@@ -42,6 +43,7 @@ HeathrowIC::HeathrowIC() : PCIDevice("mac-io/heathrow")
gMachineObj->add_subdevice("ViaCuda", this->viacuda);
this->screamer = new AWACDevice();
+ this->snd_out_dma = new DMAChannel();
}
HeathrowIC::~HeathrowIC()
@@ -83,6 +85,33 @@ void HeathrowIC::pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size)
}
}
+uint32_t HeathrowIC::dma_read(uint32_t offset, int size)
+{
+ uint32_t res = 0;
+
+ switch(offset >> 8) {
+ case 8:
+ res = this->snd_out_dma->reg_read(offset & 0xFF, size);
+ break;
+ default:
+ LOG_F(WARNING, "Unsupported DMA channel read, offset=0x%X", offset);
+ }
+
+ return res;
+}
+
+void HeathrowIC::dma_write(uint32_t offset, uint32_t value, int size)
+{
+ switch(offset >> 8) {
+ case 8:
+ this->snd_out_dma->reg_write(offset & 0xFF, value, size);
+ break;
+ default:
+ LOG_F(WARNING, "Unsupported DMA channel write, offset=0x%X, val=0x%X", offset, value);
+ }
+}
+
+
uint32_t HeathrowIC::read(uint32_t offset, int size)
{
uint32_t res = 0;
@@ -96,7 +125,7 @@ uint32_t HeathrowIC::read(uint32_t offset, int size)
res = mio_ctrl_read(offset, size);
break;
case 8:
- LOG_F(WARNING, "Attempting to read DMA channel register space \n");
+ res = dma_read(offset - 0x8000, size);
break;
case 0x14:
res = this->screamer->snd_ctrl_read(offset - 0x14000, size);
@@ -128,7 +157,7 @@ void HeathrowIC::write(uint32_t offset, uint32_t value, int size)
mio_ctrl_write(offset, value, size);
break;
case 8:
- LOG_F(WARNING, "Attempting to write to DMA channel register space \n");
+ dma_write(offset - 0x8000, value, size);
break;
case 0x14:
this->screamer->snd_ctrl_write(offset - 0x14000, value, size);
diff --git a/devices/macio.h b/devices/macio.h
index 603d3a5..97c37a3 100644
--- a/devices/macio.h
+++ b/devices/macio.h
@@ -60,6 +60,7 @@ along with this program. If not, see .
#include "viacuda.h"
#include "nvram.h"
#include "awacs.h"
+#include "dbdma.h"
/**
Heathrow ASIC emulation
@@ -104,6 +105,9 @@ public:
void write(uint32_t offset, uint32_t value, int size);
protected:
+ uint32_t dma_read(uint32_t offset, int size);
+ void dma_write(uint32_t offset, uint32_t value, int size);
+
uint32_t mio_ctrl_read(uint32_t offset, int size);
void mio_ctrl_write(uint32_t offset, uint32_t value, int size);
@@ -130,6 +134,8 @@ private:
ViaCuda *viacuda; /* VIA cell with Cuda MCU attached to it */
NVram *nvram; /* NVRAM cell */
AWACDevice *screamer; /* Screamer audio codec instance */
+
+ DMAChannel *snd_out_dma;
};
#endif /* MACIO_H */