summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/arm/dyncom/arm_dyncom_dec.cpp2
-rw-r--r--src/core/arm/dyncom/arm_dyncom_interpreter.cpp29
-rw-r--r--src/core/arm/skyeye_common/armemu.h2
-rw-r--r--src/core/arm/skyeye_common/vfp/vfpdouble.cpp4
-rw-r--r--src/core/arm/skyeye_common/vfp/vfpinstr.cpp8
-rw-r--r--src/core/hle/config_mem.cpp96
-rw-r--r--src/core/hle/config_mem.h2
-rw-r--r--src/core/hle/hle.cpp2
-rw-r--r--src/core/hle/service/gsp_gpu.cpp34
-rw-r--r--src/core/hle/service/gsp_gpu.h4
-rw-r--r--src/core/hle/service/service.cpp2
-rw-r--r--src/core/hle/shared_page.cpp8
-rw-r--r--src/core/hw/gpu.cpp41
-rw-r--r--src/core/hw/gpu.h51
14 files changed, 192 insertions, 93 deletions
diff --git a/src/core/arm/dyncom/arm_dyncom_dec.cpp b/src/core/arm/dyncom/arm_dyncom_dec.cpp
index ffa627352..9f3b90fd0 100644
--- a/src/core/arm/dyncom/arm_dyncom_dec.cpp
+++ b/src/core/arm/dyncom/arm_dyncom_dec.cpp
@@ -42,7 +42,7 @@ const ISEITEM arm_instruction[] = {
{ "srs", 4, 6, 25, 31, 0x0000007c, 22, 22, 0x00000001, 16, 20, 0x0000000d, 8, 11, 0x00000005 },
{ "rfe", 4, 6, 25, 31, 0x0000007c, 22, 22, 0x00000000, 20, 20, 0x00000001, 8, 11, 0x0000000a },
- { "bkpt", 2, 3, 20, 31, 0x00000e12, 4, 7, 0x00000007 },
+ { "bkpt", 2, 3, 20, 27, 0x00000012, 4, 7, 0x00000007 },
{ "blx", 1, 3, 25, 31, 0x0000007d },
{ "cps", 3, 6, 20, 31, 0x00000f10, 16, 16, 0x00000000, 5, 5, 0x00000000 },
{ "pld", 4, 4, 26, 31, 0x0000003d, 24, 24, 0x00000001, 20, 22, 0x00000005, 12, 15, 0x0000000f },
diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
index f4b3c4734..b691ffbc3 100644
--- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
+++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
@@ -792,6 +792,7 @@ typedef struct _stm_inst {
} stm_inst;
struct bkpt_inst {
+ u32 imm;
};
struct blx1_inst {
@@ -1371,7 +1372,22 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(bic)(unsigned int inst, int index)
inst_base->br = INDIRECT_BRANCH;
return inst_base;
}
-static ARM_INST_PTR INTERPRETER_TRANSLATE(bkpt)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("BKPT"); }
+
+static ARM_INST_PTR INTERPRETER_TRANSLATE(bkpt)(unsigned int inst, int index)
+{
+ arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(bkpt_inst));
+ bkpt_inst* const inst_cream = (bkpt_inst*)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+ inst_base->load_r15 = 0;
+
+ inst_cream->imm = BITS(inst, 8, 19) | BITS(inst, 0, 3);
+
+ return inst_base;
+}
+
static ARM_INST_PTR INTERPRETER_TRANSLATE(blx)(unsigned int inst, int index)
{
arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(blx_inst));
@@ -3211,6 +3227,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(usada8)(unsigned int inst, int index)
inst_cream->op1 = BITS(inst, 20, 24);
inst_cream->op2 = BITS(inst, 5, 7);
+ inst_cream->Rd = BITS(inst, 16, 19);
inst_cream->Rm = BITS(inst, 8, 11);
inst_cream->Rn = BITS(inst, 0, 3);
inst_cream->Ra = BITS(inst, 12, 15);
@@ -4080,6 +4097,16 @@ unsigned InterpreterMainLoop(ARMul_State* state) {
GOTO_NEXT_INST;
}
BKPT_INST:
+ {
+ if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) {
+ bkpt_inst* const inst_cream = (bkpt_inst*)inst_base->component;
+ LOG_DEBUG(Core_ARM11, "Breakpoint instruction hit. Immediate: 0x%08X", inst_cream->imm);
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(bkpt_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
BLX_INST:
{
blx_inst *inst_cream = (blx_inst *)inst_base->component;
diff --git a/src/core/arm/skyeye_common/armemu.h b/src/core/arm/skyeye_common/armemu.h
index 8bfd4e0f0..2a1c50779 100644
--- a/src/core/arm/skyeye_common/armemu.h
+++ b/src/core/arm/skyeye_common/armemu.h
@@ -35,7 +35,7 @@ enum : u32 {
// Masks for groups of bits in the APSR.
MODEBITS = 0x1F,
- INTBITS = 0xC0,
+ INTBITS = 0x1C0,
};
// Different ways to start the next instruction.
diff --git a/src/core/arm/skyeye_common/vfp/vfpdouble.cpp b/src/core/arm/skyeye_common/vfp/vfpdouble.cpp
index 17726b8bb..1a05ef8c1 100644
--- a/src/core/arm/skyeye_common/vfp/vfpdouble.cpp
+++ b/src/core/arm/skyeye_common/vfp/vfpdouble.cpp
@@ -381,7 +381,7 @@ static u32 vfp_compare(ARMul_State* state, int dd, int signal_on_qnan, int dm, u
s64 d, m;
u32 ret = 0;
- LOG_TRACE(Core_ARM11, "In %s, state=0x%x, fpscr=0x%x\n", __FUNCTION__, state, fpscr);
+ LOG_TRACE(Core_ARM11, "In %s, state=0x%p, fpscr=0x%x\n", __FUNCTION__, state, fpscr);
m = vfp_get_double(state, dm);
if (vfp_double_packed_exponent(m) == 2047 && vfp_double_packed_mantissa(m)) {
ret |= FPSCR_CFLAG | FPSCR_VFLAG;
@@ -436,7 +436,7 @@ static u32 vfp_compare(ARMul_State* state, int dd, int signal_on_qnan, int dm, u
ret |= FPSCR_CFLAG;
}
}
- LOG_TRACE(Core_ARM11, "In %s, state=0x%x, ret=0x%x\n", __FUNCTION__, state, ret);
+ LOG_TRACE(Core_ARM11, "In %s, state=0x%p, ret=0x%x\n", __FUNCTION__, state, ret);
return ret;
}
diff --git a/src/core/arm/skyeye_common/vfp/vfpinstr.cpp b/src/core/arm/skyeye_common/vfp/vfpinstr.cpp
index 1f1b5b1c3..b9b96c388 100644
--- a/src/core/arm/skyeye_common/vfp/vfpinstr.cpp
+++ b/src/core/arm/skyeye_common/vfp/vfpinstr.cpp
@@ -1443,7 +1443,7 @@ VPUSH_INST:
addr = cpu->Reg[R13] - inst_cream->imm32;
- for (int i = 0; i < inst_cream->regs; i++)
+ for (unsigned int i = 0; i < inst_cream->regs; i++)
{
if (inst_cream->single)
{
@@ -1512,7 +1512,7 @@ VSTM_INST: /* encoding 1 */
addr = (inst_cream->add ? cpu->Reg[inst_cream->n] : cpu->Reg[inst_cream->n] - inst_cream->imm32);
- for (int i = 0; i < inst_cream->regs; i++)
+ for (unsigned int i = 0; i < inst_cream->regs; i++)
{
if (inst_cream->single)
{
@@ -1581,7 +1581,7 @@ VPOP_INST:
addr = cpu->Reg[R13];
- for (int i = 0; i < inst_cream->regs; i++)
+ for (unsigned int i = 0; i < inst_cream->regs; i++)
{
if (inst_cream->single)
{
@@ -1718,7 +1718,7 @@ VLDM_INST:
addr = (inst_cream->add ? cpu->Reg[inst_cream->n] : cpu->Reg[inst_cream->n] - inst_cream->imm32);
- for (int i = 0; i < inst_cream->regs; i++)
+ for (unsigned int i = 0; i < inst_cream->regs; i++)
{
if (inst_cream->single)
{
diff --git a/src/core/hle/config_mem.cpp b/src/core/hle/config_mem.cpp
index 68d3071f5..b10c19d1d 100644
--- a/src/core/hle/config_mem.cpp
+++ b/src/core/hle/config_mem.cpp
@@ -3,60 +3,54 @@
// Refer to the license.txt file included.
#include "common/common_types.h"
-#include "common/logging/log.h"
+#include "common/common_funcs.h"
+#include "core/core.h"
+#include "core/mem_map.h"
#include "core/hle/config_mem.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
namespace ConfigMem {
-enum {
- KERNEL_VERSIONREVISION = 0x1FF80001,
- KERNEL_VERSIONMINOR = 0x1FF80002,
- KERNEL_VERSIONMAJOR = 0x1FF80003,
- UPDATEFLAG = 0x1FF80004,
- NSTID = 0x1FF80008,
- SYSCOREVER = 0x1FF80010,
- UNITINFO = 0x1FF80014,
- KERNEL_CTRSDKVERSION = 0x1FF80018,
- APPMEMTYPE = 0x1FF80030,
- APPMEMALLOC = 0x1FF80040,
- FIRM_VERSIONREVISION = 0x1FF80061,
- FIRM_VERSIONMINOR = 0x1FF80062,
- FIRM_VERSIONMAJOR = 0x1FF80063,
- FIRM_SYSCOREVER = 0x1FF80064,
- FIRM_CTRSDKVERSION = 0x1FF80068,
+struct ConfigMemDef {
+ u8 kernel_unk; // 0
+ u8 kernel_version_rev; // 1
+ u8 kernel_version_min; // 2
+ u8 kernel_version_maj; // 3
+ u32 update_flag; // 4
+ u64 ns_tid; // 8
+ u32 sys_core_ver; // 10
+ u8 unit_info; // 14
+ u8 boot_firm; // 15
+ u8 prev_firm; // 16
+ INSERT_PADDING_BYTES(0x1); // 17
+ u32 ctr_sdk_ver; // 18
+ INSERT_PADDING_BYTES(0x30 - 0x1C); // 1C
+ u32 app_mem_type; // 30
+ INSERT_PADDING_BYTES(0x40 - 0x34); // 34
+ u32 app_mem_alloc; // 40
+ u32 sys_mem_alloc; // 44
+ u32 base_mem_alloc; // 48
+ INSERT_PADDING_BYTES(0x60 - 0x4C); // 4C
+ u8 firm_unk; // 60
+ u8 firm_version_rev; // 61
+ u8 firm_version_min; // 62
+ u8 firm_version_maj; // 63
+ u32 firm_sys_core_ver; // 64
+ u32 firm_ctr_sdk_ver; // 68
+ INSERT_PADDING_BYTES(0x1000 - 0x6C); // 6C
};
-template <typename T>
-inline void Read(T &var, const u32 addr) {
- switch (addr) {
-
- // Bit 0 set for Retail
- case UNITINFO:
- var = 0x00000001;
- break;
-
- // Set app memory size to 64MB?
- case APPMEMALLOC:
- var = 0x04000000;
- break;
+static_assert(sizeof(ConfigMemDef) == Memory::CONFIG_MEMORY_SIZE, "Config Memory structure size is wrong");
- // Unknown - normally set to: 0x08000000 - (APPMEMALLOC + *0x1FF80048)
- // (Total FCRAM size - APPMEMALLOC - *0x1FF80048)
- case 0x1FF80044:
- var = 0x08000000 - (0x04000000 + 0x1400000);
- break;
+static ConfigMemDef config_mem;
- // Unknown - normally set to: 0x1400000 (20MB)
- case 0x1FF80048:
- var = 0x1400000;
- break;
-
- default:
- LOG_ERROR(Kernel, "unknown addr=0x%08X", addr);
- }
+template <typename T>
+inline void Read(T &var, const u32 addr) {
+ u32 offset = addr - Memory::CONFIG_MEMORY_VADDR;
+ ASSERT(offset < Memory::CONFIG_MEMORY_SIZE);
+ var = *(reinterpret_cast<T*>(((uintptr_t)&config_mem) + offset));
}
// Explicitly instantiate template functions because we aren't defining this in the header:
@@ -66,5 +60,21 @@ template void Read<u32>(u32 &var, const u32 addr);
template void Read<u16>(u16 &var, const u32 addr);
template void Read<u8>(u8 &var, const u32 addr);
+void Init() {
+ config_mem.update_flag = 0; // No update
+ config_mem.sys_core_ver = 0x2;
+ config_mem.unit_info = 0x1; // Bit 0 set for Retail
+ config_mem.prev_firm = 0;
+ config_mem.app_mem_type = 0; // Defualt app mem type
+ config_mem.unit_info = 0x1; // Bit 0 set for Retail
+ config_mem.app_mem_alloc = 0x04000000; // Default app memory size is 64MB
+ config_mem.base_mem_alloc = 0x01400000; // Default base memory is 20MB
+ config_mem.sys_mem_alloc = Memory::FCRAM_SIZE - (config_mem.app_mem_alloc + config_mem.base_mem_alloc);
+ config_mem.firm_unk = 0;
+ config_mem.firm_version_rev = 0;
+ config_mem.firm_version_min = 0x40;
+ config_mem.firm_version_maj = 0x2;
+ config_mem.firm_sys_core_ver = 0x2;
+}
} // namespace
diff --git a/src/core/hle/config_mem.h b/src/core/hle/config_mem.h
index 3975af18f..94853901a 100644
--- a/src/core/hle/config_mem.h
+++ b/src/core/hle/config_mem.h
@@ -18,4 +18,6 @@ namespace ConfigMem {
template <typename T>
void Read(T &var, const u32 addr);
+void Init();
+
} // namespace
diff --git a/src/core/hle/hle.cpp b/src/core/hle/hle.cpp
index 529133ca7..b0066e15e 100644
--- a/src/core/hle/hle.cpp
+++ b/src/core/hle/hle.cpp
@@ -7,6 +7,7 @@
#include "core/arm/arm_interface.h"
#include "core/mem_map.h"
#include "core/hle/hle.h"
+#include "core/hle/config_mem.h"
#include "core/hle/shared_page.h"
#include "core/hle/kernel/thread.h"
#include "core/hle/service/service.h"
@@ -75,6 +76,7 @@ void Init() {
RegisterAllModules();
+ ConfigMem::Init();
SharedPage::Init();
LOG_DEBUG(Kernel, "initialized OK");
diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp
index 31e61391f..c23cfa3c8 100644
--- a/src/core/hle/service/gsp_gpu.cpp
+++ b/src/core/hle/service/gsp_gpu.cpp
@@ -368,28 +368,28 @@ static void ExecuteCommand(const Command& command, u32 thread_id) {
case CommandId::SET_MEMORY_FILL:
{
auto& params = command.memory_fill;
- WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].address_start)),
- Memory::VirtualToPhysicalAddress(params.start1) >> 3);
- WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].address_end)),
- Memory::VirtualToPhysicalAddress(params.end1) >> 3);
- WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].size)), params.end1 - params.start1);
- WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].value)), params.value1);
-
- WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].address_start)),
- Memory::VirtualToPhysicalAddress(params.start2) >> 3);
- WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].address_end)),
- Memory::VirtualToPhysicalAddress(params.end2) >> 3);
- WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].size)), params.end2 - params.start2);
- WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].value)), params.value2);
+ WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].address_start)),
+ Memory::VirtualToPhysicalAddress(params.start1) >> 3);
+ WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].address_end)),
+ Memory::VirtualToPhysicalAddress(params.end1) >> 3);
+ WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].value_32bit)), params.value1);
+ WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].control)), params.control1);
+
+ WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].address_start)),
+ Memory::VirtualToPhysicalAddress(params.start2) >> 3);
+ WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].address_end)),
+ Memory::VirtualToPhysicalAddress(params.end2) >> 3);
+ WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].value_32bit)), params.value2);
+ WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].control)), params.control2);
break;
}
case CommandId::SET_DISPLAY_TRANSFER:
{
auto& params = command.image_copy;
- WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.input_address)),
+ WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.input_address)),
Memory::VirtualToPhysicalAddress(params.in_buffer_address) >> 3);
- WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.output_address)),
+ WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.output_address)),
Memory::VirtualToPhysicalAddress(params.out_buffer_address) >> 3);
WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.input_size)), params.in_buffer_size);
WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.output_size)), params.out_buffer_size);
@@ -402,9 +402,9 @@ static void ExecuteCommand(const Command& command, u32 thread_id) {
case CommandId::SET_TEXTURE_COPY:
{
auto& params = command.image_copy;
- WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.input_address)),
+ WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.input_address)),
Memory::VirtualToPhysicalAddress(params.in_buffer_address) >> 3);
- WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.output_address)),
+ WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.output_address)),
Memory::VirtualToPhysicalAddress(params.out_buffer_address) >> 3);
WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.input_size)), params.in_buffer_size);
WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.output_size)), params.out_buffer_size);
diff --git a/src/core/hle/service/gsp_gpu.h b/src/core/hle/service/gsp_gpu.h
index 65abb194a..a435d418a 100644
--- a/src/core/hle/service/gsp_gpu.h
+++ b/src/core/hle/service/gsp_gpu.h
@@ -109,9 +109,13 @@ struct Command {
u32 start1;
u32 value1;
u32 end1;
+
u32 start2;
u32 value2;
u32 end2;
+
+ u16 control1;
+ u16 control2;
} memory_fill;
struct {
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index e0979ea5d..5dce8068e 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -71,6 +71,7 @@ static void AddService(Interface* interface) {
/// Initialize ServiceManager
void Init() {
AddNamedPort(new SRV::Interface);
+ AddNamedPort(new ERR_F::Interface);
AddService(new AC_U::Interface);
AddService(new ACT_U::Interface);
@@ -90,7 +91,6 @@ void Init() {
AddService(new CFG_U::Interface);
AddService(new CSND_SND::Interface);
AddService(new DSP_DSP::Interface);
- AddService(new ERR_F::Interface);
AddService(new FRD_A::Interface);
AddService(new FRD_U::Interface);
AddService(new FS::FSUserInterface);
diff --git a/src/core/hle/shared_page.cpp b/src/core/hle/shared_page.cpp
index f0726ef09..568dad684 100644
--- a/src/core/hle/shared_page.cpp
+++ b/src/core/hle/shared_page.cpp
@@ -3,6 +3,7 @@
// Refer to the license.txt file included.
#include "common/common_types.h"
+#include "common/common_funcs.h"
#include "core/core.h"
#include "core/mem_map.h"
@@ -13,13 +14,6 @@
namespace SharedPage {
-// helper macro to properly align structure members.
-// Calling INSERT_PADDING_BYTES will add a new member variable with a name like "pad121",
-// depending on the current source line to make sure variable names are unique.
-#define INSERT_PADDING_BYTES_HELPER1(x, y) x ## y
-#define INSERT_PADDING_BYTES_HELPER2(x, y) INSERT_PADDING_BYTES_HELPER1(x, y)
-#define INSERT_PADDING_BYTES(num_words) u8 INSERT_PADDING_BYTES_HELPER2(pad, __LINE__)[(num_words)]
-
// see http://3dbrew.org/wiki/Configuration_Memory#Shared_Memory_Page_For_ARM11_Processes
#pragma pack(1)
diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp
index aad0e5d0d..bd7d92cd1 100644
--- a/src/core/hw/gpu.cpp
+++ b/src/core/hw/gpu.cpp
@@ -67,23 +67,38 @@ inline void Write(u32 addr, const T data) {
switch (index) {
// Memory fills are triggered once the fill value is written.
- // NOTE: This is not verified.
- case GPU_REG_INDEX_WORKAROUND(memory_fill_config[0].value, 0x00004 + 0x3):
- case GPU_REG_INDEX_WORKAROUND(memory_fill_config[1].value, 0x00008 + 0x3):
+ case GPU_REG_INDEX_WORKAROUND(memory_fill_config[0].trigger, 0x00004 + 0x3):
+ case GPU_REG_INDEX_WORKAROUND(memory_fill_config[1].trigger, 0x00008 + 0x3):
{
- const bool is_second_filler = (index != GPU_REG_INDEX(memory_fill_config[0].value));
- const auto& config = g_regs.memory_fill_config[is_second_filler];
-
- // TODO: Not sure if this check should be done at GSP level instead
- if (config.address_start) {
- // TODO: Not sure if this algorithm is correct, particularly because it doesn't use the size member at all
- u32* start = (u32*)Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetStartAddress()));
- u32* end = (u32*)Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetEndAddress()));
- for (u32* ptr = start; ptr < end; ++ptr)
- *ptr = bswap32(config.value); // TODO: This is just a workaround to missing framebuffer format emulation
+ const bool is_second_filler = (index != GPU_REG_INDEX(memory_fill_config[0].trigger));
+ auto& config = g_regs.memory_fill_config[is_second_filler];
+
+ if (config.address_start && config.trigger) {
+ u8* start = Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetStartAddress()));
+ u8* end = Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetEndAddress()));
+
+ if (config.fill_24bit) {
+ // fill with 24-bit values
+ for (u8* ptr = start; ptr < end; ptr += 3) {
+ ptr[0] = config.value_24bit_b;
+ ptr[1] = config.value_24bit_g;
+ ptr[2] = config.value_24bit_r;
+ }
+ } else if (config.fill_32bit) {
+ // fill with 32-bit values
+ for (u32* ptr = (u32*)start; ptr < (u32*)end; ++ptr)
+ *ptr = config.value_32bit;
+ } else {
+ // fill with 16-bit values
+ for (u16* ptr = (u16*)start; ptr < (u16*)end; ++ptr)
+ *ptr = config.value_16bit;
+ }
LOG_TRACE(HW_GPU, "MemoryFill from 0x%08x to 0x%08x", config.GetStartAddress(), config.GetEndAddress());
+ config.trigger = 0;
+ config.finished = 1;
+
if (!is_second_filler) {
GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PSC0);
} else {
diff --git a/src/core/hw/gpu.h b/src/core/hw/gpu.h
index 7c3a17ee5..df9aa0d71 100644
--- a/src/core/hw/gpu.h
+++ b/src/core/hw/gpu.h
@@ -53,6 +53,7 @@ struct Regs {
"Structure size and register block length don't match")
#endif
+ // All of those formats are described in reverse byte order, since the 3DS is little-endian.
enum class PixelFormat : u32 {
RGBA8 = 0,
RGB8 = 1,
@@ -61,13 +62,57 @@ struct Regs {
RGBA4 = 4,
};
+ /**
+ * Returns the number of bytes per pixel.
+ */
+ static int BytesPerPixel(PixelFormat format) {
+ switch (format) {
+ case PixelFormat::RGBA8:
+ return 4;
+ case PixelFormat::RGB8:
+ return 3;
+ case PixelFormat::RGB565:
+ case PixelFormat::RGB5A1:
+ case PixelFormat::RGBA4:
+ return 2;
+ default:
+ UNIMPLEMENTED();
+ }
+ }
+
INSERT_PADDING_WORDS(0x4);
struct {
u32 address_start;
- u32 address_end; // ?
- u32 size;
- u32 value; // ?
+ u32 address_end;
+
+ union {
+ u32 value_32bit;
+
+ BitField<0, 16, u32> value_16bit;
+
+ // TODO: Verify component order
+ BitField< 0, 8, u32> value_24bit_r;
+ BitField< 8, 8, u32> value_24bit_g;
+ BitField<16, 8, u32> value_24bit_b;
+ };
+
+ union {
+ u32 control;
+
+ // Setting this field to 1 triggers the memory fill.
+ // This field also acts as a status flag, and gets reset to 0 upon completion.
+ BitField<0, 1, u32> trigger;
+
+ // Set to 1 upon completion.
+ BitField<0, 1, u32> finished;
+
+ // 0: fill with 16- or 32-bit wide values; 1: fill with 24-bit wide values
+ BitField<8, 1, u32> fill_24bit;
+
+ // 0: fill with 16-bit wide values; 1: fill with 32-bit wide values
+ BitField<9, 1, u32> fill_32bit;
+ };
inline u32 GetStartAddress() const {
return DecodeAddressRegister(address_start);