diff options
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/arm/dyncom/arm_dyncom_dec.cpp | 2 | ||||
-rw-r--r-- | src/core/arm/dyncom/arm_dyncom_interpreter.cpp | 29 | ||||
-rw-r--r-- | src/core/arm/skyeye_common/armemu.h | 2 | ||||
-rw-r--r-- | src/core/arm/skyeye_common/vfp/vfpdouble.cpp | 4 | ||||
-rw-r--r-- | src/core/arm/skyeye_common/vfp/vfpinstr.cpp | 8 | ||||
-rw-r--r-- | src/core/hle/config_mem.cpp | 96 | ||||
-rw-r--r-- | src/core/hle/config_mem.h | 2 | ||||
-rw-r--r-- | src/core/hle/hle.cpp | 2 | ||||
-rw-r--r-- | src/core/hle/service/gsp_gpu.cpp | 34 | ||||
-rw-r--r-- | src/core/hle/service/gsp_gpu.h | 4 | ||||
-rw-r--r-- | src/core/hle/service/service.cpp | 2 | ||||
-rw-r--r-- | src/core/hle/shared_page.cpp | 8 | ||||
-rw-r--r-- | src/core/hw/gpu.cpp | 41 | ||||
-rw-r--r-- | src/core/hw/gpu.h | 51 |
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); |