commit 4c5dbdcb42aeda46186fc1c6595f15d3992afd3b Author: Souryo Date: Tue Jun 10 16:58:37 2014 -0400 Initial commit diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..1ff0c423 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..1bc915c5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,156 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results + +[Dd]ebug/ +[Rr]elease/ +x64/ +build/ +[Bb]in/ +[Oo]bj/ + +# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets +!packages/*/build/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.log +*.scc + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +*.ncrunch* +.*crunch*.local.xml + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.Publish.xml + +# NuGet Packages Directory +## TODO: If you have NuGet Package Restore enabled, uncomment the next line +#packages/ + +# Windows Azure Build Output +csx +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.[Pp]ublish.xml +*.pfx +*.publishsettings + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file to a newer +# Visual Studio version. Backup files are not needed, because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +App_Data/*.mdf +App_Data/*.ldf + + +#LightSwitch generated files +GeneratedArtifacts/ +_Pvt_Extensions/ +ModelManifest.xml + +# ========================= +# Windows detritus +# ========================= + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Mac desktop service store files +.DS_Store diff --git a/6502_functional_test.bin b/6502_functional_test.bin new file mode 100644 index 00000000..8a20227a Binary files /dev/null and b/6502_functional_test.bin differ diff --git a/CPU.cpp b/CPU.cpp new file mode 100644 index 00000000..475bb754 --- /dev/null +++ b/CPU.cpp @@ -0,0 +1,40 @@ +#include "stdafx.h" +#include "CPU.h" +#include "Timer.h" + +void Core::Reset() +{ + _state.A = 0; + _state.PC = 0x0400; + _state.SP = 0xFF; + _state.X = 0; + _state.Y = 0; + _state.PS = PSFlags::Zero | PSFlags::Reserved;// | PSFlags::Interrupt; +} + +void Core::Exec() +{ + uint16_t lastPC = 65535; + int executedCount = 0; + std::list pcList; + + Timer timer; + while(true) { + _currentPC = _state.PC; + uint8_t opCode = ReadByte(); + if(_opTable[opCode] != 0) { + (this->*_opTable[opCode])(); + } else { + std::cout << "Invalid opcode: PC:" << _currentPC << std::endl; + } + lastPC = _currentPC; + executedCount++; + + if(executedCount >= 200000000) { + break; + } + } + + std::cout << "Executed:" << executedCount << " in " << timer.GetElapsedMS() << " ms"; +} + diff --git a/CPU.h b/CPU.h new file mode 100644 index 00000000..6e214c0b --- /dev/null +++ b/CPU.h @@ -0,0 +1,736 @@ +#include "stdafx.h" + +namespace PSFlags +{ + enum PSFlags : uint8_t + { + Carry = 0x01, + Zero = 0x02, + Interrupt = 0x04, + Decimal = 0x08, + Break = 0x10, + Reserved = 0x20, + Overflow = 0x40, + Negative = 0x80 + }; +} + +struct State +{ + uint16_t PC; + uint8_t SP; + uint8_t A; + uint8_t X; + uint8_t Y; + uint8_t PS; +}; + +class Core +{ +private: + typedef void(Core::*Func)(); + + Func _opTable[256]; + State _state; + int8_t* _memory; + uint16_t _currentPC; + + inline uint8_t Core::ReadByte() + { + return _memory[_state.PC++]; + } + + uint16_t Core::ReadWord() + { + uint16_t value = (uint16_t)(((uint8_t)_memory[_state.PC] | (((uint8_t)_memory[_state.PC + 1]) << 8))); + _state.PC += 2; + return value; + } + + void ClearFlags(uint8_t flags) + { + _state.PS &= ~flags; + } + + uint16_t lastNegative = 0; + void SetFlags(uint8_t flags) + { + if(flags & PSFlags::Negative) { + lastNegative = _state.PC; + } + _state.PS |= flags; + } + + bool CheckFlag(uint8_t flag) + { + return (_state.PS & flag) == flag; + } + + void SetZeroNegativeFlags(uint8_t value) + { + if(value == 0) { + SetFlags(PSFlags::Zero); + } else if(value & 0x80) { + SetFlags(PSFlags::Negative); + } + } + + void MemoryWrite(uint16_t addr, uint8_t value) + { + //SetZeroNegativeFlags(value); + _memory[addr] = value; + if(addr == 0x200) { + std::cout << "------------------" << std::endl; + std::cout << "TEST NUMBER: " << std::dec << (int)value << std::endl; + std::cout << "------------------" << std::endl; + } else { + //std::cout << "(0x" << std::hex << (short)_currentPC << ") W: 0x" << std::hex << (short)addr << " = 0x" << std::hex << (short)value << std::endl; + } + } + + uint8_t MemoryRead(uint16_t addr) { + //std::cout << "\t\t\t\t(0x" << std::hex << (short)_currentPC << ") R: 0x" << std::hex << (short)addr << " = 0x" << std::hex << (short)_memory[addr] << std::endl; + return _memory[addr]; + } + + uint16_t MemoryReadWord(uint16_t addr) { + return (_memory[addr] | (_memory[addr + 1] << 8)); + } + + void SetRegister(uint8_t ®, int8_t value) { + ClearFlags(PSFlags::Zero | PSFlags::Negative); + SetZeroNegativeFlags(value); + reg = value; + } + + void Push(uint8_t value) { + _memory[SP() + 0x100] = value; + SetSP(SP() - 1); + } + + void Push(uint16_t value) { + Push((uint8_t)(value >> 8)); + Push((uint8_t)value); + } + + uint8_t Pop() { + SetSP(SP() + 1); + int8_t value = _memory[0x100 + SP()]; + return value; + } + + uint16_t PopWord() { + return Pop() | (Pop() << 8); + } + + uint8_t A() { return _state.A; } + void SetA(uint8_t value) { SetRegister(_state.A, value); } + uint8_t X() { return _state.X; } + void SetX(uint8_t value) { SetRegister(_state.X, value); } + uint8_t Y() { return _state.Y; } + void SetY(uint8_t value) { SetRegister(_state.Y, value); } + uint8_t SP() { return _state.SP; } + void SetSP(uint8_t value) { _state.SP = value; } + uint8_t PS() { return _state.PS; } + void SetPS(uint8_t value) { _state.PS = value | PSFlags::Reserved; } + uint16_t PC() { return _state.PC; } + void SetPC(uint16_t value) { _state.PC = value; } + + uint8_t GetImmediate() { return ReadByte(); } + uint8_t GetZero() { return MemoryRead(GetZeroAddr()); } + uint8_t GetZeroAddr() { return ReadByte(); } + + uint8_t GetZeroX() { return MemoryRead(GetZeroXAddr()); } + uint8_t GetZeroXAddr() { return ReadByte() + X(); } + + int8_t GetZeroY() { return MemoryRead(GetZeroYAddr()); } + int8_t GetZeroYAddr() { return ReadByte() + Y(); } + + + int8_t GetAbs() { return MemoryRead(GetAbsAddr()); } + uint16_t GetAbsAddr() { return ReadWord(); } + + int8_t GetAbsX() { return MemoryRead(GetAbsXAddr()); } + uint16_t GetAbsXAddr() { + return ReadWord() + X(); + } + + int8_t GetAbsY() { return MemoryRead(GetAbsYAddr()); } + uint16_t GetAbsYAddr() { + return ReadWord() + Y(); + } + + uint16_t GetInd() { return MemoryReadWord(ReadByte() | (ReadByte() << 8)); } + + int8_t GetIndX() { return MemoryRead(GetIndXAddr()); } + uint16_t GetIndXAddr() { + uint8_t zero = ReadByte() + X(); + //std::cout << (int)zero << std::endl; + uint16_t addr = MemoryRead(zero) | (MemoryRead(zero + 1) << 8); + return addr; + } + + int8_t GetIndY() { return MemoryRead(GetIndYAddr()); } + uint16_t GetIndYAddr() { + uint8_t zero = ReadByte(); + //std::cout << (int)zero << std::endl; + uint16_t addr = MemoryRead(zero) | (MemoryRead(zero + 1) << 8); + return addr + Y(); + } + + + void AND(int8_t value) { SetA(A() & value); } + void XOR(int8_t value) { + SetA(A() ^ value); + } + void OR(int8_t value) { SetA(A() | value); } + + void ADC(uint8_t value) { + uint16_t result = (uint16_t)A() + (uint16_t)value + (CheckFlag(PSFlags::Carry) ? PSFlags::Carry : 0x00); + if(result == 0x100) { + //std::cout << std::hex << (short)A() << " + " << (short)value << (CheckFlag(PSFlags::Carry) ? "(+1) " : "") << " = " << (short)result << std::endl; + } + + ClearFlags(PSFlags::Carry | PSFlags::Negative | PSFlags::Overflow | PSFlags::Zero); + SetZeroNegativeFlags((uint8_t)result); + if(~(A() ^ value) & (A() ^ result) & 0x80) { + SetFlags(PSFlags::Overflow); + } + if(result > 0xFF) { + SetFlags(PSFlags::Carry); + } + SetA((uint8_t)result); + } + + void SBC(int8_t value) { + ADC(value ^ 0xFF); + /*uint8_t result = A() - (value - ~(CheckFlag(PSFlags::Carry) ? PSFlags::Carry : 0x00)); + + ClearFlags(PSFlags::Carry | PSFlags::Negative | PSFlags::Overflow | PSFlags::Zero); + + if (result & 0x80) { + SetFlags(PSFlags::Overflow); + } + + SetA(result);*/ + } + + void CMP(uint8_t reg, uint8_t value) { + ClearFlags(PSFlags::Carry | PSFlags::Negative | PSFlags::Zero); + if(reg >= value) { + SetFlags(PSFlags::Carry); + } + if(reg == value) { + SetFlags(PSFlags::Zero); + } + if(reg < value) { + SetFlags(PSFlags::Negative); + } + } + + void CPA(int8_t value) { CMP(A(), value); } + void CPX(int8_t value) { CMP(X(), value); } + void CPY(int8_t value) { CMP(Y(), value); } + + void INC(uint16_t addr) { + ClearFlags(PSFlags::Negative | PSFlags::Zero); + uint8_t memory = MemoryRead(addr) + 1; + SetZeroNegativeFlags(memory); + MemoryWrite(addr, memory); + } + + void DEC(uint16_t addr) { + ClearFlags(PSFlags::Negative | PSFlags::Zero); + uint8_t memory = MemoryRead(addr) - 1; + SetZeroNegativeFlags(memory); + MemoryWrite(addr, memory); + } + + uint8_t ASL(uint8_t value) + { + ClearFlags(PSFlags::Carry | PSFlags::Negative | PSFlags::Zero); + if(value & 0x80) { + SetFlags(PSFlags::Carry); + } + + uint8_t result = value << 1; + SetZeroNegativeFlags(result); + return result; + } + + uint8_t LSR(uint8_t value) { + ClearFlags(PSFlags::Carry | PSFlags::Negative | PSFlags::Zero); + if(value & 0x01) { + SetFlags(PSFlags::Carry); + } + + uint8_t result = value >> 1; + SetZeroNegativeFlags(result); + return value >> 1; + } + + uint8_t ROL(uint8_t value) { + bool carryFlag = CheckFlag(PSFlags::Carry); + ClearFlags(PSFlags::Carry | PSFlags::Negative | PSFlags::Zero); + + if(value & 0x80) { + SetFlags(PSFlags::Carry); + } + + uint8_t result = (value << 1 | (carryFlag ? 0x01 : 0x00)); + SetZeroNegativeFlags(result); + return result; + } + + uint8_t ROR(uint8_t value) { + bool carryFlag = CheckFlag(PSFlags::Carry); + ClearFlags(PSFlags::Carry | PSFlags::Negative | PSFlags::Zero); + if(value & 0x01) { + SetFlags(PSFlags::Carry); + } + + uint8_t result = (value >> 1 | (carryFlag ? 0x80 : 0x00)); + SetZeroNegativeFlags(result); + return result; + } + + void ASLAddr(uint16_t addr) { + int8_t value = MemoryRead(addr); + MemoryWrite(addr, ASL(value)); + } + + void LSRAddr(uint16_t addr) { + int8_t value = MemoryRead(addr); + MemoryWrite(addr, LSR(value)); + } + + void ROLAddr(uint16_t addr) { + int8_t value = MemoryRead(addr); + MemoryWrite(addr, ROL(value)); + } + + void RORAddr(uint16_t addr) { + int8_t value = MemoryRead(addr); + MemoryWrite(addr, ROR(value)); + } + + void JMP(uint16_t addr) { + _state.PC = addr; + } + + void BranchRelative(bool branch) { + int8_t offset = GetImmediate(); + if(branch) { + SetPC(PC() + offset); + if(_currentPC == PC()) { + std::cout << "Infinite loop at: 0x" << std::hex << (short)_currentPC; + std::cout << std::endl; + Reset(); + } + } + } + +#pragma region OP Codes + void LDA_Imm() { SetA(GetImmediate()); } + void LDA_Zero() { SetA(GetZero()); } + void LDA_ZeroX() { SetA(GetZeroX()); } + void LDA_Abs() { SetA(GetAbs()); } + void LDA_AbsX() { SetA(GetAbsX()); } + void LDA_AbsY() { SetA(GetAbsY()); } + void LDA_IndX() { SetA(GetIndX()); } + void LDA_IndY() { SetA(GetIndY()); } + + void LDX_Imm() { SetX(GetImmediate()); } + void LDX_Zero() { SetX(GetZero()); } + void LDX_ZeroY() { SetX(GetZeroY()); } + void LDX_Abs() { SetX(GetAbs()); } + void LDX_AbsY() { SetX(GetAbsY()); } + + void LDY_Imm() { SetY(GetImmediate()); } + void LDY_Zero() { SetY(GetZero()); } + void LDY_ZeroX() { SetY(GetZeroX()); } + void LDY_Abs() { SetY(GetAbs()); } + void LDY_AbsX() { SetY(GetAbsX()); } + + void STA_Zero() { MemoryWrite(ReadByte(), A()); } + void STA_ZeroX() { MemoryWrite((uint8_t)(ReadByte() + X()), A()); } + void STA_Abs() { MemoryWrite(ReadWord(), A()); } + void STA_AbsX() { MemoryWrite(GetAbsXAddr(), A()); } + void STA_AbsY() { MemoryWrite(GetAbsYAddr(), A()); } + void STA_IndX() { MemoryWrite(GetIndXAddr(), A()); } + void STA_IndY() { MemoryWrite(GetIndYAddr(), A()); } + + void STX_Zero() { MemoryWrite(ReadByte(), X()); } + void STX_ZeroY() { MemoryWrite((uint8_t)(ReadByte() + Y()), X()); } + void STX_Abs() { MemoryWrite(ReadWord(), X()); } + + void STY_Zero() { MemoryWrite(ReadByte(), Y()); } + void STY_ZeroX() { MemoryWrite((uint8_t)(ReadByte() + X()), Y()); } + void STY_Abs() { MemoryWrite(ReadWord(), Y()); } + + void TAX() { SetX(A()); } + void TAY() { SetY(A()); } + void TSX() { SetX(SP()); } + void TXA() { SetA(X()); } + void TXS() { SetSP(X()); } + void TYA() { SetA(Y()); } + + void PHA() { Push(A()); } + void PHP() { + SetFlags(PSFlags::Break); + Push((uint8_t)PS()); + } + void PLA() { SetA(Pop()); } + void PLP() { SetPS(Pop()); } + + void AND_Imm() { AND(GetImmediate()); } + void AND_Zero() { AND(GetZero()); } + void AND_ZeroX() { AND(GetZeroX()); } + void AND_Abs() { AND(GetAbs()); } + void AND_AbsX() { AND(GetAbsX()); } + void AND_AbsY() { AND(GetAbsY()); } + void AND_IndX() { AND(GetIndX()); } + void AND_IndY() { AND(GetIndY()); } + + void EOR_Imm() { XOR(GetImmediate()); } + void EOR_Zero() { XOR(GetZero()); } + void EOR_ZeroX() { XOR(GetZeroX()); } + void EOR_Abs() { XOR(GetAbs()); } + void EOR_AbsX() { XOR(GetAbsX()); } + void EOR_AbsY() { XOR(GetAbsY()); } + void EOR_IndX() { XOR(GetIndX()); } + void EOR_IndY() { XOR(GetIndY()); } + + void ORA_Imm() { OR(GetImmediate()); } + void ORA_Zero() { OR(GetZero()); } + void ORA_ZeroX() { OR(GetZeroX()); } + void ORA_Abs() { OR(GetAbs()); } + void ORA_AbsX() { OR(GetAbsX()); } + void ORA_AbsY() { OR(GetAbsY()); } + void ORA_IndX() { OR(GetIndX()); } + void ORA_IndY() { OR(GetIndY()); } + + void BIT(uint8_t value) { + ClearFlags(PSFlags::Zero | PSFlags::Overflow | PSFlags::Negative); + if((A() & value) == 0) { + SetFlags(PSFlags::Zero); + } + if(value & 0x40) { + SetFlags(PSFlags::Overflow); + } + if(value & 0x80) { + SetFlags(PSFlags::Negative); + } + } + + void BIT_Zero() { + BIT(GetZero()); + } + void BIT_Abs() { + BIT(GetAbs()); + } + + void ADC_Imm() { ADC(GetImmediate()); } + void ADC_Zero() { ADC(GetZero()); } + void ADC_ZeroX() { ADC(GetZeroX()); } + void ADC_Abs() { ADC(GetAbs()); } + void ADC_AbsX() { ADC(GetAbsX()); } + void ADC_AbsY() { ADC(GetAbsY()); } + void ADC_IndX() { ADC(GetIndX()); } + void ADC_IndY() { ADC(GetIndY()); } + + void SBC_Imm() { SBC(GetImmediate()); } + void SBC_Zero() { SBC(GetZero()); } + void SBC_ZeroX() { SBC(GetZeroX()); } + void SBC_Abs() { SBC(GetAbs()); } + void SBC_AbsX() { SBC(GetAbsX()); } + void SBC_AbsY() { SBC(GetAbsY()); } + void SBC_IndX() { SBC(GetIndX()); } + void SBC_IndY() { SBC(GetIndY()); } + + void CMP_Imm() { CPA(GetImmediate()); } + void CMP_Zero() { CPA(GetZero()); } + void CMP_ZeroX() { CPA(GetZeroX()); } + void CMP_Abs() { CPA(GetAbs()); } + void CMP_AbsX() { CPA(GetAbsX()); } + void CMP_AbsY() { CPA(GetAbsY()); } + void CMP_IndX() { CPA(GetIndX()); } + void CMP_IndY() { CPA(GetIndY()); } + + void CPX_Imm() { CPX(GetImmediate()); } + void CPX_Zero() { CPX(GetZero()); } + void CPX_Abs() { CPX(GetAbs()); } + + void CPY_Imm() { CPY(GetImmediate()); } + void CPY_Zero() { CPY(GetZero()); } + void CPY_Abs() { CPY(GetAbs()); } + + void INC_Zero() { INC(GetZeroAddr()); } + void INC_ZeroX() { INC(GetZeroXAddr()); } + void INC_Abs() { INC(GetAbsAddr()); } + void INC_AbsX() { INC(GetAbsXAddr()); } + void INX() { SetX(X() + 1); } + void INY() { SetY(Y() + 1); } + + void DEC_Zero() { DEC(GetZeroAddr()); } + void DEC_ZeroX() { DEC(GetZeroXAddr()); } + void DEC_Abs() { DEC(GetAbsAddr()); } + void DEC_AbsX() { DEC(GetAbsXAddr()); } + void DEX() { SetX(X() - 1); } + void DEY() { SetY(Y() - 1); } + + void ASL_Acc() { SetA(ASL(A())); } + void ASL_Zero() { ASLAddr(GetZeroAddr()); } + void ASL_ZeroX() { ASLAddr(GetZeroXAddr()); } + void ASL_Abs() { ASLAddr(GetAbsAddr()); } + void ASL_AbsX() { ASLAddr(GetAbsXAddr()); } + + void LSR_Acc() { SetA(LSR(A())); } + void LSR_Zero() { LSRAddr(GetZeroAddr()); } + void LSR_ZeroX() { LSRAddr(GetZeroXAddr()); } + void LSR_Abs() { LSRAddr(GetAbsAddr()); } + void LSR_AbsX() { LSRAddr(GetAbsXAddr()); } + + void ROL_Acc() { SetA(ROL(A())); } + void ROL_Zero() { ROLAddr(GetZeroAddr()); } + void ROL_ZeroX() { ROLAddr(GetZeroXAddr()); } + void ROL_Abs() { ROLAddr(GetAbsAddr()); } + void ROL_AbsX() { ROLAddr(GetAbsXAddr()); } + + void ROR_Acc() { SetA(ROR(A())); } + void ROR_Zero() { RORAddr(GetZeroAddr()); } + void ROR_ZeroX() { RORAddr(GetZeroXAddr()); } + void ROR_Abs() { RORAddr(GetAbsAddr()); } + void ROR_AbsX() { RORAddr(GetAbsXAddr()); } + + void JMP_Abs() { + auto currentPC = _state.PC - 1; + auto newPC = ReadWord(); + if(currentPC == newPC) { + std::cout << "Infinite loop at: " << std::hex << (short)newPC << std::endl; + } + JMP(newPC); + } + void JMP_Ind() { JMP(GetInd()); } + void JSR() { + Push((uint16_t)(PC() + 1)); + JMP(GetAbsAddr()); + } + void RTS() { + SetPC(PopWord() + 1); + } + + void BCC() { + BranchRelative(!CheckFlag(PSFlags::Carry)); + } + + void BCS() { + BranchRelative(CheckFlag(PSFlags::Carry)); + } + + void BEQ() { + BranchRelative(CheckFlag(PSFlags::Zero)); + } + + void BMI() { + BranchRelative(CheckFlag(PSFlags::Negative)); + } + + void BNE() { + BranchRelative(!CheckFlag(PSFlags::Zero)); + } + + void BPL() { + BranchRelative(!CheckFlag(PSFlags::Negative)); + } + + void BVC() { + BranchRelative(!CheckFlag(PSFlags::Overflow)); + } + + void BVS() { + BranchRelative(CheckFlag(PSFlags::Overflow)); + } + + void CLC() { ClearFlags(PSFlags::Carry); } + void CLD() { ClearFlags(PSFlags::Decimal); } + void CLI() { ClearFlags(PSFlags::Interrupt); } + void CLV() { ClearFlags(PSFlags::Overflow); } + void SEC() { SetFlags(PSFlags::Carry); } + void SED() { SetFlags(PSFlags::Decimal); } + void SEI() { SetFlags(PSFlags::Interrupt); } + + void BRK() { + SetFlags(PSFlags::Break); + Push((uint16_t)(PC() + 1)); + Push((uint8_t)PS()); + SetFlags(PSFlags::Interrupt); + ClearFlags(PSFlags::Break); + SetPC((uint8_t)_memory[0xFFFE] | ((uint8_t)_memory[0xFFFF] << 8)); + } + + void NOP() {} + void RTI() { + SetPS(Pop()); + SetPC(PopWord()); + } +#pragma endregion +public: + Core(int8_t *memory) : _memory(memory) { + Reset(); + memset(_opTable, 0, 256 * sizeof(void*)); + _opTable[0x00] = &Core::BRK; + _opTable[0x01] = &Core::ORA_IndX; + _opTable[0x05] = &Core::ORA_Zero; + _opTable[0x06] = &Core::ASL_Zero; + _opTable[0x08] = &Core::PHP; + _opTable[0x09] = &Core::ORA_Imm; + _opTable[0x0A] = &Core::ASL_Acc; + _opTable[0x0D] = &Core::ORA_Abs; + _opTable[0x0E] = &Core::ASL_Abs; + _opTable[0x10] = &Core::BPL; + _opTable[0x11] = &Core::ORA_IndY; + _opTable[0x15] = &Core::ORA_ZeroX; + _opTable[0x16] = &Core::ASL_ZeroX; + _opTable[0x18] = &Core::CLC; + _opTable[0x19] = &Core::ORA_AbsY; + _opTable[0x1D] = &Core::ORA_AbsX; + _opTable[0x1E] = &Core::ASL_AbsX; + _opTable[0x20] = &Core::JSR; + _opTable[0x21] = &Core::AND_IndX; + _opTable[0x24] = &Core::BIT_Zero; + _opTable[0x25] = &Core::AND_Zero; + _opTable[0x26] = &Core::ROL_Zero; + _opTable[0x28] = &Core::PLP; + _opTable[0x29] = &Core::AND_Imm; + _opTable[0x2A] = &Core::ROL_Acc; + _opTable[0x2C] = &Core::BIT_Abs; + _opTable[0x2D] = &Core::AND_Abs; + _opTable[0x2E] = &Core::ROL_Abs; + _opTable[0x30] = &Core::BMI; + _opTable[0x31] = &Core::AND_IndY; + _opTable[0x35] = &Core::AND_ZeroX; + _opTable[0x36] = &Core::ROL_ZeroX; + _opTable[0x38] = &Core::SEC; + _opTable[0x39] = &Core::AND_AbsY; + _opTable[0x3D] = &Core::AND_AbsX; + _opTable[0x3E] = &Core::ROL_AbsX; + _opTable[0x40] = &Core::RTI; + _opTable[0x41] = &Core::EOR_IndX; + _opTable[0x45] = &Core::EOR_Zero; + _opTable[0x46] = &Core::LSR_Zero; + _opTable[0x48] = &Core::PHA; + _opTable[0x49] = &Core::EOR_Imm; + _opTable[0x4A] = &Core::LSR_Acc; + _opTable[0x4C] = &Core::JMP_Abs; + _opTable[0x4D] = &Core::EOR_Abs; + _opTable[0x4E] = &Core::LSR_Abs; + _opTable[0x50] = &Core::BVC; + _opTable[0x51] = &Core::EOR_IndY; + _opTable[0x55] = &Core::EOR_ZeroX; + _opTable[0x56] = &Core::LSR_ZeroX; + _opTable[0x58] = &Core::CLI; + _opTable[0x59] = &Core::EOR_AbsY; + _opTable[0x5D] = &Core::EOR_AbsX; + _opTable[0x5E] = &Core::LSR_AbsX; + _opTable[0x60] = &Core::RTS; + _opTable[0x61] = &Core::ADC_IndX; + _opTable[0x65] = &Core::ADC_Zero; + _opTable[0x66] = &Core::ROR_Zero; + _opTable[0x68] = &Core::PLA; + _opTable[0x69] = &Core::ADC_Imm; + _opTable[0x6A] = &Core::ROR_Acc; + _opTable[0x6C] = &Core::JMP_Ind; + _opTable[0x6D] = &Core::ADC_Abs; + _opTable[0x6E] = &Core::ROR_Abs; + _opTable[0x70] = &Core::BVS; + _opTable[0x71] = &Core::ADC_IndY; + _opTable[0x75] = &Core::ADC_ZeroX; + _opTable[0x76] = &Core::ROR_ZeroX; + _opTable[0x78] = &Core::SEI; + _opTable[0x79] = &Core::ADC_AbsY; + _opTable[0x7D] = &Core::ADC_AbsX; + _opTable[0x7E] = &Core::ROR_AbsX; + _opTable[0x81] = &Core::STA_IndX; + _opTable[0x84] = &Core::STY_Zero; + _opTable[0x85] = &Core::STA_Zero; + _opTable[0x86] = &Core::STX_Zero; + _opTable[0x88] = &Core::DEY; + _opTable[0x8A] = &Core::TXA; + _opTable[0x8C] = &Core::STY_Abs; + _opTable[0x8D] = &Core::STA_Abs; + _opTable[0x8E] = &Core::STX_Abs; + _opTable[0x90] = &Core::BCC; + _opTable[0x91] = &Core::STA_IndY; + _opTable[0x94] = &Core::STY_ZeroX; + _opTable[0x95] = &Core::STA_ZeroX; + _opTable[0x96] = &Core::STX_ZeroY; + _opTable[0x98] = &Core::TYA; + _opTable[0x99] = &Core::STA_AbsY; + _opTable[0x9A] = &Core::TXS; + _opTable[0x9D] = &Core::STA_AbsX; + _opTable[0xA0] = &Core::LDY_Imm; + _opTable[0xA1] = &Core::LDA_IndX; + _opTable[0xA2] = &Core::LDX_Imm; + _opTable[0xA4] = &Core::LDY_Zero; + _opTable[0xA5] = &Core::LDA_Zero; + _opTable[0xA6] = &Core::LDX_Zero; + _opTable[0xA8] = &Core::TAY; + _opTable[0xA9] = &Core::LDA_Imm; + _opTable[0xAA] = &Core::TAX; + _opTable[0xAC] = &Core::LDY_Abs; + _opTable[0xAD] = &Core::LDA_Abs; + _opTable[0xAE] = &Core::LDX_Abs; + _opTable[0xB0] = &Core::BCS; + _opTable[0xB1] = &Core::LDA_IndY; + _opTable[0xB4] = &Core::LDY_ZeroX; + _opTable[0xB5] = &Core::LDA_ZeroX; + _opTable[0xB6] = &Core::LDX_ZeroY; + _opTable[0xB8] = &Core::CLV; + _opTable[0xB9] = &Core::LDA_AbsY; + _opTable[0xBA] = &Core::TSX; + _opTable[0xBC] = &Core::LDY_AbsX; + _opTable[0xBD] = &Core::LDA_AbsX; + _opTable[0xBE] = &Core::LDX_AbsY; + _opTable[0xC0] = &Core::CPY_Imm; + _opTable[0xC1] = &Core::CMP_IndX; + _opTable[0xC4] = &Core::CPY_Zero; + _opTable[0xC5] = &Core::CMP_Zero; + _opTable[0xC6] = &Core::DEC_Zero; + _opTable[0xC8] = &Core::INY; + _opTable[0xC9] = &Core::CMP_Imm; + _opTable[0xCA] = &Core::DEX; + _opTable[0xCC] = &Core::CPY_Abs; + _opTable[0xCD] = &Core::CMP_Abs; + _opTable[0xCE] = &Core::DEC_Abs; + _opTable[0xD0] = &Core::BNE; + _opTable[0xD1] = &Core::CMP_IndY; + _opTable[0xD5] = &Core::CMP_ZeroX; + _opTable[0xD6] = &Core::DEC_ZeroX; + _opTable[0xD8] = &Core::CLD; + _opTable[0xD9] = &Core::CMP_AbsY; + _opTable[0xDD] = &Core::CMP_AbsX; + _opTable[0xDE] = &Core::DEC_AbsX; + _opTable[0xE0] = &Core::CPX_Imm; + _opTable[0xE1] = &Core::SBC_IndX; + _opTable[0xE4] = &Core::CPX_Zero; + _opTable[0xE5] = &Core::SBC_Zero; + _opTable[0xE6] = &Core::INC_Zero; + _opTable[0xE8] = &Core::INX; + _opTable[0xE9] = &Core::SBC_Imm; + _opTable[0xEA] = &Core::NOP; + _opTable[0xEC] = &Core::CPX_Abs; + _opTable[0xED] = &Core::SBC_Abs; + _opTable[0xEE] = &Core::INC_Abs; + _opTable[0xF0] = &Core::BEQ; + _opTable[0xF1] = &Core::SBC_IndY; + _opTable[0xF5] = &Core::SBC_ZeroX; + _opTable[0xF6] = &Core::INC_ZeroX; + _opTable[0xF8] = &Core::SED; + _opTable[0xF9] = &Core::SBC_AbsY; + _opTable[0xFD] = &Core::SBC_AbsX; + _opTable[0xFE] = &Core::INC_AbsX; + } + void Reset(); + void Exec(); +}; diff --git a/Core.vcxproj b/Core.vcxproj new file mode 100644 index 00000000..9ee28c0f --- /dev/null +++ b/Core.vcxproj @@ -0,0 +1,104 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {78FEF1A1-6DF1-4CBB-A373-AE6FA7CE5CE0} + Win32Proj + Core + Core + + + + Application + true + v120 + Unicode + + + Application + false + v120 + true + Unicode + + + + + + + + + + + + + true + + + false + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) + true + + + Console + true + + + + + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) + true + AnySuitable + true + + + Console + true + true + true + + + + + + + + + + + + + + + Create + + + + + + + \ No newline at end of file diff --git a/Core.vcxproj.filters b/Core.vcxproj.filters new file mode 100644 index 00000000..a204d396 --- /dev/null +++ b/Core.vcxproj.filters @@ -0,0 +1,45 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Header Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/NES.sln b/NES.sln new file mode 100644 index 00000000..f0f7211e --- /dev/null +++ b/NES.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.30501.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Core", "Core.vcxproj", "{78FEF1A1-6DF1-4CBB-A373-AE6FA7CE5CE0}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {78FEF1A1-6DF1-4CBB-A373-AE6FA7CE5CE0}.Debug|Win32.ActiveCfg = Debug|Win32 + {78FEF1A1-6DF1-4CBB-A373-AE6FA7CE5CE0}.Debug|Win32.Build.0 = Debug|Win32 + {78FEF1A1-6DF1-4CBB-A373-AE6FA7CE5CE0}.Release|Win32.ActiveCfg = Release|Win32 + {78FEF1A1-6DF1-4CBB-A373-AE6FA7CE5CE0}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/ReadMe.txt b/ReadMe.txt new file mode 100644 index 00000000..4cb8a2f4 --- /dev/null +++ b/ReadMe.txt @@ -0,0 +1,40 @@ +======================================================================== + CONSOLE APPLICATION : ConsoleApplication1 Project Overview +======================================================================== + +AppWizard has created this ConsoleApplication1 application for you. + +This file contains a summary of what you will find in each of the files that +make up your ConsoleApplication1 application. + + +ConsoleApplication1.vcxproj + This is the main project file for VC++ projects generated using an Application Wizard. + It contains information about the version of Visual C++ that generated the file, and + information about the platforms, configurations, and project features selected with the + Application Wizard. + +ConsoleApplication1.vcxproj.filters + This is the filters file for VC++ projects generated using an Application Wizard. + It contains information about the association between the files in your project + and the filters. This association is used in the IDE to show grouping of files with + similar extensions under a specific node (for e.g. ".cpp" files are associated with the + "Source Files" filter). + +ConsoleApplication1.cpp + This is the main application source file. + +///////////////////////////////////////////////////////////////////////////// +Other standard files: + +StdAfx.h, StdAfx.cpp + These files are used to build a precompiled header (PCH) file + named ConsoleApplication1.pch and a precompiled types file named StdAfx.obj. + +///////////////////////////////////////////////////////////////////////////// +Other notes: + +AppWizard uses "TODO:" comments to indicate parts of the source code you +should add to or customize. + +///////////////////////////////////////////////////////////////////////////// diff --git a/Timer.h b/Timer.h new file mode 100644 index 00000000..20738930 --- /dev/null +++ b/Timer.h @@ -0,0 +1,28 @@ +#include "stdafx.h" + +class Timer +{ + private: + double _frequency = 0.0; + LARGE_INTEGER _start; + + public: + Timer() { + LARGE_INTEGER li; + if(!QueryPerformanceFrequency(&li)) { + throw; + } + + _frequency = double(li.QuadPart) / 1000.0; + + QueryPerformanceCounter(&li); + _start = li; + } + + double GetElapsedMS() + { + LARGE_INTEGER li; + QueryPerformanceCounter(&li); + return double(li.QuadPart - _start.QuadPart) / _frequency; + } +}; \ No newline at end of file diff --git a/main.cpp b/main.cpp new file mode 100644 index 00000000..c60d420b --- /dev/null +++ b/main.cpp @@ -0,0 +1,164 @@ +#include "stdafx.h" +#include "CPU.h" + +/* +template +class Event +{ + typedef void(*Func)(Types...); + private: + std::list handlerList; + Func lastFunc; + + public: + void RegisterHandler(Func handler); + void operator+=(Func handler); + void operator()(Types ...types); +}; + +template +void Event::RegisterHandler(Func handler) +{ + this->handlerList.push_back(handler); + lastFunc = this->handlerList.size() == 1 ? handler : nullptr; +} + +template +void Event::operator+=(Func handler) { + this->RegisterHandler(handler); +} + +template +void Event::operator()(Types... types) +{ + if (lastFunc) { + lastFunc(types...); + } else { + for (auto handler : this->handlerList) { + handler(types...); + } + } +} + +template +class TemplatedClass +{ + public: + T Sum(T a, T b); +}; + +template +T TemplatedClass::Sum(T a, T b) +{ + return a + b; +} + +template using ptr = std::unique_ptr; + +class Test +{ + private: + int counter = 0; + Test(); + + public: + int Sum(int, int); + void NewThread(); + static std::unique_ptr NewInstance(); +}; + +Test::Test() +{ + +} + +int Test::Sum(int x, int y) +{ + return x + y; +} + +void Test::NewThread() +{ + for (int i = 0; i < 100; i++) { + std::this_thread::sleep_for(std::chrono::duration(1000)); + printf("test %i", this->counter); + this->counter++; + } +} + +std::unique_ptr Test::NewInstance() +{ + return std::unique_ptr(new Test()); +} + +void somefunction(void) +{ + printf("test11111"); +} + +void func2(int a) +{ + //printf("%i", a); +}*/ + +int _tmain(int argc, _TCHAR* argv[]) +{ + std::ifstream romFile("6502_functional_test.bin", std::ios::in | std::ios::binary); + if(!romFile) { + std::cout << "Error"; + } + + int8_t romMemory[65536]; + romFile.read((char *)romMemory, 65536); + /*int8_t* memory = new int8_t[8000]; + memory[0x0600] = 0xA9; + memory[0x0601] = 0x55;*/ + + Core core(romMemory); + core.Exec(); + + /*Event<> eventHandler; + eventHandler += somefunction; + + Event intHandler; + intHandler += func2; + intHandler += func2; + intHandler += func2; + + for (int i = 0; i < 1000000; i++) { + intHandler(i); + } + eventHandler(); + + TemplatedClass DoubleSum; + printf("%d", DoubleSum.Sum(10.0, 20.0)); + + TemplatedClass StringSum; + std::cout << StringSum.Sum("asdas", "dsadasdsa"); + + auto str1 = std::string("aaaa"); + auto str2 = std::string("bbbb"); + auto str3 = str1 + str2; + std::cout << str3; + + std::unique_ptr test; + + if (!test) { + test = Test::NewInstance(); + } + + std::thread t1(&Test::NewThread, test.get()); + + std::thread t2([]() { + printf("test2"); + }); + + if (test) { + printf("%i", test->Sum(1000, 10)); + } + + t1.join(); + */ + return 0; +} + diff --git a/stdafx.cpp b/stdafx.cpp new file mode 100644 index 00000000..1577c4e3 --- /dev/null +++ b/stdafx.cpp @@ -0,0 +1 @@ +#include "stdafx.h" \ No newline at end of file diff --git a/stdafx.h b/stdafx.h new file mode 100644 index 00000000..50806df7 --- /dev/null +++ b/stdafx.h @@ -0,0 +1,26 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#include "targetver.h" + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + + +// TODO: reference additional headers your program requires here diff --git a/targetver.h b/targetver.h new file mode 100644 index 00000000..87c0086d --- /dev/null +++ b/targetver.h @@ -0,0 +1,8 @@ +#pragma once + +// Including SDKDDKVer.h defines the highest available Windows platform. + +// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and +// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. + +#include