Merge pull request #558 from kevinhartman/gsp-writereg-mask

Implemented WriteHWRegsWithMask for GSP
This commit is contained in:
bunnei 2015-02-11 16:08:28 -05:00
commit 0200414ef9

View File

@ -48,20 +48,42 @@ static inline InterruptRelayQueue* GetInterruptRelayQueue(u32 thread_id) {
return reinterpret_cast<InterruptRelayQueue*>(ptr.ValueOr(nullptr)); return reinterpret_cast<InterruptRelayQueue*>(ptr.ValueOr(nullptr));
} }
static void WriteHWRegs(u32 base_address, u32 size_in_bytes, const u32* data) { /**
* Checks if the parameters in a register write call are valid and logs in the case that
* they are not
* @param base_address The first address in the sequence of registers that will be written
* @param size_in_bytes The number of registers that will be written
* @return true if the parameters are valid, false otherwise
*/
static bool CheckWriteParameters(u32 base_address, u32 size_in_bytes) {
// TODO: Return proper error codes // TODO: Return proper error codes
if (base_address + size_in_bytes >= 0x420000) { if (base_address + size_in_bytes >= 0x420000) {
LOG_ERROR(Service_GSP, "Write address out of range! (address=0x%08x, size=0x%08x)", LOG_ERROR(Service_GSP, "Write address out of range! (address=0x%08x, size=0x%08x)",
base_address, size_in_bytes); base_address, size_in_bytes);
return; return false;
} }
// size should be word-aligned // size should be word-aligned
if ((size_in_bytes % 4) != 0) { if ((size_in_bytes % 4) != 0) {
LOG_ERROR(Service_GSP, "Invalid size 0x%08x", size_in_bytes); LOG_ERROR(Service_GSP, "Invalid size 0x%08x", size_in_bytes);
return; return false;
} }
return true;
}
/**
* Writes sequential GSP GPU hardware registers using an array of source data
*
* @param base_address The address of the first register in the sequence
* @param size_in_bytes The number of registers to update (size of data)
* @param data A pointer to the source data
*/
static void WriteHWRegs(u32 base_address, u32 size_in_bytes, const u32* data) {
// TODO: Return proper error codes
if (!CheckWriteParameters(base_address, size_in_bytes))
return;
while (size_in_bytes > 0) { while (size_in_bytes > 0) {
GPU::Write<u32>(base_address + 0x1EB00000, *data); GPU::Write<u32>(base_address + 0x1EB00000, *data);
@ -71,17 +93,80 @@ static void WriteHWRegs(u32 base_address, u32 size_in_bytes, const u32* data) {
} }
} }
/// Write a GSP GPU hardware register /**
* GSP_GPU::WriteHWRegs service function
*
* Writes sequential GSP GPU hardware registers
*
* Inputs:
* 1 : address of first GPU register
* 2 : number of registers to write sequentially
* 4 : pointer to source data array
*/
static void WriteHWRegs(Service::Interface* self) { static void WriteHWRegs(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer(); u32* cmd_buff = Kernel::GetCommandBuffer();
u32 reg_addr = cmd_buff[1]; u32 reg_addr = cmd_buff[1];
u32 size = cmd_buff[2]; u32 size = cmd_buff[2];
u32* src = (u32*)Memory::GetPointer(cmd_buff[0x4]); u32* src = (u32*)Memory::GetPointer(cmd_buff[4]);
WriteHWRegs(reg_addr, size, src); WriteHWRegs(reg_addr, size, src);
} }
/**
* Updates sequential GSP GPU hardware registers using parallel arrays of source data and masks.
* For each register, the value is updated only where the mask is high
*
* @param base_address The address of the first register in the sequence
* @param size_in_bytes The number of registers to update (size of data)
* @param data A pointer to the source data to use for updates
* @param masks A pointer to the masks
*/
static void WriteHWRegsWithMask(u32 base_address, u32 size_in_bytes, const u32* data, const u32* masks) {
// TODO: Return proper error codes
if (!CheckWriteParameters(base_address, size_in_bytes))
return;
while (size_in_bytes > 0) {
const u32 reg_address = base_address + 0x1EB00000;
u32 reg_value;
GPU::Read<u32>(reg_value, reg_address);
// Update the current value of the register only for set mask bits
reg_value = (reg_value & ~*masks) | (*data | *masks);
GPU::Write<u32>(reg_address, reg_value);
size_in_bytes -= 4;
++data;
++masks;
base_address += 4;
}
}
/**
* GSP_GPU::WriteHWRegsWithMask service function
*
* Updates sequential GSP GPU hardware registers using masks
*
* Inputs:
* 1 : address of first GPU register
* 2 : number of registers to update sequentially
* 4 : pointer to source data array
* 6 : pointer to mask array
*/
static void WriteHWRegsWithMask(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 reg_addr = cmd_buff[1];
u32 size = cmd_buff[2];
u32* src_data = (u32*)Memory::GetPointer(cmd_buff[4]);
u32* mask_data = (u32*)Memory::GetPointer(cmd_buff[6]);
WriteHWRegsWithMask(reg_addr, size, src_data, mask_data);
}
/// Read a GSP GPU hardware register /// Read a GSP GPU hardware register
static void ReadHWRegs(Service::Interface* self) { static void ReadHWRegs(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer(); u32* cmd_buff = Kernel::GetCommandBuffer();
@ -350,7 +435,7 @@ static void TriggerCmdReqQueue(Service::Interface* self) {
const Interface::FunctionInfo FunctionTable[] = { const Interface::FunctionInfo FunctionTable[] = {
{0x00010082, WriteHWRegs, "WriteHWRegs"}, {0x00010082, WriteHWRegs, "WriteHWRegs"},
{0x00020084, nullptr, "WriteHWRegsWithMask"}, {0x00020084, WriteHWRegsWithMask, "WriteHWRegsWithMask"},
{0x00030082, nullptr, "WriteHWRegRepeat"}, {0x00030082, nullptr, "WriteHWRegRepeat"},
{0x00040080, ReadHWRegs, "ReadHWRegs"}, {0x00040080, ReadHWRegs, "ReadHWRegs"},
{0x00050200, SetBufferSwap, "SetBufferSwap"}, {0x00050200, SetBufferSwap, "SetBufferSwap"},