Example #1
0
/**
 * Manually uncommit a memory region, must match a known mapping in gMemoryMap.
 */
bool
uncommit(ppcaddr_t address,
         ppcaddr_t size)
{
   auto mapping = findMapping(address, size);

   if (!mapping) {
      decaf_abort("Invalid mem::commit attempt, must exactly match a know mapping");
      return false;
   }

   if (mapping->flags & MapFlags::AutoCommit) {
      decaf_abort("Attempted to manually uncommit an autocommit mapping");
      return false;
   }

   if (!mapping->address) {
      // Already uncommitted
      return true;
   }

   if (!platform::uncommitMemory(mapping->address, size)) {
      // Failed to uncommit? Really?
      return false;
   }

   mapping->address = 0;
   return true;
}
Example #2
0
void
GLDriver::drawIndex2(const pm4::DrawIndex2 &data)
{
   if (!checkReadyDraw()) {
      return;
   }

   auto vgt_primitive_type = getRegister<latte::VGT_PRIMITIVE_TYPE>(latte::Register::VGT_PRIMITIVE_TYPE);
   auto sq_vtx_base_vtx_loc = getRegister<latte::SQ_VTX_BASE_VTX_LOC>(latte::Register::SQ_VTX_BASE_VTX_LOC);
   auto vgt_dma_index_type = getRegister<latte::VGT_DMA_INDEX_TYPE>(latte::Register::VGT_DMA_INDEX_TYPE);
   auto vgt_dma_num_instances = getRegister<latte::VGT_DMA_NUM_INSTANCES>(latte::Register::VGT_DMA_NUM_INSTANCES);
   auto vgt_strmout_en = getRegister<latte::VGT_STRMOUT_EN>(latte::Register::VGT_STRMOUT_EN);

   // Swap and indexBytes are separate because you can have 32-bit swap,
   //   but 16-bit indices in some cases...  This is also why we pre-swap
   //   the data before intercepting QUAD and POLYGON draws.
   if (vgt_dma_index_type.SWAP_MODE() == latte::VGT_DMA_SWAP_16_BIT) {
      auto *src = static_cast<uint16_t*>(data.addr.get());
      auto indices = std::vector<uint16_t>(data.count);

      if (vgt_dma_index_type.INDEX_TYPE() != latte::VGT_INDEX_16) {
         decaf_abort(fmt::format("Unexpected INDEX_TYPE {} for VGT_DMA_SWAP_16_BIT", vgt_dma_index_type.INDEX_TYPE()));
      }

      for (auto i = 0u; i < data.count; ++i) {
         indices[i] = byte_swap(src[i]);
      }

      drawPrimitives(data.count,
                     indices.data(),
                     vgt_dma_index_type.INDEX_TYPE());
   } else if (vgt_dma_index_type.SWAP_MODE() == latte::VGT_DMA_SWAP_32_BIT) {
      auto *src = static_cast<uint32_t*>(data.addr.get());
      auto indices = std::vector<uint32_t>(data.count);

      if (vgt_dma_index_type.INDEX_TYPE() != latte::VGT_INDEX_32) {
         decaf_abort(fmt::format("Unexpected INDEX_TYPE {} for VGT_DMA_SWAP_32_BIT", vgt_dma_index_type.INDEX_TYPE()));
      }

      for (auto i = 0u; i < data.count; ++i) {
         indices[i] = byte_swap(src[i]);
      }

      drawPrimitives(data.count,
                     indices.data(),
                     vgt_dma_index_type.INDEX_TYPE());
   } else if (vgt_dma_index_type.SWAP_MODE() == latte::VGT_DMA_SWAP_NONE) {
      drawPrimitives(data.count,
                     data.addr,
                     vgt_dma_index_type.INDEX_TYPE());
   } else {
      decaf_abort(fmt::format("Unimplemented vgt_dma_index_type.SWAP_MODE {}", vgt_dma_index_type.SWAP_MODE()));
   }
}
Example #3
0
vk::BlendFactor
getVkBlendFactor(latte::CB_BLEND_FUNC func)
{
   switch (func) {
   case latte::CB_BLEND_FUNC::ZERO:
      return vk::BlendFactor::eZero;
   case latte::CB_BLEND_FUNC::ONE:
      return vk::BlendFactor::eOne;
   case latte::CB_BLEND_FUNC::SRC_COLOR:
      return vk::BlendFactor::eSrcColor;
   case latte::CB_BLEND_FUNC::ONE_MINUS_SRC_COLOR:
      return vk::BlendFactor::eOneMinusSrcColor;
   case latte::CB_BLEND_FUNC::SRC_ALPHA:
      return vk::BlendFactor::eSrcAlpha;
   case latte::CB_BLEND_FUNC::ONE_MINUS_SRC_ALPHA:
      return vk::BlendFactor::eOneMinusSrcAlpha;
   case latte::CB_BLEND_FUNC::DST_ALPHA:
      return vk::BlendFactor::eDstAlpha;
   case latte::CB_BLEND_FUNC::ONE_MINUS_DST_ALPHA:
      return vk::BlendFactor::eOneMinusDstAlpha;
   case latte::CB_BLEND_FUNC::DST_COLOR:
      return vk::BlendFactor::eDstColor;
   case latte::CB_BLEND_FUNC::ONE_MINUS_DST_COLOR:
      return vk::BlendFactor::eOneMinusDstColor;
   case latte::CB_BLEND_FUNC::SRC_ALPHA_SATURATE:
      return vk::BlendFactor::eSrcAlphaSaturate;
   case latte::CB_BLEND_FUNC::BOTH_SRC_ALPHA:
      decaf_abort("Unsupported BOTH_SRC_ALPHA blend function");
   case latte::CB_BLEND_FUNC::BOTH_INV_SRC_ALPHA:
      decaf_abort("Unsupported BOTH_INV_SRC_ALPHA blend function");
   case latte::CB_BLEND_FUNC::CONSTANT_COLOR:
      return vk::BlendFactor::eConstantColor;
   case latte::CB_BLEND_FUNC::ONE_MINUS_CONSTANT_COLOR:
      return vk::BlendFactor::eOneMinusConstantColor;
   case latte::CB_BLEND_FUNC::SRC1_COLOR:
      return vk::BlendFactor::eSrc1Color;
   case latte::CB_BLEND_FUNC::ONE_MINUS_SRC1_COLOR:
      return vk::BlendFactor::eOneMinusSrc1Color;
   case latte::CB_BLEND_FUNC::SRC1_ALPHA:
      return vk::BlendFactor::eSrc1Alpha;
   case latte::CB_BLEND_FUNC::ONE_MINUS_SRC1_ALPHA:
      return vk::BlendFactor::eOneMinusSrc1Alpha;
   case latte::CB_BLEND_FUNC::CONSTANT_ALPHA:
      return vk::BlendFactor::eConstantAlpha;
   case latte::CB_BLEND_FUNC::ONE_MINUS_CONSTANT_ALPHA:
      return vk::BlendFactor::eOneMinusConstantAlpha;
   default:
      decaf_abort("Unexpected blend function");
   }
}
static uint32_t
getAlignedBlockSize(virt_ptr<MEMExpHeapBlock> block,
                    uint32_t alignment,
                    MEMExpHeapDirection dir)
{
   if (dir == MEMExpHeapDirection::FromStart) {
      auto dataStart = virt_cast<uint8_t *>(block) + sizeof(MEMExpHeapBlock);
      auto dataEnd = dataStart + block->blockSize;
      auto alignedDataStart = align_up(dataStart, alignment);

      if (alignedDataStart >= dataEnd) {
         return 0;
      }

      return static_cast<uint32_t>(dataEnd - alignedDataStart);
   } else if (dir == MEMExpHeapDirection::FromEnd) {
      auto dataStart = virt_cast<uint8_t *>(block) + sizeof(MEMExpHeapBlock);
      auto dataEnd = dataStart + block->blockSize;
      auto alignedDataEnd = align_down(dataEnd, alignment);

      if (alignedDataEnd <= dataStart) {
         return 0;
      }

      return static_cast<uint32_t>(alignedDataEnd - dataStart);
   } else {
      decaf_abort("Unexpected ExpHeap direction");
   }
}
bool
getDataFormatIsFloat(latte::SQ_DATA_FORMAT format)
{
   switch (format) {

   case latte::SQ_DATA_FORMAT::FMT_16_FLOAT:
   case latte::SQ_DATA_FORMAT::FMT_32_FLOAT:
   case latte::SQ_DATA_FORMAT::FMT_16_16_FLOAT:
   case latte::SQ_DATA_FORMAT::FMT_32_32_FLOAT:
   case latte::SQ_DATA_FORMAT::FMT_16_16_16_FLOAT:
   case latte::SQ_DATA_FORMAT::FMT_32_32_32_FLOAT:
   case latte::SQ_DATA_FORMAT::FMT_16_16_16_16_FLOAT:
   case latte::SQ_DATA_FORMAT::FMT_32_32_32_32_FLOAT:
      return true;
   case latte::SQ_DATA_FORMAT::FMT_8:
   case latte::SQ_DATA_FORMAT::FMT_16:
   case latte::SQ_DATA_FORMAT::FMT_32:
   case latte::SQ_DATA_FORMAT::FMT_8_8:
   case latte::SQ_DATA_FORMAT::FMT_16_16:
   case latte::SQ_DATA_FORMAT::FMT_32_32:
   case latte::SQ_DATA_FORMAT::FMT_8_8_8:
   case latte::SQ_DATA_FORMAT::FMT_16_16_16:
   case latte::SQ_DATA_FORMAT::FMT_32_32_32:
   case latte::SQ_DATA_FORMAT::FMT_2_10_10_10:
   case latte::SQ_DATA_FORMAT::FMT_10_10_10_2:
   case latte::SQ_DATA_FORMAT::FMT_8_8_8_8:
   case latte::SQ_DATA_FORMAT::FMT_16_16_16_16:
   case latte::SQ_DATA_FORMAT::FMT_32_32_32_32:
      return false;
   default:
      decaf_abort(fmt::format("Unimplemented attribute format: {}", format));
   }
}
uint32_t
getDataFormatComponentBits(latte::SQ_DATA_FORMAT format)
{
   switch (format) {
   case latte::SQ_DATA_FORMAT::FMT_8:
   case latte::SQ_DATA_FORMAT::FMT_8_8:
   case latte::SQ_DATA_FORMAT::FMT_8_8_8:
   case latte::SQ_DATA_FORMAT::FMT_8_8_8_8:
      return 8;
   case latte::SQ_DATA_FORMAT::FMT_16:
   case latte::SQ_DATA_FORMAT::FMT_16_FLOAT:
   case latte::SQ_DATA_FORMAT::FMT_16_16:
   case latte::SQ_DATA_FORMAT::FMT_16_16_FLOAT:
   case latte::SQ_DATA_FORMAT::FMT_16_16_16:
   case latte::SQ_DATA_FORMAT::FMT_16_16_16_FLOAT:
   case latte::SQ_DATA_FORMAT::FMT_16_16_16_16:
   case latte::SQ_DATA_FORMAT::FMT_16_16_16_16_FLOAT:
      return 16;
   case latte::SQ_DATA_FORMAT::FMT_32:
   case latte::SQ_DATA_FORMAT::FMT_32_FLOAT:
   case latte::SQ_DATA_FORMAT::FMT_32_32:
   case latte::SQ_DATA_FORMAT::FMT_32_32_FLOAT:
   case latte::SQ_DATA_FORMAT::FMT_32_32_32:
   case latte::SQ_DATA_FORMAT::FMT_32_32_32_FLOAT:
   case latte::SQ_DATA_FORMAT::FMT_32_32_32_32:
   case latte::SQ_DATA_FORMAT::FMT_32_32_32_32_FLOAT:
      return 32;
   default:
      decaf_abort(fmt::format("Unimplemented attribute format: {}", format));
   }
}
Example #7
0
static gl::GLenum
getTextureTarget(latte::SQ_TEX_DIM dim)
{
   switch (dim)
   {
   case latte::SQ_TEX_DIM_1D:
      return gl::GL_TEXTURE_1D;
   case latte::SQ_TEX_DIM_2D:
      return gl::GL_TEXTURE_2D;
   case latte::SQ_TEX_DIM_3D:
      return gl::GL_TEXTURE_3D;
   case latte::SQ_TEX_DIM_CUBEMAP:
      return gl::GL_TEXTURE_CUBE_MAP;
   case latte::SQ_TEX_DIM_1D_ARRAY:
      return gl::GL_TEXTURE_1D_ARRAY;
   case latte::SQ_TEX_DIM_2D_ARRAY:
      return gl::GL_TEXTURE_2D_ARRAY;
   case latte::SQ_TEX_DIM_2D_MSAA:
      return gl::GL_TEXTURE_2D_MULTISAMPLE;
   case latte::SQ_TEX_DIM_2D_ARRAY_MSAA:
      return gl::GL_TEXTURE_2D_MULTISAMPLE_ARRAY;
   default:
      decaf_abort(fmt::format("Unimplemented SQ_TEX_DIM {}", dim));
   }
}
void
decreaseIndent(State &state)
{
   if (state.indent.size() >= SingleIndent.size()) {
      state.indent.resize(state.indent.size() - SingleIndent.size());
   } else {
      decaf_abort("Invalid decrease indent");
   }
}
Example #9
0
void
Driver::decafSetBuffer(const latte::pm4::DecafSetBuffer &data)
{
   SwapChainObject **swapChain;
   if (data.scanTarget == latte::pm4::ScanTarget::TV) {
      swapChain = &mTvSwapChain;
   } else if (data.scanTarget == latte::pm4::ScanTarget::DRC) {
      swapChain = &mDrcSwapChain;
   } else {
      decaf_abort("Unexpected decafSetBuffer target");
   }

   // Release the existing swap chain if we had it...
   if (*swapChain) {
      releaseSwapChain(*swapChain);
      *swapChain = nullptr;
   }

   // Allocate a new swap chain
   auto swapChainDesc = SwapChainDesc {
      data.buffer,
      data.width,
      data.height
   };
   auto newSwapChain = allocateSwapChain(swapChainDesc);

   // Give the swapchain a name so its easy to see.
   if (data.scanTarget == latte::pm4::ScanTarget::TV) {
      setVkObjectName(newSwapChain->image, fmt::format("swapchain_tv").c_str());
   } else if (data.scanTarget == latte::pm4::ScanTarget::DRC) {
      setVkObjectName(newSwapChain->image, fmt::format("swapchain_drc").c_str());
   } else {
         decaf_abort("Unexpected decafSetBuffer target");
   }

   // Assign the new swap chain
   *swapChain = newSwapChain;

   // Only make this swapchain presentable after this frame has completed
   // (we need to run the frame at least once for setup to complete before use).
   addRetireTask([=](){
      newSwapChain->presentable = true;
   });
}
/**
 * Find the export from a library handle.
 *
 * Note that for TLS there will be a symbol, but no section,
 * and for normal data / code there with be a section but no symbol.
 */
int
OSDynLoad_FindExport(ModuleHandle handle,
                     int isData,
                     char const *name,
                     be_val<ppcaddr_t> *outAddr)
{
   auto module = handle->ptr;
   auto addr = module->findExport(name);

   *outAddr = addr;

   if (!addr) {
      gLog->debug("OSDynLoad_FindExport export {} not found", name);
      return 0xBAD10001;
   }

   // Let's first try to verify the export type based off the section it is in
   auto section = module->findAddressSection(addr);

   if (section) {
      if (isData) {
         if (section->type != kernel::loader::LoadedSectionType::Data) {
            gLog->debug("OSDynLoad_FindExport export {} expected data, found function", name);
            return 0xBAD10001;
         }
      } else {
         if (section->type != kernel::loader::LoadedSectionType::Code) {
            gLog->debug("OSDynLoad_FindExport export {} expected function, found data", name);
            return 0xBAD10001;
         }
      }

      return 0;
   }

   // Now let's try to verify it based off it's symbol
   auto symbol = module->findSymbol(addr);

   if (symbol) {
      if (symbol->type == kernel::loader::SymbolType::TLS) {
         return 0xBAD10033;
      } else if (isData && symbol->type != kernel::loader::SymbolType::Data) {
         gLog->debug("OSDynLoad_FindExport export {} expected data, found function", name);
         return 0xBAD10001;
      } else if (!isData && symbol->type != kernel::loader::SymbolType::Function) {
         gLog->debug("OSDynLoad_FindExport export {} expected function, found data", name);
         return 0xBAD10001;
      }

      return 0;
   }

   // Couldn't find a section or a symbol for the export, this should never happen...!
   decaf_abort(fmt::format("OSDynLoad_FindExport could not find symbol or section for export address 0x{:08X}", addr));
   return 0xBAD10001;
}
Example #11
0
static int32_t
syscall(uint32_t id)
{
   switch (id) {
   case GHSSyscallID::time:
      return syscall_time();
   default:
      decaf_abort(fmt::format("Unsupported ghs syscalls {:x}", id));
   }
}
Example #12
0
static uint32_t *
allocateFromPool(uint32_t wantedSize,
                 uint32_t &allocatedSize)
{
   std::unique_lock<std::mutex> lock(sBufferPoolMutex);

   // Minimum allocation is 0x100 dwords
   wantedSize = std::max(0x100u, wantedSize);

   // Lets make sure we are not trying to make an impossible allocation
   if (wantedSize > sBufferPoolEnd - sBufferPoolBase) {
      decaf_abort("Command buffer allocation greater than entire pool size");
   }

   uint32_t availableSize = 0;

   if (sBufferPoolTailPtr == nullptr) {
      decaf_check(sBufferPoolHeadPtr == sBufferPoolBase);

      availableSize = static_cast<uint32_t>(sBufferPoolEnd - sBufferPoolBase);
      sBufferPoolTailPtr = sBufferPoolHeadPtr;
   } else {
      if (sBufferPoolHeadPtr < sBufferPoolTailPtr) {
         availableSize = static_cast<uint32_t>(sBufferPoolTailPtr - sBufferPoolHeadPtr);

         if (availableSize < wantedSize) {
            return nullptr;
         }
      } else {
         availableSize = static_cast<uint32_t>(sBufferPoolEnd - sBufferPoolHeadPtr);

         if (availableSize < wantedSize) {
            availableSize = static_cast<uint32_t>(sBufferPoolTailPtr - sBufferPoolBase);

            if (availableSize < wantedSize) {
               return nullptr;
            }

            // Lets mark down that we wasted some space so that returnToPool is able
            //  to verify that pool releases are always happening in-order.  Then we
            //  move the head to the base of the pool to allocate from there.
            sBufferPoolSkipped = static_cast<uint32_t>(sBufferPoolEnd - sBufferPoolHeadPtr);
            sBufferPoolHeadPtr = sBufferPoolBase;
         }
      }
   }

   allocatedSize = std::min(0x20000u, availableSize);

   auto allocatedBuffer = sBufferPoolHeadPtr;
   sBufferPoolHeadPtr += allocatedSize;

   return allocatedBuffer;
}
Example #13
0
static gl::GLenum
getTextureXYFilter(latte::SQ_TEX_XY_FILTER filter)
{
   switch (filter) {
   case latte::SQ_TEX_XY_FILTER_POINT:
      return gl::GL_NEAREST;
   case latte::SQ_TEX_XY_FILTER_BILINEAR:
      return gl::GL_LINEAR;
   default:
      decaf_abort(fmt::format("Unimplemented texture xy filter {}", filter));
   }
}
Example #14
0
void
Driver::decafCopyColorToScan(const latte::pm4::DecafCopyColorToScan &data)
{
   flushPendingDraws();

   ColorBufferDesc colorBuffer;
   colorBuffer.base256b = data.cb_color_base.BASE_256B();
   colorBuffer.pitchTileMax = data.cb_color_size.PITCH_TILE_MAX();
   colorBuffer.sliceTileMax = data.cb_color_size.SLICE_TILE_MAX();
   colorBuffer.format = data.cb_color_info.FORMAT();
   colorBuffer.numberType = data.cb_color_info.NUMBER_TYPE();
   colorBuffer.arrayMode = data.cb_color_info.ARRAY_MODE();
   colorBuffer.sliceStart = 0;
   colorBuffer.sliceEnd = 1;
   auto surfaceView = getColorBuffer(colorBuffer);
   auto surface = surfaceView->surface;

   SwapChainObject *target = nullptr;
   if (data.scanTarget == latte::pm4::ScanTarget::TV) {
      target = mTvSwapChain;
   } else if (data.scanTarget == latte::pm4::ScanTarget::DRC) {
      target = mDrcSwapChain;
   } else {
      decaf_abort("decafCopyColorToScan called for unknown scanTarget");
   }

   transitionSurface(surface, ResourceUsage::TransferSrc, vk::ImageLayout::eTransferSrcOptimal, { 0, 1 });

   // TODO: We actually need to call AVMSetTVScale inside of the SetBuffer functions
   // and then pass that data all the way down to here so we can scale correctly.
   auto copyWidth = target->desc.width;
   auto copyHeight = target->desc.height;
   if (surface->desc.width < target->desc.width) {
      copyWidth = surface->desc.width;
   }
   if (surface->desc.height < target->desc.height) {
      copyHeight = surface->desc.height;
   }

   vk::ImageBlit blitRegion(
      vk::ImageSubresourceLayers(vk::ImageAspectFlagBits::eColor, 0, 0, 1),
      { vk::Offset3D(0, 0, 0), vk::Offset3D(copyWidth, copyHeight, 1) },
      vk::ImageSubresourceLayers(vk::ImageAspectFlagBits::eColor, 0, 0, 1),
      { vk::Offset3D(0, 0, 0), vk::Offset3D(target->desc.width, target->desc.height, 1) });

   mActiveCommandBuffer.blitImage(
      surface->image,
      vk::ImageLayout::eTransferSrcOptimal,
      target->image,
      vk::ImageLayout::eTransferDstOptimal,
      { blitRegion },
      vk::Filter::eNearest);
}
std::string
getDataFormatName(latte::SQ_DATA_FORMAT format)
{
   switch (format) {
   case latte::SQ_DATA_FORMAT::FMT_8:
      return "FMT_8";
   case latte::SQ_DATA_FORMAT::FMT_16:
      return "FMT_16";
   case latte::SQ_DATA_FORMAT::FMT_16_FLOAT:
      return "FMT_16_FLOAT";
   case latte::SQ_DATA_FORMAT::FMT_32:
      return "FMT_32";
   case latte::SQ_DATA_FORMAT::FMT_32_FLOAT:
      return "FMT_32_FLOAT";
   case latte::SQ_DATA_FORMAT::FMT_8_8:
      return "FMT_8_8";
   case latte::SQ_DATA_FORMAT::FMT_16_16:
      return "FMT_16_16";
   case latte::SQ_DATA_FORMAT::FMT_16_16_FLOAT:
      return "FMT_16_16_FLOAT";
   case latte::SQ_DATA_FORMAT::FMT_32_32:
      return "FMT_32_32";
   case latte::SQ_DATA_FORMAT::FMT_32_32_FLOAT:
      return "FMT_32_32_FLOAT";
   case latte::SQ_DATA_FORMAT::FMT_8_8_8:
      return "FMT_8_8_8";
   case latte::SQ_DATA_FORMAT::FMT_16_16_16:
      return "FMT_16_16_16";
   case latte::SQ_DATA_FORMAT::FMT_16_16_16_FLOAT:
      return "FMT_16_16_16_FLOAT";
   case latte::SQ_DATA_FORMAT::FMT_32_32_32:
      return "FMT_32_32_32";
   case latte::SQ_DATA_FORMAT::FMT_32_32_32_FLOAT:
      return "FMT_32_32_32_FLOAT";
   case latte::SQ_DATA_FORMAT::FMT_8_8_8_8:
      return "FMT_8_8_8_8";
   case latte::SQ_DATA_FORMAT::FMT_16_16_16_16:
      return "FMT_16_16_16_16";
   case latte::SQ_DATA_FORMAT::FMT_16_16_16_16_FLOAT:
      return "FMT_16_16_16_16_FLOAT";
   case latte::SQ_DATA_FORMAT::FMT_32_32_32_32:
      return "FMT_32_32_32_32";
   case latte::SQ_DATA_FORMAT::FMT_32_32_32_32_FLOAT:
      return "FMT_32_32_32_32_FLOAT";
   case latte::SQ_DATA_FORMAT::FMT_2_10_10_10:
      return "FMT_2_10_10_10";
   case latte::SQ_DATA_FORMAT::FMT_10_10_10_2:
      return "FMT_10_10_10_2";
   default:
      decaf_abort(fmt::format("Unimplemented attribute format: {}", format));
   }
}
Example #16
0
static void
cpuFaultFiberEntryPoint(void *addr)
{
   // We may have been in the middle of a kernel function...
   if (coreinit::internal::isSchedulerLocked()) {
      coreinit::internal::unlockScheduler();
   }

   // Move back an instruction so we can re-exucute the failed instruction
   //  and so that the debugger shows the right stop point.
   cpu::this_core::state()->nia -= 4;

   // Alert the debugger if it cares.
   if (decaf::config::debugger::enabled) {
      coreinit::internal::pauseCoreTime(true);
      debugger::handleDbgBreakInterrupt();
      coreinit::internal::pauseCoreTime(false);

      // This will shut down the thread and reschedule.  This is required
      //  since returning from the segfault handler is an error.
      coreinit::OSExitThread(0);
   }

   auto core = cpu::this_core::state();
   decaf_assert(core, "Uh oh? CPU fault Handler with invalid core");

   gLog->critical("{}", coreStateToString(core));

   if (sFaultReason == FaultReason::Segfault) {
      decaf_abort(fmt::format("Invalid memory access for address {:08X} with nia 0x{:08X}\n",
         sSegfaultAddress, core->nia));
   } else if (sFaultReason == FaultReason::IllInst) {
      decaf_abort(fmt::format("Invalid instruction at nia 0x{:08X}\n",
         core->nia));
   } else {
      decaf_abort(fmt::format("Unexpected fault occured, fault reason was {} at 0x{:08X}\n",
         static_cast<uint32_t>(sFaultReason), core->nia));
   }
}
Example #17
0
// Move from Special Purpose Register
static bool
mfspr(PPCEmuAssembler& a, Instruction instr)
{
   auto spr = decodeSPR(instr);

   auto dst = a.loadRegisterWrite(a.gpr[instr.rD]);

   switch (spr) {
   case SPR::XER:
      a.mov(dst, a.loadRegisterRead(a.xer));
      break;
   case SPR::LR:
      a.mov(dst, a.lrMem);
      break;
   case SPR::CTR:
      a.mov(dst, a.ctrMem);
      break;
   case SPR::UGQR0:
      a.mov(dst, a.loadRegisterRead(a.gqr[0]));
      break;
   case SPR::UGQR1:
      a.mov(dst, a.loadRegisterRead(a.gqr[1]));
      break;
   case SPR::UGQR2:
      a.mov(dst, a.loadRegisterRead(a.gqr[2]));
      break;
   case SPR::UGQR3:
      a.mov(dst, a.loadRegisterRead(a.gqr[3]));
      break;
   case SPR::UGQR4:
      a.mov(dst, a.loadRegisterRead(a.gqr[4]));
      break;
   case SPR::UGQR5:
      a.mov(dst, a.loadRegisterRead(a.gqr[5]));
      break;
   case SPR::UGQR6:
      a.mov(dst, a.loadRegisterRead(a.gqr[6]));
      break;
   case SPR::UGQR7:
      a.mov(dst, a.loadRegisterRead(a.gqr[7]));
      break;
   case SPR::UPIR:
      a.mov(dst, a.coreIdMem);
      break;
   default:
      decaf_abort(fmt::format("Invalid mfspr SPR {}", static_cast<uint32_t>(spr)));
   }

   return true;
}
latte::SQ_TILE_MODE
getArrayModeTileMode(latte::BUFFER_ARRAY_MODE mode)
{
   switch (mode) {
   case latte::BUFFER_ARRAY_MODE::LINEAR_GENERAL:
      return latte::SQ_TILE_MODE::DEFAULT;
   case latte::BUFFER_ARRAY_MODE::LINEAR_ALIGNED:
      return latte::SQ_TILE_MODE::LINEAR_ALIGNED;
   case latte::BUFFER_ARRAY_MODE::TILED_2D_THIN1:
      return latte::SQ_TILE_MODE::TILED_2D_THIN1;
   default:
      decaf_abort(fmt::format("Unimplemented surface array mode: {}", mode));
   }
}
Example #19
0
std::string
controllerTypeToString(ControllerType type)
{
   switch (type) {
   case None:
      return "none";
   case Keyboard:
      return "keyboard";
   case Joystick:
      return "joystick";
   }

   decaf_abort(fmt::format("Invalid controller type {}", type));
}
void
OSEnableOverlayArena(uint32_t unk,
                     be_val<uint32_t> *addr,
                     be_val<uint32_t> *size)
{
   if (!sOverlayArenaEnabled) {
      if (!mem::commit(mem::OverlayArenaBase, mem::OverlayArenaSize)) {
         decaf_abort("Failed to allocate loader overlay memory");
      }

      sOverlayArenaEnabled = true;
   }

   OSGetOverlayArenaRange(addr, size);
}
Example #21
0
gl::GLenum
getBlendFunc(latte::CB_BLEND_FUNC func)
{
   switch (func) {
   case latte::CB_BLEND_ZERO:
      return gl::GL_ZERO;
   case latte::CB_BLEND_ONE:
      return gl::GL_ONE;
   case latte::CB_BLEND_SRC_COLOR:
      return gl::GL_SRC_COLOR;
   case latte::CB_BLEND_ONE_MINUS_SRC_COLOR:
      return gl::GL_ONE_MINUS_SRC_COLOR;
   case latte::CB_BLEND_SRC_ALPHA:
      return gl::GL_SRC_ALPHA;
   case latte::CB_BLEND_ONE_MINUS_SRC_ALPHA:
      return gl::GL_ONE_MINUS_SRC_ALPHA;
   case latte::CB_BLEND_DST_ALPHA:
      return gl::GL_DST_ALPHA;
   case latte::CB_BLEND_ONE_MINUS_DST_ALPHA:
      return gl::GL_ONE_MINUS_DST_ALPHA;
   case latte::CB_BLEND_DST_COLOR:
      return gl::GL_DST_COLOR;
   case latte::CB_BLEND_ONE_MINUS_DST_COLOR:
      return gl::GL_ONE_MINUS_DST_COLOR;
   case latte::CB_BLEND_SRC_ALPHA_SATURATE:
      return gl::GL_SRC_ALPHA_SATURATE;
   case latte::CB_BLEND_CONSTANT_COLOR:
      return gl::GL_CONSTANT_COLOR;
   case latte::CB_BLEND_ONE_MINUS_CONSTANT_COLOR:
      return gl::GL_ONE_MINUS_CONSTANT_COLOR;
   case latte::CB_BLEND_SRC1_COLOR:
      return gl::GL_SRC1_COLOR;
   case latte::CB_BLEND_ONE_MINUS_SRC1_COLOR:
      return gl::GL_ONE_MINUS_SRC1_COLOR;
   case latte::CB_BLEND_SRC1_ALPHA:
      return gl::GL_SRC1_ALPHA;
   case latte::CB_BLEND_ONE_MINUS_SRC1_ALPHA:
      return gl::GL_ONE_MINUS_SRC1_ALPHA;
   case latte::CB_BLEND_CONSTANT_ALPHA:
      return gl::GL_CONSTANT_ALPHA;
   case latte::CB_BLEND_ONE_MINUS_CONSTANT_ALPHA:
      return gl::GL_ONE_MINUS_CONSTANT_ALPHA;
   default:
      decaf_abort(fmt::format("Unimplemented CB_BLEND_FUNC {}", func));
   }
}
static uint32_t
appIoThreadEntry(uint32_t coreId, void *arg2)
{
   auto queue = &sAppIo->queues[coreId];
   OSInitMessageQueue(queue, &sAppIo->messages[coreId * MessagesPerCore], MessagesPerCore);

   while (true) {
      OSMessage msg;
      OSReceiveMessage(queue, &msg, OSMessageFlags::Blocking);

      auto funcType = static_cast<OSFunctionType>(msg.args[2].value());

      switch (funcType) {
      case OSFunctionType::FsaCmdAsync:
      {
         auto result = FSAGetAsyncResult(&msg);
         if (result->userCallback) {
            result->userCallback(result->error,
                                 result->command,
                                 result->request,
                                 result->response,
                                 result->userContext);
         }
         break;
      }
      case OSFunctionType::FsCmdAsync:
      {
         auto result = FSGetAsyncResult(&msg);
         if (result->asyncData.userCallback) {
            result->asyncData.userCallback(result->client,
                                           result->block,
                                           result->status,
                                           result->asyncData.userContext);
         }
         break;
      }
      case OSFunctionType::FsCmdHandler:
      {
         fsCmdBlockHandleResult(reinterpret_cast<FSCmdBlockBody *>(msg.message.get()));
         break;
      }
      default:
         decaf_abort(fmt::format("Unimplemented OSFunctionType {}", funcType));
      }
   }
}
Example #23
0
bool
DecafSDL::initVulkanGraphics()
{
#ifdef DECAF_VULKAN
   mGraphicsDriver = new DecafSDLVulkan();

   if (!mGraphicsDriver->initialise(WindowWidth, WindowHeight)) {
      gCliLog->error("Failed to create Vulkan graphics window");
      return false;
   }

   sActiveGfx = "Vulkan";
   return true;
#else
   decaf_abort("Vulkan support was not included in this build");
#endif
}
Example #24
0
bool
DecafSDL::initDx12Graphics()
{
#ifdef DECAF_DX12
   mGraphicsDriver = new DecafSDLDX12();

   if (!mGraphicsDriver->initialise(WindowWidth, WindowHeight)) {
      gCliLog->error("Failed to create DX12 graphics window");
      return false;
   }

   sActiveGfx = "DX12";
   return true;
#else
   decaf_abort("DX12 support was not included in this build");
#endif
}
Example #25
0
bool
DecafSDL::initGlGraphics()
{
#ifdef DECAF_GL
   mGraphicsDriver = new DecafSDLOpenGL();

   if (!mGraphicsDriver->initialise(WindowWidth, WindowHeight)) {
      gCliLog->error("Failed to create GL graphics window");
      return false;
   }

   sActiveGfx = "GL";
   return true;
#else
   decaf_abort("GL support was not included in this build");
#endif
}
std::string
disassemble(const gsl::span<const uint8_t> &binary, bool isSubroutine)
{
   disassembler::State state;
   state.binary = binary;
   state.cfPC = 0;
   state.groupPC = 0;

   for (auto i = 0; i < binary.size(); i += sizeof(ControlFlowInst)) {
      auto cf = *reinterpret_cast<const ControlFlowInst *>(binary.data() + i);
      auto id = cf.word1.CF_INST();
      auto type = cf.word1.CF_INST_TYPE();

      switch (type) {
      case SQ_CF_INST_TYPE_NORMAL:
         disassembler::disassembleNormal(state, cf);
         break;
      case SQ_CF_INST_TYPE_EXPORT:
         disassembler::disassembleExport(state, cf);
         break;
      case SQ_CF_INST_TYPE_ALU:
      case SQ_CF_INST_TYPE_ALU_EXTENDED:
         disassembler::disassembleControlFlowALU(state, cf);
         break;
      default:
         decaf_abort(fmt::format("Invalid top level instruction type {}", type));
      }

      if (cf.word1.CF_INST() == SQ_CF_INST_RETURN && isSubroutine) {
         break;
      }

      if (cf.word1.CF_INST_TYPE() == SQ_CF_INST_TYPE_NORMAL
       || cf.word1.CF_INST_TYPE() == SQ_CF_INST_TYPE_EXPORT) {
         if (cf.word1.END_OF_PROGRAM()) {
            break;
         }
      }

      state.cfPC++;
      state.out << "\n";
   }

   return state.out.str();
}
Example #27
0
static bool
spinReleaseLock(OSSpinLock *spinlock)
{
   auto thread = OSGetCurrentThread();
   auto owner = mem::untranslate(thread);

   if (spinlock->recursion > 0u) {
      --spinlock->recursion;
      return false;
   } else if (spinlock->owner.load(std::memory_order_relaxed) == owner) {
      spinlock->owner = 0u;
      decreaseSpinLockCount(thread);
      return true;
   }

   decaf_abort("Attempt to release spin lock which is not owned.");
   return true;
}
Example #28
0
gl::GLenum
getBlendEquation(latte::CB_COMB_FUNC func)
{
   switch (func) {
   case latte::CB_COMB_DST_PLUS_SRC:
      return gl::GL_FUNC_ADD;
   case latte::CB_COMB_SRC_MINUS_DST:
      return gl::GL_FUNC_SUBTRACT;
   case latte::CB_COMB_MIN_DST_SRC:
      return gl::GL_MIN;
   case latte::CB_COMB_MAX_DST_SRC:
      return gl::GL_MAX;
   case latte::CB_COMB_DST_MINUS_SRC:
      return gl::GL_FUNC_REVERSE_SUBTRACT;
   default:
      decaf_abort(fmt::format("Unimplemented CB_COMB_FUNC {}", func));
   }
}
Example #29
0
static gl::GLenum
getCompressedTextureDataType(latte::SQ_DATA_FORMAT format, uint32_t degamma)
{
   switch (format) {
   case latte::FMT_BC1:
      return degamma ? gl::GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT : gl::GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
   case latte::FMT_BC2:
      return degamma ? gl::GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT : gl::GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
   case latte::FMT_BC3:
      return degamma ? gl::GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT : gl::GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
   case latte::FMT_BC4:
      return degamma ? gl::GL_COMPRESSED_SIGNED_RED_RGTC1 : gl::GL_COMPRESSED_RED_RGTC1;
   case latte::FMT_BC5:
      return degamma ? gl::GL_COMPRESSED_SIGNED_RG_RGTC2 : gl::GL_COMPRESSED_RG_RGTC2;
   default:
      decaf_abort(fmt::format("Unimplemented compressed texture format {}", format));
   }
}
Example #30
0
vk::BlendOp
getVkBlendOp(latte::CB_COMB_FUNC func)
{
   switch (func) {
   case latte::CB_COMB_FUNC::DST_PLUS_SRC:
      return vk::BlendOp::eAdd;
   case latte::CB_COMB_FUNC::SRC_MINUS_DST:
      return vk::BlendOp::eSubtract;
   case latte::CB_COMB_FUNC::MIN_DST_SRC:
      return vk::BlendOp::eMin;
   case latte::CB_COMB_FUNC::MAX_DST_SRC:
      return vk::BlendOp::eMax;
   case latte::CB_COMB_FUNC::DST_MINUS_SRC:
      return vk::BlendOp::eReverseSubtract;
   default:
      decaf_abort("Unexpected blend op");
   }
}