mirror of
https://github.com/Lime3DS/Lime3DS
synced 2024-12-26 00:52:46 -06:00
Pica/GPU: Change hardware registers to use physical addresses rather than virtual ones.
This cleans up the mess that address reading/writing had become and makes the code a *lot* more sensible. This adds a physical<->virtual address converter to mem_map.h. For further accuracy, we will want to properly extend this to support a wider range of address regions. For now, this makes simply homebrew applications work in a good manner though.
This commit is contained in:
parent
bd798390d5
commit
7b6a7d7dfb
8 changed files with 81 additions and 217 deletions
|
@ -173,7 +173,7 @@ void ExecuteCommand(const Command& command) {
|
||||||
case CommandId::SET_COMMAND_LIST_LAST:
|
case CommandId::SET_COMMAND_LIST_LAST:
|
||||||
{
|
{
|
||||||
auto& params = command.set_command_list_last;
|
auto& params = command.set_command_list_last;
|
||||||
WriteGPURegister(GPU_REG_INDEX(command_processor_config.address), params.address >> 3);
|
WriteGPURegister(GPU_REG_INDEX(command_processor_config.address), Memory::VirtualToPhysicalAddress(params.address) >> 3);
|
||||||
WriteGPURegister(GPU_REG_INDEX(command_processor_config.size), params.size >> 3);
|
WriteGPURegister(GPU_REG_INDEX(command_processor_config.size), params.size >> 3);
|
||||||
|
|
||||||
// TODO: Not sure if we are supposed to always write this .. seems to trigger processing though
|
// TODO: Not sure if we are supposed to always write this .. seems to trigger processing though
|
||||||
|
@ -193,13 +193,13 @@ void ExecuteCommand(const Command& command) {
|
||||||
case CommandId::SET_MEMORY_FILL:
|
case CommandId::SET_MEMORY_FILL:
|
||||||
{
|
{
|
||||||
auto& params = command.memory_fill;
|
auto& params = command.memory_fill;
|
||||||
WriteGPURegister(GPU_REG_INDEX(memory_fill_config[0].address_start), params.start1 >> 3);
|
WriteGPURegister(GPU_REG_INDEX(memory_fill_config[0].address_start), Memory::VirtualToPhysicalAddress(params.start1) >> 3);
|
||||||
WriteGPURegister(GPU_REG_INDEX(memory_fill_config[0].address_end), params.end1 >> 3);
|
WriteGPURegister(GPU_REG_INDEX(memory_fill_config[0].address_end), Memory::VirtualToPhysicalAddress(params.end1) >> 3);
|
||||||
WriteGPURegister(GPU_REG_INDEX(memory_fill_config[0].size), params.end1 - params.start1);
|
WriteGPURegister(GPU_REG_INDEX(memory_fill_config[0].size), params.end1 - params.start1);
|
||||||
WriteGPURegister(GPU_REG_INDEX(memory_fill_config[0].value), params.value1);
|
WriteGPURegister(GPU_REG_INDEX(memory_fill_config[0].value), params.value1);
|
||||||
|
|
||||||
WriteGPURegister(GPU_REG_INDEX(memory_fill_config[1].address_start), params.start2 >> 3);
|
WriteGPURegister(GPU_REG_INDEX(memory_fill_config[1].address_start), Memory::VirtualToPhysicalAddress(params.start2) >> 3);
|
||||||
WriteGPURegister(GPU_REG_INDEX(memory_fill_config[1].address_end), params.end2 >> 3);
|
WriteGPURegister(GPU_REG_INDEX(memory_fill_config[1].address_end), Memory::VirtualToPhysicalAddress(params.end2) >> 3);
|
||||||
WriteGPURegister(GPU_REG_INDEX(memory_fill_config[1].size), params.end2 - params.start2);
|
WriteGPURegister(GPU_REG_INDEX(memory_fill_config[1].size), params.end2 - params.start2);
|
||||||
WriteGPURegister(GPU_REG_INDEX(memory_fill_config[1].value), params.value2);
|
WriteGPURegister(GPU_REG_INDEX(memory_fill_config[1].value), params.value2);
|
||||||
break;
|
break;
|
||||||
|
@ -208,8 +208,8 @@ void ExecuteCommand(const Command& command) {
|
||||||
case CommandId::SET_DISPLAY_TRANSFER:
|
case CommandId::SET_DISPLAY_TRANSFER:
|
||||||
{
|
{
|
||||||
auto& params = command.image_copy;
|
auto& params = command.image_copy;
|
||||||
WriteGPURegister(GPU_REG_INDEX(display_transfer_config.input_address), params.in_buffer_address >> 3);
|
WriteGPURegister(GPU_REG_INDEX(display_transfer_config.input_address), Memory::VirtualToPhysicalAddress(params.in_buffer_address) >> 3);
|
||||||
WriteGPURegister(GPU_REG_INDEX(display_transfer_config.output_address), params.out_buffer_address >> 3);
|
WriteGPURegister(GPU_REG_INDEX(display_transfer_config.output_address), Memory::VirtualToPhysicalAddress(params.out_buffer_address) >> 3);
|
||||||
WriteGPURegister(GPU_REG_INDEX(display_transfer_config.input_size), params.in_buffer_size);
|
WriteGPURegister(GPU_REG_INDEX(display_transfer_config.input_size), params.in_buffer_size);
|
||||||
WriteGPURegister(GPU_REG_INDEX(display_transfer_config.output_size), params.out_buffer_size);
|
WriteGPURegister(GPU_REG_INDEX(display_transfer_config.output_size), params.out_buffer_size);
|
||||||
WriteGPURegister(GPU_REG_INDEX(display_transfer_config.flags), params.flags);
|
WriteGPURegister(GPU_REG_INDEX(display_transfer_config.flags), params.flags);
|
||||||
|
@ -230,8 +230,8 @@ void ExecuteCommand(const Command& command) {
|
||||||
case CommandId::SET_TEXTURE_COPY:
|
case CommandId::SET_TEXTURE_COPY:
|
||||||
{
|
{
|
||||||
auto& params = command.image_copy;
|
auto& params = command.image_copy;
|
||||||
WriteGPURegister(GPU_REG_INDEX(display_transfer_config.input_address), params.in_buffer_address >> 3);
|
WriteGPURegister(GPU_REG_INDEX(display_transfer_config.input_address), Memory::VirtualToPhysicalAddress(params.in_buffer_address) >> 3);
|
||||||
WriteGPURegister(GPU_REG_INDEX(display_transfer_config.output_address), params.out_buffer_address >> 3);
|
WriteGPURegister(GPU_REG_INDEX(display_transfer_config.output_address), Memory::VirtualToPhysicalAddress(params.out_buffer_address) >> 3);
|
||||||
WriteGPURegister(GPU_REG_INDEX(display_transfer_config.input_size), params.in_buffer_size);
|
WriteGPURegister(GPU_REG_INDEX(display_transfer_config.input_size), params.in_buffer_size);
|
||||||
WriteGPURegister(GPU_REG_INDEX(display_transfer_config.output_size), params.out_buffer_size);
|
WriteGPURegister(GPU_REG_INDEX(display_transfer_config.output_size), params.out_buffer_size);
|
||||||
WriteGPURegister(GPU_REG_INDEX(display_transfer_config.flags), params.flags);
|
WriteGPURegister(GPU_REG_INDEX(display_transfer_config.flags), params.flags);
|
||||||
|
|
|
@ -24,83 +24,6 @@ Regs g_regs;
|
||||||
u32 g_cur_line = 0; ///< Current vertical screen line
|
u32 g_cur_line = 0; ///< Current vertical screen line
|
||||||
u64 g_last_line_ticks = 0; ///< CPU tick count from last vertical screen line
|
u64 g_last_line_ticks = 0; ///< CPU tick count from last vertical screen line
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets whether the framebuffers are in the GSP heap (FCRAM) or VRAM
|
|
||||||
* @param
|
|
||||||
*/
|
|
||||||
void SetFramebufferLocation(const FramebufferLocation mode) {
|
|
||||||
switch (mode) {
|
|
||||||
case FRAMEBUFFER_LOCATION_FCRAM:
|
|
||||||
{
|
|
||||||
auto& framebuffer_top = g_regs.framebuffer_config[0];
|
|
||||||
auto& framebuffer_sub = g_regs.framebuffer_config[1];
|
|
||||||
|
|
||||||
framebuffer_top.address_left1 = PADDR_TOP_LEFT_FRAME1;
|
|
||||||
framebuffer_top.address_left2 = PADDR_TOP_LEFT_FRAME2;
|
|
||||||
framebuffer_top.address_right1 = PADDR_TOP_RIGHT_FRAME1;
|
|
||||||
framebuffer_top.address_right2 = PADDR_TOP_RIGHT_FRAME2;
|
|
||||||
framebuffer_sub.address_left1 = PADDR_SUB_FRAME1;
|
|
||||||
//framebuffer_sub.address_left2 = unknown;
|
|
||||||
framebuffer_sub.address_right1 = PADDR_SUB_FRAME2;
|
|
||||||
//framebuffer_sub.address_right2 = unknown;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case FRAMEBUFFER_LOCATION_VRAM:
|
|
||||||
{
|
|
||||||
auto& framebuffer_top = g_regs.framebuffer_config[0];
|
|
||||||
auto& framebuffer_sub = g_regs.framebuffer_config[1];
|
|
||||||
|
|
||||||
framebuffer_top.address_left1 = PADDR_VRAM_TOP_LEFT_FRAME1;
|
|
||||||
framebuffer_top.address_left2 = PADDR_VRAM_TOP_LEFT_FRAME2;
|
|
||||||
framebuffer_top.address_right1 = PADDR_VRAM_TOP_RIGHT_FRAME1;
|
|
||||||
framebuffer_top.address_right2 = PADDR_VRAM_TOP_RIGHT_FRAME2;
|
|
||||||
framebuffer_sub.address_left1 = PADDR_VRAM_SUB_FRAME1;
|
|
||||||
//framebuffer_sub.address_left2 = unknown;
|
|
||||||
framebuffer_sub.address_right1 = PADDR_VRAM_SUB_FRAME2;
|
|
||||||
//framebuffer_sub.address_right2 = unknown;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the location of the framebuffers
|
|
||||||
* @return Location of framebuffers as FramebufferLocation enum
|
|
||||||
*/
|
|
||||||
FramebufferLocation GetFramebufferLocation(u32 address) {
|
|
||||||
if ((address & ~Memory::VRAM_MASK) == Memory::VRAM_PADDR) {
|
|
||||||
return FRAMEBUFFER_LOCATION_VRAM;
|
|
||||||
} else if ((address & ~Memory::FCRAM_MASK) == Memory::FCRAM_PADDR) {
|
|
||||||
return FRAMEBUFFER_LOCATION_FCRAM;
|
|
||||||
} else {
|
|
||||||
ERROR_LOG(GPU, "unknown framebuffer location!");
|
|
||||||
}
|
|
||||||
return FRAMEBUFFER_LOCATION_UNKNOWN;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 GetFramebufferAddr(const u32 address) {
|
|
||||||
switch (GetFramebufferLocation(address)) {
|
|
||||||
case FRAMEBUFFER_LOCATION_FCRAM:
|
|
||||||
return Memory::VirtualAddressFromPhysical_FCRAM(address);
|
|
||||||
case FRAMEBUFFER_LOCATION_VRAM:
|
|
||||||
return Memory::VirtualAddressFromPhysical_VRAM(address);
|
|
||||||
default:
|
|
||||||
ERROR_LOG(GPU, "unknown framebuffer location");
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a read-only pointer to a framebuffer in memory
|
|
||||||
* @param address Physical address of framebuffer
|
|
||||||
* @return Returns const pointer to raw framebuffer
|
|
||||||
*/
|
|
||||||
const u8* GetFramebufferPointer(const u32 address) {
|
|
||||||
u32 addr = GetFramebufferAddr(address);
|
|
||||||
return (addr != 0) ? Memory::GetPointer(addr) : nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline void Read(T &var, const u32 raw_addr) {
|
inline void Read(T &var, const u32 raw_addr) {
|
||||||
u32 addr = raw_addr - 0x1EF00000;
|
u32 addr = raw_addr - 0x1EF00000;
|
||||||
|
@ -141,8 +64,8 @@ inline void Write(u32 addr, const T data) {
|
||||||
// TODO: Not sure if this check should be done at GSP level instead
|
// TODO: Not sure if this check should be done at GSP level instead
|
||||||
if (config.address_start) {
|
if (config.address_start) {
|
||||||
// TODO: Not sure if this algorithm is correct, particularly because it doesn't use the size member at all
|
// TODO: Not sure if this algorithm is correct, particularly because it doesn't use the size member at all
|
||||||
u32* start = (u32*)Memory::GetPointer(config.GetStartAddress());
|
u32* start = (u32*)Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetStartAddress()));
|
||||||
u32* end = (u32*)Memory::GetPointer(config.GetEndAddress());
|
u32* end = (u32*)Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetEndAddress()));
|
||||||
for (u32* ptr = start; ptr < end; ++ptr)
|
for (u32* ptr = start; ptr < end; ++ptr)
|
||||||
*ptr = bswap32(config.value); // TODO: This is just a workaround to missing framebuffer format emulation
|
*ptr = bswap32(config.value); // TODO: This is just a workaround to missing framebuffer format emulation
|
||||||
|
|
||||||
|
@ -155,8 +78,8 @@ inline void Write(u32 addr, const T data) {
|
||||||
{
|
{
|
||||||
const auto& config = g_regs.display_transfer_config;
|
const auto& config = g_regs.display_transfer_config;
|
||||||
if (config.trigger & 1) {
|
if (config.trigger & 1) {
|
||||||
u8* source_pointer = Memory::GetPointer(config.GetPhysicalInputAddress());
|
u8* source_pointer = Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetPhysicalInputAddress()));
|
||||||
u8* dest_pointer = Memory::GetPointer(config.GetPhysicalOutputAddress());
|
u8* dest_pointer = Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetPhysicalOutputAddress()));
|
||||||
|
|
||||||
for (int y = 0; y < config.output_height; ++y) {
|
for (int y = 0; y < config.output_height; ++y) {
|
||||||
// TODO: Why does the register seem to hold twice the framebuffer width?
|
// TODO: Why does the register seem to hold twice the framebuffer width?
|
||||||
|
@ -276,11 +199,22 @@ void Init() {
|
||||||
g_cur_line = 0;
|
g_cur_line = 0;
|
||||||
g_last_line_ticks = Core::g_app_core->GetTicks();
|
g_last_line_ticks = Core::g_app_core->GetTicks();
|
||||||
|
|
||||||
// SetFramebufferLocation(FRAMEBUFFER_LOCATION_FCRAM);
|
|
||||||
SetFramebufferLocation(FRAMEBUFFER_LOCATION_VRAM);
|
|
||||||
|
|
||||||
auto& framebuffer_top = g_regs.framebuffer_config[0];
|
auto& framebuffer_top = g_regs.framebuffer_config[0];
|
||||||
auto& framebuffer_sub = g_regs.framebuffer_config[1];
|
auto& framebuffer_sub = g_regs.framebuffer_config[1];
|
||||||
|
|
||||||
|
// Setup default framebuffer addresses (located in VRAM)
|
||||||
|
// .. or at least these are the ones used by system applets.
|
||||||
|
// There's probably a smarter way to come up with addresses
|
||||||
|
// like this which does not require hardcoding.
|
||||||
|
framebuffer_top.address_left1 = 0x181E6000;
|
||||||
|
framebuffer_top.address_left2 = 0x1822C800;
|
||||||
|
framebuffer_top.address_right1 = 0x18273000;
|
||||||
|
framebuffer_top.address_right2 = 0x182B9800;
|
||||||
|
framebuffer_sub.address_left1 = 0x1848F000;
|
||||||
|
//framebuffer_sub.address_left2 = unknown;
|
||||||
|
framebuffer_sub.address_right1 = 0x184C7800;
|
||||||
|
//framebuffer_sub.address_right2 = unknown;
|
||||||
|
|
||||||
// TODO: Width should be 240 instead?
|
// TODO: Width should be 240 instead?
|
||||||
framebuffer_top.width = 480;
|
framebuffer_top.width = 480;
|
||||||
framebuffer_top.height = 400;
|
framebuffer_top.height = 400;
|
||||||
|
|
|
@ -249,72 +249,6 @@ static_assert(sizeof(Regs) == 0x1000 * sizeof(u32), "Invalid total size of regis
|
||||||
|
|
||||||
extern Regs g_regs;
|
extern Regs g_regs;
|
||||||
|
|
||||||
enum {
|
|
||||||
TOP_ASPECT_X = 0x5,
|
|
||||||
TOP_ASPECT_Y = 0x3,
|
|
||||||
|
|
||||||
TOP_HEIGHT = 240,
|
|
||||||
TOP_WIDTH = 400,
|
|
||||||
BOTTOM_WIDTH = 320,
|
|
||||||
|
|
||||||
// Physical addresses in FCRAM (chosen arbitrarily)
|
|
||||||
PADDR_TOP_LEFT_FRAME1 = 0x201D4C00,
|
|
||||||
PADDR_TOP_LEFT_FRAME2 = 0x202D4C00,
|
|
||||||
PADDR_TOP_RIGHT_FRAME1 = 0x203D4C00,
|
|
||||||
PADDR_TOP_RIGHT_FRAME2 = 0x204D4C00,
|
|
||||||
PADDR_SUB_FRAME1 = 0x205D4C00,
|
|
||||||
PADDR_SUB_FRAME2 = 0x206D4C00,
|
|
||||||
// Physical addresses in FCRAM used by ARM9 applications
|
|
||||||
/* PADDR_TOP_LEFT_FRAME1 = 0x20184E60,
|
|
||||||
PADDR_TOP_LEFT_FRAME2 = 0x201CB370,
|
|
||||||
PADDR_TOP_RIGHT_FRAME1 = 0x20282160,
|
|
||||||
PADDR_TOP_RIGHT_FRAME2 = 0x202C8670,
|
|
||||||
PADDR_SUB_FRAME1 = 0x202118E0,
|
|
||||||
PADDR_SUB_FRAME2 = 0x20249CF0,*/
|
|
||||||
|
|
||||||
// Physical addresses in VRAM
|
|
||||||
// TODO: These should just be deduced from the ones above
|
|
||||||
PADDR_VRAM_TOP_LEFT_FRAME1 = 0x181D4C00,
|
|
||||||
PADDR_VRAM_TOP_LEFT_FRAME2 = 0x182D4C00,
|
|
||||||
PADDR_VRAM_TOP_RIGHT_FRAME1 = 0x183D4C00,
|
|
||||||
PADDR_VRAM_TOP_RIGHT_FRAME2 = 0x184D4C00,
|
|
||||||
PADDR_VRAM_SUB_FRAME1 = 0x185D4C00,
|
|
||||||
PADDR_VRAM_SUB_FRAME2 = 0x186D4C00,
|
|
||||||
// Physical addresses in VRAM used by ARM9 applications
|
|
||||||
/* PADDR_VRAM_TOP_LEFT_FRAME2 = 0x181CB370,
|
|
||||||
PADDR_VRAM_TOP_RIGHT_FRAME1 = 0x18282160,
|
|
||||||
PADDR_VRAM_TOP_RIGHT_FRAME2 = 0x182C8670,
|
|
||||||
PADDR_VRAM_SUB_FRAME1 = 0x182118E0,
|
|
||||||
PADDR_VRAM_SUB_FRAME2 = 0x18249CF0,*/
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Framebuffer location
|
|
||||||
enum FramebufferLocation {
|
|
||||||
FRAMEBUFFER_LOCATION_UNKNOWN, ///< Framebuffer location is unknown
|
|
||||||
FRAMEBUFFER_LOCATION_FCRAM, ///< Framebuffer is in the GSP heap
|
|
||||||
FRAMEBUFFER_LOCATION_VRAM, ///< Framebuffer is in VRAM
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets whether the framebuffers are in the GSP heap (FCRAM) or VRAM
|
|
||||||
* @param
|
|
||||||
*/
|
|
||||||
void SetFramebufferLocation(const FramebufferLocation mode);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a read-only pointer to a framebuffer in memory
|
|
||||||
* @param address Physical address of framebuffer
|
|
||||||
* @return Returns const pointer to raw framebuffer
|
|
||||||
*/
|
|
||||||
const u8* GetFramebufferPointer(const u32 address);
|
|
||||||
|
|
||||||
u32 GetFramebufferAddr(const u32 address);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the location of the framebuffers
|
|
||||||
*/
|
|
||||||
FramebufferLocation GetFramebufferLocation(u32 address);
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void Read(T &var, const u32 addr);
|
void Read(T &var, const u32 addr);
|
||||||
|
|
||||||
|
|
|
@ -72,14 +72,14 @@ void Init() {
|
||||||
|
|
||||||
g_base = MemoryMap_Setup(g_views, kNumMemViews, flags, &g_arena);
|
g_base = MemoryMap_Setup(g_views, kNumMemViews, flags, &g_arena);
|
||||||
|
|
||||||
NOTICE_LOG(MEMMAP, "initialized OK, RAM at %p (mirror at 0 @ %p)", g_heap,
|
NOTICE_LOG(MEMMAP, "initialized OK, RAM at %p (mirror at 0 @ %p)", g_heap,
|
||||||
g_physical_fcram);
|
g_physical_fcram);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shutdown() {
|
void Shutdown() {
|
||||||
u32 flags = 0;
|
u32 flags = 0;
|
||||||
MemoryMap_Shutdown(g_views, kNumMemViews, flags, &g_arena);
|
MemoryMap_Shutdown(g_views, kNumMemViews, flags, &g_arena);
|
||||||
|
|
||||||
g_arena.ReleaseSpace();
|
g_arena.ReleaseSpace();
|
||||||
g_base = NULL;
|
g_base = NULL;
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,6 @@ namespace Memory {
|
||||||
enum {
|
enum {
|
||||||
BOOTROM_SIZE = 0x00010000, ///< Bootrom (super secret code/data @ 0x8000) size
|
BOOTROM_SIZE = 0x00010000, ///< Bootrom (super secret code/data @ 0x8000) size
|
||||||
MPCORE_PRIV_SIZE = 0x00002000, ///< MPCore private memory region size
|
MPCORE_PRIV_SIZE = 0x00002000, ///< MPCore private memory region size
|
||||||
VRAM_SIZE = 0x00600000, ///< VRAM size
|
|
||||||
DSP_SIZE = 0x00080000, ///< DSP memory size
|
DSP_SIZE = 0x00080000, ///< DSP memory size
|
||||||
AXI_WRAM_SIZE = 0x00080000, ///< AXI WRAM size
|
AXI_WRAM_SIZE = 0x00080000, ///< AXI WRAM size
|
||||||
|
|
||||||
|
@ -23,8 +22,6 @@ enum {
|
||||||
FCRAM_PADDR_END = (FCRAM_PADDR + FCRAM_SIZE), ///< FCRAM end of physical space
|
FCRAM_PADDR_END = (FCRAM_PADDR + FCRAM_SIZE), ///< FCRAM end of physical space
|
||||||
FCRAM_VADDR = 0x08000000, ///< FCRAM virtual address
|
FCRAM_VADDR = 0x08000000, ///< FCRAM virtual address
|
||||||
FCRAM_VADDR_END = (FCRAM_VADDR + FCRAM_SIZE), ///< FCRAM end of virtual space
|
FCRAM_VADDR_END = (FCRAM_VADDR + FCRAM_SIZE), ///< FCRAM end of virtual space
|
||||||
FCRAM_VADDR_FW0B = 0xF0000000, ///< FCRAM adress for firmare FW0B
|
|
||||||
FCRAM_VADDR_FW0B_END = (FCRAM_VADDR_FW0B + FCRAM_SIZE), ///< FCRAM adress end for FW0B
|
|
||||||
FCRAM_MASK = (FCRAM_SIZE - 1), ///< FCRAM mask
|
FCRAM_MASK = (FCRAM_SIZE - 1), ///< FCRAM mask
|
||||||
|
|
||||||
SHARED_MEMORY_SIZE = 0x04000000, ///< Shared memory size
|
SHARED_MEMORY_SIZE = 0x04000000, ///< Shared memory size
|
||||||
|
@ -73,6 +70,7 @@ enum {
|
||||||
HARDWARE_IO_PADDR_END = (HARDWARE_IO_PADDR + HARDWARE_IO_SIZE),
|
HARDWARE_IO_PADDR_END = (HARDWARE_IO_PADDR + HARDWARE_IO_SIZE),
|
||||||
HARDWARE_IO_VADDR_END = (HARDWARE_IO_VADDR + HARDWARE_IO_SIZE),
|
HARDWARE_IO_VADDR_END = (HARDWARE_IO_VADDR + HARDWARE_IO_SIZE),
|
||||||
|
|
||||||
|
VRAM_SIZE = 0x00600000,
|
||||||
VRAM_PADDR = 0x18000000,
|
VRAM_PADDR = 0x18000000,
|
||||||
VRAM_VADDR = 0x1F000000,
|
VRAM_VADDR = 0x1F000000,
|
||||||
VRAM_PADDR_END = (VRAM_PADDR + VRAM_SIZE),
|
VRAM_PADDR_END = (VRAM_PADDR + VRAM_SIZE),
|
||||||
|
@ -112,7 +110,7 @@ struct MemoryBlock {
|
||||||
|
|
||||||
// In 64-bit, this might point to "high memory" (above the 32-bit limit),
|
// In 64-bit, this might point to "high memory" (above the 32-bit limit),
|
||||||
// so be sure to load it into a 64-bit register.
|
// so be sure to load it into a 64-bit register.
|
||||||
extern u8 *g_base;
|
extern u8 *g_base;
|
||||||
|
|
||||||
// These are guaranteed to point to "low memory" addresses (sub-32-bit).
|
// These are guaranteed to point to "low memory" addresses (sub-32-bit).
|
||||||
// 64-bit: Pointers to low-mem (sub-0x10000000) mirror
|
// 64-bit: Pointers to low-mem (sub-0x10000000) mirror
|
||||||
|
@ -147,7 +145,7 @@ void Write32(const u32 addr, const u32 data);
|
||||||
|
|
||||||
void WriteBlock(const u32 addr, const u8* data, const int size);
|
void WriteBlock(const u32 addr, const u8* data, const int size);
|
||||||
|
|
||||||
u8* GetPointer(const u32 Address);
|
u8* GetPointer(const u32 virtual_address);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maps a block of memory on the heap
|
* Maps a block of memory on the heap
|
||||||
|
@ -169,16 +167,10 @@ inline const char* GetCharPointer(const u32 address) {
|
||||||
return (const char *)GetPointer(address);
|
return (const char *)GetPointer(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const u32 VirtualAddressFromPhysical_FCRAM(const u32 address) {
|
/// Converts a physical address to virtual address
|
||||||
return ((address & FCRAM_MASK) | FCRAM_VADDR);
|
u32 PhysicalToVirtualAddress(const u32 addr);
|
||||||
}
|
|
||||||
|
|
||||||
inline const u32 VirtualAddressFromPhysical_IO(const u32 address) {
|
/// Converts a virtual address to physical address
|
||||||
return (address + 0x0EB00000);
|
u32 VirtualToPhysicalAddress(const u32 addr);
|
||||||
}
|
|
||||||
|
|
||||||
inline const u32 VirtualAddressFromPhysical_VRAM(const u32 address) {
|
|
||||||
return (address + 0x07000000);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
@ -17,37 +17,44 @@ std::map<u32, MemoryBlock> g_heap_map;
|
||||||
std::map<u32, MemoryBlock> g_heap_gsp_map;
|
std::map<u32, MemoryBlock> g_heap_gsp_map;
|
||||||
std::map<u32, MemoryBlock> g_shared_map;
|
std::map<u32, MemoryBlock> g_shared_map;
|
||||||
|
|
||||||
/// Convert a physical address (or firmware-specific virtual address) to primary virtual address
|
/// Convert a physical address to virtual address
|
||||||
u32 _VirtualAddress(const u32 addr) {
|
u32 PhysicalToVirtualAddress(const u32 addr) {
|
||||||
// Our memory interface read/write functions assume virtual addresses. Put any physical address
|
// Our memory interface read/write functions assume virtual addresses. Put any physical address
|
||||||
// to virtual address translations here. This is obviously quite hacky... But we're not doing
|
// to virtual address translations here. This is quite hacky, but necessary until we implement
|
||||||
// any MMU emulation yet or anything
|
// proper MMU emulation.
|
||||||
if ((addr >= FCRAM_PADDR) && (addr < FCRAM_PADDR_END)) {
|
// TODO: Screw it, I'll let bunnei figure out how to do this properly.
|
||||||
return VirtualAddressFromPhysical_FCRAM(addr);
|
if ((addr >= VRAM_PADDR) && (addr < VRAM_PADDR_END)) {
|
||||||
|
return addr - VRAM_PADDR + VRAM_VADDR;
|
||||||
// Virtual address mapping FW0B
|
}else if ((addr >= FCRAM_PADDR) && (addr < FCRAM_PADDR_END)) {
|
||||||
} else if ((addr >= FCRAM_VADDR_FW0B) && (addr < FCRAM_VADDR_FW0B_END)) {
|
return addr - FCRAM_PADDR + FCRAM_VADDR;
|
||||||
return VirtualAddressFromPhysical_FCRAM(addr);
|
|
||||||
|
|
||||||
// Hardware IO
|
|
||||||
// TODO(bunnei): FixMe
|
|
||||||
// This isn't going to work... The physical address of HARDWARE_IO conflicts with the virtual
|
|
||||||
// address of shared memory.
|
|
||||||
//} else if ((addr >= HARDWARE_IO_PADDR) && (addr < HARDWARE_IO_PADDR_END)) {
|
|
||||||
// return (addr + 0x0EB00000);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ERROR_LOG(MEMMAP, "Unknown physical address @ 0x%08x", addr);
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert a physical address to virtual address
|
||||||
|
u32 VirtualToPhysicalAddress(const u32 addr) {
|
||||||
|
// Our memory interface read/write functions assume virtual addresses. Put any physical address
|
||||||
|
// to virtual address translations here. This is quite hacky, but necessary until we implement
|
||||||
|
// proper MMU emulation.
|
||||||
|
// TODO: Screw it, I'll let bunnei figure out how to do this properly.
|
||||||
|
if ((addr >= VRAM_VADDR) && (addr < VRAM_VADDR_END)) {
|
||||||
|
return addr - 0x07000000;
|
||||||
|
} else if ((addr >= FCRAM_VADDR) && (addr < FCRAM_VADDR_END)) {
|
||||||
|
return addr - FCRAM_VADDR + FCRAM_PADDR;
|
||||||
|
}
|
||||||
|
|
||||||
|
ERROR_LOG(MEMMAP, "Unknown virtual address @ 0x%08x", addr);
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline void Read(T &var, const u32 addr) {
|
inline void Read(T &var, const u32 vaddr) {
|
||||||
// TODO: Figure out the fastest order of tests for both read and write (they are probably different).
|
// TODO: Figure out the fastest order of tests for both read and write (they are probably different).
|
||||||
// TODO: Make sure this represents the mirrors in a correct way.
|
// TODO: Make sure this represents the mirrors in a correct way.
|
||||||
// Could just do a base-relative read, too.... TODO
|
// Could just do a base-relative read, too.... TODO
|
||||||
|
|
||||||
const u32 vaddr = _VirtualAddress(addr);
|
|
||||||
|
|
||||||
// Kernel memory command buffer
|
// Kernel memory command buffer
|
||||||
if (vaddr >= KERNEL_MEMORY_VADDR && vaddr < KERNEL_MEMORY_VADDR_END) {
|
if (vaddr >= KERNEL_MEMORY_VADDR && vaddr < KERNEL_MEMORY_VADDR_END) {
|
||||||
var = *((const T*)&g_kernel_mem[vaddr & KERNEL_MEMORY_MASK]);
|
var = *((const T*)&g_kernel_mem[vaddr & KERNEL_MEMORY_MASK]);
|
||||||
|
@ -91,9 +98,8 @@ inline void Read(T &var, const u32 addr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline void Write(u32 addr, const T data) {
|
inline void Write(u32 vaddr, const T data) {
|
||||||
u32 vaddr = _VirtualAddress(addr);
|
|
||||||
|
|
||||||
// Kernel memory command buffer
|
// Kernel memory command buffer
|
||||||
if (vaddr >= KERNEL_MEMORY_VADDR && vaddr < KERNEL_MEMORY_VADDR_END) {
|
if (vaddr >= KERNEL_MEMORY_VADDR && vaddr < KERNEL_MEMORY_VADDR_END) {
|
||||||
*(T*)&g_kernel_mem[vaddr & KERNEL_MEMORY_MASK] = data;
|
*(T*)&g_kernel_mem[vaddr & KERNEL_MEMORY_MASK] = data;
|
||||||
|
@ -133,16 +139,14 @@ inline void Write(u32 addr, const T data) {
|
||||||
// _assert_msg_(MEMMAP, false, "umimplemented write to Configuration Memory");
|
// _assert_msg_(MEMMAP, false, "umimplemented write to Configuration Memory");
|
||||||
//} else if ((vaddr & 0xFFFFF000) == 0x1FF81000) {
|
//} else if ((vaddr & 0xFFFFF000) == 0x1FF81000) {
|
||||||
// _assert_msg_(MEMMAP, false, "umimplemented write to shared page");
|
// _assert_msg_(MEMMAP, false, "umimplemented write to shared page");
|
||||||
|
|
||||||
// Error out...
|
// Error out...
|
||||||
} else {
|
} else {
|
||||||
ERROR_LOG(MEMMAP, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, data, vaddr);
|
ERROR_LOG(MEMMAP, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, data, vaddr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 *GetPointer(const u32 addr) {
|
u8 *GetPointer(const u32 vaddr) {
|
||||||
const u32 vaddr = _VirtualAddress(addr);
|
|
||||||
|
|
||||||
// Kernel memory command buffer
|
// Kernel memory command buffer
|
||||||
if (vaddr >= KERNEL_MEMORY_VADDR && vaddr < KERNEL_MEMORY_VADDR_END) {
|
if (vaddr >= KERNEL_MEMORY_VADDR && vaddr < KERNEL_MEMORY_VADDR_END) {
|
||||||
return g_kernel_mem + (vaddr & KERNEL_MEMORY_MASK);
|
return g_kernel_mem + (vaddr & KERNEL_MEMORY_MASK);
|
||||||
|
@ -185,12 +189,12 @@ u8 *GetPointer(const u32 addr) {
|
||||||
*/
|
*/
|
||||||
u32 MapBlock_Heap(u32 size, u32 operation, u32 permissions) {
|
u32 MapBlock_Heap(u32 size, u32 operation, u32 permissions) {
|
||||||
MemoryBlock block;
|
MemoryBlock block;
|
||||||
|
|
||||||
block.base_address = HEAP_VADDR;
|
block.base_address = HEAP_VADDR;
|
||||||
block.size = size;
|
block.size = size;
|
||||||
block.operation = operation;
|
block.operation = operation;
|
||||||
block.permissions = permissions;
|
block.permissions = permissions;
|
||||||
|
|
||||||
if (g_heap_map.size() > 0) {
|
if (g_heap_map.size() > 0) {
|
||||||
const MemoryBlock last_block = g_heap_map.rbegin()->second;
|
const MemoryBlock last_block = g_heap_map.rbegin()->second;
|
||||||
block.address = last_block.address + last_block.size;
|
block.address = last_block.address + last_block.size;
|
||||||
|
@ -208,12 +212,12 @@ u32 MapBlock_Heap(u32 size, u32 operation, u32 permissions) {
|
||||||
*/
|
*/
|
||||||
u32 MapBlock_HeapGSP(u32 size, u32 operation, u32 permissions) {
|
u32 MapBlock_HeapGSP(u32 size, u32 operation, u32 permissions) {
|
||||||
MemoryBlock block;
|
MemoryBlock block;
|
||||||
|
|
||||||
block.base_address = HEAP_GSP_VADDR;
|
block.base_address = HEAP_GSP_VADDR;
|
||||||
block.size = size;
|
block.size = size;
|
||||||
block.operation = operation;
|
block.operation = operation;
|
||||||
block.permissions = permissions;
|
block.permissions = permissions;
|
||||||
|
|
||||||
if (g_heap_gsp_map.size() > 0) {
|
if (g_heap_gsp_map.size() > 0) {
|
||||||
const MemoryBlock last_block = g_heap_gsp_map.rbegin()->second;
|
const MemoryBlock last_block = g_heap_gsp_map.rbegin()->second;
|
||||||
block.address = last_block.address + last_block.size;
|
block.address = last_block.address + last_block.size;
|
||||||
|
|
|
@ -45,7 +45,7 @@ struct Regs {
|
||||||
INSERT_PADDING_WORDS(0x41);
|
INSERT_PADDING_WORDS(0x41);
|
||||||
|
|
||||||
BitField<0, 24, u32> viewport_size_x;
|
BitField<0, 24, u32> viewport_size_x;
|
||||||
INSERT_PADDING_WORDS(1);
|
INSERT_PADDING_WORDS(0x1);
|
||||||
BitField<0, 24, u32> viewport_size_y;
|
BitField<0, 24, u32> viewport_size_y;
|
||||||
|
|
||||||
INSERT_PADDING_WORDS(0x1bc);
|
INSERT_PADDING_WORDS(0x1bc);
|
||||||
|
|
|
@ -81,20 +81,20 @@ void RendererOpenGL::RenderXFB(const common::Rect& src_rect, const common::Rect&
|
||||||
const auto& framebuffer_top = GPU::g_regs.framebuffer_config[0];
|
const auto& framebuffer_top = GPU::g_regs.framebuffer_config[0];
|
||||||
const auto& framebuffer_sub = GPU::g_regs.framebuffer_config[1];
|
const auto& framebuffer_sub = GPU::g_regs.framebuffer_config[1];
|
||||||
const u32 active_fb_top = (framebuffer_top.active_fb == 1)
|
const u32 active_fb_top = (framebuffer_top.active_fb == 1)
|
||||||
? framebuffer_top.address_left2
|
? Memory::PhysicalToVirtualAddress(framebuffer_top.address_left2)
|
||||||
: framebuffer_top.address_left1;
|
: Memory::PhysicalToVirtualAddress(framebuffer_top.address_left1);
|
||||||
const u32 active_fb_sub = (framebuffer_sub.active_fb == 1)
|
const u32 active_fb_sub = (framebuffer_sub.active_fb == 1)
|
||||||
? framebuffer_sub.address_left2
|
? Memory::PhysicalToVirtualAddress(framebuffer_sub.address_left2)
|
||||||
: framebuffer_sub.address_left1;
|
: Memory::PhysicalToVirtualAddress(framebuffer_sub.address_left1);
|
||||||
|
|
||||||
DEBUG_LOG(GPU, "RenderXFB: 0x%08x bytes from 0x%08x(%dx%d), fmt %x",
|
DEBUG_LOG(GPU, "RenderXFB: 0x%08x bytes from 0x%08x(%dx%d), fmt %x",
|
||||||
framebuffer_top.stride * framebuffer_top.height,
|
framebuffer_top.stride * framebuffer_top.height,
|
||||||
GPU::GetFramebufferAddr(active_fb_top), (int)framebuffer_top.width,
|
active_fb_top, (int)framebuffer_top.width,
|
||||||
(int)framebuffer_top.height, (int)framebuffer_top.format);
|
(int)framebuffer_top.height, (int)framebuffer_top.format);
|
||||||
|
|
||||||
// TODO: This should consider the GPU registers for framebuffer width, height and stride.
|
// TODO: This should consider the GPU registers for framebuffer width, height and stride.
|
||||||
FlipFramebuffer(GPU::GetFramebufferPointer(active_fb_top), m_xfb_top_flipped);
|
FlipFramebuffer(Memory::GetPointer(active_fb_top), m_xfb_top_flipped);
|
||||||
FlipFramebuffer(GPU::GetFramebufferPointer(active_fb_sub), m_xfb_bottom_flipped);
|
FlipFramebuffer(Memory::GetPointer(active_fb_sub), m_xfb_bottom_flipped);
|
||||||
|
|
||||||
// Blit the top framebuffer
|
// Blit the top framebuffer
|
||||||
// ------------------------
|
// ------------------------
|
||||||
|
|
Loading…
Reference in a new issue