From 5e7eebe0782d9a6b8865e9079790b9635fb1d5f7 Mon Sep 17 00:00:00 2001 From: Sour Date: Mon, 11 Feb 2019 22:41:34 -0500 Subject: [PATCH] CPU: Fixed immediate more 8-bit vs 16-bit logic + Added bare minimum logic to load a rom and start executing it --- Core/Core.vcxproj | 1 + Core/Core.vcxproj.filters | 1 + Core/Cpu.cpp | 139 +++++++++++++++++++++++--------------- Core/Cpu.h | 11 +-- Core/CpuTypes.h | 6 +- Core/MemoryManager.h | 123 +++++++++++++++++++++++++++++++++ Core/main.cpp | 26 ++----- 7 files changed, 222 insertions(+), 85 deletions(-) create mode 100644 Core/MemoryManager.h diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index ddae04d..73252f2 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -45,6 +45,7 @@ + diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index 3d5c93d..c20746d 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -4,6 +4,7 @@ + diff --git a/Core/Cpu.cpp b/Core/Cpu.cpp index bd38640..6d5837f 100644 --- a/Core/Cpu.cpp +++ b/Core/Cpu.cpp @@ -1,10 +1,34 @@ #include "stdafx.h" #include "CpuTypes.h" #include "Cpu.h" +#include "MemoryManager.h" #include "../Utilities/HexUtilities.h" +//TODO: PER doesn't load the right number of bytes? + uint8_t lastTest = -1; bool _enableLogging = false; +string opNames[256] = { + //0 1 2 3 4 5 6 7 8 9 A B C D E F + "BRK", "ORA", "COP", "ORA", "TSB", "ORA", "ASL", "ORA", "PHP", "ORA", "ASL", "PHD", "TSB", "ORA", "ASL", "ORA", // 0 + "BPL", "ORA", "ORA", "ORA", "TRB", "ORA", "ASL", "ORA", "CLC", "ORA", "INC", "TCS", "TRB", "ORA", "ASL", "ORA", // 1 + "JSR", "AND", "JSL", "AND", "BIT", "AND", "ROL", "AND", "PLP", "AND", "ROL", "PLD", "BIT", "AND", "ROL", "AND", // 2 + "BMI", "AND", "AND", "AND", "BIT", "AND", "ROL", "AND", "SEC", "AND", "DEC", "TSC", "BIT", "AND", "ROL", "AND", // 3 + "RTI", "EOR", "WDM", "EOR", "MVP", "EOR", "LSR", "EOR", "PHA", "EOR", "LSR", "PHK", "JMP", "EOR", "LSR", "EOR", // 4 + "BVC", "EOR", "EOR", "EOR", "MVN", "EOR", "LSR", "EOR", "CLI", "EOR", "PHY", "TCD", "JMP", "EOR", "LSR", "EOR", // 5 + "RTS", "ADC", "PER", "ADC", "STZ", "ADC", "ROR", "ADC", "PLA", "ADC", "ROR", "RTL", "JMP", "ADC", "ROR", "ADC", // 6 + "BVS", "ADC", "ADC", "ADC", "STZ", "ADC", "ROR", "ADC", "SEI", "ADC", "PLY", "TDC", "JMP", "ADC", "ROR", "ADC", // 7 + "BRA", "STA", "BRL", "STA", "STY", "STA", "STX", "STA", "DEY", "BIT", "TXA", "PHB", "STY", "STA", "STX", "STA", // 8 + "BCC", "STA", "STA", "STA", "STY", "STA", "STX", "STA", "TYA", "STA", "TXS", "TXY", "STZ", "STA", "STZ", "STA", // 9 + "LDY", "LDA", "LDX", "LDA", "LDY", "LDA", "LDX", "LDA", "TAY", "LDA", "TAX", "PLB", "LDY", "LDA", "LDX", "LDA", // A + "BCS", "LDA", "LDA", "LDA", "LDY", "LDA", "LDX", "LDA", "CLV", "LDA", "TSX", "TYX", "LDY", "LDA", "LDX", "LDA", // B + "CPY", "CMP", "REP", "CMP", "CPY", "CMP", "DEC", "CMP", "INY", "CMP", "DEX", "WAI", "CPY", "CMP", "DEC", "CMP", // C + "BNE", "CMP", "CMP", "CMP", "PEI", "CMP", "DEC", "CMP", "CLD", "CMP", "PHX", "STP", "JML", "CMP", "DEC", "CMP", // D + "CPX", "SBC", "SEP", "SBC", "CPX", "SBC", "INC", "SBC", "INX", "SBC", "NOP", "XBA", "CPX", "SBC", "INC", "SBC", // E + "BEQ", "SBC", "SBC", "SBC", "PEA", "SBC", "INC", "SBC", "SED", "SBC", "PLX", "XCE", "JSR", "SBC", "INC", "SBC" // F +}; + + /************************ Add/substract operations @@ -925,7 +949,7 @@ void Cpu::WAI() //Wait for interrupt } -Cpu::Cpu(uint8_t* memory, bool enableLogging) +Cpu::Cpu(shared_ptr memoryManager) { typedef Cpu C; Func opTable[256] = { @@ -951,31 +975,32 @@ Cpu::Cpu(uint8_t* memory, bool enableLogging) typedef AddrMode M; AddrMode addrMode[256] = { //0 1 2 3 4 5 6 7 8 9 A B C D E F - M::Stk, M::DirIdxIndX, M::Stk, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Stk, M::Imm, M::Acc, M::Stk, M::Abs, M::Abs, M::Abs, M::AbsLng, // 0 + M::Stk, M::DirIdxIndX, M::Stk, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Stk, M::ImmM, M::Acc, M::Stk, M::Abs, M::Abs, M::Abs, M::AbsLng, // 0 M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::Dir, M::DirIdxX, M::DirIdxX, M::DirIndLngIdxY, M::Imp, M::AbsIdxY, M::Acc, M::Imp, M::Abs, M::AbsIdxX, M::AbsIdxX, M::AbsLngIdxX, // 1 - M::Abs, M::DirIdxIndX, M::AbsLng, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Stk, M::Imm, M::Acc, M::Stk, M::Abs, M::Abs, M::Abs, M::AbsLng, // 2 + M::Abs, M::DirIdxIndX, M::AbsLng, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Stk, M::ImmM, M::Acc, M::Stk, M::Abs, M::Abs, M::Abs, M::AbsLng, // 2 M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::DirIdxX, M::DirIdxX, M::DirIdxX, M::DirIndLngIdxY, M::Imp, M::AbsIdxY, M::Acc, M::Imp, M::AbsIdxX, M::AbsIdxX, M::AbsIdxX, M::AbsLngIdxX, // 3 - M::Stk, M::DirIdxIndX, M::Imm, M::StkRel, M::BlkMov, M::Dir, M::Dir, M::DirIndLng, M::Stk, M::Imm, M::Acc, M::Stk, M::Abs, M::Abs, M::Abs, M::AbsLng, // 4 + M::Stk, M::DirIdxIndX, M::Imm8, M::StkRel, M::BlkMov, M::Dir, M::Dir, M::DirIndLng, M::Stk, M::ImmM, M::Acc, M::Stk, M::Abs, M::Abs, M::Abs, M::AbsLng, // 4 M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::BlkMov, M::DirIdxX, M::DirIdxX, M::DirIndLngIdxY, M::Imp, M::AbsIdxY, M::Stk, M::Imp, M::AbsLng, M::AbsIdxX, M::AbsIdxX, M::AbsLngIdxX, // 5 - M::Stk, M::DirIdxIndX, M::Stk, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Stk, M::Imm, M::Acc, M::Stk, M::AbsInd, M::Abs, M::Abs, M::AbsLng, // 6 + M::Stk, M::DirIdxIndX, M::Stk, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Stk, M::ImmM, M::Acc, M::Stk, M::AbsInd, M::Abs, M::Abs, M::AbsLng, // 6 M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::DirIdxX, M::DirIdxX, M::DirIdxX, M::DirIndLngIdxY, M::Imp, M::AbsIdxY, M::Stk, M::Imp, M::AbsIdxXInd, M::AbsIdxX, M::AbsIdxX, M::AbsLngIdxX, // 7 - M::Rel, M::DirIdxIndX, M::RelLng, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Imp, M::Imm, M::Imp, M::Stk, M::Abs, M::Abs, M::Abs, M::AbsLng, // 8 + M::Rel, M::DirIdxIndX, M::RelLng, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Imp, M::ImmM, M::Imp, M::Stk, M::Abs, M::Abs, M::Abs, M::AbsLng, // 8 M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::DirIdxX, M::DirIdxX, M::DirIdxY, M::DirIndLngIdxY, M::Imp, M::AbsIdxY, M::Imp, M::Imp, M::Abs, M::AbsIdxX, M::AbsIdxX, M::AbsLngIdxX, // 9 - M::Imm, M::DirIdxIndX, M::Imm, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Imp, M::Imm, M::Imp, M::Stk, M::Abs, M::Abs, M::Abs, M::AbsLng, // A + M::ImmX, M::DirIdxIndX, M::ImmX, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Imp, M::ImmM, M::Imp, M::Stk, M::Abs, M::Abs, M::Abs, M::AbsLng, // A M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::DirIdxX, M::DirIdxX, M::DirIdxY, M::DirIndLngIdxY, M::Imp, M::AbsIdxY, M::Imp, M::Imp, M::AbsIdxX, M::AbsIdxX, M::AbsIdxY, M::AbsLngIdxX, // B - M::Imm, M::DirIdxIndX, M::Imm, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Imp, M::Imm, M::Imp, M::Imp, M::Abs, M::Abs, M::Abs, M::AbsLng, // C + M::ImmX, M::DirIdxIndX, M::Imm8, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Imp, M::ImmM, M::Imp, M::Imp, M::Abs, M::Abs, M::Abs, M::AbsLng, // C M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::Stk, M::DirIdxX, M::DirIdxX, M::DirIndLngIdxY, M::Imp, M::AbsIdxY, M::Stk, M::Imp, M::AbsIndLng, M::AbsIdxX, M::AbsIdxX, M::AbsLngIdxX, // D - M::Imm, M::DirIdxIndX, M::Imm, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Imp, M::Imm, M::Imp, M::Imp, M::Abs, M::Abs, M::Abs, M::AbsLng, // E + M::ImmX, M::DirIdxIndX, M::Imm8, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Imp, M::ImmM, M::Imp, M::Imp, M::Abs, M::Abs, M::Abs, M::AbsLng, // E M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::Stk, M::DirIdxX, M::DirIdxX, M::DirIndLngIdxY, M::Imp, M::AbsIdxY, M::Stk, M::Imp, M::AbsIdxXInd, M::AbsIdxX, M::AbsIdxX, M::AbsLngIdxX // F }; memcpy(_opTable, opTable, sizeof(opTable)); memcpy(_addrMode, addrMode, sizeof(addrMode)); - _enableLogging = enableLogging; - _memory = memory; + _memoryManager = memoryManager; + _enableLogging = false; _state = {}; - _state.PC = 0x400; + _state.PC = ReadDataWord(Cpu::ResetVector); + _state.SP = 0x1FF; _state.EmulationMode = true; SetFlags(ProcFlags::MemoryMode8); SetFlags(ProcFlags::IndexMode8); @@ -991,20 +1016,19 @@ void Cpu::Reset() void Cpu::Exec() { - if(lastTest != _memory[0x200] || _enableLogging) { - std::cout << - "$" << HexUtilities::ToHex(_state.PC) << - " $" << HexUtilities::ToHex(_memory[_state.PC]) << - " A:$" << HexUtilities::ToHex(_state.A) << - " X:$" << HexUtilities::ToHex(_state.X) << - " Y:$" << HexUtilities::ToHex(_state.Y) << - " Test#:" << HexUtilities::ToHex(_memory[0x200]) << - std::endl; - lastTest = _memory[0x200]; - if(_memory[0x200] >= 0x2B) { - _enableLogging = true; - } - } + /*std::cout << + "$" << HexUtilities::ToHex(_state.K) << ":" << HexUtilities::ToHex(_state.PC) << + " $" << HexUtilities::ToHex(ReadCode(_state.PC)) << + " (" << opNames[ReadCode(_state.PC)] << ")" << + " A:$" << HexUtilities::ToHex(_state.A) << + " X:$" << HexUtilities::ToHex(_state.X) << + " Y:$" << HexUtilities::ToHex(_state.Y) << + " S:$" << HexUtilities::ToHex(_state.SP) << + " D:$" << HexUtilities::ToHex(_state.D) << + " DB:$" << HexUtilities::ToHex(_state.DBR) << + " P:$" << HexUtilities::ToHex(_state.PS) << + std::endl;*/ + uint8_t opCode = GetOpCode(); _instAddrMode = _addrMode[opCode]; _operand = FetchEffectiveAddress(); @@ -1062,12 +1086,12 @@ uint32_t Cpu::ReadOperandLong() uint8_t Cpu::ReadCode(uint16_t addr, MemoryOperationType type) { - return _memory[(_state.K << 16) | addr]; + return _memoryManager->Read((_state.K << 16) | addr); } uint8_t Cpu::ReadData(uint32_t addr, MemoryOperationType type) { - return _memory[addr]; + return _memoryManager->Read(addr); } uint16_t Cpu::ReadDataWord(uint32_t addr, MemoryOperationType type) @@ -1087,7 +1111,7 @@ uint32_t Cpu::ReadDataLong(uint32_t addr, MemoryOperationType type) void Cpu::Write(uint32_t addr, uint8_t value, MemoryOperationType type) { - _memory[addr] = value; + _memoryManager->Write(addr, value); if(_enableLogging) { std::cout << "W: $" << HexUtilities::ToHex(addr) << " = $" << HexUtilities::ToHex(value) << std::endl; } @@ -1101,7 +1125,7 @@ void Cpu::WriteWord(uint32_t addr, uint16_t value, MemoryOperationType type) uint8_t Cpu::GetByteValue() { - if(_instAddrMode == AddrMode::Imm) { + if(_instAddrMode <= AddrMode::ImmM) { return (uint8_t)_operand; } else { return ReadData(_operand); @@ -1110,7 +1134,7 @@ uint8_t Cpu::GetByteValue() uint16_t Cpu::GetWordValue() { - if(_instAddrMode == AddrMode::Imm) { + if(_instAddrMode <= AddrMode::ImmM) { return (uint16_t)_operand; } else { return ReadDataWord(_operand); @@ -1136,7 +1160,7 @@ uint8_t Cpu::PopByte() } else { _state.SP++; } - return _memory[_state.SP]; + return ReadData(_state.SP); } void Cpu::PushWord(uint16_t value) @@ -1165,38 +1189,38 @@ uint16_t Cpu::GetDirectAddress(uint8_t baseAddress, uint16_t offset, bool allowE uint32_t Cpu::FetchEffectiveAddress() { switch(_instAddrMode) { - /* OK */ case AddrMode::Abs: return GetBank() | ReadOperandWord(); - /* OK */ case AddrMode::AbsIdxXInd: return ReadDataWord((_state.K << 16) | ReadOperandWord()); //JMP/JSR - /* OK */ case AddrMode::AbsIdxX: return (GetBank() | ReadOperandWord()) + _state.X; - /* OK */ case AddrMode::AbsIdxY: return (GetBank() | ReadOperandWord()) + _state.Y; - /* OK */ case AddrMode::AbsInd: return ReadDataWord(ReadOperandWord()); //JMP only - /* OK */ case AddrMode::AbsIndLng: return ReadDataLong(ReadOperandLong()); //JML only + case AddrMode::Abs: return GetBank() | ReadOperandWord(); + case AddrMode::AbsIdxXInd: return ReadDataWord((_state.K << 16) | ReadOperandWord()); //JMP/JSR + case AddrMode::AbsIdxX: return (GetBank() | ReadOperandWord()) + _state.X; + case AddrMode::AbsIdxY: return (GetBank() | ReadOperandWord()) + _state.Y; + case AddrMode::AbsInd: return ReadDataWord(ReadOperandWord()); //JMP only + case AddrMode::AbsIndLng: return ReadDataLong(ReadOperandLong()); //JML only - /* OK */ case AddrMode::AbsLngIdxX: return ReadOperandLong() + _state.X; - /* OK */ case AddrMode::AbsLng: return ReadOperandLong(); + case AddrMode::AbsLngIdxX: return ReadOperandLong() + _state.X; + case AddrMode::AbsLng: return ReadOperandLong(); - /* OK */ case AddrMode::Acc: DummyRead(); return 0; + case AddrMode::Acc: DummyRead(); return 0; case AddrMode::BlkMov: return ReadOperandWord(); - /* OK */ case AddrMode::DirIdxIndX: { + case AddrMode::DirIdxIndX: { uint8_t operand = ReadOperandByte(); uint8_t lsb = ReadData(GetDirectAddress(operand, _state.X)); uint8_t msb = ReadData(GetDirectAddress(operand, _state.X + 1)); return GetBank() | (msb << 8) | lsb; } - /* OK */ case AddrMode::DirIdxX: return GetDirectAddress(ReadOperandByte(), _state.X); - /* OK */ case AddrMode::DirIdxY: return GetDirectAddress(ReadOperandByte(), _state.Y); + case AddrMode::DirIdxX: return GetDirectAddress(ReadOperandByte(), _state.X); + case AddrMode::DirIdxY: return GetDirectAddress(ReadOperandByte(), _state.Y); - /* OK */ case AddrMode::DirIndIdxY:{ + case AddrMode::DirIndIdxY:{ uint8_t operand = ReadOperandByte(); uint8_t lsb = ReadData(GetDirectAddress(operand)); uint8_t msb = ReadData(GetDirectAddress(operand, 1)); return (GetBank() | (msb << 8) | lsb) + _state.Y; } - /* OK */ case AddrMode::DirIndLngIdxY: { + case AddrMode::DirIndLngIdxY: { uint8_t operand = ReadOperandByte(); uint8_t b1 = ReadData(GetDirectAddress(operand)); uint8_t b2 = ReadData(GetDirectAddress(operand, 1)); @@ -1204,7 +1228,7 @@ uint32_t Cpu::FetchEffectiveAddress() return ((b3 << 16) | (b2 << 8) | b1) + _state.Y; } - /* OK */ case AddrMode::DirIndLng: { + case AddrMode::DirIndLng: { uint8_t operand = ReadOperandByte(); uint8_t b1 = ReadData(GetDirectAddress(operand)); uint8_t b2 = ReadData(GetDirectAddress(operand, 1)); @@ -1212,25 +1236,28 @@ uint32_t Cpu::FetchEffectiveAddress() return (b3 << 16) | (b2 << 8) | b1; } - /* OK */ case AddrMode::DirInd: { + case AddrMode::DirInd: { uint8_t operand = ReadOperandByte(); uint8_t lsb = ReadData(GetDirectAddress(operand)); uint8_t msb = ReadData(GetDirectAddress(operand, 1)); return GetBank() | (msb << 8) | lsb; } - /* OK */ case AddrMode::Dir: return GetDirectAddress(ReadOperandByte()); + case AddrMode::Dir: return GetDirectAddress(ReadOperandByte()); - /* OK */ case AddrMode::Imm: return _state.EmulationMode ? ReadOperandByte() : ReadOperandWord(); - /* OK */ case AddrMode::Imp: DummyRead(); return 0; + case AddrMode::Imm8: return ReadOperandByte(); + case AddrMode::ImmX: return CheckFlag(ProcFlags::IndexMode8) ? ReadOperandByte() : ReadOperandWord(); + case AddrMode::ImmM: return CheckFlag(ProcFlags::MemoryMode8) ? ReadOperandByte() : ReadOperandWord(); + + case AddrMode::Imp: DummyRead(); return 0; - /* OK */ case AddrMode::RelLng: return ReadOperandWord(); - /* OK */ case AddrMode::Rel: return ReadOperandByte(); + case AddrMode::RelLng: return ReadOperandWord(); + case AddrMode::Rel: return ReadOperandByte(); - /* OK */ case AddrMode::Stk: return _state.SP; - /* OK */ case AddrMode::StkRel: return (uint16_t)(ReadOperandByte() + _state.SP); + case AddrMode::Stk: return _state.SP; + case AddrMode::StkRel: return (uint16_t)(ReadOperandByte() + _state.SP); - /* OK */ case AddrMode::StkRelIndIdxY: { + case AddrMode::StkRelIndIdxY: { uint16_t addr = (uint16_t)(ReadOperandByte() + _state.SP); return (GetBank() | addr) + _state.Y; } diff --git a/Core/Cpu.h b/Core/Cpu.h index c241c18..884233d 100644 --- a/Core/Cpu.h +++ b/Core/Cpu.h @@ -2,6 +2,8 @@ #include "stdafx.h" #include "CpuTypes.h" +class MemoryManager; + class Cpu { public: @@ -21,13 +23,12 @@ private: static constexpr uint32_t LegacyCoprocessorVector = 0x00FFF4; typedef void(Cpu::*Func)(); - + + shared_ptr _memoryManager; CpuState _state; AddrMode _instAddrMode; uint32_t _operand; - uint8_t *_memory; - Func _opTable[256]; AddrMode _addrMode[256]; @@ -54,7 +55,7 @@ private: void SetFlags(uint8_t flags); bool CheckFlag(uint8_t flag); - uint8_t ReadCode(uint16_t addr, MemoryOperationType type); + uint8_t ReadCode(uint16_t addr, MemoryOperationType type = MemoryOperationType::Read); uint8_t ReadData(uint32_t addr, MemoryOperationType type = MemoryOperationType::Read); uint16_t ReadDataWord(uint32_t addr, MemoryOperationType type = MemoryOperationType::Read); uint32_t ReadDataLong(uint32_t addr, MemoryOperationType type = MemoryOperationType::Read); @@ -224,7 +225,7 @@ private: void WAI(); public: - Cpu(uint8_t* memory, bool enableLogging); + Cpu(shared_ptr memoryManager); ~Cpu(); void Reset(); diff --git a/Core/CpuTypes.h b/Core/CpuTypes.h index 156a68a..1507500 100644 --- a/Core/CpuTypes.h +++ b/Core/CpuTypes.h @@ -52,8 +52,11 @@ namespace ProcFlags }; } -enum class AddrMode +enum class AddrMode : uint8_t { + Imm8, + ImmX, + ImmM, Abs, AbsIdxXInd, //JMP/JSR only AbsIdxX, @@ -72,7 +75,6 @@ enum class AddrMode DirIndLng, DirInd, Dir, - Imm, Imp, RelLng, Rel, diff --git a/Core/MemoryManager.h b/Core/MemoryManager.h new file mode 100644 index 0000000..39442b0 --- /dev/null +++ b/Core/MemoryManager.h @@ -0,0 +1,123 @@ +#pragma once +#include "stdafx.h" + +class IMemoryHandler +{ +public: + virtual uint8_t Read(uint32_t addr) = 0; + virtual void Write(uint32_t addr, uint8_t value) = 0; + + //virtual void GetMemoryRanges(MemoryRanges &ranges) = 0; + //virtual uint8_t PeekRAM(uint16_t addr) { return 0; } + + virtual ~IMemoryHandler() {} +}; + +class BaseCartridge : public IMemoryHandler +{ +private: + uint32_t _prgRomSize; + uint8_t* _prgRom; + +public: + BaseCartridge() + { + _prgRomSize = 1024 * 1024; + _prgRom = new uint8_t[_prgRomSize]; + + ifstream rom("..\\bin\\x64\\Debug\\game.sfc", ios::binary); + rom.read((char*)_prgRom, _prgRomSize); + } + + 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 + { + } +}; + +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 +{ +private: + uint8_t * _workRam; + IMemoryHandler* _handlers[0x100 * 0x10]; + vector> _workRamHandlers; + unique_ptr _cart; + +public: + MemoryManager() + { + _cart.reset(new BaseCartridge()); + + _workRam = new uint8_t[128 * 1024]; + for(uint32_t i = 0; i < 128 * 1024; i += 0x1000) { + _workRamHandlers.push_back(unique_ptr(new WorkRamHandler(_workRam + i))); + RegisterHandler(0x7E0000 | i, 0x7E0000 | (i + 0xFFF), _workRamHandlers[_workRamHandlers.size() - 1].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()); + } + } + + ~MemoryManager() + { + } + + void RegisterHandler(uint32_t startAddr, uint32_t endAddr, IMemoryHandler* handler) + { + if((startAddr & 0xFFF) != 0 || (endAddr & 0xFFF) != 0xFFF) { + throw new std::runtime_error("invalid start/end address"); + } + + for(uint32_t addr = startAddr; addr < endAddr; addr += 0x1000) { + _handlers[addr >> 12] = handler; + } + } + + uint8_t Read(uint32_t addr) + { + if(_handlers[addr >> 12]) { + return _handlers[addr >> 12]->Read(addr); + } else { + return 0; + } + } + + void Write(uint32_t addr, uint8_t value) + { + if(_handlers[addr >> 12]) { + return _handlers[addr >> 12]->Write(addr, value); + } + } +}; \ No newline at end of file diff --git a/Core/main.cpp b/Core/main.cpp index 8cc9b65..7b5b607 100644 --- a/Core/main.cpp +++ b/Core/main.cpp @@ -1,37 +1,19 @@ #include "stdafx.h" #include "Cpu.h" +#include "MemoryManager.h" #include "../Utilities/Timer.h" int main() { - uint8_t* memory = new uint8_t[0x1000000]; - memset(memory, 0, 0x1000000); - ifstream testRom("..\\bin\\x64\\Debug\\6502_functional_test_v2.bin", ios::binary); - if(testRom) { - testRom.read((char*)memory+0x400, 0x10000); - } - - shared_ptr cpu(new Cpu(memory, false)); + shared_ptr memoryManager(new MemoryManager()); + shared_ptr cpu(new Cpu(memoryManager)); Timer timer; - while(cpu->GetPc() != 0x32E9) { + while(cpu->opCount < 10000000) { cpu->Exec(); } std::cout << "Time: " << std::to_string(timer.GetElapsedMS()) << std::endl; std::cout << "OP Count: " << std::to_string(cpu->opCount) << std::endl; std::cout << "OP/sec: " << std::to_string(cpu->opCount * 1000 / timer.GetElapsedMS()) << std::endl; -/* - memset(memory, 0, 0x1000000); - ifstream testRom2("..\\bin\\x64\\Debug\\65C02_extended_opcodes_test.bin", ios::binary); - if(testRom2) { - testRom2.read((char*)memory, 0x10000); - } - - cpu.reset(new Cpu(memory, true)); - timer.Reset(); - while(true) { - cpu->Exec(); - } - */ while(true); } \ No newline at end of file