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);