Core: Fixed for memory mappings, implemented multiplication register, added logging to help debugging missing functionalities
This commit is contained in:
parent
0757ccefa6
commit
93e8fd9d5e
22 changed files with 646 additions and 102 deletions
128
Core/BaseCartridge.cpp
Normal file
128
Core/BaseCartridge.cpp
Normal file
|
@ -0,0 +1,128 @@
|
|||
#include "stdafx.h"
|
||||
#include "BaseCartridge.h"
|
||||
#include "RamHandler.h"
|
||||
#include "RomHandler.h"
|
||||
#include "MemoryManager.h"
|
||||
#include "IMemoryHandler.h"
|
||||
#include "../Utilities/VirtualFile.h"
|
||||
|
||||
BaseCartridge::~BaseCartridge()
|
||||
{
|
||||
delete[] _prgRom;
|
||||
delete[] _saveRam;
|
||||
}
|
||||
|
||||
shared_ptr<BaseCartridge> BaseCartridge::CreateCartridge(VirtualFile &romFile, VirtualFile &patchFile)
|
||||
{
|
||||
if(romFile.IsValid()) {
|
||||
vector<uint8_t> romData;
|
||||
romFile.ReadFile(romData);
|
||||
|
||||
shared_ptr<BaseCartridge> cart(new BaseCartridge());
|
||||
cart->_prgRomSize = (uint32_t)romData.size();
|
||||
cart->_prgRom = new uint8_t[cart->_prgRomSize];
|
||||
memcpy(cart->_prgRom, romData.data(), cart->_prgRomSize);
|
||||
cart->Init();
|
||||
|
||||
return cart;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void BaseCartridge::Init()
|
||||
{
|
||||
uint32_t headerOffset = 0;
|
||||
if(((0x400 << _prgRom[0x7FD7]) == _prgRomSize && (_prgRom[0x7FD5] & 0x20)) || _prgRomSize < 0xFFFF) {
|
||||
//LoROM
|
||||
headerOffset = 0x7FB0;
|
||||
} else if((0x400 << _prgRom[0xFFD7]) == _prgRomSize && (_prgRom[0xFFD5] & 0x20)) {
|
||||
//HiROM
|
||||
headerOffset = 0xFFB0;
|
||||
} else if(_prgRom[0x7FD5] & 0x20) {
|
||||
//LoROM
|
||||
headerOffset = 0x7FB0;
|
||||
} else if(_prgRom[0xFFD5] & 0x20) {
|
||||
//HiROM
|
||||
headerOffset = 0xFFB0;
|
||||
} else {
|
||||
throw new std::runtime_error("invalid rom (?)");
|
||||
}
|
||||
|
||||
_cartInfo = *(SnesCartInformation*)(&_prgRom[headerOffset]);
|
||||
|
||||
_saveRamSize = _cartInfo.SramSize > 0 ? 1024 * (1 << _cartInfo.SramSize) : 0;
|
||||
_saveRam = new uint8_t[_saveRamSize];
|
||||
}
|
||||
|
||||
CartFlags::CartFlags BaseCartridge::GetCartFlags()
|
||||
{
|
||||
uint32_t flags = 0;
|
||||
if(_cartInfo.MapMode & 0x04) {
|
||||
flags |= CartFlags::ExHiRom;
|
||||
} else if(_cartInfo.MapMode & 0x02) {
|
||||
flags |= CartFlags::ExLoRom;
|
||||
} else if(_cartInfo.MapMode & 0x01) {
|
||||
flags |= CartFlags::HiRom;
|
||||
} else {
|
||||
flags |= CartFlags::LoRom;
|
||||
}
|
||||
|
||||
if(_cartInfo.MapMode & 0x10) {
|
||||
flags |= CartFlags::FastRom;
|
||||
}
|
||||
|
||||
return (CartFlags::CartFlags)flags;
|
||||
}
|
||||
|
||||
void BaseCartridge::MapBanks(MemoryManager &mm, vector<unique_ptr<IMemoryHandler>> &handlers, uint8_t startBank, uint8_t endBank, uint16_t startPage, uint16_t endPage, uint16_t pageIncrement, bool mirror)
|
||||
{
|
||||
if(handlers.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t pageNumber = 0;
|
||||
for(uint32_t i = startBank; i <= endBank; i++) {
|
||||
uint32_t baseAddress = i << 16;
|
||||
pageNumber += pageIncrement;
|
||||
for(uint32_t j = startPage; j <= endPage; j++) {
|
||||
mm.RegisterHandler(baseAddress + (j * 0x1000), baseAddress + (j * 0x1000) | 0xFFF, handlers[pageNumber].get());
|
||||
//MessageManager::Log("Map [$" + HexUtilities::ToHex(i) + ":" + HexUtilities::ToHex(j)[1] + "xxx] to page number " + HexUtilities::ToHex(pageNumber));
|
||||
pageNumber++;
|
||||
if(pageNumber >= handlers.size()) {
|
||||
if(mirror) {
|
||||
pageNumber = 0;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BaseCartridge::RegisterHandlers(MemoryManager &mm)
|
||||
{
|
||||
for(uint32_t i = 0; i < _prgRomSize; i += 0x1000) {
|
||||
_prgRomHandlers.push_back(unique_ptr<RomHandler>(new RomHandler(_prgRom + i)));
|
||||
}
|
||||
|
||||
for(uint32_t i = 0; i < _saveRamSize; i += 0x1000) {
|
||||
_saveRamHandlers.push_back(unique_ptr<RamHandler>(new RamHandler(_saveRam + i)));
|
||||
}
|
||||
|
||||
if(GetCartFlags() & CartFlags::LoRom) {
|
||||
MapBanks(mm, _prgRomHandlers, 0x00, 0x6F, 0x08, 0x0F, 0, true);
|
||||
MapBanks(mm, _saveRamHandlers, 0x70, 0x7D, 0x00, 0x0F, 0, true);
|
||||
|
||||
MapBanks(mm, _prgRomHandlers, 0x80, 0xEF, 0x08, 0x0F, 0, true);
|
||||
MapBanks(mm, _saveRamHandlers, 0xF0, 0xFF, 0x00, 0x0F, 0, true);
|
||||
} else {
|
||||
MapBanks(mm, _prgRomHandlers, 0x40, 0x7D, 0x00, 0x0F, 0, true);
|
||||
MapBanks(mm, _prgRomHandlers, 0xC0, 0xFF, 0x00, 0x0F, 0, true);
|
||||
MapBanks(mm, _prgRomHandlers, 0x00, 0x3F, 0x08, 0x0F, 8, true);
|
||||
MapBanks(mm, _prgRomHandlers, 0x80, 0xBF, 0x08, 0x0F, 8, true);
|
||||
|
||||
MapBanks(mm, _saveRamHandlers, 0x20, 0x3F, 0x06, 0x07, 0, true);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,50 +1,72 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "IMemoryHandler.h"
|
||||
#include "../Utilities/VirtualFile.h"
|
||||
|
||||
class BaseCartridge : public IMemoryHandler
|
||||
class MemoryManager;
|
||||
class VirtualFile;
|
||||
|
||||
struct SnesCartInformation
|
||||
{
|
||||
uint8_t MakerCode[2];
|
||||
uint8_t GameCode[4];
|
||||
uint8_t Reserved[7];
|
||||
uint8_t ExpansionRamSize;
|
||||
uint8_t SpecialVersion;
|
||||
uint8_t CartridgeType;
|
||||
|
||||
char CartName[21];
|
||||
uint8_t MapMode;
|
||||
uint8_t RomType;
|
||||
uint8_t RomSize;
|
||||
uint8_t SramSize;
|
||||
|
||||
uint8_t DestinationCode;
|
||||
uint8_t Reserved2;
|
||||
uint8_t Version;
|
||||
|
||||
uint8_t ChecksumComplement[2];
|
||||
uint8_t Checksum[2];
|
||||
};
|
||||
|
||||
namespace CartFlags
|
||||
{
|
||||
enum CartFlags
|
||||
{
|
||||
LoRom = 1,
|
||||
HiRom = 2,
|
||||
FastRom = 4,
|
||||
ExLoRom = 8,
|
||||
ExHiRom = 16
|
||||
};
|
||||
}
|
||||
|
||||
class BaseCartridge
|
||||
{
|
||||
private:
|
||||
vector<unique_ptr<IMemoryHandler>> _prgRomHandlers;
|
||||
vector<unique_ptr<IMemoryHandler>> _saveRamHandlers;
|
||||
SnesCartInformation _cartInfo;
|
||||
|
||||
uint8_t* _prgRom = nullptr;
|
||||
uint8_t* _saveRam = nullptr;
|
||||
|
||||
uint32_t _prgRomSize = 0;
|
||||
uint32_t _saveRamSize = 0;
|
||||
|
||||
bool _isHiRom = false;
|
||||
|
||||
void MapBanks(MemoryManager &mm, vector<unique_ptr<IMemoryHandler>> &handlers, uint8_t startBank, uint8_t endBank, uint16_t startPage = 0, uint16_t endPage = 0x0F, uint16_t pageIncrement = 0, bool mirror = false);
|
||||
|
||||
public:
|
||||
~BaseCartridge()
|
||||
{
|
||||
delete[] _prgRom;
|
||||
delete[] _saveRam;
|
||||
}
|
||||
~BaseCartridge();
|
||||
|
||||
static shared_ptr<BaseCartridge> CreateCartridge(VirtualFile romFile, VirtualFile patchFile)
|
||||
{
|
||||
if(romFile.IsValid()) {
|
||||
vector<uint8_t> romData;
|
||||
romFile.ReadFile(romData);
|
||||
static shared_ptr<BaseCartridge> CreateCartridge(VirtualFile &romFile, VirtualFile &patchFile);
|
||||
|
||||
shared_ptr<BaseCartridge> cart(new BaseCartridge());
|
||||
cart->_prgRomSize = (uint32_t)romData.size();
|
||||
cart->_prgRom = new uint8_t[cart->_prgRomSize];
|
||||
memcpy(cart->_prgRom, romData.data(), cart->_prgRomSize);
|
||||
void Init();
|
||||
|
||||
return cart;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
CartFlags::CartFlags GetCartFlags();
|
||||
|
||||
uint8_t Read(uint32_t addr) override
|
||||
{
|
||||
uint8_t bank = (addr >> 16) & 0x7F;
|
||||
return _prgRom[((bank * 0x8000) | (addr & 0x7FFF)) & (_prgRomSize - 1)];
|
||||
}
|
||||
|
||||
void Write(uint32_t addr, uint8_t value) override
|
||||
{
|
||||
}
|
||||
void RegisterHandlers(MemoryManager &mm);
|
||||
|
||||
uint8_t* DebugGetPrgRom() { return _prgRom; }
|
||||
uint8_t* DebugGetSaveRam() { return _saveRam; }
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "VideoDecoder.h"
|
||||
#include "VideoRenderer.h"
|
||||
#include "DebugHud.h"
|
||||
#include "MessageManager.h"
|
||||
#include "../Utilities/Timer.h"
|
||||
#include "../Utilities/VirtualFile.h"
|
||||
|
||||
|
@ -82,6 +83,8 @@ void Console::LoadRom(VirtualFile romFile, VirtualFile patchFile)
|
|||
|
||||
shared_ptr<BaseCartridge> cart = BaseCartridge::CreateCartridge(romFile, patchFile);
|
||||
if(cart) {
|
||||
MessageManager::ClearLog();
|
||||
|
||||
_ppu.reset(new Ppu(shared_from_this()));
|
||||
_spc.reset(new Spc(shared_from_this()));
|
||||
_cart = cart;
|
||||
|
|
|
@ -82,6 +82,8 @@
|
|||
<ClInclude Include="NotificationManager.h" />
|
||||
<ClInclude Include="Ppu.h" />
|
||||
<ClInclude Include="PpuTypes.h" />
|
||||
<ClInclude Include="RamHandler.h" />
|
||||
<ClInclude Include="RomHandler.h" />
|
||||
<ClInclude Include="SettingTypes.h" />
|
||||
<ClInclude Include="SNES_SPC.h" />
|
||||
<ClInclude Include="SoundMixer.h" />
|
||||
|
@ -95,6 +97,7 @@
|
|||
<ClInclude Include="VideoRenderer.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="BaseCartridge.cpp" />
|
||||
<ClCompile Include="BaseRenderer.cpp" />
|
||||
<ClCompile Include="BaseSoundManager.cpp" />
|
||||
<ClCompile Include="BaseVideoFilter.cpp" />
|
||||
|
|
|
@ -149,6 +149,12 @@
|
|||
<ClInclude Include="SoundMixer.h">
|
||||
<Filter>Misc</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="RomHandler.h">
|
||||
<Filter>SNES</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="RamHandler.h">
|
||||
<Filter>SNES</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="stdafx.cpp" />
|
||||
|
@ -230,6 +236,9 @@
|
|||
<ClCompile Include="SoundMixer.cpp">
|
||||
<Filter>Misc</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="BaseCartridge.cpp">
|
||||
<Filter>SNES</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="SNES">
|
||||
|
|
|
@ -21,7 +21,7 @@ DisassemblyInfo::DisassemblyInfo(CpuState &state, MemoryManager *memoryManager)
|
|||
_opSize = GetOperandSize() + 1;
|
||||
|
||||
for(int i = 1; i < _opSize; i++) {
|
||||
_byteCode[i] = memoryManager->Peek(addr+i);
|
||||
_byteCode[i] = memoryManager->Peek((addr+i) & 0xFFFFFF);
|
||||
}
|
||||
|
||||
_emulationMode = state.EmulationMode;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "stdafx.h"
|
||||
#include "DmaController.h"
|
||||
#include "MemoryManager.h"
|
||||
#include "MessageManager.h"
|
||||
|
||||
DmaController::DmaController(MemoryManager *memoryManager)
|
||||
{
|
||||
|
@ -37,6 +38,8 @@ void DmaController::RunDma(DmaChannelConfig &channel)
|
|||
//"Note, however, that writing $0000 to this register actually results in a transfer of $10000 bytes, not 0."
|
||||
uint32_t bytesLeft = channel.TransferSize ? channel.TransferSize : 0x10000;
|
||||
|
||||
MessageManager::Log("Run DMA: " + HexUtilities::ToHex(channel.DestAddress) + " -> " + HexUtilities::ToHex(channel.SrcAddress) + " Bytes: " + std::to_string(bytesLeft));
|
||||
|
||||
while(bytesLeft > 0) {
|
||||
//Manual DMA transfers run to the end of the transfer when started
|
||||
RunSingleTransfer(channel, bytesLeft);
|
||||
|
@ -55,6 +58,13 @@ void DmaController::Write(uint16_t addr, uint8_t value)
|
|||
}
|
||||
break;
|
||||
|
||||
case 0x420C:
|
||||
//HDMAEN - HDMA Enable
|
||||
if(value > 0) {
|
||||
MessageManager::DisplayMessage("Debug", "Unsupported HDMA operation");
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x4300: case 0x4310: case 0x4320: case 0x4330: case 0x4340: case 0x4350: case 0x4360: case 0x4370:
|
||||
{
|
||||
//DMAPx - DMA Control for Channel x
|
||||
|
|
|
@ -3,9 +3,11 @@
|
|||
#include "Console.h"
|
||||
#include "Ppu.h"
|
||||
#include "Spc.h"
|
||||
#include "RamHandler.h"
|
||||
#include "DmaController.h"
|
||||
#include "BaseCartridge.h"
|
||||
#include "IMemoryHandler.h"
|
||||
#include "MessageManager.h"
|
||||
#include "../Utilities/HexUtilities.h"
|
||||
|
||||
class CpuRegisterHandler : public IMemoryHandler
|
||||
|
@ -14,13 +16,18 @@ private:
|
|||
Ppu *_ppu;
|
||||
Spc *_spc;
|
||||
DmaController *_dmaController;
|
||||
uint8_t *_workRam;
|
||||
uint32_t _wramPosition;
|
||||
|
||||
public:
|
||||
CpuRegisterHandler(Ppu *ppu, Spc *spc, DmaController *dmaController)
|
||||
CpuRegisterHandler(Ppu *ppu, Spc *spc, DmaController *dmaController, uint8_t *workRam)
|
||||
{
|
||||
_ppu = ppu;
|
||||
_spc = spc;
|
||||
_dmaController = dmaController;
|
||||
|
||||
_workRam = workRam;
|
||||
_wramPosition = 0;
|
||||
}
|
||||
|
||||
uint8_t Read(uint32_t addr) override
|
||||
|
@ -38,35 +45,25 @@ public:
|
|||
addr &= 0xFFFF;
|
||||
if(addr >= 0x2140 && addr <= 0x217F) {
|
||||
return _spc->Write(addr & 0x03, value);
|
||||
} if(addr >= 0x2180 && addr <= 0x2183) {
|
||||
switch(addr & 0xFFFF) {
|
||||
case 0x2180:
|
||||
_workRam[_wramPosition] = value;
|
||||
_wramPosition = (_wramPosition + 1) & (0x1FFFF);
|
||||
break;
|
||||
|
||||
case 0x2181: _wramPosition = (_wramPosition & 0x1FF00) | value; break;
|
||||
case 0x2182: _wramPosition = (_wramPosition & 0x100FF) | (value << 8); break;
|
||||
case 0x2183: _wramPosition = (_wramPosition & 0xFFFF) | ((value & 0x01) << 16); break;
|
||||
}
|
||||
} else if(addr == 0x420B || addr == 0x420C || addr >= 0x4300) {
|
||||
_dmaController->Write(addr, value);
|
||||
} else {
|
||||
_ppu->Write(addr, value);
|
||||
_dmaController->Write(addr, value);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class WorkRamHandler : public IMemoryHandler
|
||||
{
|
||||
private:
|
||||
uint8_t *_workRam;
|
||||
|
||||
public:
|
||||
WorkRamHandler(uint8_t *workRam)
|
||||
{
|
||||
_workRam = workRam;
|
||||
}
|
||||
|
||||
uint8_t Read(uint32_t addr) override
|
||||
{
|
||||
return _workRam[addr & 0xFFF];
|
||||
}
|
||||
|
||||
void Write(uint32_t addr, uint8_t value) override
|
||||
{
|
||||
_workRam[addr & 0xFFF] = value;
|
||||
}
|
||||
};
|
||||
|
||||
class MemoryManager
|
||||
{
|
||||
public:
|
||||
|
@ -75,15 +72,15 @@ public:
|
|||
private:
|
||||
shared_ptr<Console> _console;
|
||||
|
||||
uint8_t * _workRam;
|
||||
IMemoryHandler* _handlers[0x100 * 0x10];
|
||||
vector<unique_ptr<WorkRamHandler>> _workRamHandlers;
|
||||
shared_ptr<BaseCartridge> _cart;
|
||||
shared_ptr<CpuRegisterHandler> _cpuRegisterHandler;
|
||||
shared_ptr<Ppu> _ppu;
|
||||
shared_ptr<DmaController> _dmaController;
|
||||
|
||||
uint32_t _wramPosition;
|
||||
IMemoryHandler* _handlers[0x100 * 0x10];
|
||||
vector<unique_ptr<RamHandler>> _workRamHandlers;
|
||||
|
||||
uint8_t * _workRam;
|
||||
|
||||
uint64_t _masterClock;
|
||||
uint64_t _lastMasterClock;
|
||||
|
@ -97,15 +94,16 @@ public:
|
|||
_cart = console->GetCartridge();
|
||||
_ppu = console->GetPpu();
|
||||
|
||||
_workRam = new uint8_t[MemoryManager::WorkRamSize];
|
||||
|
||||
_dmaController.reset(new DmaController(console->GetMemoryManager().get()));
|
||||
_cpuRegisterHandler.reset(new CpuRegisterHandler(_ppu.get(), console->GetSpc().get(), _dmaController.get()));
|
||||
_cpuRegisterHandler.reset(new CpuRegisterHandler(_ppu.get(), console->GetSpc().get(), _dmaController.get(), _workRam));
|
||||
|
||||
memset(_handlers, 0, sizeof(_handlers));
|
||||
_workRam = new uint8_t[MemoryManager::WorkRamSize];
|
||||
//memset(_workRam, 0, 128 * 1024);
|
||||
|
||||
for(uint32_t i = 0; i < 128 * 1024; i += 0x1000) {
|
||||
_workRamHandlers.push_back(unique_ptr<WorkRamHandler>(new WorkRamHandler(_workRam + i)));
|
||||
_workRamHandlers.push_back(unique_ptr<RamHandler>(new RamHandler(_workRam + i)));
|
||||
RegisterHandler(0x7E0000 | i, 0x7E0000 | (i + 0xFFF), _workRamHandlers[_workRamHandlers.size() - 1].get());
|
||||
}
|
||||
|
||||
|
@ -117,13 +115,17 @@ public:
|
|||
RegisterHandler(((i | 0x80) << 16) | 0x4000, ((i | 0x80) << 16) | 0x4FFF, _cpuRegisterHandler.get());
|
||||
}
|
||||
|
||||
RegisterHandler(0x0000, 0x0FFF, _workRamHandlers[0].get());
|
||||
RegisterHandler(0x1000, 0x1FFF, _workRamHandlers[1].get());
|
||||
|
||||
for(int bank = 0; bank < 0x20; bank++) {
|
||||
RegisterHandler((bank << 16) | 0x8000, (bank << 16) | 0xFFFF, _cart.get());
|
||||
RegisterHandler(((0x80 | bank) << 16) | 0x8000, ((0x80 | bank) << 16) | 0xFFFF, _cart.get());
|
||||
for(int i = 0; i < 0x3F; i++) {
|
||||
RegisterHandler((i << 16) | 0x0000, (i << 16) | 0x0FFF, _workRamHandlers[0].get());
|
||||
RegisterHandler((i << 16) | 0x1000, (i << 16) | 0x1FFF, _workRamHandlers[1].get());
|
||||
}
|
||||
|
||||
for(int i = 0x80; i < 0xBF; i++) {
|
||||
RegisterHandler((i << 16) | 0x0000, (i << 16) | 0x0FFF, _workRamHandlers[0].get());
|
||||
RegisterHandler((i << 16) | 0x1000, (i << 16) | 0x1FFF, _workRamHandlers[1].get());
|
||||
}
|
||||
|
||||
_cart->RegisterHandlers(*this);
|
||||
}
|
||||
|
||||
~MemoryManager()
|
||||
|
@ -138,6 +140,10 @@ public:
|
|||
}
|
||||
|
||||
for(uint32_t addr = startAddr; addr < endAddr; addr += 0x1000) {
|
||||
if(_handlers[addr >> 12]) {
|
||||
throw new std::runtime_error("handler already set");
|
||||
}
|
||||
|
||||
_handlers[addr >> 12] = handler;
|
||||
}
|
||||
}
|
||||
|
@ -191,7 +197,10 @@ public:
|
|||
if(_handlers[addr >> 12]) {
|
||||
value = _handlers[addr >> 12]->Read(addr);
|
||||
} else {
|
||||
//std::cout << "Read - missing handler: $" << HexUtilities::ToHex(addr) << std::endl;
|
||||
//open bus
|
||||
value = (addr>> 12);
|
||||
|
||||
MessageManager::DisplayMessage("Debug", "Read - missing handler: $" + HexUtilities::ToHex(addr));
|
||||
}
|
||||
_console->ProcessCpuRead(addr, value, type);
|
||||
return value;
|
||||
|
@ -203,8 +212,6 @@ public:
|
|||
uint8_t value = 0;
|
||||
if(_handlers[addr >> 12]) {
|
||||
value = _handlers[addr >> 12]->Read(addr);
|
||||
} else {
|
||||
//std::cout << "Read - missing handler: $" << HexUtilities::ToHex(addr) << std::endl;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
@ -213,30 +220,11 @@ public:
|
|||
{
|
||||
IncrementMasterClock(addr);
|
||||
|
||||
switch(addr & 0xFFFF) {
|
||||
case 0x2180:
|
||||
_workRam[_wramPosition] = value;
|
||||
_wramPosition++;
|
||||
break;
|
||||
|
||||
case 0x2181:
|
||||
_wramPosition = (_wramPosition & 0x1FF00) | value;
|
||||
break;
|
||||
|
||||
case 0x2182:
|
||||
_wramPosition = (_wramPosition & 0x100FF) | (value << 8);
|
||||
break;
|
||||
|
||||
case 0x2183:
|
||||
_wramPosition = (_wramPosition & 0xFFFF) | ((value & 0x01) << 16);
|
||||
break;
|
||||
}
|
||||
|
||||
_console->ProcessCpuWrite(addr, value, type);
|
||||
if(_handlers[addr >> 12]) {
|
||||
return _handlers[addr >> 12]->Write(addr, value);
|
||||
} else {
|
||||
//std::cout << "Write - missing handler: $" << HexUtilities::ToHex(addr) << " = " << HexUtilities::ToHex(value) << std::endl;
|
||||
MessageManager::DisplayMessage("Debug", "Write - missing handler: $" + HexUtilities::ToHex(addr) + " = " + HexUtilities::ToHex(value));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -172,6 +172,12 @@ void MessageManager::Log(string message)
|
|||
#endif
|
||||
}
|
||||
|
||||
void MessageManager::ClearLog()
|
||||
{
|
||||
auto lock = _logLock.AcquireSafe();
|
||||
_log.clear();
|
||||
}
|
||||
|
||||
string MessageManager::GetLog()
|
||||
{
|
||||
auto lock = _logLock.AcquireSafe();
|
||||
|
|
|
@ -27,5 +27,6 @@ public:
|
|||
static void DisplayMessage(string title, string message, string param1 = "", string param2 = "");
|
||||
|
||||
static void Log(string message = "");
|
||||
static void ClearLog();
|
||||
static string GetLog();
|
||||
};
|
||||
|
|
17
Core/Ppu.cpp
17
Core/Ppu.cpp
|
@ -192,6 +192,13 @@ uint8_t Ppu::Read(uint16_t addr)
|
|||
(_scanline >= 225 ? 0x80 : 0) |
|
||||
((_cycle >= 0x121 || _cycle <= 0x15) ? 0x40 : 0)
|
||||
);
|
||||
|
||||
case 0x4216: return (uint8_t)_multResult;
|
||||
case 0x4217: return (uint8_t)(_multResult >> 8);
|
||||
|
||||
default:
|
||||
MessageManager::DisplayMessage("Debug", "Unimplemented register read: " + HexUtilities::ToHex(addr));
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -284,10 +291,20 @@ void Ppu::Write(uint32_t addr, uint8_t value)
|
|||
//_autoJoypadRead = (value & 0x01) != 0;
|
||||
break;
|
||||
|
||||
case 0x4202: _multOperand1 = value; break;
|
||||
case 0x4203:
|
||||
_multOperand2 = value;
|
||||
_multResult = _multOperand1 * _multOperand2;
|
||||
break;
|
||||
|
||||
case 0x4207: _horizontalTimer = (_horizontalTimer & 0x100) | value; break;
|
||||
case 0x4208: _horizontalTimer = (_horizontalTimer & 0xFF) | ((value & 0x01) << 8); break;
|
||||
|
||||
case 0x4209: _verticalTimer = (_verticalTimer & 0x100) | value; break;
|
||||
case 0x420A: _verticalTimer = (_verticalTimer & 0xFF) | ((value & 0x01) << 8); break;
|
||||
|
||||
default:
|
||||
MessageManager::DisplayMessage("Debug", "Unimplemented register write: " + HexUtilities::ToHex(addr));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,6 +35,10 @@ private:
|
|||
uint8_t _vramIncrementValue;
|
||||
uint8_t _vramAddressRemapping;
|
||||
bool _vramAddrIncrementOnSecondReg;
|
||||
|
||||
uint8_t _multOperand1 = 0;
|
||||
uint8_t _multOperand2 = 0;
|
||||
uint16_t _multResult = 0;
|
||||
|
||||
uint16_t _cgramAddress;
|
||||
uint8_t _cgram[Ppu::CgRamSize];
|
||||
|
|
25
Core/RamHandler.h
Normal file
25
Core/RamHandler.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "IMemoryHandler.h"
|
||||
|
||||
class RamHandler : public IMemoryHandler
|
||||
{
|
||||
private:
|
||||
uint8_t * _ram;
|
||||
|
||||
public:
|
||||
RamHandler(uint8_t *ram)
|
||||
{
|
||||
_ram = ram;
|
||||
}
|
||||
|
||||
uint8_t Read(uint32_t addr) override
|
||||
{
|
||||
return _ram[addr & 0xFFF];
|
||||
}
|
||||
|
||||
void Write(uint32_t addr, uint8_t value) override
|
||||
{
|
||||
_ram[addr & 0xFFF] = value;
|
||||
}
|
||||
};
|
24
Core/RomHandler.h
Normal file
24
Core/RomHandler.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "IMemoryHandler.h"
|
||||
|
||||
class RomHandler : public IMemoryHandler
|
||||
{
|
||||
private:
|
||||
uint8_t * _rom;
|
||||
|
||||
public:
|
||||
RomHandler(uint8_t *rom)
|
||||
{
|
||||
_rom = rom;
|
||||
}
|
||||
|
||||
uint8_t Read(uint32_t addr) override
|
||||
{
|
||||
return _rom[addr & 0xFFF];
|
||||
}
|
||||
|
||||
void Write(uint32_t addr, uint8_t value) override
|
||||
{
|
||||
}
|
||||
};
|
|
@ -284,14 +284,6 @@ void TraceLogger::AddRow(DisassemblyInfo &disassemblyInfo, DebugState &state)
|
|||
_logCount++;
|
||||
}
|
||||
|
||||
if(_logToFile) {
|
||||
GetTraceRow(_outputBuffer, state.Cpu, state.Ppu, disassemblyInfo);
|
||||
if(_outputBuffer.size() > 32768) {
|
||||
_outputFile << _outputBuffer;
|
||||
_outputBuffer.clear();
|
||||
}
|
||||
}
|
||||
|
||||
_currentPos = (_currentPos + 1) % ExecutionLogSize;
|
||||
}
|
||||
/*
|
||||
|
@ -307,10 +299,20 @@ void TraceLogger::LogNonExec(OperationInfo& operationInfo)
|
|||
|
||||
void TraceLogger::LogEffectiveAddress(uint32_t effectiveAddress)
|
||||
{
|
||||
uint32_t pos;
|
||||
if(_currentPos > 0) {
|
||||
_disassemblyCache[_currentPos - 1].SetEffectiveAddress(effectiveAddress);
|
||||
pos = _currentPos - 1;
|
||||
} else {
|
||||
_disassemblyCache[ExecutionLogSize - 1].SetEffectiveAddress(effectiveAddress);
|
||||
pos = ExecutionLogSize - 1;
|
||||
}
|
||||
|
||||
_disassemblyCache[pos].SetEffectiveAddress(effectiveAddress);
|
||||
if(_logToFile) {
|
||||
GetTraceRow(_outputBuffer, _cpuStateCache[pos], _ppuStateCache[pos], _disassemblyCache[pos]);
|
||||
if(_outputBuffer.size() > 32768) {
|
||||
_outputFile << _outputBuffer;
|
||||
_outputBuffer.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ void VideoDecoder::GetScreenSize(ScreenSize &size, bool ignoreScale)
|
|||
|
||||
size.Scale = scale;*/
|
||||
|
||||
if(true || ignoreScale) {
|
||||
if(ignoreScale) {
|
||||
size.Width = 256;
|
||||
size.Height = 224;
|
||||
} else {
|
||||
|
|
54
UI/Forms/frmLogWindow.cs
Normal file
54
UI/Forms/frmLogWindow.cs
Normal file
|
@ -0,0 +1,54 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Mesen.GUI.Forms
|
||||
{
|
||||
public partial class frmLogWindow : BaseForm
|
||||
{
|
||||
private string _currentLog;
|
||||
public frmLogWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
protected override void OnLoad(EventArgs e)
|
||||
{
|
||||
base.OnLoad(e);
|
||||
}
|
||||
|
||||
protected override void OnShown(EventArgs e)
|
||||
{
|
||||
base.OnShown(e);
|
||||
UpdateLog(EmuApi.GetLog());
|
||||
}
|
||||
|
||||
private void UpdateLog(string log)
|
||||
{
|
||||
_currentLog = log;
|
||||
txtLog.Text = _currentLog;
|
||||
txtLog.SelectionLength = 0;
|
||||
txtLog.SelectionStart = txtLog.Text.Length;
|
||||
txtLog.ScrollToCaret();
|
||||
}
|
||||
|
||||
private void btnClose_Click(object sender, EventArgs e)
|
||||
{
|
||||
this.Close();
|
||||
}
|
||||
|
||||
private void tmrRefresh_Tick(object sender, EventArgs e)
|
||||
{
|
||||
string newLog = EmuApi.GetLog();
|
||||
if(_currentLog != newLog) {
|
||||
UpdateLog(newLog);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
108
UI/Forms/frmLogWindow.designer.cs
generated
Normal file
108
UI/Forms/frmLogWindow.designer.cs
generated
Normal file
|
@ -0,0 +1,108 @@
|
|||
namespace Mesen.GUI.Forms
|
||||
{
|
||||
partial class frmLogWindow
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if(disposing && (components != null)) {
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.components = new System.ComponentModel.Container();
|
||||
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.btnClose = new System.Windows.Forms.Button();
|
||||
this.txtLog = new System.Windows.Forms.TextBox();
|
||||
this.tmrRefresh = new System.Windows.Forms.Timer(this.components);
|
||||
this.tableLayoutPanel1.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// tableLayoutPanel1
|
||||
//
|
||||
this.tableLayoutPanel1.ColumnCount = 2;
|
||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
||||
this.tableLayoutPanel1.Controls.Add(this.txtLog, 0, 0);
|
||||
this.tableLayoutPanel1.Controls.Add(this.btnClose, 1, 1);
|
||||
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
|
||||
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
|
||||
this.tableLayoutPanel1.RowCount = 2;
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel1.Size = new System.Drawing.Size(480, 377);
|
||||
this.tableLayoutPanel1.TabIndex = 0;
|
||||
//
|
||||
// btnClose
|
||||
//
|
||||
this.btnClose.DialogResult = System.Windows.Forms.DialogResult.OK;
|
||||
this.btnClose.Location = new System.Drawing.Point(407, 349);
|
||||
this.btnClose.Name = "btnClose";
|
||||
this.btnClose.Size = new System.Drawing.Size(70, 25);
|
||||
this.btnClose.TabIndex = 0;
|
||||
this.btnClose.Text = "Close";
|
||||
this.btnClose.UseVisualStyleBackColor = true;
|
||||
this.btnClose.Click += new System.EventHandler(this.btnClose_Click);
|
||||
//
|
||||
// txtLog
|
||||
//
|
||||
this.txtLog.BackColor = System.Drawing.Color.White;
|
||||
this.tableLayoutPanel1.SetColumnSpan(this.txtLog, 2);
|
||||
this.txtLog.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.txtLog.Font = new System.Drawing.Font("Arial", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.txtLog.Location = new System.Drawing.Point(3, 3);
|
||||
this.txtLog.Multiline = true;
|
||||
this.txtLog.Name = "txtLog";
|
||||
this.txtLog.ReadOnly = true;
|
||||
this.txtLog.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
|
||||
this.txtLog.Size = new System.Drawing.Size(474, 340);
|
||||
this.txtLog.TabIndex = 1;
|
||||
//
|
||||
// tmrRefresh
|
||||
//
|
||||
this.tmrRefresh.Enabled = true;
|
||||
this.tmrRefresh.Tick += new System.EventHandler(this.tmrRefresh_Tick);
|
||||
//
|
||||
// frmLogWindow
|
||||
//
|
||||
this.AcceptButton = this.btnClose;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.CancelButton = this.btnClose;
|
||||
this.ClientSize = new System.Drawing.Size(480, 377);
|
||||
this.Controls.Add(this.tableLayoutPanel1);
|
||||
this.Name = "frmLogWindow";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
this.Text = "Log Window";
|
||||
this.tableLayoutPanel1.ResumeLayout(false);
|
||||
this.tableLayoutPanel1.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
|
||||
private System.Windows.Forms.TextBox txtLog;
|
||||
private System.Windows.Forms.Button btnClose;
|
||||
private System.Windows.Forms.Timer tmrRefresh;
|
||||
}
|
||||
}
|
126
UI/Forms/frmLogWindow.resx
Normal file
126
UI/Forms/frmLogWindow.resx
Normal file
|
@ -0,0 +1,126 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="toolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
<metadata name="tmrRefresh.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>107, 17</value>
|
||||
</metadata>
|
||||
</root>
|
|
@ -32,6 +32,8 @@ namespace Mesen.GUI.Forms
|
|||
|
||||
_notifListener = new NotificationListener();
|
||||
_notifListener.OnNotification += OnNotificationReceived;
|
||||
|
||||
new frmLogWindow().Show();
|
||||
}
|
||||
|
||||
protected override void OnFormClosing(FormClosingEventArgs e)
|
||||
|
|
|
@ -39,5 +39,8 @@ namespace Mesen.GUI
|
|||
[DllImport(DllPath)] public static extern void SetMousePosition(double x, double y);
|
||||
|
||||
[DllImport(DllPath)] public static extern void SetDisplayLanguage(Language lang);
|
||||
|
||||
[DllImport(DllPath, EntryPoint = "GetLog")] private static extern IntPtr GetLogWrapper();
|
||||
public static string GetLog() { return Utf8Marshaler.PtrToStringUtf8(EmuApi.GetLogWrapper()).Replace("\n", Environment.NewLine); }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -385,6 +385,12 @@
|
|||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Forms\EntityBinder.cs" />
|
||||
<Compile Include="Forms\frmLogWindow.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Forms\frmLogWindow.designer.cs">
|
||||
<DependentUpon>frmLogWindow.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Forms\frmMain.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
|
@ -467,6 +473,9 @@
|
|||
<EmbeddedResource Include="Forms\BaseInputForm.resx">
|
||||
<DependentUpon>BaseInputForm.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Forms\frmLogWindow.resx">
|
||||
<DependentUpon>frmLogWindow.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Forms\frmMain.resx">
|
||||
<DependentUpon>frmMain.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
|
|
Loading…
Add table
Reference in a new issue