-CPU code changes to implement all dummy reads/writes. Each memory access runs the PPU for 3 cycles (PPU is now controlled by the CPU)

-Optimizations + PGO (profile guided optimization) build support
This commit is contained in:
Souryo 2015-07-04 22:21:14 -04:00
parent b01e94d64d
commit f3df2ecf17
13 changed files with 367 additions and 254 deletions

View file

@ -59,9 +59,9 @@ void APU::WriteRAM(uint16_t addr, uint8_t value)
}
}
bool APU::Exec(uint32_t executedCycles)
bool APU::Exec(uint32_t currentCPUCycle)
{
_currentClock += executedCycles;
_currentClock = currentCPUCycle;
if(_currentClock >= 29780) {
_apu.end_frame(_currentClock);

View file

@ -35,8 +35,13 @@ class BaseMapper : public IMemoryHandler, public Snapshotable
uint32_t* _chrSlotPages;
uint32_t _chrShift = -1;
uint32_t _chrSlotMaxIndex = -1;
uint32_t _prgShift = -1;
uint32_t _prgSlotMaxIndex = -1;
uint32_t _chrPageMask = -1;
uint32_t _prgPageMask = -1;
virtual void InitMapper() = 0;
public:
@ -93,20 +98,12 @@ class BaseMapper : public IMemoryHandler, public Snapshotable
uint32_t AddrToPRGSlot(uint16_t addr)
{
if(_prgShift == -1) {
_prgShift = this->log2(GetPRGSlotCount());
}
return (addr >> (15 - _prgShift)) & (GetPRGSlotCount() - 1);
return (addr >> _prgShift) & _prgSlotMaxIndex;
}
uint32_t AddrToCHRSlot(uint16_t addr)
{
if(_chrShift == -1) {
_chrShift = this->log2(GetCHRSlotCount());
}
return (addr >> (13 - _chrShift)) & (GetCHRSlotCount() - 1);
return (addr >> _chrShift) & _chrSlotMaxIndex;
}
wstring GetBatteryFilename()
@ -184,6 +181,14 @@ class BaseMapper : public IMemoryHandler, public Snapshotable
_prgSlotPages = new uint32_t[GetPRGSlotCount()];
_chrSlotPages = new uint32_t[GetCHRSlotCount()];
_prgShift = 15 - this->log2(GetPRGSlotCount());
_prgSlotMaxIndex = GetPRGSlotCount() - 1;
_chrShift = 13 - this->log2(GetCHRSlotCount());
_chrSlotMaxIndex = GetCHRSlotCount() - 1;
_chrPageMask = GetCHRPageSize() - 1;
_prgPageMask = GetPRGPageSize() - 1;
InitMapper();
}
@ -245,7 +250,7 @@ class BaseMapper : public IMemoryHandler, public Snapshotable
virtual uint8_t ReadRAM(uint16_t addr)
{
if(addr >= 0x8000) {
return _prgPages[AddrToPRGSlot(addr)][addr & (GetPRGPageSize() - 1)];
return _prgPages[AddrToPRGSlot(addr)][addr & _prgPageMask];
} else if(addr >= 0x6000) {
return _SRAM[addr & 0x1FFF];
} else if(addr >= 0x4000) {
@ -268,7 +273,7 @@ class BaseMapper : public IMemoryHandler, public Snapshotable
uint32_t ToAbsoluteAddress(uint16_t addr)
{
return GetPRGPageSize() * (_prgSlotPages[AddrToPRGSlot(addr)] % GetPRGPageCount()) + (addr & (GetPRGPageSize() - 1));
return GetPRGPageSize() * (_prgSlotPages[AddrToPRGSlot(addr)] % GetPRGPageCount()) + (addr & _prgPageMask);
}
int32_t FromAbsoluteAddress(uint32_t addr)
@ -319,13 +324,13 @@ class BaseMapper : public IMemoryHandler, public Snapshotable
virtual uint8_t ReadVRAM(uint16_t addr)
{
return _chrPages[AddrToCHRSlot(addr)][addr & (GetCHRPageSize() - 1)];
return _chrPages[AddrToCHRSlot(addr)][addr & _chrPageMask];
}
virtual void WriteVRAM(uint16_t addr, uint8_t value)
{
if(_hasCHRRAM) {
_chrPages[AddrToCHRSlot(addr)][addr & (GetCHRPageSize() - 1)] = value;
_chrPages[AddrToCHRSlot(addr)][addr & _chrPageMask] = value;
} else {
//assert(false);
}

View file

@ -1,5 +1,6 @@
#include "stdafx.h"
#include "CPU.h"
#include "PPU.h"
CPU* CPU::Instance = nullptr;
@ -28,66 +29,27 @@ CPU::CPU(MemoryManager *memoryManager) : _memoryManager(memoryManager)
};
AddrMode addrMode[] = {
Imm, IndX, None, IndX, Zero, Zero, Zero, Zero, Imp, Imm, Imp, Imm, Abs, Abs, Abs, Abs,
Rel, IndY, None, IndYW, ZeroX, ZeroX, ZeroX, ZeroX, Imp, AbsY, Imp, AbsYW, AbsX, AbsX, AbsXW, AbsXW,
Abs, IndX, None, IndX, Zero, Zero, Zero, Zero, Imp, Imm, Imp, Imm, Abs, Abs, Abs, Abs,
Rel, IndY, None, IndYW, ZeroX, ZeroX, ZeroX, ZeroX, Imp, AbsY, Imp, AbsYW, AbsX, AbsX, AbsXW, AbsXW,
Imp, IndX, None, IndX, Zero, Zero, Zero, Zero, Imp, Imm, Imp, Imm, Abs, Abs, Abs, Abs,
Rel, IndY, None, IndYW, ZeroX, ZeroX, ZeroX, ZeroX, Imp, AbsY, Imp, AbsYW, AbsX, AbsX, AbsXW, AbsXW,
Imp, IndX, None, IndX, Zero, Zero, Zero, Zero, Imp, Imm, Imp, Imm, Abs, Abs, Abs, Abs,
Rel, IndY, None, IndYW, ZeroX, ZeroX, ZeroX, ZeroX, Imp, AbsY, Imp, AbsYW, AbsX, AbsX, AbsXW, AbsXW,
Imm, IndX, Imm, IndX, Zero, Zero, Zero, Zero, Imp, Imm, Imp, Imm, Abs, Abs, Abs, Abs,
Rel, IndYW, None, IndY, ZeroX, ZeroX, ZeroY, ZeroY, Imp, AbsYW, Imp, AbsY, AbsXW, AbsXW, AbsYW, AbsY,
Imm, IndX, Imm, IndX, Zero, Zero, Zero, Zero, Imp, Imm, Imp, Imm, Abs, Abs, Abs, Abs,
Rel, IndY, None, IndY, ZeroX, ZeroX, ZeroY, ZeroY, Imp, AbsY, Imp, AbsY, AbsX, AbsX, AbsY, AbsY,
Imm, IndX, Imm, IndX, Zero, Zero, Zero, Zero, Imp, Imm, Imp, Imm, Abs, Abs, Abs, Abs,
Rel, IndY, None, IndYW, ZeroX, ZeroX, ZeroX, ZeroX, Imp, AbsY, Imp, AbsYW, AbsX, AbsX, AbsXW, AbsXW,
Imm, IndX, Imm, IndX, Zero, Zero, Zero, Zero, Imp, Imm, Imp, Imm, Abs, Abs, Abs, Abs,
Rel, IndY, None, IndYW, ZeroX, ZeroX, ZeroX, ZeroX, Imp, AbsY, Imp, AbsYW, AbsX, AbsX, AbsXW, AbsXW,
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
Imp, IndX, None, IndX, Zero, Zero, Zero, Zero, Imp, Imm, Imp, Imm, Abs, Abs, Abs, Abs, //0
Rel, IndY, None, IndYW, ZeroX, ZeroX, ZeroX, ZeroX, Imp, AbsY, Imp, AbsYW, AbsX, AbsX, AbsXW, AbsXW, //1
Abs, IndX, None, IndX, Zero, Zero, Zero, Zero, Imp, Imm, Imp, Imm, Abs, Abs, Abs, Abs, //2
Rel, IndY, None, IndYW, ZeroX, ZeroX, ZeroX, ZeroX, Imp, AbsY, Imp, AbsYW, AbsX, AbsX, AbsXW, AbsXW, //3
Imp, IndX, None, IndX, Zero, Zero, Zero, Zero, Imp, Imm, Imp, Imm, Abs, Abs, Abs, Abs, //4
Rel, IndY, None, IndYW, ZeroX, ZeroX, ZeroX, ZeroX, Imp, AbsY, Imp, AbsYW, AbsX, AbsX, AbsXW, AbsXW, //5
Imp, IndX, None, IndX, Zero, Zero, Zero, Zero, Imp, Imm, Imp, Imm, Abs, Abs, Abs, Abs, //6
Rel, IndY, None, IndYW, ZeroX, ZeroX, ZeroX, ZeroX, Imp, AbsY, Imp, AbsYW, AbsX, AbsX, AbsXW, AbsXW, //7
Imm, IndX, Imm, IndX, Zero, Zero, Zero, Zero, Imp, Imm, Imp, Imm, Abs, Abs, Abs, Abs, //8
Rel, IndYW, None, IndY, ZeroX, ZeroX, ZeroY, ZeroY, Imp, AbsYW, Imp, AbsY, AbsXW, AbsXW, AbsYW, AbsY, //9
Imm, IndX, Imm, IndX, Zero, Zero, Zero, Zero, Imp, Imm, Imp, Imm, Abs, Abs, Abs, Abs, //A
Rel, IndY, None, IndY, ZeroX, ZeroX, ZeroY, ZeroY, Imp, AbsY, Imp, AbsY, AbsX, AbsX, AbsY, AbsY, //B
Imm, IndX, Imm, IndX, Zero, Zero, Zero, Zero, Imp, Imm, Imp, Imm, Abs, Abs, Abs, Abs, //C
Rel, IndY, None, IndYW, ZeroX, ZeroX, ZeroX, ZeroX, Imp, AbsY, Imp, AbsYW, AbsX, AbsX, AbsXW, AbsXW, //D
Imm, IndX, Imm, IndX, Zero, Zero, Zero, Zero, Imp, Imm, Imp, Imm, Abs, Abs, Abs, Abs, //E
Rel, IndY, None, IndYW, ZeroX, ZeroX, ZeroX, ZeroX, Imp, AbsY, Imp, AbsYW, AbsX, AbsX, AbsXW, AbsXW, //F
};
uint8_t cycles[] {
7, 6, 2, 8, 3, 3, 5, 5, 3, 2, 2, 2, 4, 4, 6, 6,
2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7,
6, 6, 2, 8, 3, 3, 5, 5, 4, 2, 2, 2, 4, 4, 6, 6,
2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7,
6, 6, 2, 8, 3, 3, 5, 5, 3, 2, 2, 2, 3, 4, 6, 6,
2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7,
6, 6, 2, 8, 3, 3, 5, 5, 4, 2, 2, 2, 5, 4, 6, 6,
2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7,
2, 6, 2, 6, 3, 3, 3, 3, 2, 2, 2, 2, 4, 4, 4, 4,
2, 6, 2, 6, 4, 4, 4, 4, 2, 5, 2, 5, 5, 5, 5, 5,
2, 6, 2, 6, 3, 3, 3, 3, 2, 2, 2, 2, 4, 4, 4, 4,
2, 5, 2, 5, 4, 4, 4, 4, 2, 4, 2, 4, 4, 4, 4, 4,
2, 6, 2, 8, 3, 3, 5, 5, 2, 2, 2, 2, 4, 4, 6, 6,
2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7,
2, 6, 3, 8, 3, 3, 5, 5, 2, 2, 2, 2, 4, 4, 6, 6,
2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7,
};
uint8_t cyclesPageCrossed[] {
7, 6, 2, 8, 3, 3, 5, 5, 3, 2, 2, 2, 4, 4, 6, 6,
3, 6, 2, 8, 4, 4, 6, 6, 2, 5, 2, 7, 5, 5, 7, 7,
6, 6, 2, 8, 3, 3, 5, 5, 4, 2, 2, 2, 4, 4, 6, 6,
3, 6, 2, 8, 4, 4, 6, 6, 2, 5, 2, 7, 5, 5, 7, 7,
6, 6, 2, 8, 3, 3, 5, 5, 3, 2, 2, 2, 3, 4, 6, 6,
3, 6, 2, 8, 4, 4, 6, 6, 2, 5, 2, 7, 5, 5, 7, 7,
6, 6, 2, 8, 3, 3, 5, 5, 4, 2, 2, 2, 5, 4, 6, 6,
3, 6, 2, 8, 4, 4, 6, 6, 2, 5, 2, 7, 5, 5, 7, 7,
2, 6, 2, 6, 3, 3, 3, 3, 2, 2, 2, 2, 4, 4, 4, 4,
3, 6, 2, 6, 4, 4, 4, 4, 2, 5, 2, 5, 5, 5, 5, 5,
2, 6, 2, 6, 3, 3, 3, 3, 2, 2, 2, 2, 4, 4, 4, 4,
3, 6, 2, 5, 4, 4, 4, 4, 2, 5, 2, 5, 5, 5, 5, 5,
2, 6, 2, 8, 3, 3, 5, 5, 2, 2, 2, 2, 4, 4, 6, 6,
3, 6, 2, 8, 4, 4, 6, 6, 2, 5, 2, 7, 5, 5, 7, 7,
2, 6, 3, 8, 3, 3, 5, 5, 2, 2, 2, 2, 4, 4, 6, 6,
3, 6, 2, 8, 4, 4, 6, 6, 2, 5, 2, 7, 5, 5, 7, 7,
};
memcpy(_opTable, opTable, sizeof(opTable));
memcpy(_cycles, cycles, sizeof(cycles));
memcpy(_addrMode, addrMode, sizeof(addrMode));
memcpy(_cyclesPageCrossed, cyclesPageCrossed, sizeof(cyclesPageCrossed));
}
void CPU::Reset(bool softReset)
@ -96,7 +58,6 @@ void CPU::Reset(bool softReset)
_state.IRQFlag = 0;
_cycleCount = 0;
_relativeCycleCount = 0;
_cyclePenalty = 0;
_state.PC = MemoryReadWord(CPU::ResetVector);
if(softReset) {
@ -116,11 +77,8 @@ void CPU::Reset(bool softReset)
uint32_t CPU::Exec()
{
//static ofstream log("log.txt", ios::out | ios::binary);
uint32_t executedCycles = 0;
if(!_runNMI && !_runIRQ) {
uint8_t opCode = GetOPCode();
if(_state.NMIFlag) {
_runNMI = true;
} else if(opCode != 0x40 && _state.IRQFlag > 0 && !CheckFlag(PSFlags::Interrupt)) {
@ -128,14 +86,12 @@ uint32_t CPU::Exec()
}
_instAddrMode = _addrMode[opCode];
_operand = FetchOperand();
if(_opTable[opCode] != nullptr) {
//std::cout << std::hex << (_state.PC - 1) << ": " << (short)opCode << std::endl;
(this->*_opTable[opCode])();
executedCycles = (IsPageCrossed() ? _cyclesPageCrossed[opCode] : _cycles[opCode]);
} else {
GetOperandAddr();
std::cout << "Invalid opcode: " << std::hex << (short)opCode;
//throw exception("Invalid opcode");
}
if(!_runIRQ && opCode == 0x40 && _state.IRQFlag > 0 && !CheckFlag(PSFlags::Interrupt)) {
@ -151,12 +107,9 @@ uint32_t CPU::Exec()
IRQ();
}
_runIRQ = false;
executedCycles = 7;
}
_cycleCount += executedCycles;
return executedCycles + GetCyclePenalty();
return _cycleCount;
}
void CPU::EndFrame()
@ -165,6 +118,28 @@ void CPU::EndFrame()
_cycleCount = 0;
}
void CPU::RunDMATransfer(uint8_t* spriteRAM, uint32_t &spriteRamAddr, uint8_t offsetValue)
{
//"the DMA procedure takes 513 CPU cycles (+1 on odd CPU cycles)"
if((CPU::GetRelativeCycleCount() + Instance->_cycleCount) % 2 != 0) {
Instance->_cycleCount++;
}
Instance->_cycleCount++;
//DMA transfer starts at SpriteRamAddr and wraps around
for(int i = 0; i < 0x100; i++) {
//Read value
uint8_t readValue = Instance->_memoryManager->Read(offsetValue*0x100 + i);
Instance->_cycleCount++;
//Write to ram
spriteRAM[(spriteRamAddr+i) & 0xFF] = readValue;
PPU::ExecStatic();
Instance->_cycleCount++;
}
}
void CPU::StreamState(bool saving)
{
Stream<uint16_t>(_state.PC);

View file

@ -59,7 +59,7 @@ private:
int32_t _cycleCount;
int32_t _relativeCycleCount;
uint32_t _cyclePenalty;
uint16_t _operand;
Func _opTable[256];
uint8_t _cycles[256];
@ -77,10 +77,17 @@ private:
uint8_t GetOPCode()
{
uint8_t value = _memoryManager->Read(_state.PC, true);
_cycleCount++;
_state.PC++;
return value;
}
void DummyRead()
{
_memoryManager->Read(_state.PC, false);
_cycleCount++;
}
uint8_t ReadByte()
{
return MemoryRead(_state.PC++);
@ -132,14 +139,19 @@ private:
void MemoryWrite(uint16_t addr, uint8_t value)
{
_memoryManager->Write(addr, value);
_cycleCount++;
}
uint8_t MemoryRead(uint16_t addr) {
return _memoryManager->Read(addr);
uint8_t value = _memoryManager->Read(addr);
_cycleCount++;
return value;
}
uint16_t MemoryReadWord(uint16_t addr) {
return _memoryManager->ReadWord(addr);
uint16_t value = _memoryManager->ReadWord(addr);
_cycleCount+=2;
return value;
}
void SetRegister(uint8_t &reg, uint8_t value) {
@ -183,40 +195,56 @@ private:
uint16_t PC() { return _state.PC; }
void SetPC(uint16_t value) { _state.PC = value; }
uint16_t GetOperandAddr()
uint16_t FetchOperand()
{
switch(_instAddrMode) {
case AddrMode::Acc:
case AddrMode::Imp: DummyRead(); return 0;
case AddrMode::Imm:
case AddrMode::Rel: return GetImmediate();
case AddrMode::Zero: return GetZeroAddr();
case AddrMode::ZeroX: return GetZeroXAddr();
case AddrMode::ZeroY: return GetZeroYAddr();
case AddrMode::Ind: return GetIndAddr();
case AddrMode::IndX: return GetIndXAddr();
case AddrMode::IndY: return GetIndYAddr(false);
case AddrMode::IndYW: return GetIndYAddr(true);
case AddrMode::Abs: return GetAbsAddr();
case AddrMode::AbsX: return GetAbsXAddr(false);
case AddrMode::AbsXW: return GetAbsXAddr(true);
case AddrMode::AbsY: return GetAbsYAddr(false);
case AddrMode::AbsYW: return GetAbsYAddr(true);
case AddrMode::Imm: return GetImmediate();
case AddrMode::IndX: return GetIndXAddr();
case AddrMode::IndY: return GetIndYAddr(false);
case AddrMode::IndYW: return GetIndYAddr(true);
case AddrMode::Zero: return GetZeroAddr();
case AddrMode::ZeroX: return GetZeroXAddr();
case AddrMode::ZeroY: return GetZeroYAddr();
}
return 0;
throw new exception();
}
uint8_t GetOperand()
uint16_t GetOperand()
{
uint16_t addr = GetOperandAddr();
return _operand;
}
if(_instAddrMode != AddrMode::Imm) {
return MemoryRead(addr);
uint8_t GetOperandValue()
{
if(_instAddrMode >= AddrMode::Zero) {
return MemoryRead(GetOperand());
} else {
return (uint8_t)addr;
return (uint8_t)GetOperand();
}
}
uint16_t GetIndAddr() { return ReadWord(); }
uint8_t GetImmediate() { return ReadByte(); }
uint8_t GetZeroAddr() { return ReadByte(); }
uint8_t GetZeroXAddr() { return ReadByte() + X(); }
uint8_t GetZeroYAddr() { return ReadByte() + Y(); }
uint8_t GetZeroXAddr() {
uint8_t value = ReadByte();
MemoryRead(value); //Dummy read
return value + X();
}
uint8_t GetZeroYAddr() {
uint8_t value = ReadByte();
MemoryRead(value); //Dummy read
return value + Y();
}
uint16_t GetAbsAddr() { return ReadWord(); }
uint16_t GetAbsXAddr(bool dummyRead = true) {
@ -243,7 +271,7 @@ private:
}
uint16_t GetInd() {
uint16_t addr = ReadWord();
uint16_t addr = GetOperand();
if((addr & 0xFF) == 0xFF) {
auto lo = MemoryRead(addr);
auto hi = MemoryRead(addr - 0xFF);
@ -288,9 +316,9 @@ private:
return addr + Y();
}
void AND() { SetA(A() & GetOperand()); }
void EOR() { SetA(A() ^ GetOperand()); }
void ORA() { SetA(A() | GetOperand()); }
void AND() { SetA(A() & GetOperandValue()); }
void EOR() { SetA(A() ^ GetOperandValue()); }
void ORA() { SetA(A() | GetOperandValue()); }
void ADD(uint8_t value)
{
@ -307,8 +335,8 @@ private:
SetA((uint8_t)result);
}
void ADC() { ADD(GetOperand()); }
void SBC() { ADD(GetOperand() ^ 0xFF); }
void ADC() { ADD(GetOperandValue()); }
void SBC() { ADD(GetOperandValue() ^ 0xFF); }
void CMP(uint8_t reg, uint8_t value)
{
@ -327,13 +355,13 @@ private:
}
}
void CPA() { CMP(A(), GetOperand()); }
void CPX() { CMP(X(), GetOperand()); }
void CPY() { CMP(Y(), GetOperand()); }
void CPA() { CMP(A(), GetOperandValue()); }
void CPX() { CMP(X(), GetOperandValue()); }
void CPY() { CMP(Y(), GetOperandValue()); }
void INC()
{
uint16_t addr = GetOperandAddr();
uint16_t addr = GetOperand();
ClearFlags(PSFlags::Negative | PSFlags::Zero);
uint8_t value = MemoryRead(addr);
@ -346,7 +374,7 @@ private:
void DEC()
{
uint16_t addr = GetOperandAddr();
uint16_t addr = GetOperand();
ClearFlags(PSFlags::Negative | PSFlags::Zero);
uint8_t value = MemoryRead(addr);
MemoryWrite(addr, value); //Dummy write
@ -405,28 +433,28 @@ private:
}
void ASLAddr() {
uint16_t addr = GetOperandAddr();
uint16_t addr = GetOperand();
uint8_t value = MemoryRead(addr);
MemoryWrite(addr, value); //Dummy write
MemoryWrite(addr, ASL(value));
}
void LSRAddr() {
uint16_t addr = GetOperandAddr();
uint16_t addr = GetOperand();
uint8_t value = MemoryRead(addr);
MemoryWrite(addr, value); //Dummy write
MemoryWrite(addr, LSR(value));
}
void ROLAddr() {
uint16_t addr = GetOperandAddr();
uint16_t addr = GetOperand();
uint8_t value = MemoryRead(addr);
MemoryWrite(addr, value); //Dummy write
MemoryWrite(addr, ROL(value));
}
void RORAddr() {
uint16_t addr = GetOperandAddr();
uint16_t addr = GetOperand();
uint8_t value = MemoryRead(addr);
MemoryWrite(addr, value); //Dummy write
MemoryWrite(addr, ROR(value));
@ -437,17 +465,19 @@ private:
}
void BranchRelative(bool branch) {
int8_t offset = GetImmediate();
int8_t offset = (int8_t)GetOperand();
if(branch) {
CheckPageCrossed(PC(), offset);
IncCycleCount(1);
if(CheckPageCrossed(PC(), offset)) {
DummyRead();
}
DummyRead();
SetPC(PC() + offset);
}
}
void BIT() {
uint8_t value = GetOperand();
uint8_t value = GetOperandValue();
ClearFlags(PSFlags::Zero | PSFlags::Overflow | PSFlags::Negative);
if((A() & value) == 0) {
SetFlags(PSFlags::Zero);
@ -466,20 +496,14 @@ private:
return pageCrossed;
}
uint32_t GetCyclePenalty() {
uint32_t cyclePenalty = _cyclePenalty;
_cyclePenalty = 0;
return cyclePenalty;
}
#pragma region OP Codes
void LDA() { SetA(GetOperand()); }
void LDX() { SetX(GetOperand()); }
void LDY() { SetY(GetOperand()); }
void LDA() { SetA(GetOperandValue()); }
void LDX() { SetX(GetOperandValue()); }
void LDY() { SetY(GetOperandValue()); }
void STA() { MemoryWrite(GetOperandAddr(), A()); }
void STX() { MemoryWrite(GetOperandAddr(), X()); }
void STY() { MemoryWrite(GetOperandAddr(), Y()); }
void STA() { MemoryWrite(GetOperand(), A()); }
void STX() { MemoryWrite(GetOperand(), X()); }
void STY() { MemoryWrite(GetOperand(), Y()); }
void TAX() { SetX(A()); }
void TAY() { SetY(A()); }
@ -493,8 +517,14 @@ private:
uint8_t flags = PS() | PSFlags::Break;
Push((uint8_t)flags);
}
void PLA() { SetA(Pop()); }
void PLP() { SetPS(Pop()); }
void PLA() {
DummyRead();
SetA(Pop());
}
void PLP() {
DummyRead();
SetPS(Pop());
}
void INX() { SetX(X() + 1); }
void INY() { SetY(Y() + 1); }
@ -515,16 +545,19 @@ private:
void ROR_Memory() { RORAddr(); }
void JMP_Abs() {
JMP(GetAbsAddr());
JMP(GetOperand());
}
void JMP_Ind() { JMP(GetInd()); }
void JSR() {
uint16_t addr = GetAbsAddr();
uint16_t addr = GetOperand();
DummyRead();
Push((uint16_t)(PC() - 1));
JMP(addr);
}
void RTS() {
uint16_t addr = PopWord();
DummyRead();
DummyRead();
SetPC(addr + 1);
}
@ -587,6 +620,8 @@ private:
}
void NMI() {
DummyRead(); //fetch opcode (and discard it - $00 (BRK) is forced into the opcode register instead)
DummyRead(); //read next instruction byte (actually the same as above, since PC increment is suppressed. Also discarded.)
Push((uint16_t)(PC()));
Push((uint8_t)PS());
SetFlags(PSFlags::Interrupt);
@ -594,6 +629,8 @@ private:
}
void IRQ() {
DummyRead(); //fetch opcode (and discard it - $00 (BRK) is forced into the opcode register instead)
DummyRead(); //read next instruction byte (actually the same as above, since PC increment is suppressed. Also discarded.)
Push((uint16_t)(PC()));
if(_state.NMIFlag) {
@ -609,14 +646,14 @@ private:
}
void RTI() {
DummyRead();
SetPS(Pop());
SetPC(PopWord());
}
void NOP() {
GetOperand();
}
#pragma endregion
protected:
@ -628,14 +665,11 @@ public:
CPU(MemoryManager *memoryManager);
static int32_t GetCycleCount() { return CPU::Instance->_cycleCount; }
static int32_t GetRelativeCycleCount() { return CPU::Instance->_relativeCycleCount + CPU::Instance->_cycleCount; }
static void IncCycleCount(uint32_t cycles) {
CPU::Instance->_cyclePenalty += cycles;
CPU::Instance->_cycleCount += cycles;
}
static void SetNMIFlag() { CPU::Instance->_state.NMIFlag = true; }
static void ClearNMIFlag() { CPU::Instance->_state.NMIFlag = false; }
static void SetIRQSource(IRQSource source) { CPU::Instance->_state.IRQFlag |= (int)source; }
static void ClearIRQSource(IRQSource source) { CPU::Instance->_state.IRQFlag &= ~(int)source; }
static void RunDMATransfer(uint8_t* spriteRAM, uint32_t &spriteRamAddr, uint8_t offsetValue);
void Reset(bool softReset);
uint32_t Exec();

View file

@ -159,13 +159,10 @@ void Console::Run()
Console::RunningLock.Acquire();
while(true) {
uint32_t executedCycles = _cpu->Exec();
_ppu->Exec();
bool frameDone = _apu->Exec(executedCycles);
bool frameDone = _apu->Exec(_cpu->Exec());
if(frameDone) {
_cpu->EndFrame();
_ppu->EndFrame();
if(CheckFlag(EmulationFlags::LimitFPS) && frameDone) {
elapsedTime = clockTimer.GetElapsedMS();
@ -273,12 +270,8 @@ bool Console::RunTest(uint8_t *expectedResult)
Console::RunningLock.Acquire();
while(true) {
uint32_t executedCycles = _cpu->Exec();
_ppu->Exec();
if(_apu->Exec(executedCycles)) {
if(_apu->Exec(_cpu->Exec())) {
_cpu->EndFrame();
_ppu->EndFrame();
}
if(timer.GetElapsedMS() > 100) {

View file

@ -59,18 +59,12 @@ void MemoryManager::WriteRegister(uint16_t addr, uint8_t value)
uint8_t MemoryManager::ReadMappedVRAM(uint16_t addr)
{
if(_vramReadHandlers[addr]) {
return _vramReadHandlers[addr]->ReadVRAM(addr);
} else {
return 0;
}
return _mapper->ReadVRAM(addr);
}
void MemoryManager::WriteMappedVRAM(uint16_t addr, uint8_t value)
{
if(_vramWriteHandlers[addr]) {
_vramWriteHandlers[addr]->WriteVRAM(addr, value);
}
return _mapper->WriteVRAM(addr, value);
}
void MemoryManager::InitializeMemoryHandlers(IMemoryHandler** memoryHandlers, IMemoryHandler* handler, vector<uint16_t> *addresses)
@ -115,7 +109,7 @@ uint8_t MemoryManager::Read(uint16_t addr, bool forExecution)
Debugger::CheckBreakpoint(forExecution ? BreakpointType::Execute : BreakpointType::Read, addr);
uint8_t value;
PPU::ExecStatic(3);
PPU::ExecStatic();
if(addr <= 0x1FFF) {
value = _internalRAM[addr & 0x07FF];
} else {
@ -128,7 +122,7 @@ void MemoryManager::Write(uint16_t addr, uint8_t value)
{
Debugger::CheckBreakpoint(BreakpointType::Write, addr);
PPU::ExecStatic(3);
PPU::ExecStatic();
if(addr <= 0x1FFF) {
_internalRAM[addr & 0x07FF] = value;
} else {
@ -143,24 +137,20 @@ uint16_t MemoryManager::ReadWord(uint16_t addr)
return lo | hi << 8;
}
void MemoryManager::ProcessVRAMAccess(uint16_t &addr)
{
addr &= 0x3FFF;
if(addr >= 0x3000) {
//Need to mirror 0x3000 writes to 0x2000, this appears to be how hardware behaves
//Required for proper MMC3 IRQ timing in Burai Fighter
addr -= 0x1000;
}
_mapper->NotifyVRAMAddressChange(addr);
}
uint8_t MemoryManager::ReadVRAM(uint16_t addr)
{
ProcessVRAMAccess(addr);
addr &= 0x3FFF;
if(addr <= 0x1FFF) {
return ReadMappedVRAM(addr & 0x1FFF);
_mapper->NotifyVRAMAddressChange(addr);
return ReadMappedVRAM(addr);
} else {
if(addr >= 0x3000) {
//Need to mirror 0x3000 writes to 0x2000, this appears to be how hardware behaves
//Required for proper MMC3 IRQ timing in Burai Fighter
addr -= 0x1000;
}
_mapper->NotifyVRAMAddressChange(addr);
switch(_mapper->GetMirroringType()) {
case MirroringType::Vertical:
return _nametableRAM[(addr&0x400)>>10][addr & 0x3FF];
@ -178,17 +168,23 @@ uint8_t MemoryManager::ReadVRAM(uint16_t addr)
case MirroringType::ScreenBOnly:
return _nametableRAM[1][addr & 0x3FF];
}
}
}
void MemoryManager::WriteVRAM(uint16_t addr, uint8_t value)
{
ProcessVRAMAccess(addr);
addr &= 0x3FFF;
if(addr <= 0x1FFF) {
_mapper->NotifyVRAMAddressChange(addr);
WriteMappedVRAM(addr, value);
} else {
if(addr >= 0x3000) {
//Need to mirror 0x3000 writes to 0x2000, this appears to be how hardware behaves
//Required for proper MMC3 IRQ timing in Burai Fighter
addr -= 0x1000;
}
_mapper->NotifyVRAMAddressChange(addr);
switch(_mapper->GetMirroringType()) {
case MirroringType::Vertical:
_nametableRAM[(addr&0x400)>>10][addr & 0x3FF] = value;

View file

@ -34,8 +34,6 @@ class MemoryManager: public Snapshotable
uint8_t ReadMappedVRAM(uint16_t addr);
void WriteMappedVRAM(uint16_t addr, uint8_t value);
void ProcessVRAMAccess(uint16_t &addr);
protected:
void StreamState(bool saving);

View file

@ -46,7 +46,6 @@ void PPU::Reset()
_scanline = 0;
_cycle = 0;
_frameCount = 0;
_cycleCount = 0;
_memoryReadBuffer = 0;
memset(_spriteRAM, 0xFF, 0x100);
@ -154,13 +153,7 @@ void PPU::WriteRAM(uint16_t addr, uint8_t value)
UpdateVideoRamAddr();
break;
case PPURegisters::SpriteDMA:
//DMA transfer starts at SpriteRamAddr and wraps around
for(int i = 0; i < 0x100; i++) {
_spriteRAM[(_state.SpriteRamAddr+i)&0xFF] = _memoryManager->Read(value*0x100 + i);
}
//"the DMA procedure takes 513 CPU cycles (+1 on odd CPU cycles)"
CPU::IncCycleCount((CPU::GetCycleCount() % 2 == 0) ? 513 : 514);
CPU::RunDMATransfer(_spriteRAM, _state.SpriteRamAddr, value);
break;
}
}
@ -399,21 +392,20 @@ void PPU::DrawPixel()
//This is called 3.7 million times per second - needs to be as fast as possible.
uint8_t offset = _state.XScroll;
bool useBackground = true;
uint32_t backgroundColor = 0;
uint32_t spriteColor = 0;
uint32_t &pixel = (((uint32_t*)_outputBuffer)[(_scanline << 8) + _cycle - 1]);
if((_cycle > 8 || _flags.BackgroundMask) && _flags.BackgroundEnabled) {
//BackgroundMask = false: Hide background in leftmost 8 pixels of screen
backgroundColor = (((_state.LowBitShift << offset) & 0x8000) >> 15) | (((_state.HighBitShift << offset) & 0x8000) >> 14);
}
uint8_t i;
if((_cycle > 8 || _flags.SpriteMask) && _flags.SpritesEnabled) {
//SpriteMask = true: Hide sprites in leftmost 8 pixels of screen
for(i = 0; i < _spriteCount; i++) {
for(uint8_t i = 0; i < _spriteCount; i++) {
int32_t shift = -((int32_t)_spriteX[i] - (int32_t)_cycle + 1);
if(shift >= 0 && shift < 8) {
uint32_t spriteColor;
if(_spriteTiles[i].HorizontalMirror) {
spriteColor = ((_spriteTiles[i].LowByte >> shift) & 0x01) | ((_spriteTiles[i].HighByte >> shift) & 0x01) << 1;
} else {
@ -424,7 +416,7 @@ void PPU::DrawPixel()
//First sprite without a 00 color, use it.
if(backgroundColor == 0 || !_spriteTiles[i].BackgroundPriority) {
//Check sprite priority
useBackground = false;
pixel = PPU_PALETTE_RGB[GetSpritePaletteEntry(_spriteTiles[i].PaletteOffset, spriteColor)];
}
if(i == 0 && backgroundColor != 0 && _sprite0Visible && _cycle != 256 && _flags.BackgroundEnabled) {
@ -434,22 +426,12 @@ void PPU::DrawPixel()
//"Should always miss when Y >= 239"
_statusFlags.Sprite0Hit = true;
}
break;
return;
}
}
}
}
uint32_t bufferPosition = _scanline * 256 + (_cycle - 1);
if(useBackground) {
// If we're grabbing the pixel from the high part of the shift register, use the previous tile's palette, not the current one
((uint32_t*)_outputBuffer)[bufferPosition] = PPU_PALETTE_RGB[GetBGPaletteEntry(offset + ((_cycle - 1) % 8) < 8 ? _previousTile.PaletteOffset : _currentTile.PaletteOffset, backgroundColor)];
} else {
((uint32_t*)_outputBuffer)[bufferPosition] = PPU_PALETTE_RGB[GetSpritePaletteEntry(_spriteTiles[i].PaletteOffset, spriteColor)];
}
//Shift the tile registers to prepare for the next cycle
ShiftTileRegisters();
pixel = PPU_PALETTE_RGB[GetBGPaletteEntry(offset + ((_cycle - 1) % 8) < 8 ? _previousTile.PaletteOffset : _currentTile.PaletteOffset, backgroundColor)];
}
void PPU::ProcessPreVBlankScanline()
@ -457,13 +439,13 @@ void PPU::ProcessPreVBlankScanline()
//For pre-render scanline & all visible scanlines
if(IsRenderingEnabled()) {
//Update video ram address according to scrolling logic
if(_cycle == 256) {
if((_cycle > 0 && _cycle < 256 && _cycle % 8 == 0) || _cycle == 328 || _cycle == 336) {
IncHorizontalScrolling();
} else if(_cycle == 256) {
IncVerticalScrolling();
} else if(_cycle == 257) {
//copy horizontal scrolling value from t
_state.VideoRamAddr = (_state.VideoRamAddr & ~0x041F) | (_state.TmpVideoRamAddr & 0x041F);
} else if((_cycle % 8 == 0 && _cycle > 0 && _cycle < 256) || _cycle == 328 || _cycle == 336) {
IncHorizontalScrolling();
}
}
@ -477,7 +459,7 @@ void PPU::ProcessPrerenderScanline()
{
ProcessPreVBlankScanline();
if(_cycle == 0) {
if(_cycle == 1) {
_statusFlags.SpriteOverflow = false;
_statusFlags.Sprite0Hit = false;
_statusFlags.VerticalBlank = false;
@ -520,6 +502,7 @@ void PPU::ProcessVisibleScanline()
}
DrawPixel();
ShiftTileRegisters();
if(IsRenderingEnabled()) {
CopyOAMData();
@ -527,9 +510,12 @@ void PPU::ProcessVisibleScanline()
if(_cycle == 256 && _scanline == 239) {
//Send frame to GUI once the last pixel has been output
PPU::VideoDevice->UpdateFrame(_outputBuffer);
if(PPU::VideoDevice) {
PPU::VideoDevice->UpdateFrame(_outputBuffer);
}
}
} else if((_cycle - 261) % 8 == 0 && _cycle <= 320) {
//Cycle 261, 269, etc.
uint32_t spriteIndex = (_cycle - 261) / 8;
LoadSpriteTileInfo(spriteIndex);
} else if(_cycle == 321 || _cycle == 329) {
@ -615,7 +601,7 @@ void PPU::CopyOAMData()
void PPU::BeginVBlank()
{
if(_cycle == 0) {
if(_cycle == 1) {
if(!_doNotSetVBFlag) {
_statusFlags.VerticalBlank = true;
if(_flags.VBlank) {
@ -633,39 +619,34 @@ void PPU::EndVBlank()
}
}
void PPU::Exec(uint32_t extraCycles)
void PPU::Exec()
{
int32_t gap = CPU::GetCycleCount() * 3 - _cycleCount;
if(gap < 0) {
gap = 0;
if(_scanline != -1 && _scanline < 240) {
ProcessVisibleScanline();
} else if(_scanline == -1) {
ProcessPrerenderScanline();
} else if(_scanline == 241) {
BeginVBlank();
} else if(_scanline == 260) {
EndVBlank();
}
gap += extraCycles;
_cycleCount += gap;
while(gap > 0) {
if(_scanline == -1) {
ProcessPrerenderScanline();
} else if(_scanline < 240) {
ProcessVisibleScanline();
} else if(_scanline == 241) {
BeginVBlank();
} else if(_scanline == 260) {
EndVBlank();
if(_cycle == 340) {
_cycle = -1;
_scanline++;
if(_scanline == 261) {
_scanline = -1;
}
if(_cycle == 340) {
_cycle = 0;
_scanline++;
if(_scanline == 261) {
_scanline = -1;
}
} else {
_cycle++;
}
gap--;
}
_cycle++;
}
void PPU::ExecStatic()
{
PPU::Instance->Exec();
PPU::Instance->Exec();
PPU::Instance->Exec();
}
void PPU::StreamState(bool saving)
@ -703,7 +684,6 @@ void PPU::StreamState(bool saving)
Stream<int32_t>(_scanline);
Stream<uint32_t>(_cycle);
Stream<uint32_t>(_frameCount);
Stream<int32_t>(_cycleCount);
Stream<uint8_t>(_memoryReadBuffer);
StreamArray<uint8_t>(_paletteRAM, 0x100);

View file

@ -124,7 +124,7 @@ class PPU : public IMemoryHandler, public Snapshotable
bool _writeOAMData;
uint32_t _overflowCounter;
bool _sprite0Added;
void UpdateStatusFlag();
void SetControlRegister(uint8_t value);
@ -193,7 +193,7 @@ class PPU : public IMemoryHandler, public Snapshotable
uint8_t ReadRAM(uint16_t addr);
void WriteRAM(uint16_t addr, uint8_t value);
void Exec(uint32_t extraCycles = 0);
void Exec();
static void RegisterVideoDevice(IVideoDevice *videoDevice)
{
@ -225,13 +225,5 @@ class PPU : public IMemoryHandler, public Snapshotable
return PPU::Instance->_scanline;
}
static void ExecStatic(uint32_t cycles)
{
PPU::Instance->Exec(cycles);
}
void EndFrame()
{
_cycleCount = 0;
}
static void ExecStatic();
};

18
NES.sln
View file

@ -24,6 +24,11 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "InteropDLL", "InteropDLL\In
{78FEF1A1-6DF1-4CBB-A373-AE6FA7CE5CE0} = {78FEF1A1-6DF1-4CBB-A373-AE6FA7CE5CE0}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PGOHelper", "PGOHelper\PGOHelper.vcxproj", "{38D74EE1-5276-4D24-AABC-104B912A27D2}"
ProjectSection(ProjectDependencies) = postProject
{37749BB2-FA78-4EC9-8990-5628FC0BBA19} = {37749BB2-FA78-4EC9-8990-5628FC0BBA19}
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -84,8 +89,21 @@ Global
{37749BB2-FA78-4EC9-8990-5628FC0BBA19}.Release|Mixed Platforms.Build.0 = Release|Win32
{37749BB2-FA78-4EC9-8990-5628FC0BBA19}.Release|Win32.ActiveCfg = Release|Win32
{37749BB2-FA78-4EC9-8990-5628FC0BBA19}.Release|Win32.Build.0 = Release|Win32
{38D74EE1-5276-4D24-AABC-104B912A27D2}.Debug|Any CPU.ActiveCfg = Debug|Win32
{38D74EE1-5276-4D24-AABC-104B912A27D2}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
{38D74EE1-5276-4D24-AABC-104B912A27D2}.Debug|Mixed Platforms.Build.0 = Debug|Win32
{38D74EE1-5276-4D24-AABC-104B912A27D2}.Debug|Win32.ActiveCfg = Debug|Win32
{38D74EE1-5276-4D24-AABC-104B912A27D2}.Debug|Win32.Build.0 = Debug|Win32
{38D74EE1-5276-4D24-AABC-104B912A27D2}.Release|Any CPU.ActiveCfg = Release|Win32
{38D74EE1-5276-4D24-AABC-104B912A27D2}.Release|Mixed Platforms.ActiveCfg = Release|Win32
{38D74EE1-5276-4D24-AABC-104B912A27D2}.Release|Mixed Platforms.Build.0 = Release|Win32
{38D74EE1-5276-4D24-AABC-104B912A27D2}.Release|Win32.ActiveCfg = Release|Win32
{38D74EE1-5276-4D24-AABC-104B912A27D2}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(Performance) = preSolution
HasPerformanceSessions = true
EndGlobalSection
EndGlobal

14
PGOHelper/PGOHelper.cpp Normal file
View file

@ -0,0 +1,14 @@
#include <tchar.h>
extern "C" {
void __stdcall LoadROM(wchar_t* filename);
void __stdcall Run();
}
int _tmain(int argc, _TCHAR* argv[])
{
LoadROM(argv[1]);
Run();
return 0;
}

View file

@ -0,0 +1,94 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{38D74EE1-5276-4D24-AABC-104B912A27D2}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>PGOHelper</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="PGOHelper.cpp" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\InteropDLL\InteropDLL.vcxproj">
<Project>{37749bb2-fa78-4ec9-8990-5628fc0bba19}</Project>
<Private>false</Private>
<ReferenceOutputAssembly>true</ReferenceOutputAssembly>
<CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies>
<LinkLibraryDependencies>true</LinkLibraryDependencies>
<UseLibraryDependencyInputs>true</UseLibraryDependencyInputs>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View file

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="PGOHelper.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>