diff --git a/cpu/ppc/ppcmmu.cpp b/cpu/ppc/ppcmmu.cpp
index 1385e5c..d894897 100644
--- a/cpu/ppc/ppcmmu.cpp
+++ b/cpu/ppc/ppcmmu.cpp
@@ -52,6 +52,7 @@ AddressMapEntry last_read_area = { 0 };
AddressMapEntry last_write_area = { 0 };
AddressMapEntry last_exec_area = { 0 };
AddressMapEntry last_ptab_area = { 0 };
+AddressMapEntry last_dma_area = { 0 };
/* macro for generating code reading from physical memory */
@@ -110,6 +111,26 @@ AddressMapEntry last_ptab_area = { 0 };
} \
}
+uint8_t *mmu_get_dma_mem(uint32_t addr, uint32_t size)
+{
+ if (addr >= last_dma_area.start && (addr + size) <= last_dma_area.end) {
+ return last_dma_area.mem_ptr + (addr - last_dma_area.start);
+ }
+ else {
+ AddressMapEntry* entry = mem_ctrl_instance->find_range(addr);
+ if (entry && entry->type & (RT_ROM | RT_RAM)) {
+ last_dma_area.start = entry->start;
+ last_dma_area.end = entry->end;
+ last_dma_area.mem_ptr = entry->mem_ptr;
+ return last_dma_area.mem_ptr + (addr - last_dma_area.start);
+ }
+ else {
+ LOG_F(ERROR, "SOS: DMA access to unmapped memory %08X!\n", addr);
+ exit(-1); // FIXME: ugly error handling, must be the proper exception!
+ }
+ }
+}
+
void ppc_set_cur_instruction(const uint8_t* ptr)
{
ppc_cur_instruction = READ_DWORD_BE_A(ptr);
diff --git a/cpu/ppc/ppcmmu.h b/cpu/ppc/ppcmmu.h
index ca30c40..d3e8a47 100644
--- a/cpu/ppc/ppcmmu.h
+++ b/cpu/ppc/ppcmmu.h
@@ -44,6 +44,8 @@ typedef struct PPC_BAT_entry {
extern void ibat_update(uint32_t bat_reg);
extern void dbat_update(uint32_t bat_reg);
+extern uint8_t *mmu_get_dma_mem(uint32_t addr, uint32_t size);
+
extern void ppc_set_cur_instruction(const uint8_t* ptr);
extern void mem_write_byte(uint32_t addr, uint8_t value);
extern void mem_write_word(uint32_t addr, uint16_t value);
diff --git a/devices/awacs.cpp b/devices/awacs.cpp
index 8ecd8cd..3272a27 100644
--- a/devices/awacs.cpp
+++ b/devices/awacs.cpp
@@ -68,6 +68,7 @@ void AWACDevice::snd_ctrl_write(uint32_t offset, uint32_t value, int size)
switch(offset) {
case AWAC_SOUND_CTRL_REG:
this->snd_ctrl_reg = value;
+ LOG_F(INFO, "New sound control value = 0x%X", this->snd_ctrl_reg);
break;
case AWAC_CODEC_CTRL_REG:
subframe = (value >> 14) & 3;
diff --git a/devices/dbdma.cpp b/devices/dbdma.cpp
index 439c779..abd7807 100644
--- a/devices/dbdma.cpp
+++ b/devices/dbdma.cpp
@@ -25,6 +25,79 @@ along with this program. If not, see .
#include
#include "dbdma.h"
#include "endianswap.h"
+#include "cpu/ppc/ppcmmu.h"
+
+void DMAChannel::get_next_cmd(uint32_t cmd_addr, DMACmd *p_cmd)
+{
+ /* load DMACmd from physical memory */
+ memcpy((uint8_t *)p_cmd, mmu_get_dma_mem(cmd_addr, 16), 16);
+}
+
+uint8_t DMAChannel::interpret_cmd()
+{
+ DMACmd cmd_struct;
+
+ get_next_cmd(this->cmd_ptr, &cmd_struct);
+
+ this->ch_stat &= ~CH_STAT_WAKE; /* clear wake bit (DMA spec, 5.5.3.4) */
+
+ switch(cmd_struct.cmd_key >> 4) {
+ case 0:
+ LOG_F(INFO, "Executing DMA Command OUTPUT_MORE");
+ if (cmd_struct.cmd_key & 7) {
+ LOG_F(ERROR, "Key > 0 not implemented");
+ break;
+ }
+ if (cmd_struct.cmd_bits & 0x3F) {
+ LOG_F(ERROR, "non-zero i/b/w not implemented");
+ break;
+ }
+ LOG_F(INFO, "Transfer data, addr = 0x%X, length = 0x%X",
+ cmd_struct.address, cmd_struct.req_count);
+ this->cmd_ptr += 16;
+ break;
+ case 1:
+ LOG_F(INFO, "Executing DMA Command OUTPUT_LAST");
+ if (cmd_struct.cmd_key & 7) {
+ LOG_F(ERROR, "Key > 0 not implemented");
+ break;
+ }
+ if (cmd_struct.cmd_bits & 0x3F) {
+ LOG_F(ERROR, "non-zero i/b/w not implemented");
+ break;
+ }
+ LOG_F(INFO, "Transfer data, addr = 0x%X, length = 0x%X",
+ cmd_struct.address, cmd_struct.req_count);
+ this->cmd_ptr += 16;
+ break;
+ case 2:
+ LOG_F(ERROR, "Unsupported DMA Command INPUT_MORE");
+ break;
+ case 3:
+ LOG_F(ERROR, "Unsupported DMA Command INPUT_LAST");
+ break;
+ case 4:
+ LOG_F(ERROR, "Unsupported DMA Command STORE_QUAD");
+ break;
+ case 5:
+ LOG_F(ERROR, "Unsupported DMA Command LOAD_QUAD");
+ break;
+ case 6:
+ LOG_F(INFO, "Unsupported DMA Command NOP");
+ break;
+ case 7:
+ LOG_F(INFO, "DMA Command: 7 (STOP)");
+ this->ch_stat &= ~CH_STAT_ACTIVE;
+ break;
+ default:
+ LOG_F(ERROR, "Unsupported DMA command 0x%X", cmd_struct.cmd_key >> 4);
+ this->ch_stat |= CH_STAT_DEAD;
+ this->ch_stat &= ~CH_STAT_ACTIVE;
+ }
+
+ return (cmd_struct.cmd_key >> 4);
+}
+
uint32_t DMAChannel::reg_read(uint32_t offset, int size)
{
@@ -99,7 +172,7 @@ void DMAChannel::reg_write(uint32_t offset, uint32_t value, int size)
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);
+ this->cmd_ptr = value;
LOG_F(INFO, "CommandPtrLo set to 0x%X", this->cmd_ptr);
}
break;
@@ -116,6 +189,9 @@ void DMAChannel::start()
}
LOG_F(INFO, "Starting DMA channel, stat = 0x%X", this->ch_stat);
+
+ while (this->interpret_cmd() != 7) {
+ }
}
void DMAChannel::resume()
diff --git a/devices/dbdma.h b/devices/dbdma.h
index 1016559..cc5f1f9 100644
--- a/devices/dbdma.h
+++ b/devices/dbdma.h
@@ -48,6 +48,17 @@ enum {
CH_STAT_RUN = 0x8000
};
+/** DBDMA command (DBDMA spec, 5.6.1) - all fields are little-endian! */
+typedef struct DMACmd {
+ uint16_t req_count;
+ uint8_t cmd_bits;
+ uint8_t cmd_key;
+ uint32_t address;
+ uint32_t cmd_arg;
+ uint16_t res_count;
+ uint16_t xfer_stat;
+} DMACmd;
+
class DMAChannel {
public:
DMAChannel() = default;
@@ -57,6 +68,9 @@ public:
void reg_write(uint32_t offset, uint32_t value, int size);
protected:
+ void get_next_cmd(uint32_t cmd_addr, DMACmd *p_cmd);
+ uint8_t interpret_cmd(void);
+
void start(void);
void resume(void);
void abort(void);