Skip to content
Snippets Groups Projects
Commit 42172fa2 authored by Geo Ster's avatar Geo Ster
Browse files

Fix load instruction logging in IOP

* Due to load delay slots the target register doesn't get
written immediately, so use the value instead to correctly
display the loaded value in the logs
parent 62808193
No related branches found
No related tags found
No related merge requests found
#include <cpu/iop/dma.h>
#include <common/memory.h>
#include <fmt/color.h>
namespace iop
{
/* DMA Controller class implementation. */
DMAController::DMAController(ComponentManager* manager) :
manager(manager)
{
}
void DMAController::tick()
{
}
void DMAController::transfer_finished(DMAChannels dma_channel)
{
DMAChannel& channel = channels[dma_channel];
/* IRQ flags in Bit(24+n) are set upon DMAn completion -
but caution - they are set ONLY if enabled in Bit(16+n).*/
if (irq.enable & (1 << dma_channel) || irq.master_enable)
{
irq.flags |= 1 << dma_channel;
}
/* The master flag is a simple readonly flag that follows the following rules:
IF b15=1 OR (b23=1 AND (b16-22 AND b24-30)>0) THEN b31=1 ELSE b31=0
Upon 0-to-1 transition of Bit31, the IRQ3 flag (in Port 1F801070h) gets set.
Bit24-30 are acknowledged (reset to zero) when writing a "1" to that bits */
bool previous = irq.master_flag;
irq.master_flag = irq.force || (irq.master_enable && ((irq.enable & irq.flags) > 0));
if (irq.master_flag && !previous)
{
irq_pending = true;
}
}
void DMAController::start(DMAChannels dma_channel)
{
DMAChannel& channel = channels[dma_channel];
/* Start linked list copy routine. */
if (channel.control.sync_mode == SyncType::Linked_List)
{
list_copy(dma_channel);
}
else /* Start block copy routine. */
{
block_copy(dma_channel);
}
/* Complete the transfer. */
transfer_finished(dma_channel);
}
void DMAController::block_copy(DMAChannels dma_channel)
{
}
void DMAController::list_copy(DMAChannels dma_channel)
{
}
uint32_t DMAController::read(uint32_t address)
{
uint32_t off = iop::DMA.offset(address);
/* Get channel information from address. */
uint32_t channel_num = (off & 0x70) >> 4;
uint32_t offset = off & 0xf;
/* One of the main channels is enabled. */
if (channel_num >= 0 && channel_num <= 6)
{
DMAChannel& channel = channels[channel_num];
switch (offset)
{
case 0:
return channel.base;
case 4:
return channel.block.value;
case 8:
return channel.control.value;
default:
fmt::print("[IOP DMA] Unhandled DMA read at offset: {:#x}\n", off);
std::abort();
}
} /* One of the primary registers is selected. */
else if (channel_num == 7)
{
switch (offset)
{
case 0:
return control;
case 4:
return irq.value;
default:
fmt::print("[IOP DMA] Unhandled DMA read at offset: {:#x}\n", offset);
std::abort();
}
}
fmt::print("[IOP DMA] Invalid channel number {:d}\n", channel_num);
return 0;
}
void DMAController::write(uint32_t address, uint32_t val)
{
uint32_t off = iop::DMA.offset(address);
/* Get channel information from address. */
uint32_t channel_num = (off & 0x70) >> 4;
uint32_t offset = off & 0xf;
uint32_t active_channel = INT_MAX;
/* One of the main channels is enabled. */
if (channel_num >= 0 && channel_num <= 6)
{
DMAChannel channel = channels[channel_num];
switch (offset) {
case 0:
channel.base = val & 0xffffff;
break;
case 4:
channel.block.value = val;
break;
case 8:
channel.control.value = val;
break;
default:
fmt::print("[IOP DMA] Unhandled DMA channel write at offset: {:#x}\n", off);
std::abort();
}
/* Check if the channel was just activated. */
bool trigger = true;
if (channel.control.sync_mode == SyncType::Manual)
trigger = channel.control.trigger;
if (channel.control.enable && trigger)
active_channel = channel_num;
} /* One of the primary registers is selected. */
else if (channel_num == 7)
{
switch (offset)
{
case 0:
control = val;
break;
case 4:
irq.value = val;
irq.master_flag = irq.force || (irq.master_enable && ((irq.enable & irq.flags) > 0));
break;
default:
fmt::print("[IOP DMA] Unhandled DMA write at offset: {:#x}\n", offset);
std::abort();
}
}
/* Start DMA if a channel was just activated. */
if (active_channel != INT_MAX)
start((DMAChannels)active_channel);
}
}
\ No newline at end of file
#pragma once
#include <cstdint>
namespace iop
{
enum class SyncType : uint32_t
{
Manual = 0,
Request = 1,
Linked_List = 2
};
enum DMAChannels : uint32_t
{
MDECin = 0x0,
MDECout = 0x1,
GPU = 0x2,
CDROM = 0x3,
SPU = 0x4,
PIO = 0x5,
OTC = 0x6
};
/* General info about DMA for each channel. */
union DMAControlReg
{
uint32_t value;
struct
{
uint32_t trans_dir : 1;
uint32_t addr_step : 1;
uint32_t : 6;
uint32_t chop_enable : 1;
SyncType sync_mode : 2;
uint32_t : 5;
uint32_t chop_dma : 3;
uint32_t : 1;
uint32_t chop_cpu : 3;
uint32_t : 1;
uint32_t enable : 1;
uint32_t : 3;
uint32_t trigger : 1;
uint32_t : 3;
};
};
/* Holds info about block size and count. */
union DMABlockReg
{
uint32_t value;
struct
{
uint16_t block_size;
uint16_t block_count; /* Only used in Request sync mode. */
};
};
/* A DMA channel */
struct DMAChannel
{
uint32_t base;
DMABlockReg block;
DMAControlReg control;
};
/* DMA Interrupt Register. */
union DMAIRQReg
{
uint32_t value;
struct
{
uint32_t : 15;
uint32_t force : 1;
uint32_t enable : 7;
uint32_t master_enable : 1;
uint32_t flags : 7;
uint32_t master_flag : 1;
};
};
union ListPacket
{
uint32_t value;
struct
{
uint32_t next_addr : 24;
uint32_t size : 8;
};
};
/* A class that manages all DMA routines. */
class ComponentManager;
class DMAController {
public:
DMAController(ComponentManager* manager);
void tick();
void transfer_finished(DMAChannels channel);
void start(DMAChannels channel);
void block_copy(DMAChannels channel);
void list_copy(DMAChannels channel);
uint32_t read(uint32_t address);
void write(uint32_t address, uint32_t data);
public:
uint32_t control;
DMAIRQReg irq;
DMAChannel channels[7];
bool irq_pending = false;
ComponentManager* manager;
};
}
\ No newline at end of file
...@@ -491,10 +491,9 @@ namespace iop ...@@ -491,10 +491,9 @@ namespace iop
{ {
uint32_t value = (int16_t)read<uint16_t>(vaddr); uint32_t value = (int16_t)read<uint16_t>(vaddr);
load(rt, value); load(rt, value);
log("LH: GPR[{:d}] = {:#x} from address {:#x} = GPR[{:d}] ({:#x}) + {:#x}\n", rt, value, vaddr, base, gpr[base], offset);
} }
} }
log("LH: GPR[{:d}] = {:#x} from address {:#x} = GPR[{:d}] ({:#x}) + {:#x}\n", rt, gpr[rt], vaddr, base, gpr[base], offset);
} }
void IOProcessor::op_sllv() void IOProcessor::op_sllv()
...@@ -527,10 +526,9 @@ namespace iop ...@@ -527,10 +526,9 @@ namespace iop
{ {
uint32_t value = read<uint16_t>(vaddr); uint32_t value = read<uint16_t>(vaddr);
load(rt, value); load(rt, value);
log("LHU: GPR[{:d}] = {:#x} from address {:#x} = GPR[{:d}] ({:#x}) + {:#x}\n", rt, value, vaddr, base, gpr[base], offset);
} }
} }
log("LHU: GPR[{:d}] = {:#x} from address {:#x} = GPR[{:d}] ({:#x}) + {:#x}\n", rt, gpr[rt], vaddr, base, gpr[base], offset);
} }
void IOProcessor::op_rfe() void IOProcessor::op_rfe()
...@@ -730,9 +728,8 @@ namespace iop ...@@ -730,9 +728,8 @@ namespace iop
{ {
uint32_t value = read<uint8_t>(vaddr); uint32_t value = read<uint8_t>(vaddr);
load(rt, value); load(rt, value);
log("LBU: GPR[{:d}] = {:#x} from address {:#x} = GPR[{:d}] ({:#x}) + {:#x}\n", rt, value, vaddr, base, gpr[base], offset);
} }
log("LBU: GPR[{:d}] = {:#x} from address {:#x} = GPR[{:d}] ({:#x}) + {:#x}\n", rt, gpr[rt], vaddr, base, gpr[base], offset);
} }
void IOProcessor::op_blez() void IOProcessor::op_blez()
...@@ -821,10 +818,8 @@ namespace iop ...@@ -821,10 +818,8 @@ namespace iop
{ {
uint32_t value = (int8_t)read<uint8_t>(vaddr); uint32_t value = (int8_t)read<uint8_t>(vaddr);
load(rt, value); load(rt, value);
log("LB: GPR[{:d}] = {:#x} from address {:#x} = GPR[{:d}] ({:#x}) + {:#x}\n", rt, value, vaddr, base, gpr[base], offset);
} }
log("LB: GPR[{:d}] = {:#x} from address {:#x} = GPR[{:d}] ({:#x}) + {:#x}\n", rt, gpr[rt], vaddr, base, gpr[base], offset);
} }
void IOProcessor::op_jr() void IOProcessor::op_jr()
...@@ -934,10 +929,9 @@ namespace iop ...@@ -934,10 +929,9 @@ namespace iop
{ {
uint32_t value = read<uint32_t>(vaddr); uint32_t value = read<uint32_t>(vaddr);
load(rt, value); load(rt, value);
log("LW: GPR[{:d}] = {:#x} from address {:#x} = GPR[{:d}] ({:#x}) + {:#x}\n", rt, value, vaddr, base, gpr[base], offset);
} }
} }
log("LW: GPR[{:d}] = {:#x} from address {:#x} = GPR[{:d}] ({:#x}) + {:#x}\n", rt, gpr[rt], vaddr, base, gpr[base], offset);
} }
void IOProcessor::op_addi() void IOProcessor::op_addi()
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment