mirror of
https://github.com/zoriya/ComSquare.git
synced 2025-12-20 14:15:11 +00:00
Cleaning up
This commit is contained in:
66
.clang-format
Normal file
66
.clang-format
Normal file
@@ -0,0 +1,66 @@
|
||||
BasedOnStyle: LLVM
|
||||
AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveAssignments: None
|
||||
AlignOperands: DontAlign
|
||||
AllowAllArgumentsOnNextLine: false
|
||||
AllowAllConstructorInitializersOnNextLine: false
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortBlocksOnASingleLine: Always
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: Always
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortLoopsOnASingleLine: true
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
BreakBeforeBraces: Custom
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: false
|
||||
AfterClass: true
|
||||
AfterStruct: true
|
||||
AfterControlStatement: Never
|
||||
AfterEnum: true
|
||||
AfterFunction: true
|
||||
AfterNamespace: true
|
||||
AfterUnion: true
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: false
|
||||
SplitEmptyRecord: true
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
BreakInheritanceList: BeforeColon
|
||||
ColumnLimit: 0
|
||||
CompactNamespaces: false
|
||||
ContinuationIndentWidth: 4
|
||||
IndentCaseLabels: false
|
||||
IndentPPDirectives: None
|
||||
IndentWidth: 4
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
MaxEmptyLinesToKeep: 2
|
||||
NamespaceIndentation: All
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PointerAlignment: Right
|
||||
ReflowComments: false
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: false
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCpp11BracedList: true
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 0
|
||||
SpacesInAngles: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInContainerLiterals: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
TabWidth: 4
|
||||
UseTab: ForIndentation
|
||||
117
CMakeLists.txt
117
CMakeLists.txt
@@ -1,11 +1,11 @@
|
||||
cmake_minimum_required(VERSION 3.12)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
|
||||
# set the project name
|
||||
project(ComSquare)
|
||||
|
||||
# show compilation warnings
|
||||
add_compile_options(-W -Wall -Wextra -Wshadow)
|
||||
if (CMAKE_COMPILER_IS_GNUCXX)
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "-Wall -Wextra -Wshadow -Wno-unused-parameter -W -g")
|
||||
endif ()
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-O3")
|
||||
|
||||
include_directories(sources)
|
||||
|
||||
@@ -95,14 +95,15 @@ set(SOURCES
|
||||
sources/PPU/Tile.hpp
|
||||
sources/PPU/TileRenderer.cpp
|
||||
sources/PPU/TileRenderer.hpp
|
||||
)
|
||||
sources/PPU/Tile.hpp
|
||||
sources/CPU/Registers.hpp)
|
||||
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_AUTORCC ON)
|
||||
set(CMAKE_AUTOUIC ON)
|
||||
set(CMAKE_AUTOUIC_SEARCH_PATHS ./)
|
||||
|
||||
add_executable(ComSquare
|
||||
add_executable(comsquare
|
||||
sources/main.cpp
|
||||
${SOURCES}
|
||||
sources/Renderer/SFRenderer.hpp
|
||||
@@ -113,30 +114,34 @@ add_executable(ComSquare
|
||||
sources/Renderer/QtRenderer/QtWidgetSFML.hpp
|
||||
sources/Renderer/QtRenderer/QtSfmlTileRenderer.cpp
|
||||
sources/Renderer/QtRenderer/QtSfmlTileRenderer.hpp
|
||||
sources/Debugger/CPU/CPUDebug.cpp
|
||||
sources/Debugger/CPU/CPUDebug.hpp
|
||||
sources/Debugger/MemoryViewer.cpp
|
||||
sources/Debugger/MemoryViewer.hpp
|
||||
sources/Debugger/HeaderViewer.cpp
|
||||
sources/Debugger/HeaderViewer.hpp
|
||||
sources/Debugger/HeaderViewer.cpp
|
||||
sources/Debugger/HeaderViewer.hpp
|
||||
sources/Debugger/APUDebug.hpp
|
||||
sources/Debugger/APUDebug.cpp
|
||||
sources/Debugger/MemoryBusDebug.cpp
|
||||
sources/Debugger/MemoryBusDebug.hpp
|
||||
sources/Debugger/ClosableWindow.hpp
|
||||
sources/Debugger/CPU/Disassembly.cpp
|
||||
sources/Debugger/CGramDebug.cpp
|
||||
sources/Debugger/CGramDebug.hpp
|
||||
sources/Debugger/RegisterViewer.cpp
|
||||
sources/Debugger/RegisterViewer.hpp
|
||||
sources/Debugger/CPU/SymbolLoaders/WlaDx.cpp
|
||||
sources/Debugger/CPU/SymbolLoaders/WlaDx.hpp
|
||||
sources/Debugger/TileViewer/TileViewer.cpp
|
||||
sources/Debugger/TileViewer/TileViewer.hpp
|
||||
sources/Debugger/TileViewer/RAMTileRenderer.cpp
|
||||
sources/Debugger/TileViewer/RAMTileRenderer.hpp
|
||||
sources/Renderer/QtRenderer/QtSfmlTileRenderer.cpp
|
||||
sources/Renderer/QtRenderer/QtSfmlTileRenderer.hpp
|
||||
# sources/PPU/PpuDebug.cpp
|
||||
# sources/PPU/PpuDebug.hpp
|
||||
# sources/Debugger/CPU/CPUDebug.cpp
|
||||
# sources/Debugger/CPU/CPUDebug.hpp
|
||||
# sources/Debugger/MemoryViewer.cpp
|
||||
# sources/Debugger/MemoryViewer.hpp
|
||||
# sources/Debugger/HeaderViewer.cpp
|
||||
# sources/Debugger/HeaderViewer.hpp
|
||||
# sources/Debugger/HeaderViewer.cpp
|
||||
# sources/Debugger/HeaderViewer.hpp
|
||||
# sources/Debugger/APUDebug.hpp
|
||||
# sources/Debugger/APUDebug.cpp
|
||||
# sources/Debugger/MemoryBusDebug.cpp
|
||||
# sources/Debugger/MemoryBusDebug.hpp
|
||||
# sources/Debugger/ClosableWindow.hpp
|
||||
# sources/Debugger/CPU/Disassembly.cpp
|
||||
# sources/Debugger/CGramDebug.cpp
|
||||
# sources/Debugger/CGramDebug.hpp
|
||||
# sources/Debugger/RegisterViewer.cpp
|
||||
# sources/Debugger/RegisterViewer.hpp
|
||||
# sources/Debugger/CPU/SymbolLoaders/WlaDx.cpp
|
||||
# sources/Debugger/CPU/SymbolLoaders/WlaDx.hpp
|
||||
# sources/Debugger/TileViewer/TileViewer.cpp
|
||||
# sources/Debugger/TileViewer/TileViewer.hpp
|
||||
# sources/Debugger/TileViewer/RAMTileRenderer.cpp
|
||||
# sources/Debugger/TileViewer/RAMTileRenderer.hpp
|
||||
ui/tileView.ui
|
||||
ui/registersView.ui
|
||||
ui/cpuView.ui
|
||||
@@ -145,48 +150,48 @@ add_executable(ComSquare
|
||||
ui/apuView.ui
|
||||
ui/busView.ui
|
||||
resources/appResources.qrc
|
||||
)
|
||||
target_include_directories(ComSquare PRIVATE ./)
|
||||
target_compile_definitions(ComSquare PUBLIC DEBUGGER_ENABLED)
|
||||
)
|
||||
target_include_directories(comsquare PRIVATE ./)
|
||||
#target_compile_definitions(comsquare PUBLIC DEBUGGER_ENABLED)
|
||||
|
||||
find_package(Qt5 COMPONENTS Widgets REQUIRED)
|
||||
target_link_libraries(ComSquare
|
||||
target_link_libraries(comsquare
|
||||
sfml-graphics
|
||||
sfml-window
|
||||
sfml-system
|
||||
sfml-audio
|
||||
sfml-network
|
||||
Qt5::Widgets
|
||||
)
|
||||
)
|
||||
|
||||
add_executable(unit_tests EXCLUDE_FROM_ALL
|
||||
${SOURCES}
|
||||
tests/MainTest.cpp
|
||||
tests/tests.hpp
|
||||
tests/CPU/testInterupts.cpp
|
||||
# tests/APU/testAPUInstructions.cpp
|
||||
# tests/APU/testAPU.cpp
|
||||
# tests/PPU/testPpuWrite.cpp
|
||||
# tests/PPU/testPpuWriteFromVmain.cpp
|
||||
# tests/CPU/Math/testADC.cpp
|
||||
# tests/CPU/testStore.cpp
|
||||
# tests/CPU/testInternal.cpp
|
||||
# tests/CPU/testBits.cpp
|
||||
# tests/APU/testOperand.cpp
|
||||
# tests/CPU/Math/testSBC.cpp
|
||||
# tests/CPU/testTransfers.cpp
|
||||
# tests/CPU/Math/testOthersMath.cpp
|
||||
# tests/testRectangleMemory.cpp
|
||||
# tests/CPU/Math/testCMP.cpp
|
||||
# tests/CPU/testDMA.cpp
|
||||
# tests/CPU/testAddressingMode.cpp
|
||||
# tests/testMemoryBus.cpp
|
||||
)
|
||||
tests/APU/testAPUInstructions.cpp
|
||||
tests/APU/testAPU.cpp
|
||||
tests/PPU/testPpuWrite.cpp
|
||||
tests/PPU/testPpuWriteFromVmain.cpp
|
||||
tests/CPU/Math/testADC.cpp
|
||||
tests/CPU/testStore.cpp
|
||||
tests/CPU/testInternal.cpp
|
||||
tests/CPU/testBits.cpp
|
||||
tests/APU/testOperand.cpp
|
||||
tests/CPU/Math/testSBC.cpp
|
||||
tests/CPU/testTransfers.cpp
|
||||
tests/CPU/Math/testOthersMath.cpp
|
||||
tests/testRectangleMemory.cpp
|
||||
tests/CPU/Math/testCMP.cpp
|
||||
tests/CPU/testDMA.cpp
|
||||
tests/CPU/testAddressingMode.cpp
|
||||
tests/testMemoryBus.cpp
|
||||
)
|
||||
|
||||
if (CMAKE_COMPILER_IS_GNUCXX)
|
||||
# target_link_libraries(unit_tests PRIVATE -lgcov)
|
||||
# target_compile_options(unit_tests PUBLIC -fprofile-arcs -ftest-coverage)
|
||||
endif()
|
||||
# target_link_libraries(unit_tests PRIVATE -lgcov)
|
||||
# target_compile_options(unit_tests PUBLIC -fprofile-arcs -ftest-coverage)
|
||||
endif ()
|
||||
|
||||
find_package(Catch2 QUIET)
|
||||
if (NOT Catch2_FOUND)
|
||||
|
||||
@@ -2,17 +2,16 @@
|
||||
// Created by Melefo on 27/01/2020.
|
||||
//
|
||||
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
#include "APU.hpp"
|
||||
#include "../Exceptions/NotImplementedException.hpp"
|
||||
#include "../Exceptions/InvalidAddress.hpp"
|
||||
#include "../Exceptions/InvalidOpcode.hpp"
|
||||
#include "../Exceptions/NotImplementedException.hpp"
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
namespace ComSquare::APU
|
||||
{
|
||||
APU::APU(Renderer::IRenderer &renderer) :
|
||||
_renderer(renderer),
|
||||
APU::APU(Renderer::IRenderer &renderer) : _renderer(renderer),
|
||||
_map(new MemoryMap()),
|
||||
_soundBuffer(),
|
||||
_dsp(this->_soundBuffer, this->_soundBuffer.size() / 2, _map)
|
||||
@@ -751,11 +750,11 @@ namespace ComSquare::APU
|
||||
case 0xE8:
|
||||
return this->MOV(this->_internalRegisters.a, this->_getImmediateData(), 2);
|
||||
case 0xE9:
|
||||
return this->MOV(this->_internalRegisters.x, this->_getAbsoluteAddr(),4);
|
||||
return this->MOV(this->_internalRegisters.x, this->_getAbsoluteAddr(), 4);
|
||||
case 0xEA:
|
||||
return this->NOT1(this->_getAbsoluteBit());
|
||||
case 0xEB:
|
||||
return this->MOV(this->_internalRegisters.y, this->_getDirectAddr(),3);
|
||||
return this->MOV(this->_internalRegisters.y, this->_getDirectAddr(), 3);
|
||||
case 0xEC:
|
||||
return this->MOV(this->_internalRegisters.y, this->_getAbsoluteAddr(), 4);
|
||||
case 0xED:
|
||||
@@ -822,13 +821,13 @@ namespace ComSquare::APU
|
||||
this->_dsp.update();
|
||||
samples = this->_dsp.getSamplesCount();
|
||||
if (samples > 0)
|
||||
this->_renderer.playAudio(std::span{this->_soundBuffer}, samples / 2);
|
||||
this->_renderer.playAudio(std::span {this->_soundBuffer}, samples / 2);
|
||||
}
|
||||
|
||||
void APU::loadFromSPC(const std::shared_ptr<Cartridge::Cartridge>& cartridge)
|
||||
void APU::loadFromSPC(Cartridge::Cartridge &cartridge)
|
||||
{
|
||||
const uint8_t *data = cartridge->getData();
|
||||
uint24_t size = cartridge->getSize();
|
||||
const uint8_t *data = cartridge.getData();
|
||||
uint24_t size = cartridge.getSize();
|
||||
if (size < 0x101C0)
|
||||
throw InvalidAddress("Cartridge is not the right size", size);
|
||||
|
||||
@@ -839,61 +838,61 @@ namespace ComSquare::APU
|
||||
std::string date = std::string(reinterpret_cast<const char *>(data + 0x9E), 0x0B);
|
||||
std::string artist = std::string(reinterpret_cast<const char *>(data + 0xB1), 0x20);
|
||||
|
||||
this->_internalRegisters.pcl = cartridge->read(0x25);
|
||||
this->_internalRegisters.pch = cartridge->read(0x26);
|
||||
this->_internalRegisters.a = cartridge->read(0x27);
|
||||
this->_internalRegisters.x = cartridge->read(0x28);
|
||||
this->_internalRegisters.y = cartridge->read(0x29);
|
||||
this->_internalRegisters.psw = cartridge->read(0x2A);
|
||||
this->_internalRegisters.sp = cartridge->read(0x2B);
|
||||
this->_internalRegisters.pcl = cartridge.read(0x25);
|
||||
this->_internalRegisters.pch = cartridge.read(0x26);
|
||||
this->_internalRegisters.a = cartridge.read(0x27);
|
||||
this->_internalRegisters.x = cartridge.read(0x28);
|
||||
this->_internalRegisters.y = cartridge.read(0x29);
|
||||
this->_internalRegisters.psw = cartridge.read(0x2A);
|
||||
this->_internalRegisters.sp = cartridge.read(0x2B);
|
||||
|
||||
std::memcpy(this->_map->Page0.getData(), data + 0x100, this->_map->Page0.getSize());
|
||||
std::memcpy(this->_map->Page1.getData(), data + 0x200, this->_map->Page1.getSize());
|
||||
std::memcpy(this->_map->Memory.getData(), data + 0x300, this->_map->Memory.getSize());
|
||||
|
||||
this->_registers.unknown = cartridge->read(0x100 + 0xF0);
|
||||
this->_registers.ctrlreg = cartridge->read(0x100 + 0xF1);
|
||||
this->_registers.dspregAddr = cartridge->read(0x100 + 0xF2);
|
||||
this->_dsp.write(this->_registers.dspregAddr, cartridge->read(0x100 + 0xF3));
|
||||
this->_registers.port0 = cartridge->read(0x100 + 0xF4);
|
||||
this->_registers.port1 = cartridge->read(0x100 + 0xF5);
|
||||
this->_registers.port2 = cartridge->read(0x100 + 0xF6);
|
||||
this->_registers.port3 = cartridge->read(0x100 + 0xF7);
|
||||
this->_registers.regmem1 = cartridge->read(0x100 + 0xF8);
|
||||
this->_registers.regmem2 = cartridge->read(0x100 + 0xF9);
|
||||
this->_registers.timer0 = cartridge->read(0x100 + 0xFA);
|
||||
this->_registers.timer1 = cartridge->read(0x100 + 0xFB);
|
||||
this->_registers.timer2 = cartridge->read(0x100 + 0xFC);
|
||||
this->_registers.counter0 = cartridge->read(0x100 + 0xFD);
|
||||
this->_registers.counter1 = cartridge->read(0x100 + 0xFE);
|
||||
this->_registers.counter2 = cartridge->read(0x100 + 0xFF);
|
||||
this->_registers.unknown = cartridge.read(0x100 + 0xF0);
|
||||
this->_registers.ctrlreg = cartridge.read(0x100 + 0xF1);
|
||||
this->_registers.dspregAddr = cartridge.read(0x100 + 0xF2);
|
||||
this->_dsp.write(this->_registers.dspregAddr, cartridge.read(0x100 + 0xF3));
|
||||
this->_registers.port0 = cartridge.read(0x100 + 0xF4);
|
||||
this->_registers.port1 = cartridge.read(0x100 + 0xF5);
|
||||
this->_registers.port2 = cartridge.read(0x100 + 0xF6);
|
||||
this->_registers.port3 = cartridge.read(0x100 + 0xF7);
|
||||
this->_registers.regmem1 = cartridge.read(0x100 + 0xF8);
|
||||
this->_registers.regmem2 = cartridge.read(0x100 + 0xF9);
|
||||
this->_registers.timer0 = cartridge.read(0x100 + 0xFA);
|
||||
this->_registers.timer1 = cartridge.read(0x100 + 0xFB);
|
||||
this->_registers.timer2 = cartridge.read(0x100 + 0xFC);
|
||||
this->_registers.counter0 = cartridge.read(0x100 + 0xFD);
|
||||
this->_registers.counter1 = cartridge.read(0x100 + 0xFE);
|
||||
this->_registers.counter2 = cartridge.read(0x100 + 0xFF);
|
||||
|
||||
for (int i = 0x00; i < 0x80; i += 0x10)
|
||||
this->_dsp.write(i, cartridge->read(0x10100 + i));
|
||||
this->_dsp.write(i, cartridge.read(0x10100 + i));
|
||||
for (int i = 0x01; i < 0x80; i += 0x10)
|
||||
this->_dsp.write(i, cartridge->read(0x10100 + i));
|
||||
this->_dsp.write(i, cartridge.read(0x10100 + i));
|
||||
for (int i = 0x02; i < 0x80; i += 0x10)
|
||||
this->_dsp.write(i, cartridge->read(0x10100 + i));
|
||||
this->_dsp.write(i, cartridge.read(0x10100 + i));
|
||||
for (int i = 0x03; i < 0x80; i += 0x10)
|
||||
this->_dsp.write(i, cartridge->read(0x10100 + i));
|
||||
this->_dsp.write(i, cartridge.read(0x10100 + i));
|
||||
for (int i = 0x04; i < 0x80; i += 0x10)
|
||||
this->_dsp.write(i, cartridge->read(0x10100 + i));
|
||||
this->_dsp.write(i, cartridge.read(0x10100 + i));
|
||||
for (int i = 0x05; i < 0x80; i += 0x10)
|
||||
this->_dsp.write(i, cartridge->read(0x10100 + i));
|
||||
this->_dsp.write(i, cartridge.read(0x10100 + i));
|
||||
for (int i = 0x06; i < 0x80; i += 0x10)
|
||||
this->_dsp.write(i, cartridge->read(0x10100 + i));
|
||||
this->_dsp.write(i, cartridge.read(0x10100 + i));
|
||||
for (int i = 0x07; i < 0x80; i += 0x10)
|
||||
this->_dsp.write(i, cartridge->read(0x10100 + i));
|
||||
this->_dsp.write(i, cartridge.read(0x10100 + i));
|
||||
for (int i = 0x08; i < 0x80; i += 0x10)
|
||||
this->_dsp.write(i, cartridge->read(0x10100 + i));
|
||||
this->_dsp.write(i, cartridge.read(0x10100 + i));
|
||||
for (int i = 0x09; i < 0x80; i += 0x10)
|
||||
this->_dsp.write(i, cartridge->read(0x10100 + i));
|
||||
this->_dsp.write(i, cartridge.read(0x10100 + i));
|
||||
for (int i = 0x0C; i < 0x80; i += 0x10)
|
||||
this->_dsp.write(i, cartridge->read(0x10100 + i));
|
||||
this->_dsp.write(i, cartridge.read(0x10100 + i));
|
||||
for (int i = 0x0D; i < 0x80; i += 0x10)
|
||||
this->_dsp.write(i, cartridge->read(0x10100 + i));
|
||||
this->_dsp.write(i, cartridge.read(0x10100 + i));
|
||||
for (int i = 0x0F; i < 0x80; i += 0x10)
|
||||
this->_dsp.write(i, cartridge->read(0x10100 + i));
|
||||
this->_dsp.write(i, cartridge.read(0x10100 + i));
|
||||
}
|
||||
|
||||
void APU::_setNZflags(uint8_t value)
|
||||
@@ -902,10 +901,9 @@ namespace ComSquare::APU
|
||||
this->_internalRegisters.z = !value;
|
||||
}
|
||||
|
||||
MemoryMap::MemoryMap() :
|
||||
Page0(0x00F0, Apu, "APU's Page 0"),
|
||||
MemoryMap::MemoryMap() : Page0(0x00F0, Apu, "APU's Page 0"),
|
||||
Page1(0x0100, Apu, "APU's Page 1"),
|
||||
Memory(0xFDC0, Apu, "APU's Ram"),
|
||||
IPL(Apu, "IPL Rom")
|
||||
{ }
|
||||
}
|
||||
{}
|
||||
}// namespace ComSquare::APU
|
||||
@@ -390,12 +390,16 @@ namespace ComSquare::APU
|
||||
//! @brief Get the component of this accessor (used for debug purpose)
|
||||
Component getComponent() const override;
|
||||
|
||||
//! @brief Get the name of the data at the address
|
||||
//! @param addr The address (in local space)
|
||||
[[nodiscard]] std::string getValueName(uint24_t addr) const override;
|
||||
|
||||
//! @brief Get the size of the data. This size can be lower than the mapped data.
|
||||
//! @return The number of bytes inside this memory.
|
||||
uint24_t getSize() const override;
|
||||
|
||||
//! @brief Parses rom data to uploads directly into RAM and corresponding registers
|
||||
void loadFromSPC(const std::shared_ptr<Cartridge::Cartridge>& cartridge);
|
||||
void loadFromSPC(Cartridge::Cartridge &cartridge);
|
||||
|
||||
//! @brief This function execute the instructions received until the maximum number of cycles is reached.
|
||||
//! @return The number of cycles that elapsed.
|
||||
|
||||
@@ -4,18 +4,15 @@
|
||||
|
||||
#include "IPL.hpp"
|
||||
|
||||
#include <utility>
|
||||
#include "../../Exceptions/InvalidAddress.hpp"
|
||||
#include <utility>
|
||||
|
||||
namespace ComSquare::APU::IPL
|
||||
{
|
||||
IPL::IPL(Component type, std::string iplName)
|
||||
: _iplType(type),
|
||||
_iplName(std::move(iplName))
|
||||
{ }
|
||||
|
||||
IPL::~IPL()
|
||||
{ }
|
||||
{}
|
||||
|
||||
uint8_t IPL::read(uint24_t addr)
|
||||
{
|
||||
@@ -45,4 +42,10 @@ namespace ComSquare::APU::IPL
|
||||
{
|
||||
return this->_iplType;
|
||||
}
|
||||
}
|
||||
|
||||
std::string IPL::getValueName(uint24_t) const
|
||||
{
|
||||
// TODO implement this
|
||||
return "???";
|
||||
}
|
||||
}// namespace ComSquare::APU::IPL
|
||||
@@ -2,10 +2,9 @@
|
||||
// Created by Melefo on 27/02/2020.
|
||||
//
|
||||
|
||||
#ifndef COMSQUARE_IPL_HPP
|
||||
#define COMSQUARE_IPL_HPP
|
||||
#pragma once
|
||||
|
||||
#include "../../Memory/AMemory.hpp"
|
||||
#include "Memory/AMemory.hpp"
|
||||
|
||||
namespace ComSquare::APU::IPL
|
||||
{
|
||||
@@ -31,15 +30,12 @@ namespace ComSquare::APU::IPL
|
||||
public:
|
||||
//! @brief Create the rom with its value.
|
||||
explicit IPL(Component, std::string iplName);
|
||||
|
||||
//! @brief The rom can't be copied.
|
||||
IPL(const IPL &) = delete;
|
||||
|
||||
//! @brief The rom can't be assigned.
|
||||
IPL &operator=(IPL &) = delete;
|
||||
|
||||
//! @brief Destructor that free the rom.
|
||||
~IPL();
|
||||
//! @brief A default destructor
|
||||
~IPL() override = default;
|
||||
|
||||
//! @brief Read data from the component using the same method as the basic IMemory.
|
||||
//! @param addr The global 24 bits address. This method is responsible of mapping to the component's read.
|
||||
@@ -55,14 +51,16 @@ namespace ComSquare::APU::IPL
|
||||
|
||||
//! @brief Get the size of the data. This size can be lower than the mapped data.
|
||||
//! @return The number of bytes inside this memory.
|
||||
uint24_t getSize() const override;
|
||||
[[nodiscard]] uint24_t getSize() const override;
|
||||
|
||||
//! @brief Get the name of this accessor (used for debug purpose)
|
||||
std::string getName() const override;
|
||||
[[nodiscard]] std::string getName() const override;
|
||||
|
||||
//! @brief Get the component of this accessor (used for debug purpose)
|
||||
Component getComponent() const override;
|
||||
[[nodiscard]] Component getComponent() const override;
|
||||
|
||||
//! @brief Get the name of the data at the address
|
||||
//! @param addr The address (in local space)
|
||||
[[nodiscard]] std::string getValueName(uint24_t addr) const override;
|
||||
};
|
||||
}
|
||||
|
||||
#endif //COMSQUARE_IPL_HPP
|
||||
@@ -2,7 +2,7 @@
|
||||
// Created by Melefo on 25/02/2020.
|
||||
//
|
||||
|
||||
#include "../APU.hpp"
|
||||
#include "APU/APU.hpp"
|
||||
|
||||
namespace ComSquare::APU
|
||||
{
|
||||
@@ -31,4 +31,9 @@ namespace ComSquare::APU
|
||||
this->_setNZflags(this->_internalRegisters.a);
|
||||
return 3;
|
||||
}
|
||||
std::string APU::getValueName(uint24_t) const
|
||||
{
|
||||
// TODO implement this
|
||||
return "???";
|
||||
}
|
||||
}
|
||||
@@ -64,8 +64,8 @@ namespace ComSquare::CPU
|
||||
uint24_t CPU::_getDirectIndirectIndexedYAddr()
|
||||
{
|
||||
uint16_t dp = this->readPC() + this->_registers.d;
|
||||
uint24_t base = this->_bus->read(dp);
|
||||
base += this->_bus->read(dp + 1) << 8u;
|
||||
uint24_t base = this->_bus.read(dp);
|
||||
base += this->_bus.read(dp + 1) << 8u;
|
||||
base += this->_registers.dbr << 16u;
|
||||
if ((base & 0x80000000u) == (((base + this->_registers.y) & 0x80000000u)))
|
||||
this->_hasIndexCrossedPageBoundary = true;
|
||||
@@ -75,9 +75,9 @@ namespace ComSquare::CPU
|
||||
uint24_t CPU::_getDirectIndirectIndexedYLongAddr()
|
||||
{
|
||||
uint16_t dp = this->readPC() + this->_registers.d;
|
||||
uint24_t base = this->_bus->read(dp);
|
||||
base += this->_bus->read(dp + 1) << 8u;
|
||||
base += this->_bus->read(dp + 2) << 16u;
|
||||
uint24_t base = this->_bus.read(dp);
|
||||
base += this->_bus.read(dp + 1) << 8u;
|
||||
base += this->_bus.read(dp + 2) << 16u;
|
||||
return base;
|
||||
}
|
||||
|
||||
@@ -85,8 +85,8 @@ namespace ComSquare::CPU
|
||||
{
|
||||
uint16_t dp = this->readPC() + this->_registers.d;
|
||||
dp += this->_registers.x;
|
||||
uint24_t base = this->_bus->read(dp);
|
||||
base += this->_bus->read(dp + 1) << 8u;
|
||||
uint24_t base = this->_bus.read(dp);
|
||||
base += this->_bus.read(dp + 1) << 8u;
|
||||
base += this->_registers.dbr << 16u;
|
||||
return base;
|
||||
}
|
||||
@@ -137,8 +137,8 @@ namespace ComSquare::CPU
|
||||
{
|
||||
uint16_t abs = this->readPC();
|
||||
abs += this->readPC() << 8u;
|
||||
uint24_t effective = this->_bus->read(abs);
|
||||
effective += this->_bus->read(abs + 1) << 8u;
|
||||
uint24_t effective = this->_bus.read(abs);
|
||||
effective += this->_bus.read(abs + 1) << 8u;
|
||||
return effective;
|
||||
}
|
||||
|
||||
@@ -146,9 +146,9 @@ namespace ComSquare::CPU
|
||||
{
|
||||
uint16_t abs = this->readPC();
|
||||
abs += this->readPC() << 8u;
|
||||
uint24_t effective = this->_bus->read(abs);
|
||||
effective += this->_bus->read(abs + 1) << 8u;
|
||||
effective += this->_bus->read(abs + 2) << 16u;
|
||||
uint24_t effective = this->_bus.read(abs);
|
||||
effective += this->_bus.read(abs + 1) << 8u;
|
||||
effective += this->_bus.read(abs + 2) << 16u;
|
||||
return effective;
|
||||
}
|
||||
|
||||
@@ -157,16 +157,16 @@ namespace ComSquare::CPU
|
||||
uint24_t abs = this->readPC();
|
||||
abs += this->readPC() << 8u;
|
||||
abs += this->_registers.x;
|
||||
uint24_t effective = this->_bus->read(abs);
|
||||
effective += this->_bus->read(abs + 1) << 8u;
|
||||
uint24_t effective = this->_bus.read(abs);
|
||||
effective += this->_bus.read(abs + 1) << 8u;
|
||||
return effective;
|
||||
}
|
||||
|
||||
uint24_t CPU::_getDirectIndirectAddr()
|
||||
{
|
||||
uint16_t dp = this->readPC() + this->_registers.d;
|
||||
uint24_t effective = this->_bus->read(dp);
|
||||
effective += this->_bus->read(dp + 1) << 8u;
|
||||
uint24_t effective = this->_bus.read(dp);
|
||||
effective += this->_bus.read(dp + 1) << 8u;
|
||||
effective += this->_registers.dbr << 16u;
|
||||
return effective;
|
||||
}
|
||||
@@ -174,9 +174,9 @@ namespace ComSquare::CPU
|
||||
uint24_t CPU::_getDirectIndirectLongAddr()
|
||||
{
|
||||
uint16_t dp = this->readPC() + this->_registers.d;
|
||||
uint24_t effective = this->_bus->read(dp);
|
||||
effective += this->_bus->read(++dp) << 8u;
|
||||
effective += this->_bus->read(++dp) << 16u;
|
||||
uint24_t effective = this->_bus.read(dp);
|
||||
effective += this->_bus.read(++dp) << 8u;
|
||||
effective += this->_bus.read(++dp) << 16u;
|
||||
return effective;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,32 +3,21 @@
|
||||
//
|
||||
|
||||
#include "CPU.hpp"
|
||||
|
||||
#include <utility>
|
||||
#include "Exceptions/InvalidAddress.hpp"
|
||||
#include "Exceptions/InvalidOpcode.hpp"
|
||||
#include "Utility/Utility.hpp"
|
||||
#include <iostream>
|
||||
#include "../Exceptions/InvalidAddress.hpp"
|
||||
#include "../Exceptions/InvalidOpcode.hpp"
|
||||
|
||||
namespace ComSquare::CPU
|
||||
{
|
||||
CPU::CPU(std::shared_ptr<Memory::MemoryBus> bus, Cartridge::Header &cartridgeHeader)
|
||||
: _bus(std::move(bus)),
|
||||
_cartridgeHeader(cartridgeHeader)
|
||||
CPU::CPU(Memory::MemoryBus &bus, Cartridge::Header &cartridgeHeader)
|
||||
: _bus(bus),
|
||||
_cartridgeHeader(cartridgeHeader),
|
||||
_dmaChannels({DMA(bus), DMA(bus), DMA(bus), DMA(bus), DMA(bus), DMA(bus), DMA(bus), DMA(bus)})
|
||||
{
|
||||
this->RESB();
|
||||
for (DMA &channel : this->_dmaChannels)
|
||||
channel.setBus(_bus);
|
||||
}
|
||||
|
||||
bool CPU::isDebugger() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void CPU::setMemoryBus(std::shared_ptr<Memory::MemoryBus> bus)
|
||||
{
|
||||
this->_bus = std::move(bus);
|
||||
}
|
||||
|
||||
//! @bref The CPU's internal registers starts at $4200 and finish at $421F.
|
||||
uint8_t CPU::read(uint24_t addr)
|
||||
@@ -214,7 +203,7 @@ namespace ComSquare::CPU
|
||||
|
||||
uint8_t CPU::readPC()
|
||||
{
|
||||
uint8_t ret = this->_bus->read(this->_registers.pac);
|
||||
uint8_t ret = this->_bus.read(this->_registers.pac);
|
||||
this->_registers.pc++;
|
||||
return ret;
|
||||
}
|
||||
@@ -333,24 +322,24 @@ namespace ComSquare::CPU
|
||||
|
||||
void CPU::_push(uint8_t data)
|
||||
{
|
||||
this->_bus->write(this->_registers.s--, data);
|
||||
this->_bus.write(this->_registers.s--, data);
|
||||
}
|
||||
|
||||
void CPU::_push(uint16_t data)
|
||||
{
|
||||
this->_bus->write(this->_registers.s--, data >> 8u);
|
||||
this->_bus->write(this->_registers.s--, data);
|
||||
this->_bus.write(this->_registers.s--, data >> 8u);
|
||||
this->_bus.write(this->_registers.s--, data);
|
||||
}
|
||||
|
||||
uint8_t CPU::_pop()
|
||||
{
|
||||
return this->_bus->read(++this->_registers.s);
|
||||
return this->_bus.read(++this->_registers.s);
|
||||
}
|
||||
|
||||
uint16_t CPU::_pop16()
|
||||
{
|
||||
uint16_t value = this->_bus->read(++this->_registers.s);
|
||||
value +=this->_bus->read(++this->_registers.s) << 8u;
|
||||
uint16_t value = this->_bus.read(++this->_registers.s);
|
||||
value += this->_bus.read(++this->_registers.s) << 8u;
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -363,4 +352,4 @@ namespace ComSquare::CPU
|
||||
{
|
||||
return Cpu;
|
||||
}
|
||||
}
|
||||
}// namespace ComSquare::CPU
|
||||
@@ -2,8 +2,7 @@
|
||||
// Created by anonymus-raccoon on 1/24/20.
|
||||
//
|
||||
|
||||
#ifndef COMSQUARE_CPU_HPP
|
||||
#define COMSQUARE_CPU_HPP
|
||||
#pragma once
|
||||
|
||||
#include "Memory/AMemory.hpp"
|
||||
#include "Memory/MemoryBus.hpp"
|
||||
@@ -12,180 +11,21 @@
|
||||
#include "Memory/AMemory.hpp"
|
||||
#include "Instruction.hpp"
|
||||
#include "DMA/DMA.hpp"
|
||||
#include "CPU/Registers.hpp"
|
||||
#ifdef DEBUGGER_ENABLED
|
||||
#include "Debugger/RegisterViewer.hpp"
|
||||
#endif
|
||||
|
||||
namespace ComSquare::CPU
|
||||
{
|
||||
//! @brief Struct containing registers for the main CPU.
|
||||
struct Registers {
|
||||
//! @brief The Accumulator
|
||||
union {
|
||||
struct {
|
||||
uint8_t al;
|
||||
uint8_t ah;
|
||||
};
|
||||
uint16_t a;
|
||||
};
|
||||
//! @brief The Data Bank Register;
|
||||
uint8_t dbr;
|
||||
//! @brief The Direct Page register;
|
||||
union {
|
||||
struct {
|
||||
uint8_t dl;
|
||||
uint8_t dh;
|
||||
};
|
||||
uint16_t d;
|
||||
};
|
||||
union {
|
||||
struct {
|
||||
//! @brief The Program Counter;
|
||||
union {
|
||||
struct {
|
||||
uint8_t pcl;
|
||||
uint8_t pch;
|
||||
};
|
||||
uint16_t pc;
|
||||
};
|
||||
//! @brief The Program Bank Register;
|
||||
uint8_t pbr;
|
||||
};
|
||||
//! @brief The current Program Address Counter (does not exist in a snes but is useful here).
|
||||
uint24_t pac;
|
||||
};
|
||||
//! @brief The Stack pointer
|
||||
union {
|
||||
struct {
|
||||
uint8_t sl;
|
||||
uint8_t sh;
|
||||
};
|
||||
uint16_t s;
|
||||
};
|
||||
//! @brief The X index register
|
||||
union {
|
||||
struct {
|
||||
uint8_t xl;
|
||||
uint8_t xh;
|
||||
};
|
||||
uint16_t x;
|
||||
};
|
||||
//! @brief The Y index register
|
||||
union {
|
||||
struct {
|
||||
uint8_t yl;
|
||||
uint8_t yh;
|
||||
};
|
||||
uint16_t y;
|
||||
};
|
||||
|
||||
//! @brief The Processor status register;
|
||||
union {
|
||||
struct {
|
||||
//! @brief The Carry flag
|
||||
bool c : 1;
|
||||
//! @brief The Zero flag
|
||||
bool z : 1;
|
||||
//! @brief The Interrupt request disable flag
|
||||
bool i : 1;
|
||||
//! @brief The Decimal mode flag
|
||||
bool d : 1;
|
||||
//! @brief The indeX register width flag (in native mode only) - 0 = 16 bits mode, 1 = 8 bits mode OR the Break flag (in emulation mode only)
|
||||
bool x_b : 1;
|
||||
//! @brief The accumulator and Memory width flag (in native mode only) - 0 = 16 bits mode, 1 = 8 bits mode.
|
||||
bool m : 1;
|
||||
//! @brief The oVerflow flag
|
||||
bool v : 1;
|
||||
//! @brief The Negative flag
|
||||
bool n : 1;
|
||||
};
|
||||
uint8_t flags;
|
||||
} p;
|
||||
};
|
||||
|
||||
//! @brief Struct containing internal registers of the CPU.
|
||||
struct InternalRegisters
|
||||
{
|
||||
//! @brief Interrupt Enable Register
|
||||
uint8_t nmitimen;
|
||||
|
||||
//! @brief IO Port Write Register
|
||||
uint8_t wrio;
|
||||
|
||||
//! @brief Multiplicand Register A
|
||||
uint8_t wrmpya;
|
||||
//! @brief Multiplicand Register B
|
||||
uint8_t wrmpyb;
|
||||
|
||||
//! @brief Divisor & Dividend Registers (A - Low)
|
||||
uint8_t wrdivl;
|
||||
//! @brief Divisor & Dividend Registers (A - High)
|
||||
uint8_t wrdivh;
|
||||
//! @brief Divisor & Dividend Registers (B)
|
||||
uint8_t wrdivb;
|
||||
|
||||
//! @brief IRQ Timer Registers (Horizontal - Low)
|
||||
uint8_t htimel;
|
||||
//! @brief IRQ Timer Registers (Horizontal - High)
|
||||
uint8_t htimeh;
|
||||
|
||||
//! @brief IRQ Timer Registers (Vertical - Low)
|
||||
uint8_t vtimel;
|
||||
//! @brief IRQ Timer Registers (Vertical - High)
|
||||
uint8_t vtimeh;
|
||||
|
||||
//! @brief HDMA Enable Register
|
||||
uint8_t hdmaen;
|
||||
|
||||
//! @brief ROM Speed Register
|
||||
uint8_t memsel;
|
||||
|
||||
//! @brief Interrupt Flag Registers
|
||||
uint8_t rdnmi;
|
||||
//! @brief Interrupt Flag Registers - TimeUp
|
||||
uint8_t timeup;
|
||||
|
||||
//! @brief PPU Status Register
|
||||
uint8_t hvbjoy;
|
||||
|
||||
//! @brief IO Port Read Register
|
||||
uint8_t rdio;
|
||||
|
||||
//! @brief Divide Result Registers (can sometimes be used as multiplication result register) - LOW
|
||||
uint8_t rddivl;
|
||||
//! @brief Divide Result Registers (can sometimes be used as multiplication result register) - HIGH
|
||||
uint8_t rddivh;
|
||||
|
||||
//! @brief Multiplication Result Registers (can sometimes be used as divide result register) - LOW
|
||||
uint8_t rdmpyl;
|
||||
//! @brief Multiplication Result Registers (can sometimes be used as divide result register) - HIGH
|
||||
uint8_t rdmpyh;
|
||||
|
||||
//! @brief Controller Port Data Registers (Pad 1 - Low)
|
||||
uint8_t joy1l;
|
||||
//! @brief Controller Port Data Registers (Pad 1 - High)
|
||||
uint8_t joy1h;
|
||||
|
||||
//! @brief Controller Port Data Registers (Pad 2 - Low)
|
||||
uint8_t joy2l;
|
||||
//! @brief Controller Port Data Registers (Pad 2 - High)
|
||||
uint8_t joy2h;
|
||||
|
||||
//! @brief Controller Port Data Registers (Pad 3 - Low)
|
||||
uint8_t joy3l;
|
||||
//! @brief Controller Port Data Registers (Pad 3 - High)
|
||||
uint8_t joy3h;
|
||||
|
||||
//! @brief Controller Port Data Registers (Pad 4 - Low)
|
||||
uint8_t joy4l;
|
||||
//! @brief Controller Port Data Registers (Pad 4 - High)
|
||||
uint8_t joy4h;
|
||||
};
|
||||
|
||||
//! @brief The main CPU
|
||||
class CPU : public Memory::AMemory {
|
||||
class CPU : public Memory::AMemory
|
||||
{
|
||||
protected:
|
||||
//! @brief All the registers of the CPU
|
||||
Registers _registers{};
|
||||
Registers _registers {};
|
||||
//! @brief Internal registers of the CPU (accessible from the bus via addr $4200 to $421F).
|
||||
InternalRegisters _internalRegisters{};
|
||||
InternalRegisters _internalRegisters {};
|
||||
|
||||
//! @brief Is the CPU running in emulation mode (in 8bits)
|
||||
bool _isEmulationMode = true;
|
||||
@@ -195,8 +35,8 @@ namespace ComSquare::CPU
|
||||
bool _isWaitingForInterrupt = false;
|
||||
|
||||
//! @brief The memory bus to use for read/write.
|
||||
std::shared_ptr<Memory::MemoryBus> _bus;
|
||||
//! @brief The cartridge header (stored for interrupt vectors..
|
||||
Memory::MemoryBus &_bus;
|
||||
//! @brief The cartridge header (stored for interrupt vectors..)
|
||||
Cartridge::Header &_cartridgeHeader;
|
||||
|
||||
//! @brief DMA channels witch are mapped to the bus.
|
||||
@@ -250,7 +90,6 @@ namespace ComSquare::CPU
|
||||
//! @brief The <8-bit exp> is added to S and combined with DBR to form the base address. Y is added to the base address to form the effective address.
|
||||
uint24_t _getStackRelativeIndirectIndexedYAddr();
|
||||
|
||||
|
||||
//! @brief Push 8 bits of data to the stack.
|
||||
void _push(uint8_t data);
|
||||
//! @brief Push 16 bits of data to the stack.
|
||||
@@ -470,7 +309,7 @@ namespace ComSquare::CPU
|
||||
|
||||
//! @brief All the instructions of the CPU.
|
||||
//! @info Instructions are indexed by their opcode
|
||||
Instruction _instructions[0x100] = {
|
||||
const Instruction _instructions[0x100] = {
|
||||
{&CPU::BRK, 7, "brk", AddressingMode::Immediate8bits, 2}, // 00
|
||||
{&CPU::ORA, 6, "ora", AddressingMode::DirectPageIndirectIndexedByX, 2}, // 01
|
||||
{&CPU::COP, 7, "cop", AddressingMode::Immediate8bits, 2}, // 02
|
||||
@@ -729,14 +568,20 @@ namespace ComSquare::CPU
|
||||
{&CPU::SBC, 5, "sbc", AddressingMode::AbsoluteIndexedByXLong, 4}, // FF
|
||||
};
|
||||
public:
|
||||
explicit CPU(std::shared_ptr<Memory::MemoryBus> bus, Cartridge::Header &cartridgeHeader);
|
||||
//! @brief Construct a new generic CPU.
|
||||
//! @param bus The memory bus to use to transfer data.
|
||||
//! @param cartridgeHeader The header used to know interrupts, main entry point etc...
|
||||
CPU(Memory::MemoryBus &bus, Cartridge::Header &cartridgeHeader);
|
||||
//! @brief A default copy constructor
|
||||
CPU(const CPU &) = default;
|
||||
//! @brief A CPU is not assignable
|
||||
CPU &operator=(const CPU &) = delete;
|
||||
//! @brief A default destructor
|
||||
~CPU() override = default;
|
||||
|
||||
//! @brief This function continue to execute the Cartridge code.
|
||||
//! @return The number of CPU cycles that elapsed
|
||||
virtual unsigned update();
|
||||
unsigned update();
|
||||
//! @brief Read from the internal CPU register.
|
||||
//! @param addr The address to read from. The address 0x0 should refer to the first byte of the register.
|
||||
//! @throw InvalidAddress will be thrown if the address is more than $1F (the number of register).
|
||||
@@ -748,18 +593,22 @@ namespace ComSquare::CPU
|
||||
//! @throw InvalidAddress will be thrown if the address is more than $1F (the number of register).
|
||||
void write(uint24_t addr, uint8_t data) override;
|
||||
|
||||
//! @brief Get the name of the data at the address
|
||||
//! @param addr The address (in local space)
|
||||
[[nodiscard]] std::string getValueName(uint24_t addr) const override;
|
||||
|
||||
//! @brief Get the size of the data. This size can be lower than the mapped data.
|
||||
//! @return The number of bytes inside this memory.
|
||||
uint24_t getSize() const override;
|
||||
[[nodiscard]] uint24_t getSize() const override;
|
||||
|
||||
//! @brief Get the name of this accessor (used for debug purpose)
|
||||
std::string getName() const override;
|
||||
[[nodiscard]] std::string getName() const override;
|
||||
|
||||
//! @brief Get the component of this accessor (used for debug purpose)
|
||||
Component getComponent() const override;
|
||||
[[nodiscard]] Component getComponent() const override;
|
||||
|
||||
//! @brief Reset interrupt - Called on boot and when the reset button is pressed.
|
||||
virtual int RESB();
|
||||
//! @copydoc
|
||||
int RESB();
|
||||
|
||||
//! @brief Is an NMI (non-maskable interrupt) requested.
|
||||
bool IsNMIRequested = false;
|
||||
@@ -768,16 +617,8 @@ namespace ComSquare::CPU
|
||||
//! @brief Is an abort requested
|
||||
bool IsAbortRequested = false;
|
||||
|
||||
//! @brief Return true if the CPU is overloaded with debugging features.
|
||||
virtual bool isDebugger() const;
|
||||
|
||||
//! @brief Change the memory bus used by the CPU.
|
||||
virtual void setMemoryBus(std::shared_ptr<Memory::MemoryBus> bus);
|
||||
|
||||
#ifdef DEBUGGER_ENABLED
|
||||
#ifdef DEBUGGER_ENABLED
|
||||
friend Debugger::RegisterViewer;
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
#endif //COMSQUARE_CPU_HPP
|
||||
|
||||
@@ -2,18 +2,15 @@
|
||||
// Created by anonymus-raccoon on 5/26/20.
|
||||
//
|
||||
|
||||
#include <iostream>
|
||||
#include "DMA.hpp"
|
||||
#include "../../Exceptions/InvalidAddress.hpp"
|
||||
#include "Exceptions/InvalidAddress.hpp"
|
||||
|
||||
namespace ComSquare::CPU
|
||||
{
|
||||
DMA::DMA(std::shared_ptr<Memory::MemoryBus> bus) : _bus(std::move(bus)) {}
|
||||
|
||||
void DMA::setBus(std::shared_ptr<Memory::MemoryBus> bus)
|
||||
{
|
||||
this->_bus = std::move(bus);
|
||||
}
|
||||
DMA::DMA(Memory::MemoryBus &bus)
|
||||
: _bus(bus),
|
||||
enabled(false)
|
||||
{}
|
||||
|
||||
uint8_t DMA::read(uint8_t addr) const
|
||||
{
|
||||
@@ -68,24 +65,25 @@ namespace ComSquare::CPU
|
||||
|
||||
unsigned DMA::_writeOneByte(uint24_t aAddress, uint24_t bAddress)
|
||||
{
|
||||
// Address $2180 refers to the WRam data register. Write to/Read from this port when the a address is on the vram cause different behaviors.
|
||||
// Address $2180 refers to the WRam data register.
|
||||
// Write to/Read from this port when the a address is on the vram cause different behaviors.
|
||||
if (this->_port == 0x80) {
|
||||
auto accessor = this->_bus->getAccessor(aAddress);
|
||||
auto accessor = this->_bus.getAccessor(aAddress);
|
||||
if (accessor && accessor->getComponent() == WRam) {
|
||||
// WRAM->$2180 The write is not performed but the time is consumed anyway.
|
||||
if (this->_controlRegister.direction == AtoB)
|
||||
return 8;
|
||||
// $2180->WRAM No read is performed (so only 4 master cycles are needed) but the value written is invalid.
|
||||
this->_bus->write(aAddress, 0xFF);
|
||||
this->_bus.write(aAddress, 0xFF);
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
if (this->_controlRegister.direction == AtoB) {
|
||||
uint8_t data = this->_bus->read(aAddress);
|
||||
this->_bus->write(bAddress, data);
|
||||
uint8_t data = this->_bus.read(aAddress);
|
||||
this->_bus.write(bAddress, data);
|
||||
} else {
|
||||
uint8_t data = this->_bus->read(bAddress);
|
||||
this->_bus->write(aAddress, data);
|
||||
uint8_t data = this->_bus.read(bAddress);
|
||||
this->_bus.write(aAddress, data);
|
||||
}
|
||||
return 8;
|
||||
}
|
||||
@@ -106,7 +104,7 @@ namespace ComSquare::CPU
|
||||
return cycles;
|
||||
}
|
||||
|
||||
int DMA::_getModeOffset(int index)
|
||||
int DMA::_getModeOffset(int index) const
|
||||
{
|
||||
switch (this->_controlRegister.mode) {
|
||||
case OneToOne:
|
||||
@@ -127,4 +125,4 @@ namespace ComSquare::CPU
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}// namespace ComSquare::CPU
|
||||
@@ -2,25 +2,26 @@
|
||||
// Created by anonymus-raccoon on 5/26/20.
|
||||
//
|
||||
|
||||
#ifndef COMSQUARE_DMA_HPP
|
||||
#define COMSQUARE_DMA_HPP
|
||||
#pragma once
|
||||
|
||||
#include "Memory/MemoryBus.hpp"
|
||||
#include "Models/Int24.hpp"
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include "../../Models/Int24.hpp"
|
||||
#include "../../Memory/MemoryBus.hpp"
|
||||
|
||||
#ifdef DEBUGGER_ENABLED
|
||||
#include "../../Debugger/RegisterViewer.hpp"
|
||||
#include "Debugger/RegisterViewer.hpp"
|
||||
#endif
|
||||
|
||||
namespace ComSquare::CPU
|
||||
{
|
||||
//! @brief Class handling all DMA/HDMA transfers (Direct Memory Access or H-Blank Direct Memory Access)
|
||||
class DMA {
|
||||
class DMA
|
||||
{
|
||||
public:
|
||||
//! @brief The first three bytes of the DMA's control register. Used to tell how many bytes/registers there is.
|
||||
enum DMAMode {
|
||||
enum DMAMode
|
||||
{
|
||||
//! @brief 1 byte is transferred to 1 register (write once)
|
||||
OneToOne = 0b000,
|
||||
//! @brief 2 byte is transferred to 2 register (write once)
|
||||
@@ -39,63 +40,73 @@ namespace ComSquare::CPU
|
||||
FourToTwoBis = 0b111
|
||||
};
|
||||
|
||||
enum Direction {
|
||||
enum Direction
|
||||
{
|
||||
AtoB,
|
||||
BtoA
|
||||
};
|
||||
|
||||
private:
|
||||
//! @brief Write one byte using the A address, the port and the _direction. Handle special cases where no write occurs.
|
||||
//! @return The number of cycles used.
|
||||
unsigned _writeOneByte(uint24_t aAddress, uint24_t bAddress);
|
||||
//! @brief Get an offset corresponding to the current DMAMode and the index of the currently transferred byte.
|
||||
int _getModeOffset(int index);
|
||||
[[nodiscard]] int _getModeOffset(int index) const;
|
||||
|
||||
//! @brief DMA Control register (various information about the transfer)
|
||||
union {
|
||||
union
|
||||
{
|
||||
struct {
|
||||
//! @brief DMA's mode: how many bytes/registers there is, how many writes...
|
||||
DMAMode mode: 3;
|
||||
DMAMode mode : 3;
|
||||
//! @brief If this flag is set, no increment/decrement will be done.
|
||||
bool fixed: 1;
|
||||
bool fixed : 1;
|
||||
//! @brief if this flag is 0: increment. Else: decrement. (The A address)
|
||||
bool increment: 1;
|
||||
bool increment : 1;
|
||||
//! @brief Two unused bites.
|
||||
bool _: 2;
|
||||
bool _ : 2;
|
||||
//! @brief The direction of the transfer.
|
||||
Direction direction: 1;
|
||||
Direction direction : 1;
|
||||
};
|
||||
uint8_t raw;
|
||||
} _controlRegister;
|
||||
} _controlRegister {};
|
||||
|
||||
//! @brief If this is 'xx', the register accessed will be $21xx.
|
||||
uint8_t _port;
|
||||
uint8_t _port {};
|
||||
|
||||
//! @brief The absolute long address of the data from the A bus.
|
||||
union {
|
||||
union
|
||||
{
|
||||
uint8_t bytes[3];
|
||||
struct {
|
||||
uint16_t page;
|
||||
uint8_t bank;
|
||||
};
|
||||
uint24_t raw: 24;
|
||||
} _aAddress;
|
||||
uint24_t raw : 24;
|
||||
} _aAddress {};
|
||||
|
||||
//! @brief The number of bytes to be transferred.
|
||||
union {
|
||||
union
|
||||
{
|
||||
uint8_t bytes[2];
|
||||
uint16_t raw;
|
||||
} _count;
|
||||
} _count {};
|
||||
|
||||
//! @brief The memory bus to use for read/write.
|
||||
std::shared_ptr<Memory::MemoryBus> _bus;
|
||||
Memory::MemoryBus &_bus;
|
||||
|
||||
public:
|
||||
//! @brief Is this channel set to run?
|
||||
bool enabled;
|
||||
|
||||
//! @brief Set the memory bus used by this dma channel.
|
||||
void setBus(std::shared_ptr<Memory::MemoryBus> bus);
|
||||
|
||||
//! @brief Bus helper to read from this channel.
|
||||
uint8_t read(uint8_t addr) const;
|
||||
//! @param addr The address to read from
|
||||
//! @return The value at the given address.
|
||||
[[nodiscard]] uint8_t read(uint8_t addr) const;
|
||||
|
||||
//! @brief Bus helper to write to this channel.
|
||||
//! @param addr The address to write to
|
||||
//! @param data The data to write.
|
||||
void write(uint8_t addr, uint8_t data);
|
||||
|
||||
//! @brief Run the DMA for x cycles
|
||||
@@ -103,16 +114,18 @@ namespace ComSquare::CPU
|
||||
//! @return the number of cycles taken
|
||||
unsigned run(unsigned cycles);
|
||||
|
||||
DMA() = default;
|
||||
DMA(std::shared_ptr<Memory::MemoryBus> bus);
|
||||
//! @brief Create a DMA channel with a given bus
|
||||
//! @param bus The memory bus to use.
|
||||
explicit DMA(Memory::MemoryBus &bus);
|
||||
//! @brief A DMA is copy constructable.
|
||||
DMA(const DMA &) = default;
|
||||
DMA &operator=(const DMA &) = default;
|
||||
//! @brief A DMA is not assignable
|
||||
DMA &operator=(const DMA &) = delete;
|
||||
//! @brief A default destructor.
|
||||
~DMA() = default;
|
||||
|
||||
#ifdef DEBUGGER_ENABLED
|
||||
#ifdef DEBUGGER_ENABLED
|
||||
friend Debugger::RegisterViewer;
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
#endif //COMSQUARE_DMA_HPP
|
||||
}// namespace ComSquare::CPU
|
||||
|
||||
@@ -10,13 +10,13 @@ namespace ComSquare::CPU
|
||||
{
|
||||
int CPU::TSB(uint24_t valueAddr, AddressingMode mode)
|
||||
{
|
||||
uint16_t value = this->_bus->read(valueAddr);
|
||||
uint16_t value = this->_bus.read(valueAddr);
|
||||
if (!this->_registers.p.m)
|
||||
value += this->_bus->read(valueAddr + 1) << 8u;
|
||||
value += this->_bus.read(valueAddr + 1) << 8u;
|
||||
value |= this->_registers.a;
|
||||
this->_bus->write(valueAddr, value);
|
||||
this->_bus.write(valueAddr, value);
|
||||
if (!this->_registers.p.m)
|
||||
this->_bus->write(valueAddr + 1, value >> 8u);
|
||||
this->_bus.write(valueAddr + 1, value >> 8u);
|
||||
|
||||
this->_registers.p.z = value == 0;
|
||||
|
||||
@@ -30,14 +30,14 @@ namespace ComSquare::CPU
|
||||
|
||||
int CPU::TRB(uint24_t valueAddr, AddressingMode mode)
|
||||
{
|
||||
uint16_t value = this->_bus->read(valueAddr);
|
||||
uint16_t value = this->_bus.read(valueAddr);
|
||||
if (!this->_registers.p.m)
|
||||
value += this->_bus->read(valueAddr + 1) << 8u;
|
||||
value += this->_bus.read(valueAddr + 1) << 8u;
|
||||
|
||||
uint16_t newValue = value & ~this->_registers.a;
|
||||
this->_bus->write(valueAddr, newValue);
|
||||
this->_bus.write(valueAddr, newValue);
|
||||
if (!this->_registers.p.m)
|
||||
this->_bus->write(valueAddr + 1, newValue >> 8u);
|
||||
this->_bus.write(valueAddr + 1, newValue >> 8u);
|
||||
|
||||
this->_registers.p.z = (value & this->_registers.a) == 0;
|
||||
|
||||
@@ -52,9 +52,9 @@ namespace ComSquare::CPU
|
||||
int CPU::BIT(uint24_t valueAddr, AddressingMode mode)
|
||||
{
|
||||
unsigned negativeMask = this->_registers.p.m ? 0x80u : 0x8000u;
|
||||
unsigned value = this->_bus->read(valueAddr);
|
||||
unsigned value = this->_bus.read(valueAddr);
|
||||
if (!this->_registers.p.m)
|
||||
value += this->_bus->read(valueAddr + 1) << 8u;
|
||||
value += this->_bus.read(valueAddr + 1) << 8u;
|
||||
|
||||
if (mode != ImmediateForA) {
|
||||
this->_registers.p.n = value & negativeMask;
|
||||
@@ -89,18 +89,18 @@ namespace ComSquare::CPU
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t value = this->_bus->read(valueAddr);
|
||||
uint16_t value = this->_bus.read(valueAddr);
|
||||
if (!this->_registers.p.m)
|
||||
value += this->_bus->read(valueAddr + 1) << 8u;
|
||||
value += this->_bus.read(valueAddr + 1) << 8u;
|
||||
|
||||
this->_registers.p.c = value & highByte;
|
||||
value <<= 1u;
|
||||
this->_registers.p.n = value & highByte;
|
||||
this->_registers.p.z = value == 0;
|
||||
|
||||
this->_bus->write(valueAddr, value);
|
||||
this->_bus.write(valueAddr, value);
|
||||
if (!this->_registers.p.m)
|
||||
this->_bus->write(valueAddr + 1, value >> 8u);
|
||||
this->_bus.write(valueAddr + 1, value >> 8u);
|
||||
|
||||
int cycles = 2 * !this->_registers.p.m;
|
||||
switch (mode) {
|
||||
@@ -128,17 +128,17 @@ namespace ComSquare::CPU
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t value = this->_bus->read(valueAddr);
|
||||
uint16_t value = this->_bus.read(valueAddr);
|
||||
if (!this->_registers.p.m)
|
||||
value += this->_bus->read(valueAddr + 1) << 8u;
|
||||
value += this->_bus.read(valueAddr + 1) << 8u;
|
||||
|
||||
this->_registers.p.c = value & 1u;
|
||||
value >>= 1u;
|
||||
this->_registers.p.z = value == 0;
|
||||
|
||||
this->_bus->write(valueAddr, value);
|
||||
this->_bus.write(valueAddr, value);
|
||||
if (!this->_registers.p.m)
|
||||
this->_bus->write(valueAddr + 1, value >> 8u);
|
||||
this->_bus.write(valueAddr + 1, value >> 8u);
|
||||
|
||||
int cycles = 2 * !this->_registers.p.m;
|
||||
switch (mode) {
|
||||
@@ -169,9 +169,9 @@ namespace ComSquare::CPU
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t value = this->_bus->read(valueAddr);
|
||||
uint16_t value = this->_bus.read(valueAddr);
|
||||
if (!this->_registers.p.m)
|
||||
value += this->_bus->read(valueAddr + 1) << 8u;
|
||||
value += this->_bus.read(valueAddr + 1) << 8u;
|
||||
|
||||
this->_registers.p.c = value & highByte;
|
||||
value <<= 1u;
|
||||
@@ -179,9 +179,9 @@ namespace ComSquare::CPU
|
||||
this->_registers.p.n = value & highByte;
|
||||
this->_registers.p.z = value == 0;
|
||||
|
||||
this->_bus->write(valueAddr, value);
|
||||
this->_bus.write(valueAddr, value);
|
||||
if (!this->_registers.p.m)
|
||||
this->_bus->write(valueAddr + 1, value >> 8u);
|
||||
this->_bus.write(valueAddr + 1, value >> 8u);
|
||||
|
||||
int cycles = 2 * !this->_registers.p.m;
|
||||
switch (mode) {
|
||||
@@ -212,18 +212,18 @@ namespace ComSquare::CPU
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t value = this->_bus->read(valueAddr);
|
||||
uint16_t value = this->_bus.read(valueAddr);
|
||||
if (!this->_registers.p.m)
|
||||
value += this->_bus->read(valueAddr + 1) << 8u;
|
||||
value += this->_bus.read(valueAddr + 1) << 8u;
|
||||
|
||||
this->_registers.p.c = value & 1u;
|
||||
value >>= 1u;
|
||||
value |= oldCarry << highByteIndex;
|
||||
this->_registers.p.z = value == 0;
|
||||
|
||||
this->_bus->write(valueAddr, value);
|
||||
this->_bus.write(valueAddr, value);
|
||||
if (!this->_registers.p.m)
|
||||
this->_bus->write(valueAddr + 1, value >> 8u);
|
||||
this->_bus.write(valueAddr + 1, value >> 8u);
|
||||
|
||||
int cycles = 2 * !this->_registers.p.m;
|
||||
switch (mode) {
|
||||
|
||||
@@ -50,13 +50,13 @@ namespace ComSquare::CPU
|
||||
|
||||
int CPU::SEP(uint24_t valueAddr, AddressingMode)
|
||||
{
|
||||
this->_registers.p.flags |= this->_bus->read(valueAddr);
|
||||
this->_registers.p.flags |= this->_bus.read(valueAddr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CPU::REP(uint24_t valueAddr, AddressingMode)
|
||||
{
|
||||
this->_registers.p.flags &= ~this->_bus->read(valueAddr);
|
||||
this->_registers.p.flags &= ~this->_bus.read(valueAddr);
|
||||
if (this->_isEmulationMode) {
|
||||
this->_registers.p.x_b = true;
|
||||
this->_registers.p.m = true;
|
||||
@@ -189,8 +189,8 @@ namespace ComSquare::CPU
|
||||
|
||||
int CPU::PER(uint24_t valueAddr, AddressingMode)
|
||||
{
|
||||
uint16_t value = this->_bus->read(valueAddr);
|
||||
value += this->_bus->read(valueAddr + 1) << 8u;
|
||||
uint16_t value = this->_bus.read(valueAddr);
|
||||
value += this->_bus.read(valueAddr + 1) << 8u;
|
||||
value += this->_registers.pc;
|
||||
this->_push(value);
|
||||
return 0;
|
||||
@@ -226,55 +226,55 @@ namespace ComSquare::CPU
|
||||
int CPU::BCC(uint24_t valueAddr, AddressingMode)
|
||||
{
|
||||
if (!this->_registers.p.c)
|
||||
this->_registers.pc += static_cast<int8_t>(this->_bus->read(valueAddr));
|
||||
this->_registers.pc += static_cast<int8_t>(this->_bus.read(valueAddr));
|
||||
return !this->_registers.p.c + this->_isEmulationMode;
|
||||
}
|
||||
|
||||
int CPU::BCS(uint24_t valueAddr, AddressingMode)
|
||||
{
|
||||
if (this->_registers.p.c)
|
||||
this->_registers.pc += static_cast<int8_t>(this->_bus->read(valueAddr));
|
||||
this->_registers.pc += static_cast<int8_t>(this->_bus.read(valueAddr));
|
||||
return this->_registers.p.c + this->_isEmulationMode;
|
||||
}
|
||||
|
||||
int CPU::BEQ(uint24_t valueAddr, AddressingMode)
|
||||
{
|
||||
if (this->_registers.p.z)
|
||||
this->_registers.pc += static_cast<int8_t>(this->_bus->read(valueAddr));
|
||||
this->_registers.pc += static_cast<int8_t>(this->_bus.read(valueAddr));
|
||||
return this->_registers.p.z + this->_isEmulationMode;
|
||||
}
|
||||
|
||||
int CPU::BNE(uint24_t valueAddr, AddressingMode)
|
||||
{
|
||||
if (!this->_registers.p.z)
|
||||
this->_registers.pc += static_cast<int8_t>(this->_bus->read(valueAddr));
|
||||
this->_registers.pc += static_cast<int8_t>(this->_bus.read(valueAddr));
|
||||
return !this->_registers.p.z + this->_isEmulationMode;
|
||||
}
|
||||
|
||||
int CPU::BMI(uint24_t valueAddr, AddressingMode)
|
||||
{
|
||||
if (this->_registers.p.n)
|
||||
this->_registers.pc += static_cast<int8_t>(this->_bus->read(valueAddr));
|
||||
this->_registers.pc += static_cast<int8_t>(this->_bus.read(valueAddr));
|
||||
return this->_registers.p.n + this->_isEmulationMode;
|
||||
}
|
||||
|
||||
int CPU::BPL(uint24_t valueAddr, AddressingMode)
|
||||
{
|
||||
if (!this->_registers.p.n)
|
||||
this->_registers.pc += static_cast<int8_t>(this->_bus->read(valueAddr));
|
||||
this->_registers.pc += static_cast<int8_t>(this->_bus.read(valueAddr));
|
||||
return !this->_registers.p.n + this->_isEmulationMode;
|
||||
}
|
||||
|
||||
int CPU::BRA(uint24_t valueAddr, AddressingMode)
|
||||
{
|
||||
this->_registers.pc += static_cast<int8_t>(this->_bus->read(valueAddr));
|
||||
this->_registers.pc += static_cast<int8_t>(this->_bus.read(valueAddr));
|
||||
return this->_isEmulationMode;
|
||||
}
|
||||
|
||||
int CPU::BRL(uint24_t valueAddr, AddressingMode)
|
||||
{
|
||||
unsigned value = this->_bus->read(valueAddr);
|
||||
value += this->_bus->read(valueAddr + 1) << 8u;
|
||||
unsigned value = this->_bus.read(valueAddr);
|
||||
value += this->_bus.read(valueAddr + 1) << 8u;
|
||||
|
||||
this->_registers.pc += static_cast<int16_t>(value);
|
||||
return 0;
|
||||
@@ -283,14 +283,14 @@ namespace ComSquare::CPU
|
||||
int CPU::BVC(uint24_t valueAddr, AddressingMode)
|
||||
{
|
||||
if (!this->_registers.p.v)
|
||||
this->_registers.pc += static_cast<int8_t>(this->_bus->read(valueAddr));
|
||||
this->_registers.pc += static_cast<int8_t>(this->_bus.read(valueAddr));
|
||||
return !this->_registers.p.v + this->_isEmulationMode;
|
||||
}
|
||||
|
||||
int CPU::BVS(uint24_t valueAddr, AddressingMode)
|
||||
{
|
||||
if (this->_registers.p.v)
|
||||
this->_registers.pc += static_cast<int8_t>(this->_bus->read(valueAddr));
|
||||
this->_registers.pc += static_cast<int8_t>(this->_bus.read(valueAddr));
|
||||
return this->_registers.p.v + this->_isEmulationMode;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,9 +9,9 @@ namespace ComSquare::CPU
|
||||
{
|
||||
int CPU::ADC(uint24_t valueAddr, AddressingMode mode)
|
||||
{
|
||||
unsigned value = this->_bus->read(valueAddr) + this->_registers.p.c;
|
||||
unsigned value = this->_bus.read(valueAddr) + this->_registers.p.c;
|
||||
if (!this->_registers.p.m)
|
||||
value += this->_bus->read(valueAddr + 1) << 8u;
|
||||
value += this->_bus.read(valueAddr + 1) << 8u;
|
||||
unsigned negativeMask = this->_registers.p.m ? 0x80u : 0x8000u;
|
||||
unsigned maxValue = this->_registers.p.m ? UINT8_MAX : UINT16_MAX;
|
||||
|
||||
@@ -52,9 +52,9 @@ namespace ComSquare::CPU
|
||||
int CPU::SBC(uint24_t valueAddr, AddressingMode mode)
|
||||
{
|
||||
unsigned negativeMask = this->_registers.p.m ? 0x80u : 0x8000u;
|
||||
unsigned value = this->_bus->read(valueAddr);
|
||||
unsigned value = this->_bus.read(valueAddr);
|
||||
if (!this->_registers.p.m)
|
||||
value += this->_bus->read(valueAddr + 1) << 8u;
|
||||
value += this->_bus.read(valueAddr + 1) << 8u;
|
||||
bool oldCarry = this->_registers.p.c;
|
||||
|
||||
this->_registers.p.c = this->_registers.a >= value;
|
||||
@@ -94,9 +94,9 @@ namespace ComSquare::CPU
|
||||
int CPU::ORA(uint24_t valueAddr, AddressingMode mode)
|
||||
{
|
||||
unsigned negativeMask = this->_registers.p.m ? 0x80u : 0x8000u;
|
||||
unsigned value = this->_bus->read(valueAddr);
|
||||
unsigned value = this->_bus.read(valueAddr);
|
||||
if (!this->_registers.p.m)
|
||||
value += this->_bus->read(valueAddr + 1) << 8u;
|
||||
value += this->_bus.read(valueAddr + 1) << 8u;
|
||||
this->_registers.a |= value;
|
||||
this->_registers.p.z = this->_registers.a == 0;
|
||||
this->_registers.p.n = this->_registers.a & negativeMask;
|
||||
@@ -151,9 +151,9 @@ namespace ComSquare::CPU
|
||||
int CPU::CMP(uint24_t valueAddr, AddressingMode mode)
|
||||
{
|
||||
unsigned negativeMask = this->_registers.p.m ? 0x80u : 0x8000u;
|
||||
unsigned value = this->_bus->read(valueAddr);
|
||||
unsigned value = this->_bus.read(valueAddr);
|
||||
if (!this->_registers.p.m)
|
||||
value += this->_bus->read(valueAddr + 1) << 8u;
|
||||
value += this->_bus.read(valueAddr + 1) << 8u;
|
||||
unsigned result = this->_registers.a - value;
|
||||
if (this->_registers.p.m)
|
||||
result %= 0x100;
|
||||
@@ -214,7 +214,7 @@ namespace ComSquare::CPU
|
||||
|
||||
int CPU::CPX(uint24_t valueAddr, AddressingMode mode)
|
||||
{
|
||||
unsigned value = this->_bus->read(valueAddr++);
|
||||
unsigned value = this->_bus.read(valueAddr++);
|
||||
|
||||
if (this->_registers.p.x_b) {
|
||||
uint8_t x = this->_registers.x;
|
||||
@@ -222,7 +222,7 @@ namespace ComSquare::CPU
|
||||
this->_registers.p.z = x == 0;
|
||||
this->_registers.p.n = x & 0x80u;
|
||||
} else {
|
||||
value += this->_bus->read(valueAddr) << 8u;
|
||||
value += this->_bus.read(valueAddr) << 8u;
|
||||
uint16_t x = this->_registers.x;
|
||||
x -= value;
|
||||
this->_registers.p.z = x == 0;
|
||||
@@ -234,7 +234,7 @@ namespace ComSquare::CPU
|
||||
|
||||
int CPU::CPY(uint24_t valueAddr, AddressingMode mode)
|
||||
{
|
||||
unsigned value = this->_bus->read(valueAddr++);
|
||||
unsigned value = this->_bus.read(valueAddr++);
|
||||
|
||||
this->_registers.p.c = this->_registers.y >= value;
|
||||
if (this->_registers.p.x_b) {
|
||||
@@ -243,7 +243,7 @@ namespace ComSquare::CPU
|
||||
this->_registers.p.z = y == 0;
|
||||
this->_registers.p.n = y & 0x80u;
|
||||
} else {
|
||||
value += this->_bus->read(valueAddr) << 8u;
|
||||
value += this->_bus.read(valueAddr) << 8u;
|
||||
uint16_t y = this->_registers.y;
|
||||
y -= value;
|
||||
this->_registers.p.z = y == 0;
|
||||
@@ -255,9 +255,9 @@ namespace ComSquare::CPU
|
||||
int CPU::AND(uint24_t valueAddr, AddressingMode mode)
|
||||
{
|
||||
unsigned negativeMask = this->_registers.p.m ? 0x80u : 0x8000u;
|
||||
unsigned value = this->_bus->read(valueAddr);
|
||||
unsigned value = this->_bus.read(valueAddr);
|
||||
if (!this->_registers.p.m)
|
||||
value += this->_bus->read(valueAddr + 1) << 8u;
|
||||
value += this->_bus.read(valueAddr + 1) << 8u;
|
||||
|
||||
this->_registers.a &= value;
|
||||
this->_registers.p.n = this->_registers.a & negativeMask;
|
||||
@@ -297,15 +297,15 @@ namespace ComSquare::CPU
|
||||
this->_registers.ah = 0;
|
||||
result = this->_registers.a;
|
||||
} else if (!this->_registers.p.m) {
|
||||
result = this->_bus->read(valueAddr);
|
||||
result += this->_bus->read(valueAddr + 1) << 8u;
|
||||
result = this->_bus.read(valueAddr);
|
||||
result += this->_bus.read(valueAddr + 1) << 8u;
|
||||
result = (uint16_t)(result + 1);
|
||||
this->_bus->write(valueAddr, result);
|
||||
this->_bus->write(valueAddr + 1, result << 8u);
|
||||
this->_bus.write(valueAddr, result);
|
||||
this->_bus.write(valueAddr + 1, result << 8u);
|
||||
} else {
|
||||
result = this->_bus->read(valueAddr);
|
||||
result = this->_bus.read(valueAddr);
|
||||
result = (uint8_t)(result + 1);
|
||||
this->_bus->write(valueAddr, result);
|
||||
this->_bus.write(valueAddr, result);
|
||||
}
|
||||
|
||||
this->_registers.p.z = result == 0;
|
||||
@@ -337,15 +337,15 @@ namespace ComSquare::CPU
|
||||
this->_registers.ah = 0;
|
||||
result = this->_registers.a;
|
||||
} else if (!this->_registers.p.m) {
|
||||
result = this->_bus->read(valueAddr);
|
||||
result += this->_bus->read(valueAddr + 1) << 8u;
|
||||
result = this->_bus.read(valueAddr);
|
||||
result += this->_bus.read(valueAddr + 1) << 8u;
|
||||
result = (uint16_t)(result - 1);
|
||||
this->_bus->write(valueAddr, result);
|
||||
this->_bus->write(valueAddr + 1, result << 8u);
|
||||
this->_bus.write(valueAddr, result);
|
||||
this->_bus.write(valueAddr + 1, result << 8u);
|
||||
} else {
|
||||
result = this->_bus->read(valueAddr);
|
||||
result = this->_bus.read(valueAddr);
|
||||
result = (uint8_t)(result - 1);
|
||||
this->_bus->write(valueAddr, result);
|
||||
this->_bus.write(valueAddr, result);
|
||||
}
|
||||
|
||||
this->_registers.p.z = result == 0;
|
||||
@@ -369,9 +369,9 @@ namespace ComSquare::CPU
|
||||
int CPU::EOR(uint24_t valueAddr, AddressingMode mode)
|
||||
{
|
||||
unsigned negativeMask = this->_registers.p.m ? 0x80u : 0x8000u;
|
||||
unsigned value = this->_bus->read(valueAddr);
|
||||
unsigned value = this->_bus.read(valueAddr);
|
||||
if (!this->_registers.p.m)
|
||||
value += this->_bus->read(valueAddr + 1) << 8u;
|
||||
value += this->_bus.read(valueAddr + 1) << 8u;
|
||||
this->_registers.a ^= value;
|
||||
this->_registers.p.z = this->_registers.a == 0;
|
||||
this->_registers.p.n = this->_registers.a & negativeMask;
|
||||
|
||||
@@ -9,10 +9,10 @@ namespace ComSquare::CPU
|
||||
int CPU::STA(uint24_t addr, AddressingMode mode)
|
||||
{
|
||||
if (this->_registers.p.m)
|
||||
this->_bus->write(addr, this->_registers.al);
|
||||
this->_bus.write(addr, this->_registers.al);
|
||||
else {
|
||||
this->_bus->write(addr, this->_registers.al);
|
||||
this->_bus->write(addr + 1, this->_registers.ah);
|
||||
this->_bus.write(addr, this->_registers.al);
|
||||
this->_bus.write(addr + 1, this->_registers.ah);
|
||||
}
|
||||
|
||||
int cycles = !this->_registers.p.m;
|
||||
@@ -34,10 +34,10 @@ namespace ComSquare::CPU
|
||||
int CPU::STX(uint24_t addr, AddressingMode mode)
|
||||
{
|
||||
if (this->_registers.p.x_b)
|
||||
this->_bus->write(addr, this->_registers.xl);
|
||||
this->_bus.write(addr, this->_registers.xl);
|
||||
else {
|
||||
this->_bus->write(addr, this->_registers.xl);
|
||||
this->_bus->write(addr + 1, this->_registers.xh);
|
||||
this->_bus.write(addr, this->_registers.xl);
|
||||
this->_bus.write(addr + 1, this->_registers.xh);
|
||||
}
|
||||
return !this->_registers.p.x_b + (mode != Absolute && this->_registers.dl != 0);
|
||||
}
|
||||
@@ -45,19 +45,19 @@ namespace ComSquare::CPU
|
||||
int CPU::STY(uint24_t addr, AddressingMode mode)
|
||||
{
|
||||
if (this->_registers.p.x_b)
|
||||
this->_bus->write(addr, this->_registers.yl);
|
||||
this->_bus.write(addr, this->_registers.yl);
|
||||
else {
|
||||
this->_bus->write(addr, this->_registers.yl);
|
||||
this->_bus->write(addr + 1, this->_registers.yh);
|
||||
this->_bus.write(addr, this->_registers.yl);
|
||||
this->_bus.write(addr + 1, this->_registers.yh);
|
||||
}
|
||||
return !this->_registers.p.x_b + (mode != Absolute && this->_registers.dl != 0);
|
||||
}
|
||||
|
||||
int CPU::STZ(uint24_t addr, AddressingMode mode)
|
||||
{
|
||||
this->_bus->write(addr, 0x00);
|
||||
this->_bus.write(addr, 0x00);
|
||||
if (!this->_registers.p.m)
|
||||
this->_bus->write(addr + 1, 0x00);
|
||||
this->_bus.write(addr + 1, 0x00);
|
||||
if (mode == Absolute || mode == AbsoluteIndexedByX)
|
||||
return !this->_registers.p.m;
|
||||
return !this->_registers.p.m + this->_registers.dl != 0;
|
||||
@@ -66,11 +66,11 @@ namespace ComSquare::CPU
|
||||
int CPU::LDA(uint24_t addr, AddressingMode mode)
|
||||
{
|
||||
if (this->_registers.p.m) {
|
||||
this->_registers.a = this->_bus->read(addr);
|
||||
this->_registers.a = this->_bus.read(addr);
|
||||
this->_registers.p.n = this->_registers.al & 0xF0u;
|
||||
} else {
|
||||
this->_registers.al = this->_bus->read(addr);
|
||||
this->_registers.ah = this->_bus->read(addr + 1);
|
||||
this->_registers.al = this->_bus.read(addr);
|
||||
this->_registers.ah = this->_bus.read(addr + 1);
|
||||
this->_registers.p.n = this->_registers.a & 0xF000u;
|
||||
}
|
||||
this->_registers.p.z = this->_registers.a == 0x0;
|
||||
@@ -101,11 +101,11 @@ namespace ComSquare::CPU
|
||||
int CPU::LDX(uint24_t addr, AddressingMode mode)
|
||||
{
|
||||
if (this->_registers.p.x_b) {
|
||||
this->_registers.x = this->_bus->read(addr);
|
||||
this->_registers.x = this->_bus.read(addr);
|
||||
this->_registers.p.n = this->_registers.xl & 0xF0u;
|
||||
} else {
|
||||
this->_registers.xl = this->_bus->read(addr);
|
||||
this->_registers.xh = this->_bus->read(addr + 1);
|
||||
this->_registers.xl = this->_bus.read(addr);
|
||||
this->_registers.xh = this->_bus.read(addr + 1);
|
||||
this->_registers.p.n = this->_registers.x & 0xF000u;
|
||||
}
|
||||
this->_registers.p.z = this->_registers.x == 0x0;
|
||||
@@ -128,11 +128,11 @@ namespace ComSquare::CPU
|
||||
int CPU::LDY(uint24_t addr, AddressingMode mode)
|
||||
{
|
||||
if (this->_registers.p.x_b) {
|
||||
this->_registers.y = this->_bus->read(addr);
|
||||
this->_registers.y = this->_bus.read(addr);
|
||||
this->_registers.p.n = this->_registers.yl & 0xF0u;
|
||||
} else {
|
||||
this->_registers.yl = this->_bus->read(addr);
|
||||
this->_registers.yh = this->_bus->read(addr + 1);
|
||||
this->_registers.yl = this->_bus.read(addr);
|
||||
this->_registers.yh = this->_bus.read(addr + 1);
|
||||
this->_registers.p.n = this->_registers.y & 0xF000u;
|
||||
}
|
||||
this->_registers.p.z = this->_registers.y == 0x0;
|
||||
|
||||
@@ -160,8 +160,8 @@ namespace ComSquare::CPU
|
||||
|
||||
this->_registers.dbr = destBank;
|
||||
while (this->_registers.a != 0xFFFF) {
|
||||
uint8_t data = this->_bus->read(srcBank << 24u | this->_registers.x);
|
||||
this->_bus->write(destBank << 24u | this->_registers.y, data);
|
||||
uint8_t data = this->_bus.read(srcBank << 24u | this->_registers.x);
|
||||
this->_bus.write(destBank << 24u | this->_registers.y, data);
|
||||
this->_registers.x++;
|
||||
this->_registers.y++;
|
||||
this->_registers.a--;
|
||||
@@ -177,12 +177,18 @@ namespace ComSquare::CPU
|
||||
|
||||
this->_registers.dbr = destBank;
|
||||
while (this->_registers.a != 0xFFFF) {
|
||||
uint8_t data = this->_bus->read(srcBank << 24u | this->_registers.x);
|
||||
this->_bus->write(destBank << 24u | this->_registers.y, data);
|
||||
uint8_t data = this->_bus.read(srcBank << 24u | this->_registers.x);
|
||||
this->_bus.write(destBank << 24u | this->_registers.y, data);
|
||||
this->_registers.x--;
|
||||
this->_registers.y--;
|
||||
this->_registers.a--;
|
||||
}
|
||||
return 7 * length;
|
||||
}
|
||||
|
||||
std::string CPU::getValueName(uint24_t) const
|
||||
{
|
||||
// TODO implement this method
|
||||
return "???";
|
||||
}
|
||||
}
|
||||
192
sources/CPU/Registers.hpp
Normal file
192
sources/CPU/Registers.hpp
Normal file
@@ -0,0 +1,192 @@
|
||||
//
|
||||
// Created by Zoe Roux on 2021-07-03.
|
||||
//
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Models/Int24.hpp"
|
||||
|
||||
namespace ComSquare::CPU
|
||||
{
|
||||
//! @brief Struct containing registers for the main CPU.
|
||||
struct Registers
|
||||
{
|
||||
//! @brief The Accumulator
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint8_t al;
|
||||
uint8_t ah;
|
||||
};
|
||||
uint16_t a;
|
||||
};
|
||||
//! @brief The Data Bank Register;
|
||||
uint8_t dbr;
|
||||
//! @brief The Direct Page register;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint8_t dl;
|
||||
uint8_t dh;
|
||||
};
|
||||
uint16_t d;
|
||||
};
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
//! @brief The Program Counter;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint8_t pcl;
|
||||
uint8_t pch;
|
||||
};
|
||||
uint16_t pc;
|
||||
};
|
||||
//! @brief The Program Bank Register;
|
||||
uint8_t pbr;
|
||||
};
|
||||
//! @brief The current Program Address Counter (does not exist in a snes but is useful here).
|
||||
uint24_t pac;
|
||||
};
|
||||
//! @brief The Stack pointer
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint8_t sl;
|
||||
uint8_t sh;
|
||||
};
|
||||
uint16_t s;
|
||||
};
|
||||
//! @brief The X index register
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint8_t xl;
|
||||
uint8_t xh;
|
||||
};
|
||||
uint16_t x;
|
||||
};
|
||||
//! @brief The Y index register
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint8_t yl;
|
||||
uint8_t yh;
|
||||
};
|
||||
uint16_t y;
|
||||
};
|
||||
|
||||
//! @brief The Processor status register;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
//! @brief The Carry flag
|
||||
bool c: 1;
|
||||
//! @brief The Zero flag
|
||||
bool z: 1;
|
||||
//! @brief The Interrupt request disable flag
|
||||
bool i: 1;
|
||||
//! @brief The Decimal mode flag
|
||||
bool d: 1;
|
||||
//! @brief The indeX register width flag (in native mode only) - 0 = 16 bits mode, 1 = 8 bits mode OR the Break flag (in emulation mode only)
|
||||
bool x_b: 1;
|
||||
//! @brief The accumulator and Memory width flag (in native mode only) - 0 = 16 bits mode, 1 = 8 bits mode.
|
||||
bool m: 1;
|
||||
//! @brief The oVerflow flag
|
||||
bool v: 1;
|
||||
//! @brief The Negative flag
|
||||
bool n: 1;
|
||||
};
|
||||
uint8_t flags;
|
||||
} p;
|
||||
};
|
||||
|
||||
//! @brief Struct containing internal registers of the CPU.
|
||||
struct InternalRegisters
|
||||
{
|
||||
//! @brief Interrupt Enable Register
|
||||
uint8_t nmitimen;
|
||||
|
||||
//! @brief IO Port Write Register
|
||||
uint8_t wrio;
|
||||
|
||||
//! @brief Multiplicand Register A
|
||||
uint8_t wrmpya;
|
||||
//! @brief Multiplicand Register B
|
||||
uint8_t wrmpyb;
|
||||
|
||||
//! @brief Divisor & Dividend Registers (A - Low)
|
||||
uint8_t wrdivl;
|
||||
//! @brief Divisor & Dividend Registers (A - High)
|
||||
uint8_t wrdivh;
|
||||
//! @brief Divisor & Dividend Registers (B)
|
||||
uint8_t wrdivb;
|
||||
|
||||
//! @brief IRQ Timer Registers (Horizontal - Low)
|
||||
uint8_t htimel;
|
||||
//! @brief IRQ Timer Registers (Horizontal - High)
|
||||
uint8_t htimeh;
|
||||
|
||||
//! @brief IRQ Timer Registers (Vertical - Low)
|
||||
uint8_t vtimel;
|
||||
//! @brief IRQ Timer Registers (Vertical - High)
|
||||
uint8_t vtimeh;
|
||||
|
||||
//! @brief HDMA Enable Register
|
||||
uint8_t hdmaen;
|
||||
|
||||
//! @brief ROM Speed Register
|
||||
uint8_t memsel;
|
||||
|
||||
//! @brief Interrupt Flag Registers
|
||||
uint8_t rdnmi;
|
||||
//! @brief Interrupt Flag Registers - TimeUp
|
||||
uint8_t timeup;
|
||||
|
||||
//! @brief PPU Status Register
|
||||
uint8_t hvbjoy;
|
||||
|
||||
//! @brief IO Port Read Register
|
||||
uint8_t rdio;
|
||||
|
||||
//! @brief Divide Result Registers (can sometimes be used as multiplication result register) - LOW
|
||||
uint8_t rddivl;
|
||||
//! @brief Divide Result Registers (can sometimes be used as multiplication result register) - HIGH
|
||||
uint8_t rddivh;
|
||||
|
||||
//! @brief Multiplication Result Registers (can sometimes be used as divide result register) - LOW
|
||||
uint8_t rdmpyl;
|
||||
//! @brief Multiplication Result Registers (can sometimes be used as divide result register) - HIGH
|
||||
uint8_t rdmpyh;
|
||||
|
||||
//! @brief Controller Port Data Registers (Pad 1 - Low)
|
||||
uint8_t joy1l;
|
||||
//! @brief Controller Port Data Registers (Pad 1 - High)
|
||||
uint8_t joy1h;
|
||||
|
||||
//! @brief Controller Port Data Registers (Pad 2 - Low)
|
||||
uint8_t joy2l;
|
||||
//! @brief Controller Port Data Registers (Pad 2 - High)
|
||||
uint8_t joy2h;
|
||||
|
||||
//! @brief Controller Port Data Registers (Pad 3 - Low)
|
||||
uint8_t joy3l;
|
||||
//! @brief Controller Port Data Registers (Pad 3 - High)
|
||||
uint8_t joy3h;
|
||||
|
||||
//! @brief Controller Port Data Registers (Pad 4 - Low)
|
||||
uint8_t joy4l;
|
||||
//! @brief Controller Port Data Registers (Pad 4 - High)
|
||||
uint8_t joy4h;
|
||||
};
|
||||
}
|
||||
@@ -2,28 +2,36 @@
|
||||
// Created by anonymus-raccoon on 1/27/20.
|
||||
//
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <cstring>
|
||||
#include "Cartridge.hpp"
|
||||
#include "../Exceptions/InvalidAddress.hpp"
|
||||
#include "../Exceptions/InvalidRom.hpp"
|
||||
#include "../Exceptions/InvalidAction.hpp"
|
||||
#include "Exceptions/InvalidAction.hpp"
|
||||
#include "Exceptions/InvalidAddress.hpp"
|
||||
#include "Exceptions/InvalidRom.hpp"
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <sys/stat.h>
|
||||
|
||||
namespace ComSquare::Cartridge
|
||||
{
|
||||
constexpr unsigned HeaderSize = 0x40u;
|
||||
|
||||
Cartridge::Cartridge()
|
||||
: Ram::Ram(0, Rom, "Cartridge")
|
||||
{}
|
||||
|
||||
Cartridge::Cartridge(const std::string &romPath)
|
||||
: Ram::Ram(0, Rom, "Cartridge"),
|
||||
_romPath(romPath)
|
||||
{
|
||||
if (romPath.empty())
|
||||
throw InvalidRomException("Path is empty.");
|
||||
size_t size = Cartridge::getRomSize(romPath);
|
||||
FILE *rom = fopen(romPath.c_str(), "rb");
|
||||
this->loadRom(romPath);
|
||||
}
|
||||
|
||||
void Cartridge::loadRom(const std::string &path)
|
||||
{
|
||||
size_t size = Cartridge::getRomSize(path);
|
||||
FILE *rom = fopen(path.c_str(), "rb");
|
||||
|
||||
if (!rom)
|
||||
throw InvalidRomException("Could not open the rom file at " + romPath + ". " + strerror(errno));
|
||||
throw InvalidRomException("Could not open the rom file at " + path + ". " + strerror(errno));
|
||||
this->_size = size;
|
||||
this->_data = new uint8_t[size];
|
||||
std::memset(this->_data, 0, size);
|
||||
@@ -133,25 +141,25 @@ namespace ComSquare::Cartridge
|
||||
continue;
|
||||
uint8_t resetOpCode = this->_data[info.emulationInterrupts.reset - 0x8000u];
|
||||
switch (resetOpCode) {
|
||||
case 0x18: //CLI
|
||||
case 0x78: //SEI
|
||||
case 0x4C: //JMP
|
||||
case 0x5C: //JMP
|
||||
case 0x20: //JSR
|
||||
case 0x22: //JSL
|
||||
case 0x9C: //STZ
|
||||
score+= 8;
|
||||
case 0x18://CLI
|
||||
case 0x78://SEI
|
||||
case 0x4C://JMP
|
||||
case 0x5C://JMP
|
||||
case 0x20://JSR
|
||||
case 0x22://JSL
|
||||
case 0x9C://STZ
|
||||
score += 8;
|
||||
break;
|
||||
case 0xC2: //REP
|
||||
case 0xE2: //SEP
|
||||
case 0xA9: //LDA
|
||||
case 0xA2: //LDX
|
||||
case 0xA0: //LDY
|
||||
case 0xC2://REP
|
||||
case 0xE2://SEP
|
||||
case 0xA9://LDA
|
||||
case 0xA2://LDX
|
||||
case 0xA0://LDY
|
||||
score += 4;
|
||||
break;
|
||||
case 0x00: //BRK
|
||||
case 0xFF: //SBC
|
||||
case 0xCC: //CPY
|
||||
case 0x00://BRK
|
||||
case 0xFF://SBC
|
||||
case 0xCC://CPY
|
||||
score -= 8;
|
||||
break;
|
||||
default:
|
||||
@@ -209,4 +217,4 @@ namespace ComSquare::Cartridge
|
||||
{
|
||||
return this->_type;
|
||||
}
|
||||
}
|
||||
}// namespace ComSquare::Cartridge
|
||||
@@ -4,23 +4,25 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <filesystem>
|
||||
#include "Memory/AMemory.hpp"
|
||||
#include "Models/Int24.hpp"
|
||||
#include "Memory/ARectangleMemory.hpp"
|
||||
#include "InterruptVectors.hpp"
|
||||
#include "Memory/AMemory.hpp"
|
||||
#include "Memory/ARectangleMemory.hpp"
|
||||
#include "Models/Int24.hpp"
|
||||
#include "Ram/Ram.hpp"
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
|
||||
namespace ComSquare::Cartridge
|
||||
{
|
||||
enum CartridgeType {
|
||||
enum CartridgeType
|
||||
{
|
||||
Game,
|
||||
Audio
|
||||
};
|
||||
|
||||
#define ADDMAPPINGMODE(x, flag) (x = static_cast<MappingMode>(x | (flag)))
|
||||
enum MappingMode {
|
||||
#define ADDMAPPINGMODE(x, flag) (x = static_cast<MappingMode>(x | (flag)))
|
||||
enum MappingMode
|
||||
{
|
||||
LoRom = 1u << 0u,
|
||||
HiRom = 1u << 1u,
|
||||
SlowRom = 1u << 2u,
|
||||
@@ -33,7 +35,7 @@ namespace ComSquare::Cartridge
|
||||
//! @brief The name of the game
|
||||
std::string gameName;
|
||||
//! @brief The memory mapping of the ROM.
|
||||
MappingMode mappingMode{};
|
||||
MappingMode mappingMode {};
|
||||
//! @brief The rom type (special information about the rom, still don't know what).
|
||||
uint8_t romType = 0;
|
||||
//! @brief The size (in bytes) of the ram
|
||||
@@ -41,26 +43,29 @@ namespace ComSquare::Cartridge
|
||||
//! @brief The size of the SRom inside the cartridge.
|
||||
unsigned sramSize = 0;
|
||||
//! @brief Creator license ID code.
|
||||
union {
|
||||
union
|
||||
{
|
||||
uint8_t creatorIDs[2];
|
||||
uint16_t creatorID = 0;
|
||||
};
|
||||
//! @brief The version of the game
|
||||
uint8_t version = 0;
|
||||
//! @brief Checksum complement
|
||||
union {
|
||||
union
|
||||
{
|
||||
uint8_t checksumComplements[2];
|
||||
uint16_t checksumComplement = 0;
|
||||
};
|
||||
//! @brief Checksum
|
||||
union {
|
||||
union
|
||||
{
|
||||
uint8_t checksums[2];
|
||||
uint16_t checksum = 0;
|
||||
};
|
||||
//! @brief The interrupt vectors used to halt the CPU in native mode
|
||||
InterruptVectors nativeInterrupts{};
|
||||
InterruptVectors nativeInterrupts {};
|
||||
//! @brief The interrupt vectors used to halt the CPU in emulation mode
|
||||
InterruptVectors emulationInterrupts{};
|
||||
InterruptVectors emulationInterrupts {};
|
||||
|
||||
Header() = default;
|
||||
Header(const Header &) = default;
|
||||
@@ -69,7 +74,8 @@ namespace ComSquare::Cartridge
|
||||
};
|
||||
|
||||
//! @brief Contains the rom's memory/instructions.
|
||||
class Cartridge : public Ram::Ram {
|
||||
class Cartridge : public Ram::Ram
|
||||
{
|
||||
private:
|
||||
//! @brief The path of the currently loaded rom.
|
||||
std::string _romPath;
|
||||
@@ -93,10 +99,13 @@ namespace ComSquare::Cartridge
|
||||
//! @return A header struct representing the data at the memory address you passed.
|
||||
Header _mapHeader(uint32_t headerAddress);
|
||||
//! @brief Current type of the cartridge
|
||||
CartridgeType _type;
|
||||
CartridgeType _type = Game;
|
||||
//! @brief Magic Header string of a SPC Rom
|
||||
static constexpr std::string_view _magicSPC = "SNES-SPC700 Sound File Data v0.30";
|
||||
|
||||
public:
|
||||
//! @brief A default constructor that doesn't load anything.
|
||||
Cartridge();
|
||||
//! @brief Load a rom from it's path.
|
||||
explicit Cartridge(const std::string &romPath);
|
||||
//! @brief The cartridge can't be copied.
|
||||
@@ -108,13 +117,16 @@ namespace ComSquare::Cartridge
|
||||
|
||||
//! @brief The header of the cartridge.
|
||||
Header header;
|
||||
|
||||
//! @brief Return current type of the cartridge
|
||||
CartridgeType getType();
|
||||
|
||||
//! @brief Read from the rom.
|
||||
//! @param addr The address to read from. The address 0x0 should refer to the first byte of the rom's memory.
|
||||
//! @throw InvalidAddress will be thrown if the address is more than the size of the rom's memory.
|
||||
//! @return Return the data at the address.
|
||||
uint8_t read(uint24_t addr) override;
|
||||
|
||||
//! @brief Write data to the rom.
|
||||
//! @param addr The address to write to. The address 0x0 should refer to the first byte of the rom's memory.
|
||||
//! @param data The data to write.
|
||||
@@ -123,6 +135,11 @@ namespace ComSquare::Cartridge
|
||||
|
||||
//! @brief The path of the rom file
|
||||
//! @return The path of the currently loaded rom file.
|
||||
std::filesystem::path getRomPath() const;
|
||||
[[nodiscard]] std::filesystem::path getRomPath() const;
|
||||
|
||||
//! @brief Load the rom at the given path
|
||||
//! @param rom The path of the rom.
|
||||
//! @throws InvalidRomException If the rom is invalid, this exception is thrown.
|
||||
void loadRom(const std::string& path);
|
||||
};
|
||||
}
|
||||
}// namespace ComSquare::Cartridge
|
||||
@@ -2,43 +2,49 @@
|
||||
// Created by anonymus-raccoon on 1/31/20.
|
||||
//
|
||||
|
||||
#ifndef COMSQUARE_INTERRUPTVECTORS_HPP
|
||||
#define COMSQUARE_INTERRUPTVECTORS_HPP
|
||||
#pragma once
|
||||
|
||||
#include <cinttypes>
|
||||
|
||||
namespace ComSquare::Cartridge
|
||||
{
|
||||
struct InterruptVectors {
|
||||
struct InterruptVectors
|
||||
{
|
||||
//! @brief The Co-Processor enable vector.
|
||||
union {
|
||||
union
|
||||
{
|
||||
uint8_t cop8[2];
|
||||
uint16_t cop;
|
||||
};
|
||||
//! @brief The Break vector.
|
||||
union {
|
||||
union
|
||||
{
|
||||
uint8_t brk8[2];
|
||||
uint16_t brk;
|
||||
};
|
||||
//! @brief The Abort vector.
|
||||
union {
|
||||
union
|
||||
{
|
||||
uint8_t abort8[2];
|
||||
uint16_t abort;
|
||||
};
|
||||
//! @brief The non-maskable interrupt (The V-Blank interrupt).
|
||||
union {
|
||||
union
|
||||
{
|
||||
uint8_t nmi8[2];
|
||||
uint16_t nmi;
|
||||
};
|
||||
//! @brief The Reset vector (execution of the SNES starts with this reset vector in emulation mode).
|
||||
union {
|
||||
union
|
||||
{
|
||||
uint8_t reset8[2];
|
||||
uint16_t reset;
|
||||
};
|
||||
//! @brief The Interrupt Request vector.
|
||||
union {
|
||||
union
|
||||
{
|
||||
uint8_t irq8[2];
|
||||
uint16_t irq;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
#endif //COMSQUARE_INTERRUPTVECTORS_HPP
|
||||
}// namespace ComSquare::Cartridge
|
||||
@@ -25,7 +25,7 @@ namespace ComSquare::Debugger
|
||||
_painter(*this),
|
||||
_stackModel(this->_bus, *this),
|
||||
_snes(snes),
|
||||
_labels(this->_loadLabels(snes.cartridge->getRomPath()))
|
||||
_labels(this->_loadLabels(snes.cartridge.getRomPath()))
|
||||
{
|
||||
this->_window->setContextMenuPolicy(Qt::NoContextMenu);
|
||||
this->_window->setAttribute(Qt::WA_QuitOnClose, false);
|
||||
@@ -84,9 +84,10 @@ namespace ComSquare::Debugger
|
||||
try {
|
||||
unsigned cycles = 0;
|
||||
|
||||
for (auto &channel : this->_dmaChannels)
|
||||
for (auto &channel : this->_dmaChannels) {
|
||||
if (channel.enabled)
|
||||
cycles += channel.run(INT_MAX);
|
||||
}
|
||||
|
||||
if (this->_isPaused)
|
||||
return 0xFF;
|
||||
@@ -300,11 +301,11 @@ namespace ComSquare::Debugger
|
||||
std::string CPUDebug::getProceededParameters()
|
||||
{
|
||||
uint24_t pac = this->_registers.pac;
|
||||
this->_bus->forceSilence = true;
|
||||
this->_bus.forceSilence = true;
|
||||
Instruction instruction = this->_instructions[this->readPC()];
|
||||
uint24_t valueAddr = this->_getValueAddr(instruction);
|
||||
this->_registers.pac = pac;
|
||||
this->_bus->forceSilence = false;
|
||||
this->_bus.forceSilence = false;
|
||||
if (instruction.size == 1)
|
||||
return "";
|
||||
return "[" + Utility::to_hex(valueAddr, Utility::AsmPrefix) + "]";
|
||||
@@ -316,12 +317,12 @@ namespace ComSquare::Debugger
|
||||
std::string symbolPath = romPath.replace_extension(".sym");
|
||||
std::ifstream sym(symbolPath);
|
||||
|
||||
if (sym) {
|
||||
std::vector<Label> symLabels = WlaDx::parse(sym);
|
||||
labels.insert(labels.end(),
|
||||
std::make_move_iterator(symLabels.begin()),
|
||||
std::make_move_iterator(symLabels.end()));
|
||||
}
|
||||
// if (sym) {
|
||||
// std::vector<Label> symLabels = WlaDx::parse(sym);
|
||||
// labels.insert(labels.end(),
|
||||
// std::make_move_iterator(symLabels.begin()),
|
||||
// std::make_move_iterator(symLabels.end()));
|
||||
// }
|
||||
return labels;
|
||||
}
|
||||
}
|
||||
@@ -451,7 +452,7 @@ QVariant StackModel::data(const QModelIndex &index, int role) const
|
||||
return QVariant();
|
||||
uint16_t addr = index.row() * 2 + index.column();
|
||||
try {
|
||||
uint8_t value = this->_bus->read(addr, true);
|
||||
uint8_t value = this->_bus.read(addr, true);
|
||||
return (ComSquare::Utility::to_hex(value, ComSquare::Utility::NoPrefix).c_str());
|
||||
} catch (std::exception &) {
|
||||
return "??";
|
||||
|
||||
@@ -42,13 +42,13 @@ namespace ComSquare::Debugger
|
||||
ctx.mFlag = true;
|
||||
ctx.xFlag = true;
|
||||
} else {
|
||||
uint8_t m = this->_bus->read(pc - 1, true);
|
||||
uint8_t m = this->_bus.read(pc - 1, true);
|
||||
ctx.mFlag &= ~m & 0b00100000u;
|
||||
ctx.xFlag &= ~m & 0b00010000u;
|
||||
}
|
||||
}
|
||||
if (instruction.opcode == 0xE2) { // SEP
|
||||
uint8_t m = this->_bus->read(pc - 1, true);
|
||||
uint8_t m = this->_bus.read(pc - 1, true);
|
||||
ctx.mFlag |= m & 0b00100000u;
|
||||
ctx.xFlag |= m & 0b00010000u;
|
||||
}
|
||||
@@ -69,7 +69,7 @@ namespace ComSquare::Debugger
|
||||
|
||||
DisassembledInstruction CPUDebug::_parseInstruction(uint24_t pc, DisassemblyContext &ctx)
|
||||
{
|
||||
uint24_t opcode = this->_bus->read(pc, true);
|
||||
uint24_t opcode = this->_bus.read(pc, true);
|
||||
Instruction instruction = this->_instructions[opcode];
|
||||
std::string argument = this->_getInstructionParameter(instruction, pc + 1, ctx);
|
||||
return DisassembledInstruction(instruction, pc, argument, opcode);
|
||||
@@ -134,10 +134,10 @@ namespace ComSquare::Debugger
|
||||
|
||||
std::string CPUDebug::_getImmediateValue(uint24_t pc, bool dual)
|
||||
{
|
||||
unsigned value = this->_bus->read(pc, true);
|
||||
unsigned value = this->_bus.read(pc, true);
|
||||
|
||||
if (dual)
|
||||
value += this->_bus->read(pc + 1, true) << 8u;
|
||||
value += this->_bus.read(pc + 1, true) << 8u;
|
||||
std::stringstream ss;
|
||||
ss << "#$" << std::hex << value;
|
||||
return ss.str();
|
||||
@@ -145,27 +145,27 @@ namespace ComSquare::Debugger
|
||||
|
||||
std::string CPUDebug::_getDirectValue(uint24_t pc)
|
||||
{
|
||||
return Utility::to_hex(this->_bus->read(pc, true), Utility::HexString::AsmPrefix);
|
||||
return Utility::to_hex(this->_bus.read(pc, true), Utility::HexString::AsmPrefix);
|
||||
}
|
||||
|
||||
std::string CPUDebug::_getAbsoluteValue(uint24_t pc)
|
||||
{
|
||||
uint24_t value = this->_bus->read(pc, true) + (this->_bus->read(pc + 1, true) << 8u);
|
||||
uint24_t value = this->_bus.read(pc, true) + (this->_bus.read(pc + 1, true) << 8u);
|
||||
return Utility::to_hex(value, Utility::HexString::AsmPrefix);
|
||||
}
|
||||
|
||||
std::string CPUDebug::_getAbsoluteLongValue(uint24_t pc)
|
||||
{
|
||||
unsigned value = this->_bus->read(pc++, true);
|
||||
value += this->_bus->read(pc++, true) << 8u;
|
||||
value += this->_bus->read(pc, true) << 16u;
|
||||
unsigned value = this->_bus.read(pc++, true);
|
||||
value += this->_bus.read(pc++, true) << 8u;
|
||||
value += this->_bus.read(pc, true) << 16u;
|
||||
|
||||
return Utility::to_hex(value, Utility::HexString::AsmPrefix);
|
||||
}
|
||||
|
||||
std::string CPUDebug::_getDirectIndexedByXValue(uint24_t pc)
|
||||
{
|
||||
unsigned value = this->_bus->read(pc, true);
|
||||
unsigned value = this->_bus.read(pc, true);
|
||||
|
||||
std::stringstream ss;
|
||||
ss << "$" << std::hex << value << ", x";
|
||||
@@ -174,7 +174,7 @@ namespace ComSquare::Debugger
|
||||
|
||||
std::string CPUDebug::_getDirectIndexedByYValue(uint24_t pc)
|
||||
{
|
||||
unsigned value = this->_bus->read(pc, true);
|
||||
unsigned value = this->_bus.read(pc, true);
|
||||
|
||||
std::stringstream ss;
|
||||
ss << "$" << std::hex << value << ", y";
|
||||
@@ -183,38 +183,38 @@ namespace ComSquare::Debugger
|
||||
|
||||
std::string CPUDebug::_getDirectIndirectValue(uint24_t pc)
|
||||
{
|
||||
return "(" + Utility::to_hex(this->_bus->read(pc, true), Utility::AsmPrefix) + ")";
|
||||
return "(" + Utility::to_hex(this->_bus.read(pc, true), Utility::AsmPrefix) + ")";
|
||||
}
|
||||
|
||||
std::string CPUDebug::_getDirectIndirectLongValue(uint24_t pc)
|
||||
{
|
||||
return "[" + Utility::to_hex(this->_bus->read(pc, true), Utility::AsmPrefix) + "]";
|
||||
return "[" + Utility::to_hex(this->_bus.read(pc, true), Utility::AsmPrefix) + "]";
|
||||
}
|
||||
|
||||
std::string CPUDebug::_getAbsoluteIndexByXValue(uint24_t pc)
|
||||
{
|
||||
uint24_t value = this->_bus->read(pc, true) + (this->_bus->read(pc + 1, true) << 8u);
|
||||
uint24_t value = this->_bus.read(pc, true) + (this->_bus.read(pc + 1, true) << 8u);
|
||||
return Utility::to_hex(value, Utility::HexString::AsmPrefix) + ", x";
|
||||
}
|
||||
|
||||
std::string CPUDebug::_getAbsoluteIndexByYValue(uint24_t pc)
|
||||
{
|
||||
uint24_t value = this->_bus->read(pc, true) + (this->_bus->read(pc + 1, true) << 8u);
|
||||
uint24_t value = this->_bus.read(pc, true) + (this->_bus.read(pc + 1, true) << 8u);
|
||||
return Utility::to_hex(value, Utility::HexString::AsmPrefix) + ", y";
|
||||
}
|
||||
|
||||
std::string CPUDebug::_getAbsoluteIndexByXLongValue(uint24_t pc)
|
||||
{
|
||||
unsigned value = this->_bus->read(pc++, true);
|
||||
value += this->_bus->read(pc++, true) << 8u;
|
||||
value += this->_bus->read(pc, true) << 16u;
|
||||
unsigned value = this->_bus.read(pc++, true);
|
||||
value += this->_bus.read(pc++, true) << 8u;
|
||||
value += this->_bus.read(pc, true) << 16u;
|
||||
|
||||
return Utility::to_hex(value, Utility::HexString::AsmPrefix) + ", x";
|
||||
}
|
||||
|
||||
std::string CPUDebug::_getDirectIndexedByXIndirectValue(uint24_t pc)
|
||||
{
|
||||
unsigned value = this->_bus->read(pc, true);
|
||||
unsigned value = this->_bus.read(pc, true);
|
||||
|
||||
std::stringstream ss;
|
||||
ss << "($" << std::hex << value << ", x)";
|
||||
@@ -223,7 +223,7 @@ namespace ComSquare::Debugger
|
||||
|
||||
std::string CPUDebug::_getDirectIndirectIndexedByYValue(uint24_t pc)
|
||||
{
|
||||
unsigned value = this->_bus->read(pc, true);
|
||||
unsigned value = this->_bus.read(pc, true);
|
||||
|
||||
std::stringstream ss;
|
||||
ss << "($" << std::hex << value << "), y";
|
||||
@@ -232,7 +232,7 @@ namespace ComSquare::Debugger
|
||||
|
||||
std::string CPUDebug::_getDirectIndirectIndexedByYLongValue(uint24_t pc)
|
||||
{
|
||||
unsigned value = this->_bus->read(pc, true);
|
||||
unsigned value = this->_bus.read(pc, true);
|
||||
|
||||
std::stringstream ss;
|
||||
ss << "[$" << std::hex << value << "], y";
|
||||
@@ -241,32 +241,32 @@ namespace ComSquare::Debugger
|
||||
|
||||
std::string CPUDebug::_getStackRelativeValue(uint24_t pc)
|
||||
{
|
||||
return Utility::to_hex(this->_bus->read(pc, true), Utility::AsmPrefix) + ", s";
|
||||
return Utility::to_hex(this->_bus.read(pc, true), Utility::AsmPrefix) + ", s";
|
||||
}
|
||||
|
||||
std::string CPUDebug::_getStackRelativeIndirectIndexedByYValue(uint24_t pc)
|
||||
{
|
||||
return "(" + Utility::to_hex(this->_bus->read(pc, true), Utility::AsmPrefix) + ", s), y";
|
||||
return "(" + Utility::to_hex(this->_bus.read(pc, true), Utility::AsmPrefix) + ", s), y";
|
||||
}
|
||||
|
||||
std::string CPUDebug::_getAbsoluteIndirectValue(uint24_t pc)
|
||||
{
|
||||
uint24_t value = this->_bus->read(pc, true) + (this->_bus->read(pc + 1, true) << 8u);
|
||||
uint24_t value = this->_bus.read(pc, true) + (this->_bus.read(pc + 1, true) << 8u);
|
||||
return "(" + Utility::to_hex(value, Utility::HexString::AsmPrefix) + ")";
|
||||
}
|
||||
|
||||
std::string CPUDebug::_getAbsoluteIndirectLongValue(uint24_t pc)
|
||||
{
|
||||
unsigned value = this->_bus->read(pc++, true);
|
||||
value += this->_bus->read(pc++, true) << 8u;
|
||||
value += this->_bus->read(pc, true) << 16u;
|
||||
unsigned value = this->_bus.read(pc++, true);
|
||||
value += this->_bus.read(pc++, true) << 8u;
|
||||
value += this->_bus.read(pc, true) << 16u;
|
||||
|
||||
return "(" + Utility::to_hex(value, Utility::HexString::AsmPrefix) + ")";
|
||||
}
|
||||
|
||||
std::string CPUDebug::_getAbsoluteIndirectIndexedByXValue(uint24_t pc)
|
||||
{
|
||||
uint24_t value = this->_bus->read(pc, true) + (this->_bus->read(pc + 1, true) << 8u);
|
||||
uint24_t value = this->_bus.read(pc, true) + (this->_bus.read(pc + 1, true) << 8u);
|
||||
return "(" + Utility::to_hex(value, Utility::HexString::AsmPrefix) + ", x)";
|
||||
}
|
||||
}
|
||||
@@ -2,23 +2,24 @@
|
||||
// Created by anonymus-raccoon on 1/27/20.
|
||||
//
|
||||
|
||||
#ifndef COMSQUARE_INVALIDADDRESS_HPP
|
||||
#define COMSQUARE_INVALIDADDRESS_HPP
|
||||
#pragma once
|
||||
|
||||
#include "DebuggableError.hpp"
|
||||
#include <exception>
|
||||
#include <string>
|
||||
#include <ios>
|
||||
#include <sstream>
|
||||
#include "DebuggableError.hpp"
|
||||
#include <string>
|
||||
|
||||
namespace ComSquare
|
||||
{
|
||||
//! @brief Exception thrown when trying to read/write to an invalid address.
|
||||
class InvalidAddress : public DebuggableError {
|
||||
class InvalidAddress : public DebuggableError
|
||||
{
|
||||
private:
|
||||
std::string _msg;
|
||||
|
||||
public:
|
||||
InvalidAddress(std::string where, int32_t addr)
|
||||
InvalidAddress(std::string where, uint24_t addr)
|
||||
{
|
||||
std::stringstream stream;
|
||||
stream << "Could not read/write data at address: 0x" << std::hex << addr << " from " << where;
|
||||
@@ -28,9 +29,11 @@ namespace ComSquare
|
||||
};
|
||||
|
||||
//! @brief Exception thrown when trying to read/write to an invalid address in a rectangle memory region.
|
||||
class InvalidRectangleAddress : public std::exception {
|
||||
class InvalidRectangleAddress : public std::exception
|
||||
{
|
||||
private:
|
||||
std::string _msg;
|
||||
|
||||
public:
|
||||
InvalidRectangleAddress(std::string where, int32_t addr, int16_t subaddr, int16_t start, int16_t end)
|
||||
{
|
||||
@@ -44,6 +47,4 @@ namespace ComSquare
|
||||
}
|
||||
const char *what() const noexcept override { return this->_msg.c_str(); }
|
||||
};
|
||||
}
|
||||
|
||||
#endif //COMSQUARE_INVALIDADDRESS_HPP
|
||||
}// namespace ComSquare
|
||||
|
||||
@@ -21,19 +21,4 @@ namespace ComSquare::Memory
|
||||
{
|
||||
return this->_start <= addr && addr <= this->_end;
|
||||
}
|
||||
|
||||
bool AMemory::isMirror() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::shared_ptr<IMemory> AMemory::getMirrored() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string AMemory::getValueName(uint24_t) const
|
||||
{
|
||||
return "???";
|
||||
}
|
||||
}
|
||||
@@ -26,25 +26,20 @@ namespace ComSquare::Memory
|
||||
//! @param addr The absolute address (in the 24 bit bus)
|
||||
//! @return The local address (0 refers to the first byte of this component).
|
||||
//! @throw InvalidAddress is thrown if the address is not mapped by this component.
|
||||
virtual uint24_t getRelativeAddress(uint24_t addr) const override;
|
||||
[[nodiscard]] uint24_t getRelativeAddress(uint24_t addr) const override;
|
||||
|
||||
//! @brief Change starting and ending points of this mapped memory.
|
||||
//! @param start The first address mapped to this component.
|
||||
//! @param end The last address mapped to this component.
|
||||
//! @warning The start/end address should be a continuous range. You can't map address 0x0 and 0x2 but not 0x1. To do that, use two AMemory.
|
||||
void setMemoryRegion(uint24_t start, uint24_t end);
|
||||
|
||||
//! @brief Return true if this component has mapped the address.
|
||||
//! @param addr The address to check.
|
||||
//! @return True if this address is mapped to the component. False otherwise.
|
||||
virtual bool hasMemoryAt(uint24_t addr) const override;
|
||||
//! @brief Check if this memory is a mirror or not.
|
||||
//! @return True if this memory is a mirror. False otherwise.
|
||||
virtual bool isMirror() const override;
|
||||
//! @brief Get the name of the data at the address
|
||||
//! @param addr The address (in local space)
|
||||
virtual std::string getValueName(uint24_t addr) const override;
|
||||
//! @brief Return the memory accessor this accessor mirror if any
|
||||
//! @return nullptr if isMirror is false, the source otherwise.
|
||||
virtual std::shared_ptr<IMemory> getMirrored() const override;
|
||||
virtual ~AMemory() override = default;
|
||||
[[nodiscard]] bool hasMemoryAt(uint24_t addr) const override;
|
||||
|
||||
//! @brief A default destructor
|
||||
~AMemory() override = default;
|
||||
};
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#include <iostream>
|
||||
#include "ARectangleMemory.hpp"
|
||||
#include "../Exceptions/InvalidAddress.hpp"
|
||||
#include "Exceptions/InvalidAddress.hpp"
|
||||
|
||||
namespace ComSquare::Memory
|
||||
{
|
||||
@@ -42,16 +42,6 @@ namespace ComSquare::Memory
|
||||
this->_endPage = endPage;
|
||||
}
|
||||
|
||||
bool ARectangleMemory::isMirror() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::shared_ptr<IMemory> ARectangleMemory::getMirrored() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string ARectangleMemory::getValueName(uint24_t) const
|
||||
{
|
||||
return "???";
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
namespace ComSquare::Memory
|
||||
{
|
||||
//! @brief Base memory class to map non continuous rectangle to the memory. (A rectangle that spam across more than one bank but that does not start at $0000 or end at $FFFF).
|
||||
class ARectangleMemory : public IMemory {
|
||||
class ARectangleMemory : public IMemory
|
||||
{
|
||||
protected:
|
||||
//! @brief The first bank to map to.
|
||||
uint8_t _startBank = 0;
|
||||
@@ -19,16 +20,19 @@ namespace ComSquare::Memory
|
||||
uint16_t _startPage = 0;
|
||||
//! @brief The last address of each bank to map.
|
||||
uint16_t _endPage = 0;
|
||||
|
||||
public:
|
||||
//! @brief Translate an absolute address to a relative address
|
||||
//! @param addr The absolute address (in the 24 bit bus)
|
||||
//! @return The local address (0 refers to the first byte of this component).
|
||||
//! @throw InvalidAddress is thrown if the address is not mapped by this component.
|
||||
virtual uint24_t getRelativeAddress(uint24_t addr) const override;
|
||||
[[nodiscard]] uint24_t getRelativeAddress(uint24_t addr) const override;
|
||||
|
||||
//! @brief Return true if this component has mapped the address.
|
||||
//! @param addr The address to check.
|
||||
//! @return True if this address is mapped to the component. False otherwise.
|
||||
bool hasMemoryAt(uint24_t addr) const override;
|
||||
[[nodiscard]] bool hasMemoryAt(uint24_t addr) const override;
|
||||
|
||||
//! @brief Change starting and ending points of this mapped memory.
|
||||
//! @param startBank The first bank mapped to this component.
|
||||
//! @param endBank The last bank mapped to this component.
|
||||
@@ -36,15 +40,12 @@ namespace ComSquare::Memory
|
||||
//! @param endPage The end page mapped to this component (every mapped banks will have this pages lower than this mapped)
|
||||
//! @warning The start/end address should be a rectangle. To mirror memory, use the MemoryShadow class and not this one.
|
||||
void setMemoryRegion(uint8_t startBank, uint8_t endBank, uint16_t startPage, uint16_t endPage);
|
||||
//! @brief Check if this memory is a mirror or not.
|
||||
//! @return True if this memory is a mirror. False otherwise.
|
||||
virtual bool isMirror() const override;
|
||||
|
||||
//! @brief Get the name of the data at the address
|
||||
//! @param addr The address (in local space)
|
||||
virtual std::string getValueName(uint24_t addr) const override;
|
||||
//! @brief Return the memory accessor this accessor mirror if any
|
||||
//! @return nullptr if isMirror is false, the source otherwise.
|
||||
virtual std::shared_ptr<IMemory> getMirrored() const override;
|
||||
virtual ~ARectangleMemory() override = default;
|
||||
[[nodiscard]] std::string getValueName(uint24_t addr) const override;
|
||||
|
||||
//! @brief A default destructor.
|
||||
~ARectangleMemory() override = default;
|
||||
};
|
||||
}
|
||||
}// namespace ComSquare::Memory
|
||||
@@ -21,36 +21,38 @@ namespace ComSquare::Memory
|
||||
//! @throw This function should thrown an InvalidAddress for address that are not mapped to the component.
|
||||
//! @return Return the data at the address given as parameter.
|
||||
virtual uint8_t read(uint24_t addr) = 0;
|
||||
|
||||
//! @brief Write data to this component.
|
||||
//! @param addr The local address to write data (0x0 should refer to the first byte of this component).
|
||||
//! @param data The new data to write.
|
||||
//! @throw This function should thrown an InvalidAddress for address that are not mapped to the component.
|
||||
virtual void write(uint24_t addr, uint8_t data) = 0;
|
||||
|
||||
//! @brief Return true if this component has mapped the address.
|
||||
//! @param addr The address to check.
|
||||
//! @return True if this address is mapped to the component. False otherwise.
|
||||
virtual bool hasMemoryAt(uint24_t addr) const = 0;
|
||||
|
||||
//! @brief Translate an absolute address to a relative address
|
||||
//! @param addr The absolute address (in the 24 bit bus)
|
||||
//! @return The local address (0 refers to the first byte of this component).
|
||||
//! @throw InvalidAddress is thrown if the address is not mapped by this component.
|
||||
virtual uint24_t getRelativeAddress(uint24_t addr) const = 0;
|
||||
|
||||
//! @brief Get the size of the data. This size can be lower than the mapped data.
|
||||
//! @return The number of bytes inside this memory.
|
||||
virtual uint24_t getSize() const = 0;
|
||||
//! @brief Check if this memory is a mirror or not.
|
||||
//! @return True if this memory is a mirror. False otherwise.
|
||||
virtual bool isMirror() const = 0;
|
||||
|
||||
//! @brief Get the name of this accessor (used for debug purpose)
|
||||
virtual std::string getName() const = 0;
|
||||
//! @brief Get the component of this accessor (used for debug purpose)
|
||||
virtual Component getComponent() const = 0;
|
||||
|
||||
//! @brief Get the name of the data at the address
|
||||
//! @param addr The address (in local space)
|
||||
virtual std::string getValueName(uint24_t addr) const = 0;
|
||||
//! @brief Return the memory accessor this accessor mirror if any
|
||||
//! @return nullptr if isMirror is false, the source otherwise.
|
||||
virtual std::shared_ptr<IMemory> getMirrored() const = 0;
|
||||
|
||||
//! @brief A virtual default destructor.
|
||||
virtual ~IMemory() = default;
|
||||
};
|
||||
};
|
||||
@@ -4,43 +4,41 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include "MemoryBus.hpp"
|
||||
#include "../SNES.hpp"
|
||||
#include "MemoryShadow.hpp"
|
||||
#include "RectangleShadow.hpp"
|
||||
#include "../Exceptions/InvalidAddress.hpp"
|
||||
#include "SNES.hpp"
|
||||
#include "Memory/MemoryBus.hpp"
|
||||
#include "Memory/MemoryShadow.hpp"
|
||||
#include "Exceptions/InvalidAddress.hpp"
|
||||
|
||||
namespace ComSquare::Memory
|
||||
{
|
||||
std::shared_ptr<IMemory> MemoryBus::getAccessor(uint24_t addr)
|
||||
IMemory *MemoryBus::getAccessor(uint24_t addr)
|
||||
{
|
||||
auto it = std::find_if(this->_memoryAccessors.begin(), this->_memoryAccessors.end(), [addr](std::shared_ptr<IMemory> &accessor)
|
||||
auto it = std::find_if(this->_memoryAccessors.begin(), this->_memoryAccessors.end(), [addr](IMemory &accessor)
|
||||
{
|
||||
return accessor->hasMemoryAt(addr);
|
||||
return accessor.hasMemoryAt(addr);
|
||||
});
|
||||
if (it == this->_memoryAccessors.end())
|
||||
return nullptr;
|
||||
return *it;
|
||||
return &it->get();
|
||||
}
|
||||
|
||||
uint8_t MemoryBus::read(uint24_t addr)
|
||||
{
|
||||
std::shared_ptr<IMemory> handler = this->getAccessor(addr);
|
||||
IMemory *handler = this->getAccessor(addr);
|
||||
|
||||
if (!handler) {
|
||||
std::cout << "Unknown memory accessor for address $" << std::hex << addr << ". Using open bus." << std::endl;
|
||||
return this->_openBus;
|
||||
}
|
||||
|
||||
uint8_t data = handler->read(handler->getRelativeAddress(addr));
|
||||
this->_openBus = data;
|
||||
return data;
|
||||
}
|
||||
|
||||
uint8_t MemoryBus::read(uint24_t addr, bool silence)
|
||||
uint8_t MemoryBus::peek(uint24_t addr)
|
||||
{
|
||||
if (!silence)
|
||||
return this->read(addr);
|
||||
std::shared_ptr<IMemory> handler = this->getAccessor(addr);
|
||||
IMemory *handler = this->getAccessor(addr);
|
||||
|
||||
if (!handler)
|
||||
return this->_openBus;
|
||||
@@ -53,7 +51,7 @@ namespace ComSquare::Memory
|
||||
|
||||
void MemoryBus::write(uint24_t addr, uint8_t data)
|
||||
{
|
||||
std::shared_ptr<IMemory> handler = this->getAccessor(addr);
|
||||
IMemory *handler = this->getAccessor(addr);
|
||||
|
||||
if (!handler) {
|
||||
std::cout << "Unknown memory accessor for address " << std::hex << addr << ". Warning, it was a write." << std::endl;
|
||||
@@ -64,28 +62,30 @@ namespace ComSquare::Memory
|
||||
|
||||
void MemoryBus::_mirrorComponents(SNES &console, unsigned i)
|
||||
{
|
||||
this->_memoryAccessors.emplace_back(new Memory::RectangleShadow(console.wram, i, i, 0x0000, 0x1FFF));
|
||||
this->_memoryAccessors.emplace_back(new Memory::MemoryShadow(console.ppu, (i << 16u) + 0x2100, (i << 16u) + 0x213F));
|
||||
this->_memoryAccessors.emplace_back(new Memory::MemoryShadow(console.apu, (i << 16u) + 0x2140, (i << 16u) + 0x2143));
|
||||
this->_memoryAccessors.emplace_back(new Memory::MemoryShadow(console.cpu, (i << 16u) + 0x4200, (i << 16u) + 0x421F));
|
||||
this->_rectangleShadows.emplace_back(console.wram, i, i, 0x0000, 0x1FFF);
|
||||
this->_shadows.emplace_back(console.ppu, (i << 16u) + 0x2100, (i << 16u) + 0x213F);
|
||||
this->_shadows.emplace_back(console.apu, (i << 16u) + 0x2140, (i << 16u) + 0x2143);
|
||||
this->_shadows.emplace_back(console.cpu, (i << 16u) + 0x4200, (i << 16u) + 0x421F);
|
||||
}
|
||||
|
||||
void MemoryBus::mapComponents(SNES &console)
|
||||
{
|
||||
this->_memoryAccessors.clear();
|
||||
this->_shadows.clear();
|
||||
this->_rectangleShadows.clear();
|
||||
|
||||
// The WRam and PU registers are always mapped at the same address no matter the mapping mode.
|
||||
console.wram->setMemoryRegion(0x7E, 0x7F, 0x0000, 0xFFFF);
|
||||
this->_memoryAccessors.push_back(console.wram);
|
||||
console.wram.setMemoryRegion(0x7E, 0x7F, 0x0000, 0xFFFF);
|
||||
this->_memoryAccessors.emplace_back(console.wram);
|
||||
|
||||
console.ppu->setMemoryRegion(0x2100, 0x213F);
|
||||
this->_memoryAccessors.push_back(console.ppu);
|
||||
console.ppu.setMemoryRegion(0x2100, 0x213F);
|
||||
this->_memoryAccessors.emplace_back(console.ppu);
|
||||
|
||||
console.apu->setMemoryRegion(0x2140, 0x2143);
|
||||
this->_memoryAccessors.push_back(console.apu);
|
||||
console.apu.setMemoryRegion(0x2140, 0x2143);
|
||||
this->_memoryAccessors.emplace_back(console.apu);
|
||||
|
||||
console.cpu->setMemoryRegion(0x4200, 0x44FF);
|
||||
this->_memoryAccessors.push_back(console.cpu);
|
||||
console.cpu.setMemoryRegion(0x4200, 0x44FF);
|
||||
this->_memoryAccessors.emplace_back(console.cpu);
|
||||
|
||||
// TODO implement Joys.
|
||||
|
||||
@@ -96,27 +96,27 @@ namespace ComSquare::Memory
|
||||
for (uint8_t i = 0x80; i < 0xC0; i += 0x01)
|
||||
this->_mirrorComponents(console, i);
|
||||
|
||||
if (console.cartridge->header.mappingMode & Cartridge::LoRom) {
|
||||
console.cartridge->setMemoryRegion(0x80, 0xFF, 0x8000, 0xFFFF);
|
||||
this->_memoryAccessors.push_back(console.cartridge);
|
||||
if (console.cartridge.header.mappingMode & Cartridge::LoRom) {
|
||||
console.cartridge.setMemoryRegion(0x80, 0xFF, 0x8000, 0xFFFF);
|
||||
this->_memoryAccessors.emplace_back(console.cartridge);
|
||||
// Mirror on the Q1 and Q2.
|
||||
this->_memoryAccessors.emplace_back(new Memory::RectangleShadow(console.cartridge, 0x00, 0x7D, 0x8000, 0xFFFF));
|
||||
this->_rectangleShadows.emplace_back(console.cartridge, 0x00, 0x7D, 0x8000, 0xFFFF);
|
||||
// Mirror on the lower half of the Q2.
|
||||
this->_memoryAccessors.emplace_back((new Memory::RectangleShadow(console.cartridge, 0x40, 0x6F, 0x0000, 0x7FFF))->setBankOffset(0x40));
|
||||
this->_rectangleShadows.emplace_back(console.cartridge, 0x40, 0x6F, 0x0000, 0x7FFF).setBankOffset(0x40);
|
||||
// Mirror on the lower half of the Q4
|
||||
this->_memoryAccessors.emplace_back((new Memory::RectangleShadow(console.cartridge, 0xC0, 0xEF, 0x0000, 0x7FFF))->setBankOffset(0x40));
|
||||
this->_rectangleShadows.emplace_back(console.cartridge, 0xC0, 0xEF, 0x0000, 0x7FFF).setBankOffset(0x40);
|
||||
|
||||
console.sram->setMemoryRegion(0xF0, 0xFD, 0x0000, 0x7FFF);
|
||||
this->_memoryAccessors.push_back(console.sram);
|
||||
this->_memoryAccessors.emplace_back(new Memory::RectangleShadow(console.sram, 0x70, 0x7D, 0x0000, 0x7FFF));
|
||||
console.sram.setMemoryRegion(0xF0, 0xFD, 0x0000, 0x7FFF);
|
||||
this->_memoryAccessors.emplace_back(console.sram);
|
||||
this->_rectangleShadows.emplace_back(console.sram, 0x70, 0x7D, 0x0000, 0x7FFF);
|
||||
|
||||
// TODO implement the SRam accessor for the FE/FF
|
||||
}
|
||||
// TODO should implement HiRom.
|
||||
}
|
||||
|
||||
bool MemoryBus::isDebugger()
|
||||
{
|
||||
return false;
|
||||
for (auto &shadow : this->_shadows)
|
||||
this->_memoryAccessors.emplace_back(shadow);
|
||||
for (auto &shadow : this->_rectangleShadows)
|
||||
this->_memoryAccessors.emplace_back(shadow);
|
||||
}
|
||||
}
|
||||
@@ -2,13 +2,14 @@
|
||||
// Created by anonymus-raccoon on 1/23/20.
|
||||
//
|
||||
|
||||
#ifndef COMSQUARE_MEMORYBUS_HPP
|
||||
#define COMSQUARE_MEMORYBUS_HPP
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include "AMemory.hpp"
|
||||
#include "RectangleShadow.hpp"
|
||||
#include "MemoryShadow.hpp"
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace ComSquare
|
||||
{
|
||||
@@ -17,10 +18,16 @@ namespace ComSquare
|
||||
namespace Memory
|
||||
{
|
||||
//! @brief The memory bus is the component responsible of mapping addresses to components address and transmitting the data.
|
||||
class MemoryBus {
|
||||
class MemoryBus
|
||||
{
|
||||
private:
|
||||
//! @brief The list of components registered inside the bus. Every components that can read/write to a public address should be in this vector.
|
||||
std::vector<std::shared_ptr<IMemory>> _memoryAccessors;
|
||||
std::vector<std::reference_wrapper<IMemory>> _memoryAccessors;
|
||||
|
||||
//! @brief The list of simple memory shadows that are used to map duplicated zones of memory.
|
||||
std::vector<MemoryShadow> _shadows = {};
|
||||
//! @brief The list of rectangle memory shadows that are used to map duplicated zones of memory.
|
||||
std::vector<RectangleShadow> _rectangleShadows = {};
|
||||
|
||||
//! @brief WRam, CPU, PPU & APU registers are mirrored to all banks of Q1 & Q3. This function is used for the mirroring.
|
||||
//! @param console All the components.
|
||||
@@ -30,29 +37,33 @@ namespace ComSquare
|
||||
//! @brief The last value read via the memory bus.
|
||||
uint8_t _openBus = 0;
|
||||
public:
|
||||
//! @brief Create a new default memory bus.
|
||||
MemoryBus() = default;
|
||||
//! @brief A memory bus is copyable.
|
||||
MemoryBus(const MemoryBus &) = default;
|
||||
//! @brief A memory bus is assignable.
|
||||
MemoryBus &operator=(const MemoryBus &) = default;
|
||||
//! @brief A default destructor
|
||||
~MemoryBus() = default;
|
||||
|
||||
//! @brief Force silencing read to the bus.
|
||||
bool forceSilence = false;
|
||||
|
||||
//! @brief Read data at a global address.
|
||||
//! @param addr The address to read from.
|
||||
//! @return The value that the component returned for this address. If the address was mapped to ram, it simply returned the value. If the address was mapped to a register the component returned the register.
|
||||
virtual uint8_t read(uint24_t addr);
|
||||
|
||||
//! @brief Read data at a global address. This form allow read to be silenced.
|
||||
//! @param addr The address to read from.
|
||||
//! @param silence Disable login to the memory bus's debugger (if enabled). Should only be used by other debuggers. This also won't affect the open bus.
|
||||
//! @throws InvalidAddress If the address is not mapped to the bus, this exception is thrown.
|
||||
//! @return The value that the component returned for this address. If the address was mapped to ram, it simply returned the value. If the address was mapped to a register the component returned the register.
|
||||
virtual uint8_t read(uint24_t addr, bool silence);
|
||||
uint8_t read(uint24_t addr);
|
||||
|
||||
//! @brief This as the same purpose as a read but it does not change the open bus and won't throw an exception.
|
||||
//! @param addr The address to read from.
|
||||
//! @return The value that the component returned for this address. If the address was mapped to ram, it simply returned the value. If the address was mapped to a register the component returned the register.
|
||||
uint8_t peek(uint24_t addr);
|
||||
|
||||
//! @brief Write a data to a global address.
|
||||
//! @param addr The address to write to.
|
||||
//! @param data The data to write.
|
||||
virtual void write(uint24_t addr, uint8_t data);
|
||||
void write(uint24_t addr, uint8_t data);
|
||||
|
||||
//! @brief Map components to the address space using the currently loaded cartridge to set the right mapping mode.
|
||||
//! @param console All the components.
|
||||
@@ -61,13 +72,7 @@ namespace ComSquare
|
||||
//! @brief Helper function to get the components that is responsible of read/write at an address.
|
||||
//! @param addr The address you want to look for.
|
||||
//! @return The components responsible for the address param or nullptr if none was found.
|
||||
std::shared_ptr<IMemory> getAccessor(uint24_t addr);
|
||||
|
||||
//! @brief Return true if the Bus is overloaded with debugging features.
|
||||
virtual bool isDebugger();
|
||||
IMemory *getAccessor(uint24_t addr);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif //COMSQUARE_MEMORYBUS_HPP
|
||||
|
||||
@@ -4,48 +4,46 @@
|
||||
|
||||
#include "MemoryShadow.hpp"
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace ComSquare::Memory
|
||||
{
|
||||
MemoryShadow::MemoryShadow(std::shared_ptr<IMemory> initial, uint24_t start, uint24_t end)
|
||||
: _initial(std::move(initial))
|
||||
MemoryShadow::MemoryShadow(IMemory &initial, uint24_t start, uint24_t end)
|
||||
: _initial(initial)
|
||||
{
|
||||
this->setMemoryRegion(start, end);
|
||||
}
|
||||
|
||||
uint8_t MemoryShadow::read(uint24_t addr)
|
||||
{
|
||||
return this->_initial->read(addr);
|
||||
return this->_initial.read(addr);
|
||||
}
|
||||
|
||||
void MemoryShadow::write(uint24_t addr, uint8_t data)
|
||||
{
|
||||
return this->_initial->write(addr, data);
|
||||
return this->_initial.write(addr, data);
|
||||
}
|
||||
|
||||
uint24_t MemoryShadow::getSize() const
|
||||
{
|
||||
return this->_initial->getSize();
|
||||
return this->_initial.getSize();
|
||||
}
|
||||
|
||||
bool MemoryShadow::isMirror() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
std::shared_ptr<IMemory> MemoryShadow::getMirrored() const
|
||||
IMemory &MemoryShadow::getMirrored() const
|
||||
{
|
||||
return this->_initial;
|
||||
}
|
||||
|
||||
std::string MemoryShadow::getName() const
|
||||
{
|
||||
return this->_initial->getName();
|
||||
return this->_initial.getName();
|
||||
}
|
||||
|
||||
Component MemoryShadow::getComponent() const
|
||||
{
|
||||
return this->_initial->getComponent();
|
||||
return this->_initial.getComponent();
|
||||
}
|
||||
|
||||
std::string MemoryShadow::getValueName(uint24_t addr) const
|
||||
{
|
||||
return this->_initial.getValueName(addr);
|
||||
}
|
||||
}
|
||||
@@ -9,39 +9,51 @@
|
||||
|
||||
namespace ComSquare::Memory
|
||||
{
|
||||
class MemoryShadow : public AMemory {
|
||||
class MemoryShadow : public AMemory
|
||||
{
|
||||
private:
|
||||
//! @brief Memory to shadow from.
|
||||
std::shared_ptr<IMemory> _initial;
|
||||
IMemory &_initial;
|
||||
public:
|
||||
//! @brief Create a shadow for the memory given as parameter.
|
||||
MemoryShadow(std::shared_ptr<IMemory> initial, uint24_t start, uint24_t end);
|
||||
//! @param initial The memory to shadow
|
||||
//! @param start The start position of the initial memory to shadow.
|
||||
//! @param end The end position of the initial memory to shadow.
|
||||
MemoryShadow(IMemory &initial, uint24_t start, uint24_t end);
|
||||
//! @brief A memory shadow is copy constructable
|
||||
MemoryShadow(const MemoryShadow &) = default;
|
||||
MemoryShadow &operator=(const MemoryShadow &) = default;
|
||||
~MemoryShadow() = default;
|
||||
//! @brief A memory shadow is not assignable.
|
||||
MemoryShadow &operator=(const MemoryShadow &) = delete;
|
||||
//! @brief A default destructor
|
||||
~MemoryShadow() override = default;
|
||||
|
||||
//! @brief Read from the initial AMemory given.
|
||||
//! @param addr The address to read from. The address 0x0 should refer to the first byte of the initial AMemory.
|
||||
//! @throw InvalidAddress will be thrown if the address is more than the size of the initial AMemory.
|
||||
//! @return Return the data at the address.
|
||||
uint8_t read(uint24_t addr) override;
|
||||
|
||||
//! @brief Write data to the ram.
|
||||
//! @param addr The address to write to. The address 0x0 should refer to the first byte of the initial AMemory.
|
||||
//! @param data The data to write.
|
||||
//! @throw InvalidAddress will be thrown if the address is more than the size of the initial AMemory.
|
||||
void write(uint24_t addr, uint8_t data) override;
|
||||
|
||||
//! @brief Get the size of the data. This size can be lower than the mapped data.
|
||||
//! @return The number of bytes inside this memory.
|
||||
virtual uint24_t getSize() const override;
|
||||
//! @brief Check if this memory is a mirror or not.
|
||||
//! @return True if this memory is a mirror. False otherwise.
|
||||
bool isMirror() const override;
|
||||
[[nodiscard]] uint24_t getSize() const override;
|
||||
|
||||
//! @brief Get the name of this accessor (used for debug purpose)
|
||||
std::string getName() const override;
|
||||
[[nodiscard]] std::string getName() const override;
|
||||
//! @brief Get the component of this accessor (used for debug purpose)
|
||||
Component getComponent() const override;
|
||||
[[nodiscard]] Component getComponent() const override;
|
||||
|
||||
//! @brief Get the name of the data at the address
|
||||
//! @param addr The address (in local space)
|
||||
[[nodiscard]] std::string getValueName(uint24_t addr) const override;
|
||||
|
||||
//! @brief Return the memory accessor this accessor mirror if any
|
||||
//! @return nullptr if isMirror is false, the source otherwise.
|
||||
std::shared_ptr<IMemory> getMirrored() const override;
|
||||
[[nodiscard]] IMemory &getMirrored() const;
|
||||
};
|
||||
}
|
||||
@@ -3,17 +3,16 @@
|
||||
//
|
||||
|
||||
#include "RectangleShadow.hpp"
|
||||
#include <utility>
|
||||
#include <iostream>
|
||||
|
||||
namespace ComSquare::Memory
|
||||
{
|
||||
RectangleShadow::RectangleShadow(std::shared_ptr<IMemory> initial,
|
||||
RectangleShadow::RectangleShadow(IMemory &initial,
|
||||
uint8_t startBank,
|
||||
uint8_t endBank,
|
||||
uint16_t startPage,
|
||||
uint16_t endPage)
|
||||
: _initial(std::move(initial))
|
||||
: _initial(initial)
|
||||
{
|
||||
this->setMemoryRegion(startBank, endBank, startPage, endPage);
|
||||
}
|
||||
@@ -26,42 +25,36 @@ namespace ComSquare::Memory
|
||||
|
||||
uint8_t RectangleShadow::read(uint24_t addr)
|
||||
{
|
||||
return this->_initial->read(addr);
|
||||
return this->_initial.read(addr);
|
||||
}
|
||||
|
||||
void RectangleShadow::write(uint24_t addr, uint8_t data)
|
||||
{
|
||||
return this->_initial->write(addr, data);
|
||||
return this->_initial.write(addr, data);
|
||||
}
|
||||
|
||||
RectangleShadow *RectangleShadow::setBankOffset(int bankOffset)
|
||||
void RectangleShadow::setBankOffset(int bankOffset)
|
||||
{
|
||||
this->_bankOffset = bankOffset;
|
||||
return this;
|
||||
}
|
||||
|
||||
uint24_t RectangleShadow::getSize() const
|
||||
{
|
||||
return this->_initial->getSize();
|
||||
return this->_initial.getSize();
|
||||
}
|
||||
|
||||
bool RectangleShadow::isMirror() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
std::shared_ptr<IMemory> RectangleShadow::getMirrored() const
|
||||
IMemory &RectangleShadow::getMirrored() const
|
||||
{
|
||||
return this->_initial;
|
||||
}
|
||||
|
||||
std::string RectangleShadow::getName() const
|
||||
{
|
||||
return this->_initial->getName();
|
||||
return this->_initial.getName();
|
||||
}
|
||||
|
||||
Component RectangleShadow::getComponent() const
|
||||
{
|
||||
return this->_initial->getComponent();
|
||||
return this->_initial.getComponent();
|
||||
}
|
||||
}
|
||||
@@ -13,14 +13,21 @@ namespace ComSquare::Memory
|
||||
class RectangleShadow : public ARectangleMemory {
|
||||
private:
|
||||
//! @brief Memory to shadow from.
|
||||
std::shared_ptr<IMemory> _initial;
|
||||
IMemory &_initial;
|
||||
//! @brief The number of banks to add to the memory before accessing it from the initial data.
|
||||
int _bankOffset = 0;
|
||||
public:
|
||||
//! @brief Create a shadow for the memory given as parameter.
|
||||
explicit RectangleShadow(std::shared_ptr<IMemory> initial, uint8_t startBank, uint8_t endBank, uint16_t startPage, uint16_t endPage);
|
||||
//! @param startBank The starting bank of the memory to shadow.
|
||||
//! @param endBank The ending bank of the memory to shadow
|
||||
//! @param startPage The starting page of the memory to shadow
|
||||
//! @param endPage The ending page of the memory to shadow
|
||||
RectangleShadow(IMemory &initial, uint8_t startBank, uint8_t endBank, uint16_t startPage, uint16_t endPage);
|
||||
//! @brief A rectangle shadow is copy constructable.
|
||||
RectangleShadow(const RectangleShadow &) = default;
|
||||
RectangleShadow &operator=(const RectangleShadow &) = default;
|
||||
//! @brrief A rectangle shadow is not assignable
|
||||
RectangleShadow &operator=(const RectangleShadow &) = delete;
|
||||
//! @brief A default destructor.
|
||||
~RectangleShadow() override = default;
|
||||
|
||||
//! @brief Read from the initial AMemory given.
|
||||
@@ -28,31 +35,34 @@ namespace ComSquare::Memory
|
||||
//! @throw InvalidAddress will be thrown if the address is more than the size of the initial AMemory.
|
||||
//! @return Return the data at the address.
|
||||
uint8_t read(uint24_t addr) override;
|
||||
|
||||
//! @brief Write data to the ram.
|
||||
//! @param addr The address to write to. The address 0x0 should refer to the first byte of the initial AMemory.
|
||||
//! @param data The data to write.
|
||||
//! @throw InvalidAddress will be thrown if the address is more than the size of the initial AMemory.
|
||||
void write(uint24_t addr, uint8_t data) override;
|
||||
|
||||
//! @brief Translate an absolute address to a relative address
|
||||
//! @param addr The absolute address (in the 24 bit bus)
|
||||
//! @return The local address (0 refers to the first byte of this component).
|
||||
//! @throw InvalidAddress is thrown if the address is not mapped by this component.
|
||||
uint24_t getRelativeAddress(uint24_t addr) const override;
|
||||
[[nodiscard]] uint24_t getRelativeAddress(uint24_t addr) const override;
|
||||
|
||||
//! @brief Get the size of the data. This size can be lower than the mapped data.
|
||||
//! @return The number of bytes inside this memory.
|
||||
virtual uint24_t getSize() const override;
|
||||
//! @brief Check if this memory is a mirror or not.
|
||||
//! @return True if this memory is a mirror. False otherwise.
|
||||
bool isMirror() const override;
|
||||
[[nodiscard]] uint24_t getSize() const override;
|
||||
|
||||
//! @brief Get the name of this accessor (used for debug purpose)
|
||||
std::string getName() const override;
|
||||
[[nodiscard]] std::string getName() const override;
|
||||
|
||||
//! @brief Get the component of this accessor (used for debug purpose)
|
||||
Component getComponent() const override;
|
||||
[[nodiscard]] Component getComponent() const override;
|
||||
|
||||
//! @brief Return the memory accessor this accessor mirror if any
|
||||
//! @return nullptr if isMirror is false, the source otherwise.
|
||||
std::shared_ptr<IMemory> getMirrored() const override;
|
||||
[[nodiscard]] IMemory &getMirrored() const;
|
||||
|
||||
//! @brief Set the number of bank this component do not shadow. Referring to the first byte of this component will refer to the first byte of the bank at (bankOffset + start of initial memory).
|
||||
RectangleShadow *setBankOffset(int bankOffset);
|
||||
void setBankOffset(int bankOffset);
|
||||
};
|
||||
}
|
||||
@@ -2,8 +2,7 @@
|
||||
// Created by anonymus-raccoon on 3/24/20.
|
||||
//
|
||||
|
||||
#ifndef COMSQUARE_COMPONENTS_HPP
|
||||
#define COMSQUARE_COMPONENTS_HPP
|
||||
#pragma once
|
||||
|
||||
namespace ComSquare
|
||||
{
|
||||
@@ -19,4 +18,3 @@ namespace ComSquare
|
||||
SRam = 1u << 8u,
|
||||
};
|
||||
}
|
||||
#endif //COMSQUARE_COMPONENTS_HPP
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#include "PPU.hpp"
|
||||
#include "Background.hpp"
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include "Tile.hpp"
|
||||
#include "PPUUtils.hpp"
|
||||
#include "Models/Vector2.hpp"
|
||||
@@ -15,7 +14,7 @@ namespace ComSquare::PPU
|
||||
{
|
||||
Background::Background(ComSquare::PPU::PPU &ppu, int backGroundNumber, bool hasPriority):
|
||||
_ppu(ppu),
|
||||
_tileMapsConfig(ppu.getBackgroundSize(backGroundNumber)),
|
||||
_tileMapsConfig(ppu.getBackgroundMirroring(backGroundNumber)),
|
||||
_characterNbPixels(ppu.getCharacterSize(backGroundNumber)),
|
||||
_bpp(ppu.getBPP(backGroundNumber)),
|
||||
_directColor(false),
|
||||
@@ -26,9 +25,9 @@ namespace ComSquare::PPU
|
||||
_bgNumber(backGroundNumber),
|
||||
_tileBuffer({{{0}}}),
|
||||
_vram(ppu.vram),
|
||||
_cgram(ppu.cgram)
|
||||
_cgram(ppu.cgram),
|
||||
buffer({{{0}}})
|
||||
{
|
||||
memset(this->buffer, 0, sizeof(this->buffer));
|
||||
this->_tileRenderer.setRam(this->_vram);
|
||||
this->_tileRenderer.setCgram(this->_cgram);
|
||||
}
|
||||
@@ -37,19 +36,24 @@ namespace ComSquare::PPU
|
||||
{
|
||||
uint16_t vramAddress = this->_tileMapStartAddress;
|
||||
Vector2<int> offset = this->_ppu.getBgScroll(this->_bgNumber);
|
||||
this->backgroundSize.x = this->_tileMapsConfig.x * this->_characterNbPixels.x * NbCharacterWidth;
|
||||
this->backgroundSize.y = this->_tileMapsConfig.y * this->_characterNbPixels.y * NbCharacterHeight;
|
||||
this->backgroundSize.x =
|
||||
static_cast<int>(this->_tileMapsConfig.x) * this->_characterNbPixels.x * NbCharacterWidth;
|
||||
this->backgroundSize.y =
|
||||
static_cast<int>(this->_tileMapsConfig.y) * this->_characterNbPixels.y * NbCharacterHeight;
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (!(i == 1 && this->_tileMapsConfig.x == 1) && !(i > 1 && this->_tileMapsConfig.y == 1)) {
|
||||
_drawBasicTileMap(vramAddress, offset);
|
||||
}
|
||||
this->_drawBasicTileMap(vramAddress, offset);
|
||||
for (int i = 1; i < 4; i++) {
|
||||
vramAddress += TileMapByteSize;
|
||||
offset.x += NbCharacterWidth * this->_characterNbPixels.x;
|
||||
if (i == 2) {
|
||||
offset.x = 0;
|
||||
offset.y += NbCharacterHeight * this->_characterNbPixels.y;
|
||||
}
|
||||
if (i > 1 && !this->_tileMapsConfig.y)
|
||||
break;
|
||||
if ((i == 1 || i == 3) && !this->_tileMapsConfig.x)
|
||||
continue;
|
||||
this->_drawBasicTileMap(vramAddress, offset);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,7 +146,7 @@ namespace ComSquare::PPU
|
||||
this->_tileRenderer.setBpp(this->_bpp);
|
||||
}
|
||||
|
||||
void Background::setTilemaps(Vector2<int> tileMaps)
|
||||
void Background::setTilemaps(Vector2<bool> tileMaps)
|
||||
{
|
||||
this->_tileMapsConfig = tileMaps;
|
||||
}
|
||||
|
||||
@@ -31,7 +31,8 @@ namespace ComSquare::PPU
|
||||
//! @brief the ppu used to get registers values (ex: bg scroll)
|
||||
ComSquare::PPU::PPU &_ppu;
|
||||
//! @brief The tilemap configuration nb of tileMap vertically and horizontally
|
||||
Vector2<int> _tileMapsConfig;
|
||||
//! @note members are set to true if the tilemap is expended in their direction
|
||||
Vector2<bool> _tileMapsConfig;
|
||||
//! @brief The number of pixels of a character (x: width, y:height)
|
||||
Vector2<int> _characterNbPixels;
|
||||
//! @brief The number of bits per pixels to currently look for each pixel
|
||||
@@ -67,7 +68,7 @@ namespace ComSquare::PPU
|
||||
//! @brief The size of the background (x, y)
|
||||
Vector2<unsigned> backgroundSize;
|
||||
//! @brief The output buffer (pixels are written on it)
|
||||
uint32_t buffer[1024][1024];
|
||||
std::array<std::array<uint32_t, 1024>, 1024> buffer;
|
||||
|
||||
//! @brief Render a background on his internal buffer
|
||||
void renderBackground();
|
||||
@@ -84,7 +85,7 @@ namespace ComSquare::PPU
|
||||
void setBpp(int bpp);
|
||||
//! @brief setter for private variable _tileMaps
|
||||
//! @param tileMaps The tileMaps to set
|
||||
void setTilemaps(Vector2<int> tileMaps);
|
||||
void setTilemaps(Vector2<bool> tileMaps);
|
||||
|
||||
//! @brief Get the BackGround Number
|
||||
//! @return the current Background number
|
||||
|
||||
@@ -4,19 +4,22 @@
|
||||
|
||||
#include <iostream>
|
||||
#include <bitset>
|
||||
#include <cstring>
|
||||
#include "PPU.hpp"
|
||||
#include "Exceptions/NotImplementedException.hpp"
|
||||
#include "Exceptions/InvalidAddress.hpp"
|
||||
#include "Ram/Ram.hpp"
|
||||
#include "Models/Vector2.hpp"
|
||||
|
||||
namespace ComSquare::PPU::Utils::Debug {
|
||||
void populateEnvironment(PPU &ppu, int dumpNumber);
|
||||
}
|
||||
|
||||
namespace ComSquare::PPU
|
||||
{
|
||||
PPU::PPU(Renderer::IRenderer &renderer):
|
||||
vram(std::make_shared<Ram::Ram>(VramSize, ComSquare::VRam, "VRAM")),
|
||||
oamram(std::make_shared<Ram::Ram>(OAMRamSize, ComSquare::OAMRam, "OAMRAM")),
|
||||
cgram(std::make_shared<Ram::Ram>(CGRamSize, ComSquare::CGRam, "CGRAM")),
|
||||
vram(new Ram::Ram(VramSize, ComSquare::VRam, "VRAM")),
|
||||
oamram(new Ram::Ram(OAMRamSize, ComSquare::OAMRam, "OAMRAM")),
|
||||
cgram(new Ram::Ram(CGRamSize, ComSquare::CGRam, "CGRAM")),
|
||||
_renderer(renderer),
|
||||
_backgrounds{
|
||||
Background(*this, 1, false),
|
||||
@@ -27,11 +30,13 @@ namespace ComSquare::PPU
|
||||
Background(*this, 3, true),
|
||||
Background(*this, 4, false),
|
||||
Background(*this, 4, true)
|
||||
}
|
||||
},
|
||||
_mainScreen({{{0}}}),
|
||||
_subScreen({{{0}}})
|
||||
{
|
||||
memset(this->_mainScreen, 0, sizeof(this->_mainScreen));
|
||||
memset(this->_subScreen, 0, sizeof(this->_subScreen));
|
||||
this->_registers._isLowByte = true;
|
||||
|
||||
//Utils::Debug::populateEnvironment(*this, 0);
|
||||
}
|
||||
|
||||
uint8_t PPU::read(uint24_t addr)
|
||||
@@ -118,12 +123,18 @@ namespace ComSquare::PPU
|
||||
case PpuRegisters::bg2sc:
|
||||
case PpuRegisters::bg3sc:
|
||||
case PpuRegisters::bg4sc:
|
||||
this->_registers._bgsc[addr - 0x07].raw = data;
|
||||
this->_registers._bgsc[addr - PpuRegisters::bg1sc].raw = data;
|
||||
// update background tilemap address
|
||||
this->_backgrounds[addr - 0x07].setTileMapStartAddress(this->getTileMapStartAddress(addr - 0x07 + 1));
|
||||
this->_backgrounds[addr - 0x07 + 1].setTileMapStartAddress(this->getTileMapStartAddress(addr - 0x07 + 1));
|
||||
this->_backgrounds[addr - 0x07].setTilemaps({this->_registers._bgsc[addr - 0x07].tilemapHorizontalMirroring, this->_registers._bgsc[addr - 0x07].tilemapVerticalMirroring});
|
||||
this->_backgrounds[addr - 0x07 + 1].setTilemaps({this->_registers._bgsc[addr - 0x07].tilemapHorizontalMirroring, this->_registers._bgsc[addr - 0x07].tilemapVerticalMirroring});
|
||||
this->_backgrounds[addr - PpuRegisters::bg1sc].setTileMapStartAddress(
|
||||
this->getTileMapStartAddress(addr - PpuRegisters::bg1sc + 1));
|
||||
this->_backgrounds[addr - PpuRegisters::bg1sc + 1].setTileMapStartAddress(
|
||||
this->getTileMapStartAddress(addr - PpuRegisters::bg1sc + 1));
|
||||
this->_backgrounds[addr - PpuRegisters::bg1sc].setTilemaps(
|
||||
{static_cast<bool>(this->_registers._bgsc[addr - PpuRegisters::bg1sc].tilemapHorizontalMirroring),
|
||||
static_cast<bool>(this->_registers._bgsc[addr - PpuRegisters::bg1sc].tilemapVerticalMirroring)});
|
||||
this->_backgrounds[addr - PpuRegisters::bg1sc + 1].setTilemaps(
|
||||
{static_cast<bool>(this->_registers._bgsc[addr - PpuRegisters::bg1sc].tilemapHorizontalMirroring),
|
||||
static_cast<bool>(this->_registers._bgsc[addr - PpuRegisters::bg1sc].tilemapVerticalMirroring)});
|
||||
break;
|
||||
case PpuRegisters::bg12nba:
|
||||
case PpuRegisters::bg34nba:
|
||||
@@ -298,20 +309,21 @@ namespace ComSquare::PPU
|
||||
{
|
||||
(void)cycles;
|
||||
|
||||
|
||||
this->renderMainAndSubScreen();
|
||||
this->add_buffer(this->_screen, this->_subScreen);
|
||||
this->add_buffer(this->_screen, this->_mainScreen);
|
||||
//this->_backgrounds[2].renderBackground();
|
||||
//add_buffer(this->_screen, this->_backgrounds[2].buffer);
|
||||
for (unsigned long i = 0; i < 1024; i++) {
|
||||
for (unsigned long j = 0; j < 1024; j++) {
|
||||
for (unsigned long i = 0; i < this->_screen.size(); i++) {
|
||||
for (unsigned long j = 0; j < this->_screen[i].size(); j++) {
|
||||
this->_renderer.putPixel(j, i, this->_screen[i][j]);
|
||||
}
|
||||
}
|
||||
this->_renderer.drawScreen();
|
||||
memset(this->_mainScreen, 0xFF, sizeof(this->_mainScreen));
|
||||
memset(this->_subScreen, 0xFF, sizeof(this->_subScreen));
|
||||
for (auto &i : this->_mainScreen)
|
||||
i.fill(0XFF);
|
||||
for (auto &i : this->_subScreen)
|
||||
i.fill(0XFF);
|
||||
}
|
||||
|
||||
std::string PPU::getName() const
|
||||
@@ -528,12 +540,12 @@ namespace ComSquare::PPU
|
||||
return baseAddress;
|
||||
}
|
||||
|
||||
Vector2<int> PPU::getBackgroundSize(int bgNumber) const
|
||||
Vector2<bool> PPU::getBackgroundMirroring(int bgNumber) const
|
||||
{
|
||||
Vector2<int> backgroundSize(0,0);
|
||||
Vector2<bool> backgroundSize(false, false);
|
||||
|
||||
backgroundSize.y = (this->_registers._bgsc[bgNumber - 1].tilemapVerticalMirroring) ? 2 : 1;
|
||||
backgroundSize.x = (this->_registers._bgsc[bgNumber - 1].tilemapHorizontalMirroring) ? 2 : 1;
|
||||
backgroundSize.y = this->_registers._bgsc[bgNumber - 1].tilemapVerticalMirroring;
|
||||
backgroundSize.x = this->_registers._bgsc[bgNumber - 1].tilemapHorizontalMirroring;
|
||||
return backgroundSize;
|
||||
}
|
||||
|
||||
@@ -541,9 +553,9 @@ namespace ComSquare::PPU
|
||||
{
|
||||
uint16_t colorPalette;
|
||||
// should only render backgrounds needed (depending of th bgMode)
|
||||
//int i = 0;
|
||||
int i = 0;
|
||||
for (auto &_background : this->_backgrounds) {
|
||||
//i++;
|
||||
i++;
|
||||
_background.renderBackground();
|
||||
}
|
||||
// TODO make a function getDefaultBgColor
|
||||
@@ -551,9 +563,8 @@ namespace ComSquare::PPU
|
||||
colorPalette += this->cgram->read(1) << 8U;
|
||||
|
||||
uint32_t color = Utils::getRealColor(colorPalette);
|
||||
for (auto &array : this->_subScreen)
|
||||
for (auto &c : array)
|
||||
c = color;
|
||||
for (auto &row : this->_subScreen)
|
||||
row.fill(color);
|
||||
// the buffer is overwrite if necessary by a new bg so the background priority is from back to front
|
||||
// the starting palette index isn't implemented
|
||||
switch (this->_registers._bgmode.bgMode) {
|
||||
|
||||
@@ -17,6 +17,10 @@
|
||||
|
||||
#define FALLTHROUGH __attribute__((fallthrough));
|
||||
|
||||
namespace ComSquare::PPU::Utils {
|
||||
struct PpuState;
|
||||
};
|
||||
|
||||
namespace ComSquare::PPU
|
||||
{
|
||||
static constexpr uint32_t VramSize = 65536;
|
||||
@@ -554,18 +558,18 @@ namespace ComSquare::PPU
|
||||
std::shared_ptr<Ram::Ram> vram;
|
||||
std::shared_ptr<Ram::Ram> oamram;
|
||||
std::shared_ptr<Ram::Ram> cgram;
|
||||
private:
|
||||
//private:
|
||||
//! @brief Init ppuRegisters
|
||||
Registers _registers{};
|
||||
Renderer::IRenderer &_renderer;
|
||||
//! @brief Backgrounds buffers
|
||||
Background _backgrounds[8];
|
||||
//! @brief Main Screen buffer
|
||||
uint32_t _mainScreen[1024][1024];
|
||||
std::array<std::array<uint32_t, 1024>, 1024> _mainScreen;
|
||||
//! @brief Sub Screen buffer
|
||||
uint32_t _subScreen[1024][1024];
|
||||
std::array<std::array<uint32_t, 1024>, 1024> _subScreen;
|
||||
//! @brief Final Screen buffer
|
||||
uint32_t _screen[1024][1024];
|
||||
std::array<std::array<uint32_t, 1024>, 1024> _screen;
|
||||
//! @brief Used for vram read registers (0x2139 - 0x213A)
|
||||
uint16_t _vramReadBuffer = 0;
|
||||
//! @brief Struct that contain all necessary vars for the use of the registers
|
||||
@@ -615,19 +619,19 @@ namespace ComSquare::PPU
|
||||
uint16_t getTileMapStartAddress(int bgNumber) const;
|
||||
//! @brief Give the address to find the correct tileset for a given x and y
|
||||
uint16_t getTilesetAddress(int bgNumber) const;
|
||||
//! @brief Give the number of tilemaps to be rendered
|
||||
Vector2<int> getBackgroundSize(int bgNumber) const;
|
||||
//! @brief Tells if the tilemap is expanded for the x and y directions
|
||||
Vector2<bool> getBackgroundMirroring(int bgNumber) const;
|
||||
//! @brief Render the Main and sub screen correctly
|
||||
void renderMainAndSubScreen();
|
||||
//! @brief Add a bg buffer to another buffer
|
||||
template <std::size_t DEST_SIZE_X, std::size_t DEST_SIZE_Y, std::size_t SRC_SIZE_X, std::size_t SRC_SIZE_Y>
|
||||
void add_buffer(uint32_t (&bufferDest)[DEST_SIZE_Y][DEST_SIZE_X],
|
||||
const uint32_t (&bufferSrc)[SRC_SIZE_Y][SRC_SIZE_X],
|
||||
void add_buffer(std::array<std::array<uint32_t, DEST_SIZE_Y>, DEST_SIZE_X> &bufferDest,
|
||||
const std::array<std::array<uint32_t, SRC_SIZE_Y>, SRC_SIZE_X> &bufferSrc,
|
||||
const Vector2<int> &offset = {0, 0})
|
||||
{
|
||||
// TODO use std::ranges
|
||||
for (unsigned long i = 0; i < 1024; i++) {
|
||||
for (unsigned long j = 0; j < 1024; j++) {
|
||||
for (unsigned long i = 0; i < bufferSrc.size(); i++) {
|
||||
for (unsigned long j = 0; j < bufferSrc[i].size(); j++) {
|
||||
if (bufferSrc[i][j] > 0xFF) // 0xFF correspond to a black pixel with full brightness
|
||||
bufferDest[i + offset.x ][j + offset.y] = bufferSrc[i][j];
|
||||
}
|
||||
@@ -645,10 +649,11 @@ namespace ComSquare::PPU
|
||||
const Registers &getWriteRegisters() const;
|
||||
|
||||
template <std::size_t SRC_SIZE_Y, std::size_t SRC_SIZE_X>
|
||||
void add_buffer(const uint32_t (&buffer)[SRC_SIZE_Y][SRC_SIZE_X],
|
||||
void add_buffer(const std::array<std::array<uint32_t, SRC_SIZE_Y>, SRC_SIZE_X> &buffer,
|
||||
const Vector2<int> &offset = {0, 0})
|
||||
{
|
||||
// memset(this->_screen, 0xFF, sizeof(this->_screen));
|
||||
for (auto &i : this->_screen)
|
||||
i.fill(0XFF);
|
||||
for (unsigned long i = 0; i < buffer.size(); i++) {
|
||||
for (unsigned long j = 0; j < buffer[i].size(); j++) {
|
||||
if (buffer[i][j] > 0xFF) // 0xFF correspond to a black pixel with full brightness
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7,9 +7,15 @@
|
||||
|
||||
#include <stdint-gcc.h>
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <array>
|
||||
#include "Models/Vector2.hpp"
|
||||
|
||||
namespace ComSquare::PPU
|
||||
{
|
||||
class PPU;
|
||||
}
|
||||
|
||||
namespace ComSquare::PPU::Utils
|
||||
{
|
||||
|
||||
@@ -72,8 +78,5 @@ namespace ComSquare::PPU::Utils
|
||||
std::reverse(array.begin() + offset.x, array.begin() + offset.x + size.x);
|
||||
}
|
||||
|
||||
int *get_dump_vram();
|
||||
int *get_dump_cgram();
|
||||
|
||||
}
|
||||
#endif //COMSQUARE_PPU_UTILS_HPP
|
||||
3904
sources/PPU/PpuDebug.cpp
Normal file
3904
sources/PPU/PpuDebug.cpp
Normal file
File diff suppressed because it is too large
Load Diff
19
sources/PPU/PpuDebug.hpp
Normal file
19
sources/PPU/PpuDebug.hpp
Normal file
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// Created by cbihan on 03/07/2021.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Ram/Ram.hpp"
|
||||
#include "PPU.hpp"
|
||||
|
||||
|
||||
namespace ComSquare::PPU::Utils::Debug
|
||||
{
|
||||
void populateVram(std::shared_ptr<Ram::Ram> vram, int dumpNumber);
|
||||
void populateCgram(std::shared_ptr<Ram::Ram> cgram, int dumpNumber);
|
||||
|
||||
void populateEnvironment(PPU &ppu, int dumpNumber);
|
||||
}
|
||||
|
||||
|
||||
@@ -54,25 +54,30 @@ namespace ComSquare::Renderer
|
||||
{
|
||||
try {
|
||||
this->_snes.update();
|
||||
} catch (const DebuggableError &e) {
|
||||
}
|
||||
#ifdef DEBUGGER_ENABLED
|
||||
catch (const DebuggableError &e) {
|
||||
std::cout << "Invalid rom's instruction: " << e.what() << std::endl;
|
||||
this->_snes.enableCPUDebuggingWithError(e);
|
||||
} catch (std::exception &e) {
|
||||
}
|
||||
#endif
|
||||
catch (std::exception &e) {
|
||||
std::cerr << "An error occurred: " << e.what() << std::endl;
|
||||
QApplication::quit();
|
||||
}
|
||||
}
|
||||
|
||||
void QtFullSFML::reset()
|
||||
{
|
||||
this->_snes.cpu.RESB();
|
||||
}
|
||||
|
||||
#ifdef DEBUGGER_ENABLED
|
||||
void QtFullSFML::enableDebugCPU()
|
||||
{
|
||||
this->_snes.enableCPUDebugging();
|
||||
}
|
||||
|
||||
void QtFullSFML::reset()
|
||||
{
|
||||
this->_snes.cpu->RESB();
|
||||
}
|
||||
|
||||
void QtFullSFML::enableRamViewer()
|
||||
{
|
||||
this->_snes.enableRamViewer();
|
||||
@@ -107,8 +112,9 @@ namespace ComSquare::Renderer
|
||||
{
|
||||
this->_snes.enableTileViewerDebugging();
|
||||
}
|
||||
#endif
|
||||
|
||||
QtSFMLWindow::QtSFMLWindow(unsigned int height, unsigned int width)
|
||||
QtSFMLWindow::QtSFMLWindow(int height, int width)
|
||||
: QtSFML(&this->_window)
|
||||
{
|
||||
this->_window.resize(width, height);
|
||||
@@ -118,7 +124,7 @@ namespace ComSquare::Renderer
|
||||
void QtSFMLWindow::createWindow(SNES &snes, int maxFPS)
|
||||
{
|
||||
QtSFML::createWindow(snes, maxFPS);
|
||||
this->setWindowName(snes.cartridge->header.gameName);
|
||||
this->setWindowName(snes.cartridge.header.gameName);
|
||||
this->_window.setCentralWidget(this->_sfWidget);
|
||||
|
||||
QMenu *file = this->_window.menuBar()->addMenu("&File");
|
||||
@@ -126,52 +132,52 @@ namespace ComSquare::Renderer
|
||||
(void)file;
|
||||
|
||||
QMenu *game = this->_window.menuBar()->addMenu("&Game");
|
||||
QAction *reset = new QAction("Reset", &this->_window);
|
||||
auto *reset = new QAction("Reset", &this->_window);
|
||||
QMainWindow::connect(reset, &QAction::triggered, this->_sfWidget, &QtFullSFML::reset);
|
||||
game->addAction(reset);
|
||||
|
||||
|
||||
|
||||
#ifdef DEBUGGER_ENABLED
|
||||
QMenu *debugger = this->_window.menuBar()->addMenu("&Debugger");
|
||||
QAction *cpuDebugger = new QAction("CPU's Debugger", &this->_window);
|
||||
auto *cpuDebugger = new QAction("CPU's Debugger", &this->_window);
|
||||
cpuDebugger->setShortcut(Qt::Key_F1);
|
||||
QMainWindow::connect(cpuDebugger, &QAction::triggered, this->_sfWidget, &QtFullSFML::enableDebugCPU);
|
||||
debugger->addAction(cpuDebugger);
|
||||
|
||||
QAction *ramViewer = new QAction("Memory viewer", &this->_window);
|
||||
auto *ramViewer = new QAction("Memory viewer", &this->_window);
|
||||
ramViewer->setShortcut(Qt::Key_F2);
|
||||
QMainWindow::connect(ramViewer, &QAction::triggered, this->_sfWidget, &QtFullSFML::enableRamViewer);
|
||||
debugger->addAction(ramViewer);
|
||||
|
||||
QAction *headerViewer = new QAction("Header viewer", &this->_window);
|
||||
auto *headerViewer = new QAction("Header viewer", &this->_window);
|
||||
headerViewer->setShortcut(Qt::Key_F3);
|
||||
QMainWindow::connect(headerViewer, &QAction::triggered, this->_sfWidget, &QtFullSFML::enableHeaderViewer);
|
||||
debugger->addAction(headerViewer);
|
||||
|
||||
QAction *apuDebugger = new QAction("APU's Debugger", &this->_window);
|
||||
auto *apuDebugger = new QAction("APU's Debugger", &this->_window);
|
||||
apuDebugger->setShortcut(Qt::Key_F4);
|
||||
QMainWindow::connect(apuDebugger, &QAction::triggered, this->_sfWidget, &QtFullSFML::enableDebugAPU);
|
||||
debugger->addAction(apuDebugger);
|
||||
|
||||
QAction *busDebugger = new QAction("Memory bus Viewer", &this->_window);
|
||||
auto *busDebugger = new QAction("Memory bus Viewer", &this->_window);
|
||||
busDebugger->setShortcut(Qt::Key_F5);
|
||||
QMainWindow::connect(busDebugger, &QAction::triggered, this->_sfWidget, &QtFullSFML::enableDebugBus);
|
||||
debugger->addAction(busDebugger);
|
||||
|
||||
QAction *cgramDebugger = new QAction("Palette Viewer", &this->_window);
|
||||
auto *cgramDebugger = new QAction("Palette Viewer", &this->_window);
|
||||
cgramDebugger->setShortcut(Qt::Key_F6);
|
||||
QMainWindow::connect(cgramDebugger, &QAction::triggered, this->_sfWidget, &QtFullSFML::enableCgramViewer);
|
||||
debugger->addAction(cgramDebugger);
|
||||
|
||||
QAction *registerDebugger = new QAction("Registers Viewer", &this->_window);
|
||||
auto *registerDebugger = new QAction("Registers Viewer", &this->_window);
|
||||
registerDebugger->setShortcut(Qt::Key_F7);
|
||||
QMainWindow::connect(registerDebugger, &QAction::triggered, this->_sfWidget, &QtFullSFML::enableRegisterViewer);
|
||||
debugger->addAction(registerDebugger);
|
||||
|
||||
QAction *tileDebugger = new QAction("Tile Viewer", &this->_window);
|
||||
auto *tileDebugger = new QAction("Tile Viewer", &this->_window);
|
||||
tileDebugger->setShortcut(Qt::Key_F8);
|
||||
QMainWindow::connect(tileDebugger, &QAction::triggered, this->_sfWidget, &QtFullSFML::enableTileViewer);
|
||||
debugger->addAction(tileDebugger);
|
||||
#endif
|
||||
|
||||
this->_window.show();
|
||||
}
|
||||
|
||||
@@ -2,16 +2,15 @@
|
||||
// Created by anonymus-raccoon on 2/15/20.
|
||||
//
|
||||
|
||||
#ifndef COMSQUARE_QTSFML_HPP
|
||||
#define COMSQUARE_QTSFML_HPP
|
||||
#pragma once
|
||||
|
||||
#include <QtWidgets/QWidget>
|
||||
#include <SFML/Graphics/RenderWindow.hpp>
|
||||
#include <QtCore/QTimer>
|
||||
#include <QtWidgets/QMainWindow>
|
||||
#include <QtWidgets/QGridLayout>
|
||||
#include "../IRenderer.hpp"
|
||||
#include "../SFRenderer.hpp"
|
||||
#include "Renderer/IRenderer.hpp"
|
||||
#include "Renderer/SFRenderer.hpp"
|
||||
#include "QtWidgetSFML.hpp"
|
||||
|
||||
namespace ComSquare::Renderer
|
||||
@@ -23,6 +22,7 @@ namespace ComSquare::Renderer
|
||||
SNES &_snes;
|
||||
void onUpdate() override;
|
||||
public:
|
||||
#ifdef DEBUGGER_ENABLED
|
||||
//! @brief Action called when clicking on the enable CPU debugger button.
|
||||
void enableDebugCPU();
|
||||
//! @brief Action called when clicking on the enable Ram viewer button.
|
||||
@@ -39,6 +39,7 @@ namespace ComSquare::Renderer
|
||||
void enableRegisterViewer();
|
||||
//! @brief Action called when clicking on the enable Tile viewer button
|
||||
void enableTileViewer();
|
||||
#endif
|
||||
|
||||
//! @brief Action called when clicking on the reset button.
|
||||
void reset();
|
||||
@@ -46,7 +47,7 @@ namespace ComSquare::Renderer
|
||||
QtFullSFML(SNES &snes, QWidget* parent, const QPoint& position, const QSize& size, int frameRate = 0);
|
||||
QtFullSFML(const QtFullSFML &) = delete;
|
||||
QtFullSFML &operator=(const QtFullSFML &) = delete;
|
||||
~QtFullSFML() = default;
|
||||
~QtFullSFML() override = default;
|
||||
};
|
||||
|
||||
//! @brief A SFML renderer inside a QT widget.
|
||||
@@ -60,7 +61,7 @@ namespace ComSquare::Renderer
|
||||
public:
|
||||
//! @brief Use this function to create the window.
|
||||
//! @param maxFPS The number of FPS you aim to run on.
|
||||
virtual void createWindow(SNES &snes, int maxFPS) override;
|
||||
void createWindow(SNES &snes, int maxFPS) override;
|
||||
//! @brief Add a pixel to the buffer to the coordinates x, y with the color rgba.
|
||||
//! @param X horizontal index.
|
||||
//! @param Y vertical index.
|
||||
@@ -76,7 +77,7 @@ namespace ComSquare::Renderer
|
||||
//! @param newWindowName new title for the window.
|
||||
void setWindowName(std::string &newWindowName) override;
|
||||
//! @brief Constructor that return a SFML renderer inside a QT widget.
|
||||
QtSFML(QWidget *parentWidget);
|
||||
explicit QtSFML(QWidget *parentWidget);
|
||||
QtSFML(const QtSFML &) = delete;
|
||||
QtSFML &operator=(const QtSFML &) = delete;
|
||||
~QtSFML() = default;
|
||||
@@ -93,11 +94,9 @@ namespace ComSquare::Renderer
|
||||
//! @brief Constructor that return a SFML renderer inside a QT window.
|
||||
//! @param height _height of the window.
|
||||
//! @param width _width of the window.
|
||||
QtSFMLWindow(unsigned int height, unsigned int width);
|
||||
QtSFMLWindow(int height, int width);
|
||||
QtSFMLWindow(const QtSFMLWindow &) = delete;
|
||||
QtSFMLWindow &operator=(const QtSFMLWindow &) = delete;
|
||||
~QtSFMLWindow() = default;
|
||||
};
|
||||
}
|
||||
|
||||
#endif //COMSQUARE_QTSFML_HPP
|
||||
|
||||
@@ -2,13 +2,11 @@
|
||||
// Created by cbihan on 1/30/20.
|
||||
//
|
||||
|
||||
#include "SNES.hpp"
|
||||
#include "SFRenderer.hpp"
|
||||
#include <SFML/Graphics.hpp>
|
||||
#include <SFML/Audio.hpp>
|
||||
#include <SFML/System.hpp>
|
||||
#include <SFML/Window.hpp>
|
||||
#include <SFML/Graphics/RenderWindow.hpp>
|
||||
#include "SNES.hpp"
|
||||
#include <iostream>
|
||||
|
||||
namespace ComSquare::Renderer
|
||||
@@ -29,7 +27,7 @@ namespace ComSquare::Renderer
|
||||
if (icon.loadFromFile("resources/Logo.png"))
|
||||
this->_window.setIcon(314, 314, icon.getPixelsPtr());
|
||||
this->_window.setFramerateLimit(maxFPS);
|
||||
this->setWindowName(snes.cartridge->header.gameName);
|
||||
this->setWindowName(snes.cartridge.header.gameName);
|
||||
|
||||
while (!this->shouldExit) {
|
||||
snes.update();
|
||||
|
||||
137
sources/SNES.cpp
137
sources/SNES.cpp
@@ -2,60 +2,72 @@
|
||||
// Created by anonymus-raccoon on 1/27/20.
|
||||
//
|
||||
|
||||
#include <ios>
|
||||
#include <iostream>
|
||||
#include "SNES.hpp"
|
||||
#include <ios>
|
||||
#ifdef DEBUGGER_ENABLED
|
||||
#include "Debugger/CPU/CPUDebug.hpp"
|
||||
#include "Debugger/APUDebug.hpp"
|
||||
#include "Debugger/CPU/CPUDebug.hpp"
|
||||
#include "Debugger/MemoryBusDebug.hpp"
|
||||
#include "Debugger/CGramDebug.hpp"
|
||||
#include "Debugger/TileViewer/TileViewer.hpp"
|
||||
#endif
|
||||
|
||||
namespace ComSquare
|
||||
{
|
||||
SNES::SNES(const std::string &romPath, Renderer::IRenderer &renderer) :
|
||||
bus(std::make_shared<Memory::MemoryBus>()),
|
||||
cartridge(std::make_shared<Cartridge::Cartridge>(romPath)),
|
||||
wram(std::make_shared<Ram::Ram>(16384, WRam, "WRam")),
|
||||
sram(std::make_shared<Ram::Ram>(this->cartridge->header.sramSize, SRam, "SRam")),
|
||||
cpu(std::make_shared<CPU::CPU>(this->bus, cartridge->header)),
|
||||
ppu(std::make_shared<PPU::PPU>(renderer)),
|
||||
apu(std::make_shared<APU::APU>(renderer))
|
||||
SNES::SNES(Renderer::IRenderer &renderer)
|
||||
: bus(),
|
||||
cartridge(),
|
||||
wram(16384, WRam, "WRam"),
|
||||
sram(this->cartridge.header.sramSize, SRam, "SRam"),
|
||||
cpu(this->bus, cartridge.header),
|
||||
ppu(renderer),
|
||||
apu(renderer)
|
||||
{}
|
||||
|
||||
SNES::SNES(const std::string &romPath, Renderer::IRenderer &renderer)
|
||||
: bus(),
|
||||
cartridge(romPath),
|
||||
wram(16384, WRam, "WRam"),
|
||||
sram(this->cartridge.header.sramSize, SRam, "SRam"),
|
||||
cpu(this->bus, cartridge.header),
|
||||
ppu(renderer),
|
||||
apu(renderer)
|
||||
{
|
||||
this->bus->mapComponents(*this);
|
||||
if (this->cartridge->getType() == Cartridge::Audio)
|
||||
this->apu->loadFromSPC(this->cartridge);
|
||||
this->bus.mapComponents(*this);
|
||||
if (this->cartridge.getType() == Cartridge::Audio)
|
||||
this->apu.loadFromSPC(this->cartridge);
|
||||
}
|
||||
|
||||
void SNES::update()
|
||||
{
|
||||
if (this->cartridge->getType() == Cartridge::Audio)
|
||||
{
|
||||
this->apu->update(0x01);
|
||||
if (this->cartridge.getType() == Cartridge::Audio) {
|
||||
this->apu.update(0x01);
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned cycleCount = this->cpu->update();
|
||||
this->ppu->update(cycleCount);
|
||||
this->apu->update(cycleCount);
|
||||
unsigned cycleCount = this->cpu.update();
|
||||
this->ppu.update(cycleCount);
|
||||
this->apu.update(cycleCount);
|
||||
}
|
||||
|
||||
void SNES::loadRom(const std::string &path)
|
||||
{
|
||||
this->cartridge.loadRom(path);
|
||||
this->bus.mapComponents(*this);
|
||||
if (this->cartridge.getType() == Cartridge::Audio)
|
||||
this->apu.loadFromSPC(this->cartridge);
|
||||
}
|
||||
|
||||
#ifdef DEBUGGER_ENABLED
|
||||
|
||||
void SNES::enableCPUDebuggingWithError(const DebuggableError &exception)
|
||||
{
|
||||
this->enableCPUDebugging(true);
|
||||
#ifdef DEBUGGER_ENABLED
|
||||
auto cpuDebug = std::static_pointer_cast<Debugger::CPUDebug>(this->cpu);
|
||||
cpuDebug->showError(exception);
|
||||
#else
|
||||
(void)exception;
|
||||
#endif
|
||||
}
|
||||
|
||||
void SNES::enableCPUDebugging(bool pause)
|
||||
{
|
||||
#ifdef DEBUGGER_ENABLED
|
||||
if (this->cpu->isDebugger()) {
|
||||
auto cpuDebug = std::static_pointer_cast<Debugger::CPUDebug>(this->cpu);
|
||||
cpuDebug->focus();
|
||||
@@ -63,147 +75,112 @@ namespace ComSquare
|
||||
cpuDebug->pause(true);
|
||||
} else {
|
||||
this->cpu = std::make_shared<Debugger::CPUDebug>(*this->cpu, *this);
|
||||
this->bus->mapComponents(*this);
|
||||
this->bus.mapComponents(*this);
|
||||
}
|
||||
#else
|
||||
std::cerr << "Debugging features are not enabled. You can't enable the debugger." << std::endl;
|
||||
(void)pause;
|
||||
#endif
|
||||
}
|
||||
|
||||
void SNES::disableCPUDebugging()
|
||||
{
|
||||
this->cpu = std::make_shared<CPU::CPU>(*this->cpu);
|
||||
this->bus->mapComponents(*this);
|
||||
this->bus.mapComponents(*this);
|
||||
}
|
||||
|
||||
void SNES::enableRamViewer()
|
||||
{
|
||||
#ifdef DEBUGGER_ENABLED
|
||||
if (this->_ramViewer)
|
||||
this->_ramViewer->focus();
|
||||
else
|
||||
this->_ramViewer = std::make_unique<Debugger::MemoryViewer>(*this, *this->bus);
|
||||
#endif
|
||||
this->_ramViewer.emplace(*this, *this->bus);
|
||||
}
|
||||
|
||||
void SNES::disableRamViewer()
|
||||
{
|
||||
#ifdef DEBUGGER_ENABLED
|
||||
this->_ramViewer = nullptr;
|
||||
#endif
|
||||
this->_ramViewer = std::nullopt;
|
||||
}
|
||||
|
||||
void SNES::enableHeaderViewer()
|
||||
{
|
||||
#ifdef DEBUGGER_ENABLED
|
||||
if (this->_headerViewer)
|
||||
this->_headerViewer->focus();
|
||||
else
|
||||
this->_headerViewer = std::make_unique<Debugger::HeaderViewer>(*this);
|
||||
#endif
|
||||
this->_headerViewer.emplace(*this);
|
||||
}
|
||||
|
||||
void SNES::disableHeaderViewer()
|
||||
{
|
||||
#ifdef DEBUGGER_ENABLED
|
||||
this->_headerViewer = nullptr;
|
||||
#endif
|
||||
this->_headerViewer = std::nullopt;
|
||||
}
|
||||
|
||||
void SNES::enableAPUDebugging()
|
||||
{
|
||||
#ifdef DEBUGGER_ENABLED
|
||||
if (this->apu->isDebugger())
|
||||
std::static_pointer_cast<Debugger::APUDebug>(this->apu)->focus();
|
||||
else {
|
||||
this->apu = std::make_shared<Debugger::APUDebug>(*this->apu, *this);
|
||||
this->bus->mapComponents(*this);
|
||||
this->bus.mapComponents(*this);
|
||||
}
|
||||
#else
|
||||
std::cerr << "Debugging features are not enabled. You can't enable the debugger." << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
void SNES::disableAPUDebugging()
|
||||
{
|
||||
this->apu = std::make_shared<APU::APU>(*this->apu);
|
||||
this->bus->mapComponents(*this);
|
||||
this->bus.mapComponents(*this);
|
||||
}
|
||||
|
||||
void SNES::enableMemoryBusDebugging()
|
||||
{
|
||||
#ifdef DEBUGGER_ENABLED
|
||||
if (this->bus->isDebugger())
|
||||
if (this->bus.isDebugger())
|
||||
std::static_pointer_cast<Debugger::MemoryBusDebug>(this->bus)->focus();
|
||||
else
|
||||
{
|
||||
else {
|
||||
this->bus = std::make_shared<Debugger::MemoryBusDebug>(*this, *this->bus);
|
||||
this->cpu->setMemoryBus(this->bus);
|
||||
}
|
||||
#else
|
||||
std::cerr << "Debugging features are not enabled. You can't enable the debugger." << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
void SNES::disableMemoryBusDebugging()
|
||||
{
|
||||
#ifdef DEBUGGER_ENABLED
|
||||
this->bus = std::make_shared<Memory::MemoryBus>(*this->bus);
|
||||
this->cpu->setMemoryBus(this->bus);
|
||||
#else
|
||||
std::cerr << "Debugging features are not enabled. You can't enable the debugger." << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
void SNES::enableCgramDebugging()
|
||||
{
|
||||
#ifdef DEBUGGER_ENABLED
|
||||
if (this->_cgramViewer)
|
||||
this->_cgramViewer->focus();
|
||||
else
|
||||
this->_cgramViewer = std::make_unique<Debugger::CGramDebug>(*this, *this->ppu);
|
||||
#endif
|
||||
this->_cgramViewer.emplace(*this, *this->ppu);
|
||||
}
|
||||
|
||||
void SNES::disableCgramDebugging()
|
||||
{
|
||||
#ifdef DEBUGGER_ENABLED
|
||||
this->_cgramViewer = nullptr;
|
||||
#endif
|
||||
this->_cgramViewer = std::nullopt;
|
||||
}
|
||||
|
||||
void SNES::disableRegisterDebugging()
|
||||
{
|
||||
#ifdef DEBUGGER_ENABLED
|
||||
this->_registerViewer = nullptr;
|
||||
#endif
|
||||
this->_registerViewer = std::nullopt;
|
||||
}
|
||||
|
||||
void SNES::enableRegisterDebugging()
|
||||
{
|
||||
#ifdef DEBUGGER_ENABLED
|
||||
if (this->_registerViewer)
|
||||
this->_registerViewer->focus();
|
||||
else
|
||||
this->_registerViewer = std::make_unique<Debugger::RegisterViewer>(*this);
|
||||
#endif
|
||||
this->_registerViewer.emplace(*this);
|
||||
}
|
||||
|
||||
void SNES::disableTileViewerDebugging()
|
||||
{
|
||||
#ifdef DEBUGGER_ENABLED
|
||||
this->_tileViewer = nullptr;
|
||||
#endif
|
||||
this->_tileViewer = std::nullopt;
|
||||
}
|
||||
|
||||
void SNES::enableTileViewerDebugging()
|
||||
{
|
||||
#ifdef DEBUGGER_ENABLED
|
||||
if (this->_tileViewer)
|
||||
this->_tileViewer->focus();
|
||||
else
|
||||
this->_tileViewer = std::make_unique<Debugger::TileViewer>(*this, *this->ppu);
|
||||
#endif
|
||||
this->_tileViewer.emplace(*this, *this->ppu);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
}// namespace ComSquare
|
||||
|
||||
@@ -2,63 +2,84 @@
|
||||
// Created by anonymus-raccoon on 1/27/20.
|
||||
//
|
||||
|
||||
#ifndef COMSQUARE_SNES_HPP
|
||||
#define COMSQUARE_SNES_HPP
|
||||
#pragma once
|
||||
|
||||
#include "Memory/MemoryBus.hpp"
|
||||
#include "APU/APU.hpp"
|
||||
#include "CPU/CPU.hpp"
|
||||
#include "Cartridge/Cartridge.hpp"
|
||||
#include "Ram/Ram.hpp"
|
||||
#include "PPU/PPU.hpp"
|
||||
#include "APU/APU.hpp"
|
||||
#include "Renderer/IRenderer.hpp"
|
||||
#include "Exceptions/DebuggableError.hpp"
|
||||
#include "Memory/MemoryBus.hpp"
|
||||
#include "PPU/PPU.hpp"
|
||||
#include "Ram/Ram.hpp"
|
||||
#include "Renderer/IRenderer.hpp"
|
||||
#include <optional>
|
||||
|
||||
#ifdef DEBUGGER_ENABLED
|
||||
#include "Debugger/MemoryViewer.hpp"
|
||||
#include "Debugger/HeaderViewer.hpp"
|
||||
#include "Debugger/CGramDebug.hpp"
|
||||
#include "Debugger/RegisterViewer.hpp"
|
||||
#include "Debugger/TileViewer/TileViewer.hpp"
|
||||
#include "Debugger/MemoryViewer.hpp"
|
||||
#include "Debugger/HeaderViewer.hpp"
|
||||
#include "Debugger/CGramDebug.hpp"
|
||||
#include "Debugger/RegisterViewer.hpp"
|
||||
#include "Debugger/TileViewer/TileViewer.hpp"
|
||||
#endif
|
||||
|
||||
namespace ComSquare
|
||||
{
|
||||
//! @brief Container of all the components of the SNES.
|
||||
class SNES {
|
||||
class SNES
|
||||
{
|
||||
private:
|
||||
#ifdef DEBUGGER_ENABLED
|
||||
//! @brief The window that allow the user to view a memory.
|
||||
std::unique_ptr<Debugger::MemoryViewer> _ramViewer;
|
||||
std::optional<Debugger::MemoryViewer> _ramViewer;
|
||||
//! @brief The window that allow the user to view the cartridge's header.
|
||||
std::unique_ptr<Debugger::HeaderViewer> _headerViewer;
|
||||
std::optional<Debugger::HeaderViewer> _headerViewer;
|
||||
//! @brief The window that allow the user to view the CGRAM.
|
||||
std::unique_ptr<Debugger::CGramDebug> _cgramViewer;
|
||||
std::optional<Debugger::CGramDebug> _cgramViewer;
|
||||
//! @brief The window that allow the user to view registers.
|
||||
std::unique_ptr<Debugger::RegisterViewer> _registerViewer;
|
||||
//! @brief The window that allow the user to view the cgram as tiles.
|
||||
std::unique_ptr<Debugger::TileViewer> _tileViewer;
|
||||
std::optional<Debugger::RegisterViewer> _registerViewer;
|
||||
//! @brief The window that allow the user to view the CGRAM as tiles.
|
||||
std::optional<Debugger::TileViewer> _tileViewer;
|
||||
#endif
|
||||
public:
|
||||
//! @brief The memory bus that map addresses to components.
|
||||
std::shared_ptr<Memory::MemoryBus> bus;
|
||||
Memory::MemoryBus bus;
|
||||
|
||||
//! @brief Cartridge containing instructions (ROM).
|
||||
std::shared_ptr<Cartridge::Cartridge> cartridge;
|
||||
Cartridge::Cartridge cartridge;
|
||||
//! @brief Work Ram shared by all the components.
|
||||
std::shared_ptr<Ram::Ram> wram;
|
||||
Ram::Ram wram;
|
||||
//! @brief Save Ram residing inside the Cartridge in a real SNES.
|
||||
std::shared_ptr<Ram::Ram> sram;
|
||||
Ram::Ram sram;
|
||||
//! @brief Central Processing Unit of the SNES.
|
||||
std::shared_ptr<CPU::CPU> cpu;
|
||||
CPU::CPU cpu;
|
||||
//! @brief Picture Processing Unit of the SNES
|
||||
std::shared_ptr<PPU::PPU> ppu;
|
||||
PPU::PPU ppu;
|
||||
//! @brief Audio Processing Unit if the SNES
|
||||
std::shared_ptr<APU::APU> apu;
|
||||
APU::APU apu;
|
||||
|
||||
//! @brief Create all the components using a common memory bus for all of them.
|
||||
//! @param renderer The renderer to use.
|
||||
explicit SNES(Renderer::IRenderer &renderer);
|
||||
//! @brief Create all the components using a common memory bus for all of them and load a rom
|
||||
//! @param ramPath The rom to load.
|
||||
//! @param renderer The renderer to use.
|
||||
SNES(const std::string &ramPath, Renderer::IRenderer &renderer);
|
||||
//! @brief A SNES is not copyable.
|
||||
SNES(const SNES &) = delete;
|
||||
//! @brief A SNES can't be assigned
|
||||
SNES &operator=(const SNES &) = delete;
|
||||
//! @brief A default destructor.
|
||||
~SNES() = default;
|
||||
|
||||
//! @brief Call this function to update all the components
|
||||
void update();
|
||||
|
||||
//! @brief Load the rom at the given path
|
||||
//! @param rom The path of the rom.
|
||||
//! @throws InvalidRomException If the rom is invalid, this exception is thrown.
|
||||
void loadRom(const std::string& path);
|
||||
|
||||
#ifdef DEBUGGER_ENABLED
|
||||
//! @brief Disable the CPU's debugging window.
|
||||
void disableCPUDebugging();
|
||||
//! @brief Enable the CPU's debugging window.
|
||||
@@ -82,9 +103,9 @@ namespace ComSquare
|
||||
void disableMemoryBusDebugging();
|
||||
//! @brief Enable the Memory Bus's debugging window.
|
||||
void enableMemoryBusDebugging();
|
||||
//! @brief Disable the Cgram's debugging window.
|
||||
//! @brief Disable the CGRAM's debugging window.
|
||||
void disableCgramDebugging();
|
||||
//! @brief Enable the Cgram's debugging window.
|
||||
//! @brief Enable the CGRAM's debugging window.
|
||||
void enableCgramDebugging();
|
||||
//! @brief Disable the Register's debugging window.
|
||||
void disableRegisterDebugging();
|
||||
@@ -94,13 +115,6 @@ namespace ComSquare
|
||||
void disableTileViewerDebugging();
|
||||
//! @brief Enable the TileViewer's debugging window.
|
||||
void enableTileViewerDebugging();
|
||||
|
||||
//! @brief Create all the components using a common memory bus for all of them.
|
||||
SNES(const std::string &ramPath, Renderer::IRenderer &renderer);
|
||||
SNES(const SNES &) = delete;
|
||||
SNES &operator=(const SNES &) = delete;
|
||||
~SNES() = default;
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
#endif //COMSQUARE_SNES_HPP
|
||||
}// namespace ComSquare
|
||||
@@ -15,36 +15,53 @@ void usage(char *bin)
|
||||
std::cout << "ComSquare:" << std::endl
|
||||
<< "\tUsage: " << bin << " rom_path [options]" << std::endl
|
||||
<< "Options:" << std::endl
|
||||
<< "\t-h, --help: \tDisplay this help message and exit." << std::endl
|
||||
#ifdef DEBUGGER_ENABLED
|
||||
<< "\t-c, --cpu: \tEnable the debugger of the CPU." << std::endl
|
||||
<< "\t-m, --memory: \tEnable the memory viewer panel." << std::endl
|
||||
<< "\t-h, --header: \tShow the header of the cartridge." << std::endl
|
||||
<< "\t-H, --header: \tShow the header of the cartridge." << std::endl
|
||||
<< "\t-b, --bus: \tShow the memory bus's log." << std::endl
|
||||
<< "\t-g, --cgram: \tShow the palette viewer." << std::endl
|
||||
<< "\t-r, --registers: \tShow the registers viewer." << std::endl;
|
||||
<< "\t-r, --registers: \tShow the registers viewer." << std::endl
|
||||
#endif
|
||||
;
|
||||
}
|
||||
|
||||
void parseArguments(int argc, char **argv, SNES &snes)
|
||||
{
|
||||
while (true) {
|
||||
int option_index = 0;
|
||||
static struct option long_options[] = {
|
||||
{"help", no_argument, 0, 'h'},
|
||||
#ifdef DEBUGGER_ENABLED
|
||||
{"cpu", no_argument, 0, 'c'},
|
||||
{"apu", no_argument, 0, 'a'},
|
||||
{"memory", no_argument, 0, 'm'},
|
||||
{"header", no_argument, 0, 'h'},
|
||||
{"header", no_argument, 0, 'H'},
|
||||
{"bus", no_argument, 0, 'b'},
|
||||
{"cgram", no_argument, 0, 'g'},
|
||||
{"registers", no_argument, 0, 'r'},
|
||||
#endif
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
#ifdef DEBUGGER_ENABLED
|
||||
char short_options[] = "hcamHbgr";
|
||||
#else
|
||||
char short_options[] = "h";
|
||||
#endif
|
||||
|
||||
int c = getopt_long(argc, argv, "camhbgr", long_options, &option_index);
|
||||
while (true) {
|
||||
int c = getopt_long(argc, argv, short_options, long_options, &option_index);
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
switch (c) {
|
||||
case 0:
|
||||
usage(argv[0]);
|
||||
break;
|
||||
exit(2);
|
||||
case 'h':
|
||||
usage(argv[0]);
|
||||
exit(0);
|
||||
#ifdef DEBUGGER_ENABLED
|
||||
case 'c':
|
||||
snes.enableCPUDebugging();
|
||||
break;
|
||||
@@ -66,15 +83,22 @@ void parseArguments(int argc, char **argv, SNES &snes)
|
||||
case 'r':
|
||||
snes.enableRegisterDebugging();
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
exit(2);
|
||||
}
|
||||
}
|
||||
|
||||
if (optind != argc - 1) {
|
||||
usage(argv[0]);
|
||||
exit(2);
|
||||
}
|
||||
snes.loadRom(argv[optind]);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc < 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
|
||||
if (argc < 2) {
|
||||
usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
@@ -82,10 +106,13 @@ int main(int argc, char **argv)
|
||||
QApplication::setAttribute(Qt::AA_DisableWindowContextHelpButton);
|
||||
Renderer::QtSFMLWindow renderer(1100, 1100);
|
||||
try {
|
||||
SNES snes(argv[1], renderer);
|
||||
renderer.createWindow(snes, 60);
|
||||
parseArguments(argc, argv, snes);
|
||||
return QApplication::exec();
|
||||
// TODO remove the new once arrays are newed.
|
||||
auto *snes = new SNES(renderer);
|
||||
parseArguments(argc, argv, *snes);
|
||||
renderer.createWindow(*snes, 60);
|
||||
int ret = QApplication::exec();
|
||||
delete snes;
|
||||
return ret;
|
||||
}
|
||||
catch(std::exception &ex) {
|
||||
std::cerr << ex.what() << std::endl;
|
||||
|
||||
@@ -20,20 +20,20 @@ TEST_CASE("RomToVRAM DMA", "[DMA]")
|
||||
// Transferring $800 bytes from ROM ($13BE00) to VRam ($2000) via DMA channel 0
|
||||
|
||||
// Setting VRam address (since this is an indirect write)
|
||||
snes.bus->write(0x2115, 0b10000000);
|
||||
snes.bus->write(0x2117, 0x20);
|
||||
snes.bus->write(0x2116, 0);
|
||||
snes.bus.write(0x2115, 0b10000000);
|
||||
snes.bus.write(0x2117, 0x20);
|
||||
snes.bus.write(0x2116, 0);
|
||||
|
||||
snes.bus->write(0x4301, 0x18);
|
||||
snes.bus.write(0x4301, 0x18);
|
||||
REQUIRE(snes.cpu->_dmaChannels[0]._port == 0x18);
|
||||
snes.bus->write(0x4304, 0x13);
|
||||
snes.bus->write(0x4303, 0xBE);
|
||||
snes.bus->write(0x4302, 0x00);
|
||||
snes.bus.write(0x4304, 0x13);
|
||||
snes.bus.write(0x4303, 0xBE);
|
||||
snes.bus.write(0x4302, 0x00);
|
||||
REQUIRE(snes.cpu->_dmaChannels[0]._aAddress.raw == 0x13BE00);
|
||||
snes.bus->write(0x4306, 0x08);
|
||||
snes.bus->write(0x4305, 0);
|
||||
snes.bus.write(0x4306, 0x08);
|
||||
snes.bus.write(0x4305, 0);
|
||||
REQUIRE(snes.cpu->_dmaChannels[0]._count.raw == 0x0800);
|
||||
snes.bus->write(0x4300, 1);
|
||||
snes.bus.write(0x4300, 1);
|
||||
REQUIRE(snes.cpu->_dmaChannels[0]._controlRegister.direction == CPU::DMA::AtoB);
|
||||
REQUIRE(snes.cpu->_dmaChannels[0]._controlRegister._ == 0);
|
||||
REQUIRE(snes.cpu->_dmaChannels[0]._controlRegister.increment == 0);
|
||||
@@ -41,7 +41,7 @@ TEST_CASE("RomToVRAM DMA", "[DMA]")
|
||||
REQUIRE(snes.cpu->_dmaChannels[0]._controlRegister.mode == CPU::DMA::TwoToTwo);
|
||||
REQUIRE(snes.cpu->_dmaChannels[0].enabled == false);
|
||||
// Enabling DMA's channel 0
|
||||
snes.bus->write(0x420B, 1);
|
||||
snes.bus.write(0x420B, 1);
|
||||
REQUIRE(snes.cpu->_dmaChannels[0].enabled == true);
|
||||
// TODO There is an overhead of 12-24 cycles for the whole transfer. How should I know how many cycles there is?
|
||||
auto cycles = snes.cpu->_dmaChannels[0].run(1000000);
|
||||
@@ -60,11 +60,11 @@ TEST_CASE("RomToVRAM DMA", "[DMA]")
|
||||
TEST_CASE("VramWrite DMA", "[DMA]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x2117, 0x20);
|
||||
snes.bus->write(0x2116, 0x0);
|
||||
snes.bus.write(0x2117, 0x20);
|
||||
snes.bus.write(0x2116, 0x0);
|
||||
for (unsigned i = 0; i < 0x400; i++) {
|
||||
snes.bus->write(0x2119, i >> 8);
|
||||
snes.bus->write(0x2118, i);
|
||||
snes.bus.write(0x2119, i >> 8);
|
||||
snes.bus.write(0x2118, i);
|
||||
REQUIRE(snes.ppu->_registers._vmadd.vmadd == 0x2001 + i);
|
||||
}
|
||||
for(unsigned i = 0; i < 0x400; i++) {
|
||||
@@ -76,12 +76,12 @@ TEST_CASE("VramWrite DMA", "[DMA]")
|
||||
TEST_CASE("VramWriteInvertedOrder DMA", "[DMA]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x2115, 0b10000000);
|
||||
snes.bus->write(0x2117, 0x20);
|
||||
snes.bus->write(0x2116, 0x0);
|
||||
snes.bus.write(0x2115, 0b10000000);
|
||||
snes.bus.write(0x2117, 0x20);
|
||||
snes.bus.write(0x2116, 0x0);
|
||||
for (unsigned i = 0; i < 0x400; i++) {
|
||||
snes.bus->write(0x2118, i);
|
||||
snes.bus->write(0x2119, i >> 8);
|
||||
snes.bus.write(0x2118, i);
|
||||
snes.bus.write(0x2119, i >> 8);
|
||||
REQUIRE(snes.ppu->_registers._vmadd.vmadd == 0x2001 + i);
|
||||
}
|
||||
for(unsigned i = 0; i < 0x400; i++) {
|
||||
@@ -101,20 +101,20 @@ TEST_CASE("WRamToVRAM DMA", "[DMA]")
|
||||
// Transferring $800 bytes from WRAM ($00) to VRam ($2000) via DMA channel 0
|
||||
|
||||
// Setting VRam address (since this is an indirect write)
|
||||
snes.bus->write(0x2115, 0b10000000);
|
||||
snes.bus->write(0x2117, 0);
|
||||
snes.bus->write(0x2116, 0);
|
||||
snes.bus.write(0x2115, 0b10000000);
|
||||
snes.bus.write(0x2117, 0);
|
||||
snes.bus.write(0x2116, 0);
|
||||
|
||||
snes.bus->write(0x4301, 0x18);
|
||||
snes.bus.write(0x4301, 0x18);
|
||||
REQUIRE(snes.cpu->_dmaChannels[0]._port == 0x18);
|
||||
snes.bus->write(0x4304, 0x7E);
|
||||
snes.bus->write(0x4303, 0x00);
|
||||
snes.bus->write(0x4302, 0x00);
|
||||
snes.bus.write(0x4304, 0x7E);
|
||||
snes.bus.write(0x4303, 0x00);
|
||||
snes.bus.write(0x4302, 0x00);
|
||||
REQUIRE(snes.cpu->_dmaChannels[0]._aAddress.raw == 0x7E0000);
|
||||
snes.bus->write(0x4306, 0x08);
|
||||
snes.bus->write(0x4305, 0);
|
||||
snes.bus.write(0x4306, 0x08);
|
||||
snes.bus.write(0x4305, 0);
|
||||
REQUIRE(snes.cpu->_dmaChannels[0]._count.raw == 0x0800);
|
||||
snes.bus->write(0x4300, 1);
|
||||
snes.bus.write(0x4300, 1);
|
||||
REQUIRE(snes.cpu->_dmaChannels[0]._controlRegister.direction == CPU::DMA::AtoB);
|
||||
REQUIRE(snes.cpu->_dmaChannels[0]._controlRegister._ == 0);
|
||||
REQUIRE(snes.cpu->_dmaChannels[0]._controlRegister.increment == 0);
|
||||
@@ -122,7 +122,7 @@ TEST_CASE("WRamToVRAM DMA", "[DMA]")
|
||||
REQUIRE(snes.cpu->_dmaChannels[0]._controlRegister.mode == CPU::DMA::TwoToTwo);
|
||||
REQUIRE(snes.cpu->_dmaChannels[0].enabled == false);
|
||||
// Enabling DMA's channel 0
|
||||
snes.bus->write(0x420B, 1);
|
||||
snes.bus.write(0x420B, 1);
|
||||
REQUIRE(snes.cpu->_dmaChannels[0].enabled == true);
|
||||
// TODO There is an overhead of 12-24 cycles for the whole transfer. How should I know how many cycles there is?
|
||||
auto cycles = snes.cpu->_dmaChannels[0].run(1000000);
|
||||
|
||||
@@ -15,7 +15,7 @@ using namespace ComSquare;
|
||||
TEST_CASE("basicTest backgroundGetTilePixelReference", "[backgroundGetTilePixelReference]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x2100, 0b11111111);
|
||||
snes.bus.write(0x2100, 0b11111111);
|
||||
REQUIRE(snes.ppu->_registers._inidisp.fblank == true);
|
||||
REQUIRE(snes.ppu->_registers._inidisp.brightness == 0xF);
|
||||
}
|
||||
@@ -14,32 +14,32 @@ using namespace ComSquare;
|
||||
TEST_CASE("vram_data_read_full PPU_read_1", "[PPU_read_1]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x2115, 0b10000000);
|
||||
snes.bus->write(0x2116, 0);
|
||||
snes.bus->write(0x2117, 0);
|
||||
snes.bus.write(0x2115, 0b10000000);
|
||||
snes.bus.write(0x2116, 0);
|
||||
snes.bus.write(0x2117, 0);
|
||||
snes.ppu->vram->write(0, 0b11111111);
|
||||
snes.ppu->vram->write(1, 0b11111111);
|
||||
|
||||
snes.bus->write(0x2116, 0);
|
||||
snes.bus->write(0x2117, 0);
|
||||
uint8_t tmp = snes.bus->read(0x2139);
|
||||
snes.bus.write(0x2116, 0);
|
||||
snes.bus.write(0x2117, 0);
|
||||
uint8_t tmp = snes.bus.read(0x2139);
|
||||
CHECK(tmp == 0b11111111);
|
||||
tmp = snes.bus->read(0x213a);
|
||||
tmp = snes.bus.read(0x213a);
|
||||
CHECK(tmp == 0b11111111);
|
||||
}
|
||||
|
||||
TEST_CASE("vram_data_read_half PPU_read_1", "[PPU_read_1]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x2116, 0);
|
||||
snes.bus->write(0x2117, 0);
|
||||
snes.bus.write(0x2116, 0);
|
||||
snes.bus.write(0x2117, 0);
|
||||
snes.ppu->vram->write(0, 0b01101001);
|
||||
snes.ppu->vram->write(1, 0b11111111);
|
||||
|
||||
snes.bus->write(0x2116, 0);
|
||||
snes.bus->write(0x2117, 0);
|
||||
uint8_t tmp = snes.bus->read(0x2139);
|
||||
snes.bus.write(0x2116, 0);
|
||||
snes.bus.write(0x2117, 0);
|
||||
uint8_t tmp = snes.bus.read(0x2139);
|
||||
CHECK(tmp == 0b01101001);
|
||||
tmp = snes.bus->read(0x213a);
|
||||
tmp = snes.bus.read(0x213a);
|
||||
CHECK(tmp == 0b11111111);
|
||||
}
|
||||
@@ -14,7 +14,7 @@ using namespace ComSquare;
|
||||
TEST_CASE("inidisp_data_full_ones PPU_write", "[PPU_write]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x2100, 0b11111111);
|
||||
snes.bus.write(0x2100, 0b11111111);
|
||||
REQUIRE(snes.ppu->_registers._inidisp.fblank == true);
|
||||
REQUIRE(snes.ppu->_registers._inidisp.brightness == 0xF);
|
||||
}
|
||||
@@ -22,7 +22,7 @@ TEST_CASE("inidisp_data_full_ones PPU_write", "[PPU_write]")
|
||||
TEST_CASE("inidisp_data_full_zeros PPU_write", "[PPU_write]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x2100, 0b00000000);
|
||||
snes.bus.write(0x2100, 0b00000000);
|
||||
REQUIRE(snes.ppu->_registers._inidisp.fblank == false);
|
||||
REQUIRE(snes.ppu->_registers._inidisp.brightness == 0x0);
|
||||
}
|
||||
@@ -30,7 +30,7 @@ TEST_CASE("inidisp_data_full_zeros PPU_write", "[PPU_write]")
|
||||
TEST_CASE("inidisp_data_fBlank_on_brghtness_off PPU_write", "[PPU_write]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x2100, 0b10000000);
|
||||
snes.bus.write(0x2100, 0b10000000);
|
||||
REQUIRE(snes.ppu->_registers._inidisp.fblank == true);
|
||||
REQUIRE(snes.ppu->_registers._inidisp.brightness == 0x0);
|
||||
}
|
||||
@@ -38,7 +38,7 @@ TEST_CASE("inidisp_data_fBlank_on_brghtness_off PPU_write", "[PPU_write]")
|
||||
TEST_CASE("inidisp_data_fBlank_off_brghtness_max PPU_write", "[PPU_write]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x2100, 0b00001111);
|
||||
snes.bus.write(0x2100, 0b00001111);
|
||||
REQUIRE(snes.ppu->_registers._inidisp.fblank == false);
|
||||
REQUIRE(snes.ppu->_registers._inidisp.brightness == 0xF);
|
||||
}
|
||||
@@ -46,7 +46,7 @@ TEST_CASE("inidisp_data_fBlank_off_brghtness_max PPU_write", "[PPU_write]")
|
||||
TEST_CASE("inidisp_data_fBlank_off_brghtness_half PPU_write", "[PPU_write]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x2100, 0b00000101);
|
||||
snes.bus.write(0x2100, 0b00000101);
|
||||
REQUIRE(snes.ppu->_registers._inidisp.fblank == false);
|
||||
REQUIRE(snes.ppu->_registers._inidisp.brightness == 0x5);
|
||||
}
|
||||
@@ -54,7 +54,7 @@ TEST_CASE("inidisp_data_fBlank_off_brghtness_half PPU_write", "[PPU_write]")
|
||||
TEST_CASE("obsel_111_object_size_and_all_null PPU_write", "[PPU_write]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x2101, 0b11100000);
|
||||
snes.bus.write(0x2101, 0b11100000);
|
||||
REQUIRE(snes.ppu->_registers._obsel.objectSize == 0b111);
|
||||
REQUIRE(snes.ppu->_registers._obsel.nameSelect == 0b00);
|
||||
REQUIRE(snes.ppu->_registers._obsel.nameBaseSelect == 0b000);
|
||||
@@ -63,7 +63,7 @@ TEST_CASE("obsel_111_object_size_and_all_null PPU_write", "[PPU_write]")
|
||||
TEST_CASE("obsel_data_full PPU_write", "[PPU_write]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x2101, 0b11111111);
|
||||
snes.bus.write(0x2101, 0b11111111);
|
||||
REQUIRE(snes.ppu->_registers._obsel.objectSize == 0b111);
|
||||
REQUIRE(snes.ppu->_registers._obsel.nameSelect == 0b11);
|
||||
REQUIRE(snes.ppu->_registers._obsel.nameBaseSelect == 0b111);
|
||||
@@ -72,7 +72,7 @@ TEST_CASE("obsel_data_full PPU_write", "[PPU_write]")
|
||||
TEST_CASE("obsel_data_full_nameselect PPU_write", "[PPU_write]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x2101, 0b00011000);
|
||||
snes.bus.write(0x2101, 0b00011000);
|
||||
REQUIRE(snes.ppu->_registers._obsel.objectSize == 0b000);
|
||||
REQUIRE(snes.ppu->_registers._obsel.nameSelect == 0b11);
|
||||
REQUIRE(snes.ppu->_registers._obsel.nameBaseSelect == 0b000);
|
||||
@@ -81,7 +81,7 @@ TEST_CASE("obsel_data_full_nameselect PPU_write", "[PPU_write]")
|
||||
TEST_CASE("obsel_data_full_baseselect_write", "[PPU_write]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x2101, 0b00000111);
|
||||
snes.bus.write(0x2101, 0b00000111);
|
||||
REQUIRE(snes.ppu->_registers._obsel.objectSize == 0b000);
|
||||
REQUIRE(snes.ppu->_registers._obsel.nameSelect == 0b00);
|
||||
REQUIRE(snes.ppu->_registers._obsel.nameBaseSelect == 0b111);
|
||||
@@ -90,14 +90,14 @@ TEST_CASE("obsel_data_full_baseselect_write", "[PPU_write]")
|
||||
TEST_CASE("oamaddl_data_full PPU_write", "[PPU_write]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x2102, 0b11111111);
|
||||
snes.bus.write(0x2102, 0b11111111);
|
||||
REQUIRE(snes.ppu->_registers._oamadd.oamAddress == 0b011111111);
|
||||
}
|
||||
|
||||
TEST_CASE("oamaddh_data_full PPU_write", "[PPU_write]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x2103, 0b11111111);
|
||||
snes.bus.write(0x2103, 0b11111111);
|
||||
REQUIRE(snes.ppu->_registers._oamadd.objPriorityActivationBit == true);
|
||||
REQUIRE(snes.ppu->_registers._oamadd.oamAddress == 0b100000000);
|
||||
}
|
||||
@@ -105,8 +105,8 @@ TEST_CASE("oamaddh_data_full PPU_write", "[PPU_write]")
|
||||
TEST_CASE("oamaddlh_data_full PPU_write", "[PPU_write]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x2102, 0b11111111);
|
||||
snes.bus->write(0x2103, 0b11111111);
|
||||
snes.bus.write(0x2102, 0b11111111);
|
||||
snes.bus.write(0x2103, 0b11111111);
|
||||
REQUIRE(snes.ppu->_registers._oamadd.objPriorityActivationBit == true);
|
||||
REQUIRE(snes.ppu->_registers._oamadd.oamAddress == 0b111111111);
|
||||
}
|
||||
@@ -114,8 +114,8 @@ TEST_CASE("oamaddlh_data_full PPU_write", "[PPU_write]")
|
||||
TEST_CASE("oamaddlh_data_full_priorityBit_off PPU_write", "[PPU_write]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x2102, 0b11111111);
|
||||
snes.bus->write(0x2103, 0b01111111);
|
||||
snes.bus.write(0x2102, 0b11111111);
|
||||
snes.bus.write(0x2103, 0b01111111);
|
||||
REQUIRE(snes.ppu->_registers._oamadd.objPriorityActivationBit == false);
|
||||
REQUIRE(snes.ppu->_registers._oamadd.oamAddress == 0b111111111);
|
||||
}
|
||||
@@ -123,8 +123,8 @@ TEST_CASE("oamaddlh_data_full_priorityBit_off PPU_write", "[PPU_write]")
|
||||
TEST_CASE("oamaddlh_oamAdress_11_priorityBit_on PPU_write", "[PPU_write]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x2102, 0b00001011);
|
||||
snes.bus->write(0x2103, 0b10011100);
|
||||
snes.bus.write(0x2102, 0b00001011);
|
||||
snes.bus.write(0x2103, 0b10011100);
|
||||
REQUIRE(snes.ppu->_registers._oamadd.objPriorityActivationBit == true);
|
||||
REQUIRE(snes.ppu->_registers._oamadd.oamAddress == 11);
|
||||
}
|
||||
@@ -132,7 +132,7 @@ TEST_CASE("oamaddlh_oamAdress_11_priorityBit_on PPU_write", "[PPU_write]")
|
||||
TEST_CASE("bgmode_data_full PPU_write", "[PPU_write]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x2105, 0b11111111);
|
||||
snes.bus.write(0x2105, 0b11111111);
|
||||
REQUIRE(snes.ppu->_registers._bgmode.bgMode == 7);
|
||||
REQUIRE(snes.ppu->_registers._bgmode.characterSizeBg1 == true);
|
||||
REQUIRE(snes.ppu->_registers._bgmode.characterSizeBg2 == true);
|
||||
@@ -144,7 +144,7 @@ TEST_CASE("bgmode_data_full PPU_write", "[PPU_write]")
|
||||
TEST_CASE("bgmode_bgmode_5_and_bg24_on PPU_write", "[PPU_write]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x2105, 0b10100101);
|
||||
snes.bus.write(0x2105, 0b10100101);
|
||||
REQUIRE(snes.ppu->_registers._bgmode.bgMode == 5);
|
||||
REQUIRE(snes.ppu->_registers._bgmode.characterSizeBg1 == false);
|
||||
REQUIRE(snes.ppu->_registers._bgmode.characterSizeBg2 == true);
|
||||
@@ -156,7 +156,7 @@ TEST_CASE("bgmode_bgmode_5_and_bg24_on PPU_write", "[PPU_write]")
|
||||
TEST_CASE("mosaic_data_full PPU_write", "[PPU_write]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x2106, 0b11111111);
|
||||
snes.bus.write(0x2106, 0b11111111);
|
||||
REQUIRE(snes.ppu->_registers._mosaic.affectBg1 == true);
|
||||
REQUIRE(snes.ppu->_registers._mosaic.affectBg2 == true);
|
||||
REQUIRE(snes.ppu->_registers._mosaic.affectBg3 == true);
|
||||
@@ -167,7 +167,7 @@ TEST_CASE("mosaic_data_full PPU_write", "[PPU_write]")
|
||||
TEST_CASE("mosaic_affectbg23_w_1x1_size PPU_write", "[PPU_write]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x2106, 0b00000110);
|
||||
snes.bus.write(0x2106, 0b00000110);
|
||||
REQUIRE(snes.ppu->_registers._mosaic.affectBg1 == false);
|
||||
REQUIRE(snes.ppu->_registers._mosaic.affectBg2 == true);
|
||||
REQUIRE(snes.ppu->_registers._mosaic.affectBg3 == true);
|
||||
@@ -178,7 +178,7 @@ TEST_CASE("mosaic_affectbg23_w_1x1_size PPU_write", "[PPU_write]")
|
||||
TEST_CASE("mosaic_affectbg14_w_2x2_size PPU_write", "[PPU_write]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x2106, 0b00101001);
|
||||
snes.bus.write(0x2106, 0b00101001);
|
||||
REQUIRE(snes.ppu->_registers._mosaic.affectBg1 == true);
|
||||
REQUIRE(snes.ppu->_registers._mosaic.affectBg2 == false);
|
||||
REQUIRE(snes.ppu->_registers._mosaic.affectBg3 == false);
|
||||
@@ -189,7 +189,7 @@ TEST_CASE("mosaic_affectbg14_w_2x2_size PPU_write", "[PPU_write]")
|
||||
TEST_CASE("bg1sc_data_full PPU_write", "[PPU_write]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x2107, 0b11111111);
|
||||
snes.bus.write(0x2107, 0b11111111);
|
||||
REQUIRE(snes.ppu->_registers._bgsc[0].tilemapAddress == 0b111111);
|
||||
REQUIRE(snes.ppu->_registers._bgsc[0].tilemapHorizontalMirroring == true);
|
||||
REQUIRE(snes.ppu->_registers._bgsc[0].tilemapVerticalMirroring == true);
|
||||
@@ -198,7 +198,7 @@ TEST_CASE("bg1sc_data_full PPU_write", "[PPU_write]")
|
||||
TEST_CASE("bg2sc_data_full PPU_write", "[PPU_write]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x2108, 0b11111111);
|
||||
snes.bus.write(0x2108, 0b11111111);
|
||||
REQUIRE(snes.ppu->_registers._bgsc[1].tilemapAddress == 0b111111);
|
||||
REQUIRE(snes.ppu->_registers._bgsc[1].tilemapHorizontalMirroring == true);
|
||||
REQUIRE(snes.ppu->_registers._bgsc[1].tilemapVerticalMirroring == true);
|
||||
@@ -207,7 +207,7 @@ TEST_CASE("bg2sc_data_full PPU_write", "[PPU_write]")
|
||||
TEST_CASE("bg3sc_data_full PPU_write", "[PPU_write]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x2109, 0b11111111);
|
||||
snes.bus.write(0x2109, 0b11111111);
|
||||
REQUIRE(snes.ppu->_registers._bgsc[2].tilemapAddress == 0b111111);
|
||||
REQUIRE(snes.ppu->_registers._bgsc[2].tilemapHorizontalMirroring == true);
|
||||
REQUIRE(snes.ppu->_registers._bgsc[2].tilemapVerticalMirroring == true);
|
||||
@@ -216,7 +216,7 @@ TEST_CASE("bg3sc_data_full PPU_write", "[PPU_write]")
|
||||
TEST_CASE("bg4sc_data_full PPU_write", "[PPU_write]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x210A, 0b11111111);
|
||||
snes.bus.write(0x210A, 0b11111111);
|
||||
REQUIRE(snes.ppu->_registers._bgsc[3].tilemapAddress == 0b111111);
|
||||
REQUIRE(snes.ppu->_registers._bgsc[3].tilemapHorizontalMirroring == true);
|
||||
REQUIRE(snes.ppu->_registers._bgsc[3].tilemapVerticalMirroring == true);
|
||||
@@ -225,7 +225,7 @@ TEST_CASE("bg4sc_data_full PPU_write", "[PPU_write]")
|
||||
TEST_CASE("bg4sc_data_null PPU_write", "[PPU_write]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x210A, 0b00000000);
|
||||
snes.bus.write(0x210A, 0b00000000);
|
||||
REQUIRE(snes.ppu->_registers._bgsc[3].tilemapAddress == 0);
|
||||
REQUIRE(snes.ppu->_registers._bgsc[3].tilemapHorizontalMirroring == false);
|
||||
REQUIRE(snes.ppu->_registers._bgsc[3].tilemapVerticalMirroring == false);
|
||||
@@ -234,7 +234,7 @@ TEST_CASE("bg4sc_data_null PPU_write", "[PPU_write]")
|
||||
TEST_CASE("bg4sc_horizontal_off_vertical_on_random_tilemapAdress PPU_write", "[PPU_write]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x210A, 0b11000110);
|
||||
snes.bus.write(0x210A, 0b11000110);
|
||||
REQUIRE(snes.ppu->_registers._bgsc[3].tilemapAddress == 0b110001);
|
||||
REQUIRE(snes.ppu->_registers._bgsc[3].tilemapHorizontalMirroring == false);
|
||||
REQUIRE(snes.ppu->_registers._bgsc[3].tilemapVerticalMirroring == true);
|
||||
@@ -243,7 +243,7 @@ TEST_CASE("bg4sc_horizontal_off_vertical_on_random_tilemapAdress PPU_write", "[P
|
||||
TEST_CASE("bg12nba_data_full PPU_write", "[PPU_write]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x210B, 0b11111111);
|
||||
snes.bus.write(0x210B, 0b11111111);
|
||||
REQUIRE(snes.ppu->_registers._bgnba[0].baseAddressBg1a3 == 0b1111);
|
||||
REQUIRE(snes.ppu->_registers._bgnba[0].baseAddressBg2a4 == 0b1111);
|
||||
}
|
||||
@@ -251,7 +251,7 @@ TEST_CASE("bg12nba_data_full PPU_write", "[PPU_write]")
|
||||
TEST_CASE("bg34nba_data_full PPU_write", "[PPU_write]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x210C, 0b11111111);
|
||||
snes.bus.write(0x210C, 0b11111111);
|
||||
REQUIRE(snes.ppu->_registers._bgnba[1].baseAddressBg1a3 == 0b1111);
|
||||
REQUIRE(snes.ppu->_registers._bgnba[1].baseAddressBg2a4 == 0b1111);
|
||||
}
|
||||
@@ -259,7 +259,7 @@ TEST_CASE("bg34nba_data_full PPU_write", "[PPU_write]")
|
||||
TEST_CASE("bg12nba_data_random_data PPU_write", "[PPU_write]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x210B, 0b10101010);
|
||||
snes.bus.write(0x210B, 0b10101010);
|
||||
REQUIRE(snes.ppu->_registers._bgnba[0].baseAddressBg1a3 == 0b1010);
|
||||
REQUIRE(snes.ppu->_registers._bgnba[0].baseAddressBg2a4 == 0b1010);
|
||||
}
|
||||
@@ -14,7 +14,7 @@ using namespace ComSquare;
|
||||
TEST_CASE("vmain_data_full PPU_write_2", "[PPU_write_2]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x2115, 0b11111111);
|
||||
snes.bus.write(0x2115, 0b11111111);
|
||||
REQUIRE(snes.ppu->_registers._vmain.incrementMode == true);
|
||||
REQUIRE(snes.ppu->_registers._vmain.addressRemapping == 0b11);
|
||||
REQUIRE(snes.ppu->_registers._vmain.incrementAmount == 0b11);
|
||||
@@ -23,7 +23,7 @@ TEST_CASE("vmain_data_full PPU_write_2", "[PPU_write_2]")
|
||||
TEST_CASE("vmain_incrementmode_off_false_else_full PPU_write_2", "[PPU_write_2]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x2115, 0b01111111);
|
||||
snes.bus.write(0x2115, 0b01111111);
|
||||
REQUIRE(snes.ppu->_registers._vmain.incrementMode == false);
|
||||
REQUIRE(snes.ppu->_registers._vmain.addressRemapping == 0b11);
|
||||
REQUIRE(snes.ppu->_registers._vmain.incrementAmount == 0b11);
|
||||
@@ -32,7 +32,7 @@ TEST_CASE("vmain_incrementmode_off_false_else_full PPU_write_2", "[PPU_write_2]"
|
||||
TEST_CASE("vmain_addressremaping_null_else_full PPU_write_2", "[PPU_write_2]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x2115, 0b11110011);
|
||||
snes.bus.write(0x2115, 0b11110011);
|
||||
REQUIRE(snes.ppu->_registers._vmain.incrementMode == true);
|
||||
REQUIRE(snes.ppu->_registers._vmain.addressRemapping == 0b00);
|
||||
REQUIRE(snes.ppu->_registers._vmain.incrementAmount == 0b11);
|
||||
@@ -41,7 +41,7 @@ TEST_CASE("vmain_addressremaping_null_else_full PPU_write_2", "[PPU_write_2]")
|
||||
TEST_CASE("vmain_incrementamount_null_else_full PPU_write_2", "[PPU_write_2]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x2115, 0b11111100);
|
||||
snes.bus.write(0x2115, 0b11111100);
|
||||
REQUIRE(snes.ppu->_registers._vmain.incrementMode == true);
|
||||
REQUIRE(snes.ppu->_registers._vmain.addressRemapping == 0b11);
|
||||
REQUIRE(snes.ppu->_registers._vmain.incrementAmount == 0b00);
|
||||
@@ -50,19 +50,19 @@ TEST_CASE("vmain_incrementamount_null_else_full PPU_write_2", "[PPU_write_2]")
|
||||
TEST_CASE("vmadd_full_data PPU_write_2", "[PPU_write_2]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x2116, 0b11111111);
|
||||
snes.bus->write(0x2117, 0b11111111);
|
||||
snes.bus.write(0x2116, 0b11111111);
|
||||
snes.bus.write(0x2117, 0b11111111);
|
||||
REQUIRE(snes.ppu->_registers._vmadd.vmadd == 0b1111111111111111);
|
||||
}
|
||||
|
||||
TEST_CASE("vmadd_full_data_check_ram PPU_write_2", "[PPU_write_2]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x2115, 0b10000000);
|
||||
snes.bus->write(0x2116, 2);
|
||||
snes.bus->write(0x2117, 0);
|
||||
snes.bus->write(0x2118, 0xFF);
|
||||
snes.bus->write(0x2119, 0xFF);
|
||||
snes.bus.write(0x2115, 0b10000000);
|
||||
snes.bus.write(0x2116, 2);
|
||||
snes.bus.write(0x2117, 0);
|
||||
snes.bus.write(0x2118, 0xFF);
|
||||
snes.bus.write(0x2119, 0xFF);
|
||||
REQUIRE(snes.ppu->_registers._vmadd.vmadd == 3);
|
||||
REQUIRE(snes.ppu->vram->read(4) == 0xFF);
|
||||
REQUIRE(snes.ppu->vram->read(5) == 0xF);
|
||||
@@ -71,31 +71,31 @@ TEST_CASE("vmadd_full_data_check_ram PPU_write_2", "[PPU_write_2]")
|
||||
TEST_CASE("vmadd_full_high_byte_null PPU_write_2", "[PPU_write_2]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x2116, 0b11111111);
|
||||
snes.bus->write(0x2117, 0b00000000);
|
||||
snes.bus.write(0x2116, 0b11111111);
|
||||
snes.bus.write(0x2117, 0b00000000);
|
||||
REQUIRE(snes.ppu->_registers._vmadd.vmadd == 0b0000000011111111);
|
||||
}
|
||||
|
||||
TEST_CASE("vmdata_full_data PPU_write_2", "[PPU_write_2]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x2118, 0b11111111);
|
||||
snes.bus->write(0x2119, 0b11111111);
|
||||
snes.bus.write(0x2118, 0b11111111);
|
||||
snes.bus.write(0x2119, 0b11111111);
|
||||
REQUIRE(snes.ppu->_registers._vmdata.vmdata == 0b1111111111111111);
|
||||
}
|
||||
|
||||
TEST_CASE("vmdata_full_high_byte_null PPU_write_2", "[PPU_write_2]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x2118, 0b11111111);
|
||||
snes.bus->write(0x2119, 0b00000000);
|
||||
snes.bus.write(0x2118, 0b11111111);
|
||||
snes.bus.write(0x2119, 0b00000000);
|
||||
REQUIRE(snes.ppu->_registers._vmdata.vmdata == 0b0000000011111111);
|
||||
}
|
||||
|
||||
TEST_CASE("cgadd_full_high_byte_null PPU_write_2", "[PPU_write_2]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x2121, 0b11111111);
|
||||
snes.bus.write(0x2121, 0b11111111);
|
||||
REQUIRE(snes.ppu->_registers._cgadd == 0b11111111);
|
||||
REQUIRE(snes.ppu->_registers._isLowByte == true);
|
||||
}
|
||||
@@ -103,12 +103,12 @@ TEST_CASE("cgadd_full_high_byte_null PPU_write_2", "[PPU_write_2]")
|
||||
TEST_CASE("cgdata_data_full PPU_write_2", "[PPU_write_2]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x2121, 0x0);
|
||||
snes.bus->write(0x2122, 0b11111111);
|
||||
snes.bus.write(0x2121, 0x0);
|
||||
snes.bus.write(0x2122, 0b11111111);
|
||||
REQUIRE(snes.ppu->_registers._cgdata.cgdatal == 0b11111111);
|
||||
REQUIRE(snes.ppu->_registers._isLowByte == false);
|
||||
int address = snes.ppu->_registers._cgadd;
|
||||
snes.bus->write(0x2122, 0b11111000);
|
||||
snes.bus.write(0x2122, 0b11111000);
|
||||
REQUIRE(snes.ppu->_registers._cgdata.cgdatah == 0b11111000);
|
||||
REQUIRE(snes.ppu->_registers._isLowByte == true);
|
||||
REQUIRE(snes.ppu->_registers._cgadd == address + 2);
|
||||
@@ -117,7 +117,7 @@ TEST_CASE("cgdata_data_full PPU_write_2", "[PPU_write_2]")
|
||||
TEST_CASE("m7sel_data_full PPU_write_2", "[PPU_write_2]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x211A, 0b11111111);
|
||||
snes.bus.write(0x211A, 0b11111111);
|
||||
REQUIRE(snes.ppu->_registers._m7sel.playingFieldSize == true);
|
||||
REQUIRE(snes.ppu->_registers._m7sel.emptySpaceFill == true);
|
||||
REQUIRE(snes.ppu->_registers._m7sel.horizontalMirroring == true);
|
||||
@@ -127,7 +127,7 @@ TEST_CASE("m7sel_data_full PPU_write_2", "[PPU_write_2]")
|
||||
TEST_CASE("m7sel_data_actual PPU_write_2", "[PPU_write_2]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x211A, 0b01111101);
|
||||
snes.bus.write(0x211A, 0b01111101);
|
||||
REQUIRE(snes.ppu->_registers._m7sel.playingFieldSize == false);
|
||||
REQUIRE(snes.ppu->_registers._m7sel.emptySpaceFill == true);
|
||||
REQUIRE(snes.ppu->_registers._m7sel.horizontalMirroring == true);
|
||||
@@ -137,7 +137,7 @@ TEST_CASE("m7sel_data_actual PPU_write_2", "[PPU_write_2]")
|
||||
TEST_CASE("w12sel_data_full PPU_write_2", "[PPU_write_2]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x2123, 0b11111111);
|
||||
snes.bus.write(0x2123, 0b11111111);
|
||||
REQUIRE(snes.ppu->_registers._wsel[0].window1InversionForBg1Bg3Obj == true);
|
||||
REQUIRE(snes.ppu->_registers._wsel[0].enableWindow1ForBg1Bg3Obj == true);
|
||||
REQUIRE(snes.ppu->_registers._wsel[0].window2InversionForBg1Bg3Obj == true);
|
||||
@@ -151,7 +151,7 @@ TEST_CASE("w12sel_data_full PPU_write_2", "[PPU_write_2]")
|
||||
TEST_CASE("w34sel_data_full PPU_write_2", "[PPU_write_2]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x2124, 0b10101010);
|
||||
snes.bus.write(0x2124, 0b10101010);
|
||||
REQUIRE(snes.ppu->_registers._wsel[1].window1InversionForBg1Bg3Obj == true);
|
||||
REQUIRE(snes.ppu->_registers._wsel[1].enableWindow1ForBg1Bg3Obj == false);
|
||||
REQUIRE(snes.ppu->_registers._wsel[1].window2InversionForBg1Bg3Obj == true);
|
||||
@@ -165,7 +165,7 @@ TEST_CASE("w34sel_data_full PPU_write_2", "[PPU_write_2]")
|
||||
TEST_CASE("wobjsel_data_full PPU_write_2", "[PPU_write_2]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x2125, 0b10110001);
|
||||
snes.bus.write(0x2125, 0b10110001);
|
||||
REQUIRE(snes.ppu->_registers._wsel[2].window1InversionForBg1Bg3Obj == true);
|
||||
REQUIRE(snes.ppu->_registers._wsel[2].enableWindow1ForBg1Bg3Obj == false);
|
||||
REQUIRE(snes.ppu->_registers._wsel[2].window2InversionForBg1Bg3Obj == true);
|
||||
@@ -179,7 +179,7 @@ TEST_CASE("wobjsel_data_full PPU_write_2", "[PPU_write_2]")
|
||||
TEST_CASE("wbglog_data_full PPU_write_2", "[PPU_write_2]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x212A, 0b10110001);
|
||||
snes.bus.write(0x212A, 0b10110001);
|
||||
REQUIRE(snes.ppu->_registers._wbglog.maskLogicBg1 == 0b10);
|
||||
REQUIRE(snes.ppu->_registers._wbglog.maskLogicBg2 == 0b11);
|
||||
REQUIRE(snes.ppu->_registers._wbglog.maskLogicBg3 == 0b00);
|
||||
@@ -189,7 +189,7 @@ TEST_CASE("wbglog_data_full PPU_write_2", "[PPU_write_2]")
|
||||
TEST_CASE("wobjlog_data_full PPU_write_2", "[PPU_write_2]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x212B, 0b10110001);
|
||||
snes.bus.write(0x212B, 0b10110001);
|
||||
REQUIRE(snes.ppu->_registers._wobjlog.maskLogicObj == 0b01);
|
||||
REQUIRE(snes.ppu->_registers._wobjlog.maskLogicColor == 0b00);
|
||||
}
|
||||
@@ -197,7 +197,7 @@ TEST_CASE("wobjlog_data_full PPU_write_2", "[PPU_write_2]")
|
||||
TEST_CASE("tm_data_full PPU_write_2", "[PPU_write_2]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x212C, 0b10110001);
|
||||
snes.bus.write(0x212C, 0b10110001);
|
||||
REQUIRE(snes.ppu->_registers._t[0].enableWindowDisplayBg1 == true);
|
||||
REQUIRE(snes.ppu->_registers._t[0].enableWindowDisplayBg2 == false);
|
||||
REQUIRE(snes.ppu->_registers._t[0].enableWindowDisplayBg3 == false);
|
||||
@@ -208,7 +208,7 @@ TEST_CASE("tm_data_full PPU_write_2", "[PPU_write_2]")
|
||||
TEST_CASE("ts_data_full PPU_write_2", "[PPU_write_2]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x212D, 0b10101110);
|
||||
snes.bus.write(0x212D, 0b10101110);
|
||||
REQUIRE(snes.ppu->_registers._t[1].enableWindowDisplayBg1 == false);
|
||||
REQUIRE(snes.ppu->_registers._t[1].enableWindowDisplayBg2 == true);
|
||||
REQUIRE(snes.ppu->_registers._t[1].enableWindowDisplayBg3 == true);
|
||||
@@ -219,7 +219,7 @@ TEST_CASE("ts_data_full PPU_write_2", "[PPU_write_2]")
|
||||
TEST_CASE("tmw_data_full PPU_write_2", "[PPU_write_2]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x212E, 0b10101110);
|
||||
snes.bus.write(0x212E, 0b10101110);
|
||||
REQUIRE(snes.ppu->_registers._tw[0].enableWindowMaskingBg1 == false);
|
||||
REQUIRE(snes.ppu->_registers._tw[0].enableWindowMaskingBg2 == true);
|
||||
REQUIRE(snes.ppu->_registers._tw[0].enableWindowMaskingBg3 == true);
|
||||
@@ -230,7 +230,7 @@ TEST_CASE("tmw_data_full PPU_write_2", "[PPU_write_2]")
|
||||
TEST_CASE("tsw_data_full PPU_write_2", "[PPU_write_2]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x212F, 0b10100011);
|
||||
snes.bus.write(0x212F, 0b10100011);
|
||||
REQUIRE(snes.ppu->_registers._tw[1].enableWindowMaskingBg1 == true);
|
||||
REQUIRE(snes.ppu->_registers._tw[1].enableWindowMaskingBg2 == true);
|
||||
REQUIRE(snes.ppu->_registers._tw[1].enableWindowMaskingBg3 == false);
|
||||
@@ -241,7 +241,7 @@ TEST_CASE("tsw_data_full PPU_write_2", "[PPU_write_2]")
|
||||
TEST_CASE("cgwsel_data_full PPU_write_2", "[PPU_write_2]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x2130, 0b10111001);
|
||||
snes.bus.write(0x2130, 0b10111001);
|
||||
REQUIRE(snes.ppu->_registers._cgwsel.clipColorToBlackBeforeMath == 0b10);
|
||||
REQUIRE(snes.ppu->_registers._cgwsel.preventColorMath == 0b11);
|
||||
REQUIRE(snes.ppu->_registers._cgwsel.addSubscreen == false);
|
||||
@@ -251,7 +251,7 @@ TEST_CASE("cgwsel_data_full PPU_write_2", "[PPU_write_2]")
|
||||
TEST_CASE("cgadsub_data_full PPU_write_2", "[PPU_write_2]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x2131, 0b10111001);
|
||||
snes.bus.write(0x2131, 0b10111001);
|
||||
REQUIRE(snes.ppu->_registers._cgadsub.addSubtractSelect == true);
|
||||
REQUIRE(snes.ppu->_registers._cgadsub.halfColorMath == false);
|
||||
REQUIRE(snes.ppu->_registers._cgadsub.enableColorMathBackdrop == true);
|
||||
@@ -265,7 +265,7 @@ TEST_CASE("cgadsub_data_full PPU_write_2", "[PPU_write_2]")
|
||||
TEST_CASE("coldata_data_full PPU_write_2", "[PPU_write_2]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x2132, 0b10111001);
|
||||
snes.bus.write(0x2132, 0b10111001);
|
||||
REQUIRE(snes.ppu->_registers._coldata.blue == true);
|
||||
REQUIRE(snes.ppu->_registers._coldata.green == false);
|
||||
REQUIRE(snes.ppu->_registers._coldata.red == true);
|
||||
@@ -275,7 +275,7 @@ TEST_CASE("coldata_data_full PPU_write_2", "[PPU_write_2]")
|
||||
TEST_CASE("setini_data_full PPU_write_2", "[PPU_write_2]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x2133, 0b10111001);
|
||||
snes.bus.write(0x2133, 0b10111001);
|
||||
REQUIRE(snes.ppu->_registers._setini.externalSync == true);
|
||||
REQUIRE(snes.ppu->_registers._setini.mode7ExtBg == false);
|
||||
REQUIRE(snes.ppu->_registers._setini.enablePseudoHiresMode == true);
|
||||
@@ -287,14 +287,14 @@ TEST_CASE("setini_data_full PPU_write_2", "[PPU_write_2]")
|
||||
TEST_CASE("m7a_data_full PPU_write_2", "[PPU_write_2]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x211B, 0b10111001);
|
||||
snes.bus.write(0x211B, 0b10111001);
|
||||
REQUIRE(snes.ppu->_registers._m7[0].m7l == 0b10111001);
|
||||
}
|
||||
|
||||
TEST_CASE("m7c_data_low_and_high_byte PPU_write_2", "[PPU_write_2]")
|
||||
{
|
||||
Init()
|
||||
snes.bus->write(0x211D, 0b10111001);
|
||||
snes.bus->write(0x211D, 0b11111111);
|
||||
snes.bus.write(0x211D, 0b10111001);
|
||||
snes.bus.write(0x211D, 0b11111111);
|
||||
REQUIRE(snes.ppu->_registers._m7[2].m7 == 0b1011100111111111);
|
||||
}
|
||||
@@ -23,7 +23,7 @@ TEST_CASE("GetWramStart BusAccessor", "[BusAccessor]")
|
||||
Init()
|
||||
std::shared_ptr<Memory::IMemory> accessor;
|
||||
|
||||
accessor = snes.bus->getAccessor(0x7E0000);
|
||||
accessor = snes.bus.getAccessor(0x7E0000);
|
||||
REQUIRE(accessor.get() == snes.wram.get());
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ TEST_CASE("GetWramEnd BusAccessor", "[BusAccessor]")
|
||||
Init()
|
||||
std::shared_ptr<Memory::IMemory> accessor;
|
||||
|
||||
accessor = snes.bus->getAccessor(0x7FFFFF);
|
||||
accessor = snes.bus.getAccessor(0x7FFFFF);
|
||||
REQUIRE(accessor.get() == snes.wram.get());
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ TEST_CASE("GetWramMirror BusAccessor", "[BusAccessor]")
|
||||
Init()
|
||||
std::shared_ptr<Memory::RectangleShadow> accessor;
|
||||
|
||||
accessor = std::static_pointer_cast<Memory::RectangleShadow>(snes.bus->getAccessor(0x2F11FF));
|
||||
accessor = std::static_pointer_cast<Memory::RectangleShadow>(snes.bus.getAccessor(0x2F11FF));
|
||||
REQUIRE(accessor != nullptr);
|
||||
REQUIRE(accessor->_initial.get() == snes.wram.get());
|
||||
}
|
||||
@@ -51,7 +51,7 @@ TEST_CASE("GetWramMirror2 BusAccessor", "[BusAccessor]")
|
||||
Init()
|
||||
std::shared_ptr<Memory::RectangleShadow> accessor;
|
||||
|
||||
accessor = std::static_pointer_cast<Memory::RectangleShadow>(snes.bus->getAccessor(0x100000));
|
||||
accessor = std::static_pointer_cast<Memory::RectangleShadow>(snes.bus.getAccessor(0x100000));
|
||||
REQUIRE(accessor != nullptr);
|
||||
REQUIRE(accessor->_initial.get() == snes.wram.get());
|
||||
}
|
||||
@@ -61,7 +61,7 @@ TEST_CASE("GetWramMirror3 BusAccessor", "[BusAccessor]")
|
||||
Init()
|
||||
std::shared_ptr<Memory::RectangleShadow> accessor;
|
||||
|
||||
accessor = std::static_pointer_cast<Memory::RectangleShadow>(snes.bus->getAccessor(0x1010));
|
||||
accessor = std::static_pointer_cast<Memory::RectangleShadow>(snes.bus.getAccessor(0x1010));
|
||||
REQUIRE(accessor != nullptr);
|
||||
REQUIRE(accessor->_initial.get() == snes.wram.get());
|
||||
}
|
||||
@@ -69,7 +69,7 @@ TEST_CASE("GetWramMirror3 BusAccessor", "[BusAccessor]")
|
||||
TEST_CASE("GetOpenBus BusAccessor", "[BusAccessor]")
|
||||
{
|
||||
Init()
|
||||
std::shared_ptr<Memory::IMemory> accessor = snes.bus->getAccessor(0x897654);
|
||||
std::shared_ptr<Memory::IMemory> accessor = snes.bus.getAccessor(0x897654);
|
||||
REQUIRE(accessor.get() == nullptr);
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ TEST_CASE("GetSramStart BusAccessor", "[BusAccessor]")
|
||||
Init()
|
||||
std::shared_ptr<Memory::RectangleShadow> accessor;
|
||||
|
||||
accessor = std::static_pointer_cast<Memory::RectangleShadow>(snes.bus->getAccessor(0x700000));
|
||||
accessor = std::static_pointer_cast<Memory::RectangleShadow>(snes.bus.getAccessor(0x700000));
|
||||
REQUIRE(accessor);
|
||||
REQUIRE(accessor->_initial.get() == snes.sram.get());
|
||||
}
|
||||
@@ -88,7 +88,7 @@ TEST_CASE("GetSramEnd BusAccessor", "[BusAccessor]")
|
||||
Init()
|
||||
std::shared_ptr<Memory::RectangleShadow> accessor;
|
||||
|
||||
accessor = std::static_pointer_cast<Memory::RectangleShadow>(snes.bus->getAccessor(0x7D7FFF));
|
||||
accessor = std::static_pointer_cast<Memory::RectangleShadow>(snes.bus.getAccessor(0x7D7FFF));
|
||||
REQUIRE(accessor);
|
||||
REQUIRE(accessor->_initial.get() == snes.sram.get());
|
||||
}
|
||||
@@ -98,7 +98,7 @@ TEST_CASE("GetSramMirror BusAccessor", "[BusAccessor]")
|
||||
Init()
|
||||
std::shared_ptr<Memory::ARectangleMemory> accessor;
|
||||
|
||||
accessor = std::static_pointer_cast<Memory::ARectangleMemory>(snes.bus->getAccessor(0xF00123));
|
||||
accessor = std::static_pointer_cast<Memory::ARectangleMemory>(snes.bus.getAccessor(0xF00123));
|
||||
REQUIRE(accessor.get() == snes.sram.get());
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ TEST_CASE("GetAPUStart BusAccessor", "[BusAccessor]")
|
||||
Init()
|
||||
std::shared_ptr<Memory::IMemory> accessor;
|
||||
|
||||
accessor = snes.bus->getAccessor(0x002140);
|
||||
accessor = snes.bus.getAccessor(0x002140);
|
||||
REQUIRE(accessor.get() == snes.apu.get());
|
||||
}
|
||||
|
||||
@@ -116,7 +116,7 @@ TEST_CASE("GetAPUEnd BusAccessor", "[BusAccessor]")
|
||||
Init()
|
||||
std::shared_ptr<Memory::IMemory> accessor;
|
||||
|
||||
accessor = snes.bus->getAccessor(0x002143);
|
||||
accessor = snes.bus.getAccessor(0x002143);
|
||||
REQUIRE(accessor.get() == snes.apu.get());
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@ TEST_CASE("GetAPUMirror BusAccessor", "[BusAccessor]")
|
||||
Init()
|
||||
std::shared_ptr<Memory::MemoryShadow> accessor;
|
||||
|
||||
accessor = std::static_pointer_cast<Memory::MemoryShadow>(snes.bus->getAccessor(0xAB2143));
|
||||
accessor = std::static_pointer_cast<Memory::MemoryShadow>(snes.bus.getAccessor(0xAB2143));
|
||||
REQUIRE(accessor->_initial.get() == snes.apu.get());
|
||||
}
|
||||
|
||||
@@ -134,7 +134,7 @@ TEST_CASE("GetAPUMirrorFirstHalf BusAccessor", "[BusAccessor]")
|
||||
Init()
|
||||
std::shared_ptr<Memory::MemoryShadow> accessor;
|
||||
|
||||
accessor = std::static_pointer_cast<Memory::MemoryShadow>(snes.bus->getAccessor(0x052143));
|
||||
accessor = std::static_pointer_cast<Memory::MemoryShadow>(snes.bus.getAccessor(0x052143));
|
||||
REQUIRE(accessor->_initial.get() == snes.apu.get());
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ TEST_CASE("GetCPUStart BusAccessor", "[BusAccessor]")
|
||||
Init()
|
||||
std::shared_ptr<Memory::IMemory> accessor;
|
||||
|
||||
accessor = snes.bus->getAccessor(0x004200);
|
||||
accessor = snes.bus.getAccessor(0x004200);
|
||||
REQUIRE(accessor.get() == snes.cpu.get());
|
||||
}
|
||||
|
||||
@@ -152,7 +152,7 @@ TEST_CASE("GetCPUEnd BusAccessor", "[BusAccessor]")
|
||||
Init()
|
||||
std::shared_ptr<Memory::IMemory> accessor;
|
||||
|
||||
accessor = snes.bus->getAccessor(0x00421F);
|
||||
accessor = snes.bus.getAccessor(0x00421F);
|
||||
REQUIRE(accessor.get() == snes.cpu.get());
|
||||
}
|
||||
|
||||
@@ -161,7 +161,7 @@ TEST_CASE("GetPPU1Start BusAccessor", "[BusAccessor]")
|
||||
Init()
|
||||
std::shared_ptr<Memory::IMemory> accessor;
|
||||
|
||||
accessor = snes.bus->getAccessor(0x00213E);
|
||||
accessor = snes.bus.getAccessor(0x00213E);
|
||||
REQUIRE(accessor.get() == snes.ppu.get());
|
||||
}
|
||||
|
||||
@@ -170,7 +170,7 @@ TEST_CASE("GetPPU1End BusAccessor", "[BusAccessor]")
|
||||
Init()
|
||||
std::shared_ptr<Memory::IMemory> accessor;
|
||||
|
||||
accessor = snes.bus->getAccessor(0x00213F);
|
||||
accessor = snes.bus.getAccessor(0x00213F);
|
||||
REQUIRE(accessor.get() == snes.ppu.get());
|
||||
}
|
||||
|
||||
@@ -179,7 +179,7 @@ TEST_CASE("GetCPU BusAccessor", "[BusAccessor]")
|
||||
Init()
|
||||
std::shared_ptr<Memory::IMemory> accessor;
|
||||
|
||||
accessor = snes.bus->getAccessor(0x004212);
|
||||
accessor = snes.bus.getAccessor(0x004212);
|
||||
REQUIRE(accessor.get() == snes.cpu.get());
|
||||
}
|
||||
|
||||
@@ -188,7 +188,7 @@ TEST_CASE("GetPPU1Mirror BusAccessor", "[BusAccessor]")
|
||||
Init()
|
||||
std::shared_ptr<Memory::MemoryShadow> accessor;
|
||||
|
||||
accessor = std::static_pointer_cast<Memory::MemoryShadow>(snes.bus->getAccessor(0x80213F));
|
||||
accessor = std::static_pointer_cast<Memory::MemoryShadow>(snes.bus.getAccessor(0x80213F));
|
||||
REQUIRE(accessor->_initial.get() == snes.ppu.get());
|
||||
}
|
||||
|
||||
@@ -197,7 +197,7 @@ TEST_CASE("GetCPU2Mirror BusAccessor", "[BusAccessor]")
|
||||
Init()
|
||||
std::shared_ptr<Memory::MemoryShadow> accessor;
|
||||
|
||||
accessor = std::static_pointer_cast<Memory::MemoryShadow>(snes.bus->getAccessor(0x804212));
|
||||
accessor = std::static_pointer_cast<Memory::MemoryShadow>(snes.bus.getAccessor(0x804212));
|
||||
REQUIRE(accessor->_initial.get() == snes.cpu.get());
|
||||
}
|
||||
|
||||
@@ -206,7 +206,7 @@ TEST_CASE("GetRomStart BusAccessor", "[BusAccessor]")
|
||||
Init()
|
||||
std::shared_ptr<Memory::IMemory> accessor;
|
||||
|
||||
accessor = snes.bus->getAccessor(0x808000);
|
||||
accessor = snes.bus.getAccessor(0x808000);
|
||||
REQUIRE(accessor.get() == snes.cartridge.get());
|
||||
}
|
||||
|
||||
@@ -215,7 +215,7 @@ TEST_CASE("GetRomEnd BusAccessor", "[BusAccessor]")
|
||||
Init()
|
||||
std::shared_ptr<Memory::IMemory> accessor;
|
||||
|
||||
accessor = snes.bus->getAccessor(0xFFFFFF);
|
||||
accessor = snes.bus.getAccessor(0xFFFFFF);
|
||||
REQUIRE(accessor.get() == snes.cartridge.get());
|
||||
}
|
||||
|
||||
@@ -224,7 +224,7 @@ TEST_CASE("GetRomMirror BusAccessor", "[BusAccessor]")
|
||||
Init()
|
||||
std::shared_ptr<Memory::RectangleShadow> accessor;
|
||||
|
||||
accessor = std::static_pointer_cast<Memory::RectangleShadow>(snes.bus->getAccessor(0x694200));
|
||||
accessor = std::static_pointer_cast<Memory::RectangleShadow>(snes.bus.getAccessor(0x694200));
|
||||
REQUIRE(accessor);
|
||||
REQUIRE(accessor->_initial.get() == snes.cartridge.get());
|
||||
}
|
||||
@@ -234,7 +234,7 @@ TEST_CASE("GetRomMirror2 BusAccessor", "[BusAccessor]")
|
||||
Init()
|
||||
std::shared_ptr<Memory::RectangleShadow> accessor;
|
||||
|
||||
accessor = std::static_pointer_cast<Memory::RectangleShadow>(snes.bus->getAccessor(0x01FEDC));
|
||||
accessor = std::static_pointer_cast<Memory::RectangleShadow>(snes.bus.getAccessor(0x01FEDC));
|
||||
REQUIRE(accessor);
|
||||
REQUIRE(accessor->_initial.get() == snes.cartridge.get());
|
||||
}
|
||||
@@ -244,7 +244,7 @@ TEST_CASE("GetRomMirror3 BusAccessor", "[BusAccessor]")
|
||||
Init()
|
||||
std::shared_ptr<Memory::RectangleShadow> accessor;
|
||||
|
||||
accessor = std::static_pointer_cast<Memory::RectangleShadow>(snes.bus->getAccessor(0xDE1248));
|
||||
accessor = std::static_pointer_cast<Memory::RectangleShadow>(snes.bus.getAccessor(0xDE1248));
|
||||
REQUIRE(accessor);
|
||||
REQUIRE(accessor->_initial.get() == snes.cartridge.get());
|
||||
}
|
||||
@@ -254,7 +254,7 @@ TEST_CASE("Get0x0 BusAccessor", "[BusAccessor]")
|
||||
Init()
|
||||
std::shared_ptr<Memory::RectangleShadow> accessor;
|
||||
|
||||
accessor = std::static_pointer_cast<Memory::RectangleShadow>(snes.bus->getAccessor(0x0));
|
||||
accessor = std::static_pointer_cast<Memory::RectangleShadow>(snes.bus.getAccessor(0x0));
|
||||
REQUIRE(accessor);
|
||||
REQUIRE(accessor->_initial.get() == snes.wram.get());
|
||||
}
|
||||
@@ -271,7 +271,7 @@ TEST_CASE("Read0x0 BusRead", "[BusRead]")
|
||||
uint8_t data;
|
||||
|
||||
snes.wram->_data[0] = 123;
|
||||
data = snes.bus->read(0x0);
|
||||
data = snes.bus.read(0x0);
|
||||
REQUIRE(data == 123);
|
||||
}
|
||||
|
||||
@@ -280,8 +280,8 @@ TEST_CASE("Read ReadOutside", "[ReadOutside]")
|
||||
Init()
|
||||
uint8_t data;
|
||||
|
||||
snes.bus->_openBus = 123;
|
||||
data = snes.bus->read(0x002000);
|
||||
snes.bus._openBus = 123;
|
||||
data = snes.bus.read(0x002000);
|
||||
REQUIRE(data == 123);
|
||||
}
|
||||
|
||||
@@ -290,8 +290,8 @@ TEST_CASE("ReadOutside2 Read][Bus", "[Read][Bus]")
|
||||
Init()
|
||||
uint8_t data;
|
||||
|
||||
snes.bus->_openBus = 123;
|
||||
data = snes.bus->read(0xBF2FFF);
|
||||
snes.bus._openBus = 123;
|
||||
data = snes.bus.read(0xBF2FFF);
|
||||
REQUIRE(data == 123);
|
||||
}
|
||||
|
||||
@@ -300,8 +300,8 @@ TEST_CASE("ReadOutside3 Read][Bus", "[Read][Bus]")
|
||||
Init()
|
||||
uint8_t data;
|
||||
|
||||
snes.bus->_openBus = 123;
|
||||
data = snes.bus->read(0x127654);
|
||||
snes.bus._openBus = 123;
|
||||
data = snes.bus.read(0x127654);
|
||||
REQUIRE(data == 123);
|
||||
}
|
||||
|
||||
@@ -311,7 +311,7 @@ TEST_CASE("ReadAPU BusRead", "[BusRead]")
|
||||
uint8_t data;
|
||||
|
||||
snes.apu->_registers.port0 = 123;
|
||||
data = snes.bus->read(0x002140);
|
||||
data = snes.bus.read(0x002140);
|
||||
REQUIRE(data == 123);
|
||||
}
|
||||
|
||||
@@ -321,7 +321,7 @@ TEST_CASE("ReadROM BusRead", "[BusRead]")
|
||||
uint8_t data;
|
||||
|
||||
snes.cartridge->_data[5] = 123;
|
||||
data = snes.bus->read(0x808005);
|
||||
data = snes.bus.read(0x808005);
|
||||
REQUIRE(data == 123);
|
||||
}
|
||||
|
||||
@@ -331,7 +331,7 @@ TEST_CASE("ReadROMStart BusRead", "[BusRead]")
|
||||
uint8_t data;
|
||||
|
||||
snes.cartridge->_data[0] = 123;
|
||||
data = snes.bus->read(0x808000);
|
||||
data = snes.bus.read(0x808000);
|
||||
REQUIRE(data == 123);
|
||||
}
|
||||
|
||||
@@ -341,7 +341,7 @@ TEST_CASE("ReadCPU BusRead", "[BusRead]")
|
||||
uint8_t data;
|
||||
|
||||
snes.cpu->_internalRegisters.wrio = 123;
|
||||
data = snes.bus->read(0x004201);
|
||||
data = snes.bus.read(0x004201);
|
||||
REQUIRE(data == 123);
|
||||
}
|
||||
|
||||
@@ -351,7 +351,7 @@ TEST_CASE("ReadPPU BusRead", "[BusRead]")
|
||||
uint8_t data;
|
||||
|
||||
snes.ppu->_registers._mpy.mpyl = 123;
|
||||
data = snes.bus->read(0x002134);
|
||||
data = snes.bus.read(0x002134);
|
||||
REQUIRE(data == 123);
|
||||
}
|
||||
|
||||
@@ -361,7 +361,7 @@ TEST_CASE("ReadSRAM BusRead", "[BusRead]")
|
||||
uint8_t data;
|
||||
|
||||
snes.sram->_data[7] = 123;
|
||||
data = snes.bus->read(0x700007);
|
||||
data = snes.bus.read(0x700007);
|
||||
REQUIRE(data == 123);
|
||||
}
|
||||
|
||||
@@ -371,7 +371,7 @@ TEST_CASE("ReadWRAM BusRead", "[BusRead]")
|
||||
uint8_t data;
|
||||
|
||||
snes.wram->_data[3] = 123;
|
||||
data = snes.bus->read(0x7E0003);
|
||||
data = snes.bus.read(0x7E0003);
|
||||
REQUIRE(data == 123);
|
||||
}
|
||||
|
||||
@@ -381,7 +381,7 @@ TEST_CASE("ReadWRAM2 BusRead", "[BusRead]")
|
||||
uint8_t data;
|
||||
|
||||
snes.wram->_data[0x1010] = 123;
|
||||
data = snes.bus->read(0x7E1010);
|
||||
data = snes.bus.read(0x7E1010);
|
||||
REQUIRE(data == 123);
|
||||
}
|
||||
|
||||
@@ -392,7 +392,7 @@ TEST_CASE("ReadWRAMMirror BusRead", "[BusRead]")
|
||||
uint8_t data;
|
||||
|
||||
snes.wram->_data[0x1010] = 123;
|
||||
data = snes.bus->read(0x1010);
|
||||
data = snes.bus.read(0x1010);
|
||||
REQUIRE(data == 123);
|
||||
}
|
||||
|
||||
@@ -407,7 +407,7 @@ TEST_CASE("Write0x0 BusWrite", "[BusWrite]")
|
||||
Init()
|
||||
|
||||
try {
|
||||
snes.bus->write(0x0, 123);
|
||||
snes.bus.write(0x0, 123);
|
||||
} catch (std::exception &ex) {
|
||||
std::cout << ex.what() << std::endl;
|
||||
}
|
||||
@@ -419,7 +419,7 @@ TEST_CASE("WriteAPU BusWrite", "[BusWrite]")
|
||||
{
|
||||
Init()
|
||||
|
||||
snes.bus->write(0x002143, 123);
|
||||
snes.bus.write(0x002143, 123);
|
||||
REQUIRE(snes.apu->_registers.port3 == 123);
|
||||
}
|
||||
|
||||
@@ -427,7 +427,7 @@ TEST_CASE("WritePPU BusWrite", "[BusWrite]")
|
||||
{
|
||||
Init()
|
||||
|
||||
snes.bus->write(0x002106, 123);
|
||||
snes.bus.write(0x002106, 123);
|
||||
REQUIRE(snes.ppu->_registers._mosaic.raw == 123);
|
||||
}
|
||||
|
||||
@@ -435,7 +435,7 @@ TEST_CASE("WriteCPU BusWrite", "[BusWrite]")
|
||||
{
|
||||
Init()
|
||||
|
||||
snes.bus->write(0x00420D, 123);
|
||||
snes.bus.write(0x00420D, 123);
|
||||
REQUIRE(snes.cpu->_internalRegisters.memsel == 123);
|
||||
}
|
||||
|
||||
@@ -443,14 +443,14 @@ TEST_CASE("WriteROM BusWrite", "[BusWrite]")
|
||||
{
|
||||
Init()
|
||||
|
||||
REQUIRE_THROWS_AS(snes.bus->write(0x808005, 123), InvalidAction);
|
||||
REQUIRE_THROWS_AS(snes.bus.write(0x808005, 123), InvalidAction);
|
||||
}
|
||||
|
||||
TEST_CASE("WriteWRAM BusWrite", "[BusWrite]")
|
||||
{
|
||||
Init()
|
||||
|
||||
snes.bus->write(0x7E0002, 123);
|
||||
snes.bus.write(0x7E0002, 123);
|
||||
REQUIRE(snes.wram->_data[2] == 123);
|
||||
}
|
||||
|
||||
@@ -458,6 +458,6 @@ TEST_CASE("WriteSRAM BusWrite", "[BusWrite]")
|
||||
{
|
||||
Init()
|
||||
|
||||
snes.bus->write(0x700009, 123);
|
||||
snes.bus.write(0x700009, 123);
|
||||
REQUIRE(snes.sram->_data[9] == 123);
|
||||
}
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
#define Init() \
|
||||
Renderer::NoRenderer norenderer(0, 0, 0); \
|
||||
SNES snes("../tests/my_cartridge", norenderer); \
|
||||
SNES snes(norenderer); \
|
||||
snes.cartridge->_size = 100; \
|
||||
delete[] snes.cartridge->_data; \
|
||||
snes.cartridge->_data = new uint8_t[snes.cartridge->_size]; \
|
||||
|
||||
Reference in New Issue
Block a user