Mock up DBDMA channel execution for sound.

This commit is contained in:
Maxim Poliakovski 2020-03-19 02:00:18 +01:00
parent 787ebfaff1
commit 8e34c1657c
5 changed files with 115 additions and 1 deletions

View File

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

View File

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

View File

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

View File

@ -25,6 +25,79 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <thirdparty/loguru.hpp>
#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()

View File

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