Cleaning up

This commit is contained in:
Zoe Roux
2021-07-04 02:56:44 +02:00
57 changed files with 5597 additions and 5173 deletions

66
.clang-format Normal file
View 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

View File

@@ -1,11 +1,11 @@
cmake_minimum_required(VERSION 3.12) cmake_minimum_required(VERSION 3.12)
set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD 20)
# set the project name
project(ComSquare) project(ComSquare)
# show compilation warnings if (CMAKE_COMPILER_IS_GNUCXX)
add_compile_options(-W -Wall -Wextra -Wshadow) set(CMAKE_CXX_FLAGS_DEBUG "-Wall -Wextra -Wshadow -Wno-unused-parameter -W -g")
endif ()
set(CMAKE_CXX_FLAGS_RELEASE "-O3")
include_directories(sources) include_directories(sources)
@@ -95,14 +95,15 @@ set(SOURCES
sources/PPU/Tile.hpp sources/PPU/Tile.hpp
sources/PPU/TileRenderer.cpp sources/PPU/TileRenderer.cpp
sources/PPU/TileRenderer.hpp sources/PPU/TileRenderer.hpp
) sources/PPU/Tile.hpp
sources/CPU/Registers.hpp)
set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON) set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON) set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOUIC_SEARCH_PATHS ./) set(CMAKE_AUTOUIC_SEARCH_PATHS ./)
add_executable(ComSquare add_executable(comsquare
sources/main.cpp sources/main.cpp
${SOURCES} ${SOURCES}
sources/Renderer/SFRenderer.hpp sources/Renderer/SFRenderer.hpp
@@ -113,30 +114,34 @@ add_executable(ComSquare
sources/Renderer/QtRenderer/QtWidgetSFML.hpp sources/Renderer/QtRenderer/QtWidgetSFML.hpp
sources/Renderer/QtRenderer/QtSfmlTileRenderer.cpp sources/Renderer/QtRenderer/QtSfmlTileRenderer.cpp
sources/Renderer/QtRenderer/QtSfmlTileRenderer.hpp sources/Renderer/QtRenderer/QtSfmlTileRenderer.hpp
sources/Debugger/CPU/CPUDebug.cpp sources/Renderer/QtRenderer/QtSfmlTileRenderer.cpp
sources/Debugger/CPU/CPUDebug.hpp sources/Renderer/QtRenderer/QtSfmlTileRenderer.hpp
sources/Debugger/MemoryViewer.cpp # sources/PPU/PpuDebug.cpp
sources/Debugger/MemoryViewer.hpp # sources/PPU/PpuDebug.hpp
sources/Debugger/HeaderViewer.cpp # sources/Debugger/CPU/CPUDebug.cpp
sources/Debugger/HeaderViewer.hpp # sources/Debugger/CPU/CPUDebug.hpp
sources/Debugger/HeaderViewer.cpp # sources/Debugger/MemoryViewer.cpp
sources/Debugger/HeaderViewer.hpp # sources/Debugger/MemoryViewer.hpp
sources/Debugger/APUDebug.hpp # sources/Debugger/HeaderViewer.cpp
sources/Debugger/APUDebug.cpp # sources/Debugger/HeaderViewer.hpp
sources/Debugger/MemoryBusDebug.cpp # sources/Debugger/HeaderViewer.cpp
sources/Debugger/MemoryBusDebug.hpp # sources/Debugger/HeaderViewer.hpp
sources/Debugger/ClosableWindow.hpp # sources/Debugger/APUDebug.hpp
sources/Debugger/CPU/Disassembly.cpp # sources/Debugger/APUDebug.cpp
sources/Debugger/CGramDebug.cpp # sources/Debugger/MemoryBusDebug.cpp
sources/Debugger/CGramDebug.hpp # sources/Debugger/MemoryBusDebug.hpp
sources/Debugger/RegisterViewer.cpp # sources/Debugger/ClosableWindow.hpp
sources/Debugger/RegisterViewer.hpp # sources/Debugger/CPU/Disassembly.cpp
sources/Debugger/CPU/SymbolLoaders/WlaDx.cpp # sources/Debugger/CGramDebug.cpp
sources/Debugger/CPU/SymbolLoaders/WlaDx.hpp # sources/Debugger/CGramDebug.hpp
sources/Debugger/TileViewer/TileViewer.cpp # sources/Debugger/RegisterViewer.cpp
sources/Debugger/TileViewer/TileViewer.hpp # sources/Debugger/RegisterViewer.hpp
sources/Debugger/TileViewer/RAMTileRenderer.cpp # sources/Debugger/CPU/SymbolLoaders/WlaDx.cpp
sources/Debugger/TileViewer/RAMTileRenderer.hpp # 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/tileView.ui
ui/registersView.ui ui/registersView.ui
ui/cpuView.ui ui/cpuView.ui
@@ -145,48 +150,48 @@ add_executable(ComSquare
ui/apuView.ui ui/apuView.ui
ui/busView.ui ui/busView.ui
resources/appResources.qrc resources/appResources.qrc
) )
target_include_directories(ComSquare PRIVATE ./) target_include_directories(comsquare PRIVATE ./)
target_compile_definitions(ComSquare PUBLIC DEBUGGER_ENABLED) #target_compile_definitions(comsquare PUBLIC DEBUGGER_ENABLED)
find_package(Qt5 COMPONENTS Widgets REQUIRED) find_package(Qt5 COMPONENTS Widgets REQUIRED)
target_link_libraries(ComSquare target_link_libraries(comsquare
sfml-graphics sfml-graphics
sfml-window sfml-window
sfml-system sfml-system
sfml-audio sfml-audio
sfml-network sfml-network
Qt5::Widgets Qt5::Widgets
) )
add_executable(unit_tests EXCLUDE_FROM_ALL add_executable(unit_tests EXCLUDE_FROM_ALL
${SOURCES} ${SOURCES}
tests/MainTest.cpp tests/MainTest.cpp
tests/tests.hpp tests/tests.hpp
tests/CPU/testInterupts.cpp tests/CPU/testInterupts.cpp
# tests/APU/testAPUInstructions.cpp tests/APU/testAPUInstructions.cpp
# tests/APU/testAPU.cpp tests/APU/testAPU.cpp
# tests/PPU/testPpuWrite.cpp tests/PPU/testPpuWrite.cpp
# tests/PPU/testPpuWriteFromVmain.cpp tests/PPU/testPpuWriteFromVmain.cpp
# tests/CPU/Math/testADC.cpp tests/CPU/Math/testADC.cpp
# tests/CPU/testStore.cpp tests/CPU/testStore.cpp
# tests/CPU/testInternal.cpp tests/CPU/testInternal.cpp
# tests/CPU/testBits.cpp tests/CPU/testBits.cpp
# tests/APU/testOperand.cpp tests/APU/testOperand.cpp
# tests/CPU/Math/testSBC.cpp tests/CPU/Math/testSBC.cpp
# tests/CPU/testTransfers.cpp tests/CPU/testTransfers.cpp
# tests/CPU/Math/testOthersMath.cpp tests/CPU/Math/testOthersMath.cpp
# tests/testRectangleMemory.cpp tests/testRectangleMemory.cpp
# tests/CPU/Math/testCMP.cpp tests/CPU/Math/testCMP.cpp
# tests/CPU/testDMA.cpp tests/CPU/testDMA.cpp
# tests/CPU/testAddressingMode.cpp tests/CPU/testAddressingMode.cpp
# tests/testMemoryBus.cpp tests/testMemoryBus.cpp
) )
if (CMAKE_COMPILER_IS_GNUCXX) if (CMAKE_COMPILER_IS_GNUCXX)
# target_link_libraries(unit_tests PRIVATE -lgcov) # target_link_libraries(unit_tests PRIVATE -lgcov)
# target_compile_options(unit_tests PUBLIC -fprofile-arcs -ftest-coverage) # target_compile_options(unit_tests PUBLIC -fprofile-arcs -ftest-coverage)
endif() endif ()
find_package(Catch2 QUIET) find_package(Catch2 QUIET)
if (NOT Catch2_FOUND) if (NOT Catch2_FOUND)

View File

@@ -2,17 +2,16 @@
// Created by Melefo on 27/01/2020. // Created by Melefo on 27/01/2020.
// //
#include <iostream>
#include <cstring>
#include "APU.hpp" #include "APU.hpp"
#include "../Exceptions/NotImplementedException.hpp"
#include "../Exceptions/InvalidAddress.hpp" #include "../Exceptions/InvalidAddress.hpp"
#include "../Exceptions/InvalidOpcode.hpp" #include "../Exceptions/InvalidOpcode.hpp"
#include "../Exceptions/NotImplementedException.hpp"
#include <cstring>
#include <iostream>
namespace ComSquare::APU namespace ComSquare::APU
{ {
APU::APU(Renderer::IRenderer &renderer) : APU::APU(Renderer::IRenderer &renderer) : _renderer(renderer),
_renderer(renderer),
_map(new MemoryMap()), _map(new MemoryMap()),
_soundBuffer(), _soundBuffer(),
_dsp(this->_soundBuffer, this->_soundBuffer.size() / 2, _map) _dsp(this->_soundBuffer, this->_soundBuffer.size() / 2, _map)
@@ -751,11 +750,11 @@ namespace ComSquare::APU
case 0xE8: case 0xE8:
return this->MOV(this->_internalRegisters.a, this->_getImmediateData(), 2); return this->MOV(this->_internalRegisters.a, this->_getImmediateData(), 2);
case 0xE9: case 0xE9:
return this->MOV(this->_internalRegisters.x, this->_getAbsoluteAddr(),4); return this->MOV(this->_internalRegisters.x, this->_getAbsoluteAddr(), 4);
case 0xEA: case 0xEA:
return this->NOT1(this->_getAbsoluteBit()); return this->NOT1(this->_getAbsoluteBit());
case 0xEB: case 0xEB:
return this->MOV(this->_internalRegisters.y, this->_getDirectAddr(),3); return this->MOV(this->_internalRegisters.y, this->_getDirectAddr(), 3);
case 0xEC: case 0xEC:
return this->MOV(this->_internalRegisters.y, this->_getAbsoluteAddr(), 4); return this->MOV(this->_internalRegisters.y, this->_getAbsoluteAddr(), 4);
case 0xED: case 0xED:
@@ -822,13 +821,13 @@ namespace ComSquare::APU
this->_dsp.update(); this->_dsp.update();
samples = this->_dsp.getSamplesCount(); samples = this->_dsp.getSamplesCount();
if (samples > 0) 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(); const uint8_t *data = cartridge.getData();
uint24_t size = cartridge->getSize(); uint24_t size = cartridge.getSize();
if (size < 0x101C0) if (size < 0x101C0)
throw InvalidAddress("Cartridge is not the right size", size); 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 date = std::string(reinterpret_cast<const char *>(data + 0x9E), 0x0B);
std::string artist = std::string(reinterpret_cast<const char *>(data + 0xB1), 0x20); std::string artist = std::string(reinterpret_cast<const char *>(data + 0xB1), 0x20);
this->_internalRegisters.pcl = cartridge->read(0x25); this->_internalRegisters.pcl = cartridge.read(0x25);
this->_internalRegisters.pch = cartridge->read(0x26); this->_internalRegisters.pch = cartridge.read(0x26);
this->_internalRegisters.a = cartridge->read(0x27); this->_internalRegisters.a = cartridge.read(0x27);
this->_internalRegisters.x = cartridge->read(0x28); this->_internalRegisters.x = cartridge.read(0x28);
this->_internalRegisters.y = cartridge->read(0x29); this->_internalRegisters.y = cartridge.read(0x29);
this->_internalRegisters.psw = cartridge->read(0x2A); this->_internalRegisters.psw = cartridge.read(0x2A);
this->_internalRegisters.sp = cartridge->read(0x2B); this->_internalRegisters.sp = cartridge.read(0x2B);
std::memcpy(this->_map->Page0.getData(), data + 0x100, this->_map->Page0.getSize()); 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->Page1.getData(), data + 0x200, this->_map->Page1.getSize());
std::memcpy(this->_map->Memory.getData(), data + 0x300, this->_map->Memory.getSize()); std::memcpy(this->_map->Memory.getData(), data + 0x300, this->_map->Memory.getSize());
this->_registers.unknown = cartridge->read(0x100 + 0xF0); this->_registers.unknown = cartridge.read(0x100 + 0xF0);
this->_registers.ctrlreg = cartridge->read(0x100 + 0xF1); this->_registers.ctrlreg = cartridge.read(0x100 + 0xF1);
this->_registers.dspregAddr = cartridge->read(0x100 + 0xF2); this->_registers.dspregAddr = cartridge.read(0x100 + 0xF2);
this->_dsp.write(this->_registers.dspregAddr, cartridge->read(0x100 + 0xF3)); this->_dsp.write(this->_registers.dspregAddr, cartridge.read(0x100 + 0xF3));
this->_registers.port0 = cartridge->read(0x100 + 0xF4); this->_registers.port0 = cartridge.read(0x100 + 0xF4);
this->_registers.port1 = cartridge->read(0x100 + 0xF5); this->_registers.port1 = cartridge.read(0x100 + 0xF5);
this->_registers.port2 = cartridge->read(0x100 + 0xF6); this->_registers.port2 = cartridge.read(0x100 + 0xF6);
this->_registers.port3 = cartridge->read(0x100 + 0xF7); this->_registers.port3 = cartridge.read(0x100 + 0xF7);
this->_registers.regmem1 = cartridge->read(0x100 + 0xF8); this->_registers.regmem1 = cartridge.read(0x100 + 0xF8);
this->_registers.regmem2 = cartridge->read(0x100 + 0xF9); this->_registers.regmem2 = cartridge.read(0x100 + 0xF9);
this->_registers.timer0 = cartridge->read(0x100 + 0xFA); this->_registers.timer0 = cartridge.read(0x100 + 0xFA);
this->_registers.timer1 = cartridge->read(0x100 + 0xFB); this->_registers.timer1 = cartridge.read(0x100 + 0xFB);
this->_registers.timer2 = cartridge->read(0x100 + 0xFC); this->_registers.timer2 = cartridge.read(0x100 + 0xFC);
this->_registers.counter0 = cartridge->read(0x100 + 0xFD); this->_registers.counter0 = cartridge.read(0x100 + 0xFD);
this->_registers.counter1 = cartridge->read(0x100 + 0xFE); this->_registers.counter1 = cartridge.read(0x100 + 0xFE);
this->_registers.counter2 = cartridge->read(0x100 + 0xFF); this->_registers.counter2 = cartridge.read(0x100 + 0xFF);
for (int i = 0x00; i < 0x80; i += 0x10) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) void APU::_setNZflags(uint8_t value)
@@ -902,10 +901,9 @@ namespace ComSquare::APU
this->_internalRegisters.z = !value; this->_internalRegisters.z = !value;
} }
MemoryMap::MemoryMap() : MemoryMap::MemoryMap() : Page0(0x00F0, Apu, "APU's Page 0"),
Page0(0x00F0, Apu, "APU's Page 0"),
Page1(0x0100, Apu, "APU's Page 1"), Page1(0x0100, Apu, "APU's Page 1"),
Memory(0xFDC0, Apu, "APU's Ram"), Memory(0xFDC0, Apu, "APU's Ram"),
IPL(Apu, "IPL Rom") IPL(Apu, "IPL Rom")
{ } {}
} }// namespace ComSquare::APU

View File

@@ -390,12 +390,16 @@ namespace ComSquare::APU
//! @brief Get the component of this accessor (used for debug purpose) //! @brief Get the component of this accessor (used for debug purpose)
Component getComponent() const override; 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. //! @brief Get the size of the data. This size can be lower than the mapped data.
//! @return The number of bytes inside this memory. //! @return The number of bytes inside this memory.
uint24_t getSize() const override; uint24_t getSize() const override;
//! @brief Parses rom data to uploads directly into RAM and corresponding registers //! @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. //! @brief This function execute the instructions received until the maximum number of cycles is reached.
//! @return The number of cycles that elapsed. //! @return The number of cycles that elapsed.

View File

@@ -4,18 +4,15 @@
#include "IPL.hpp" #include "IPL.hpp"
#include <utility>
#include "../../Exceptions/InvalidAddress.hpp" #include "../../Exceptions/InvalidAddress.hpp"
#include <utility>
namespace ComSquare::APU::IPL namespace ComSquare::APU::IPL
{ {
IPL::IPL(Component type, std::string iplName) IPL::IPL(Component type, std::string iplName)
: _iplType(type), : _iplType(type),
_iplName(std::move(iplName)) _iplName(std::move(iplName))
{ } {}
IPL::~IPL()
{ }
uint8_t IPL::read(uint24_t addr) uint8_t IPL::read(uint24_t addr)
{ {
@@ -45,4 +42,10 @@ namespace ComSquare::APU::IPL
{ {
return this->_iplType; return this->_iplType;
} }
}
std::string IPL::getValueName(uint24_t) const
{
// TODO implement this
return "???";
}
}// namespace ComSquare::APU::IPL

View File

@@ -2,10 +2,9 @@
// Created by Melefo on 27/02/2020. // Created by Melefo on 27/02/2020.
// //
#ifndef COMSQUARE_IPL_HPP #pragma once
#define COMSQUARE_IPL_HPP
#include "../../Memory/AMemory.hpp" #include "Memory/AMemory.hpp"
namespace ComSquare::APU::IPL namespace ComSquare::APU::IPL
{ {
@@ -31,15 +30,12 @@ namespace ComSquare::APU::IPL
public: public:
//! @brief Create the rom with its value. //! @brief Create the rom with its value.
explicit IPL(Component, std::string iplName); explicit IPL(Component, std::string iplName);
//! @brief The rom can't be copied. //! @brief The rom can't be copied.
IPL(const IPL &) = delete; IPL(const IPL &) = delete;
//! @brief The rom can't be assigned. //! @brief The rom can't be assigned.
IPL &operator=(IPL &) = delete; IPL &operator=(IPL &) = delete;
//! @brief A default destructor
//! @brief Destructor that free the rom. ~IPL() override = default;
~IPL();
//! @brief Read data from the component using the same method as the basic IMemory. //! @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. //! @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. //! @brief Get the size of the data. This size can be lower than the mapped data.
//! @return The number of bytes inside this memory. //! @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) //! @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) //! @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

View File

@@ -2,7 +2,7 @@
// Created by Melefo on 25/02/2020. // Created by Melefo on 25/02/2020.
// //
#include "../APU.hpp" #include "APU/APU.hpp"
namespace ComSquare::APU namespace ComSquare::APU
{ {
@@ -31,4 +31,9 @@ namespace ComSquare::APU
this->_setNZflags(this->_internalRegisters.a); this->_setNZflags(this->_internalRegisters.a);
return 3; return 3;
} }
std::string APU::getValueName(uint24_t) const
{
// TODO implement this
return "???";
}
} }

View File

@@ -64,8 +64,8 @@ namespace ComSquare::CPU
uint24_t CPU::_getDirectIndirectIndexedYAddr() uint24_t CPU::_getDirectIndirectIndexedYAddr()
{ {
uint16_t dp = this->readPC() + this->_registers.d; uint16_t dp = this->readPC() + this->_registers.d;
uint24_t base = this->_bus->read(dp); uint24_t base = this->_bus.read(dp);
base += this->_bus->read(dp + 1) << 8u; base += this->_bus.read(dp + 1) << 8u;
base += this->_registers.dbr << 16u; base += this->_registers.dbr << 16u;
if ((base & 0x80000000u) == (((base + this->_registers.y) & 0x80000000u))) if ((base & 0x80000000u) == (((base + this->_registers.y) & 0x80000000u)))
this->_hasIndexCrossedPageBoundary = true; this->_hasIndexCrossedPageBoundary = true;
@@ -75,9 +75,9 @@ namespace ComSquare::CPU
uint24_t CPU::_getDirectIndirectIndexedYLongAddr() uint24_t CPU::_getDirectIndirectIndexedYLongAddr()
{ {
uint16_t dp = this->readPC() + this->_registers.d; uint16_t dp = this->readPC() + this->_registers.d;
uint24_t base = this->_bus->read(dp); uint24_t base = this->_bus.read(dp);
base += this->_bus->read(dp + 1) << 8u; base += this->_bus.read(dp + 1) << 8u;
base += this->_bus->read(dp + 2) << 16u; base += this->_bus.read(dp + 2) << 16u;
return base; return base;
} }
@@ -85,8 +85,8 @@ namespace ComSquare::CPU
{ {
uint16_t dp = this->readPC() + this->_registers.d; uint16_t dp = this->readPC() + this->_registers.d;
dp += this->_registers.x; dp += this->_registers.x;
uint24_t base = this->_bus->read(dp); uint24_t base = this->_bus.read(dp);
base += this->_bus->read(dp + 1) << 8u; base += this->_bus.read(dp + 1) << 8u;
base += this->_registers.dbr << 16u; base += this->_registers.dbr << 16u;
return base; return base;
} }
@@ -137,8 +137,8 @@ namespace ComSquare::CPU
{ {
uint16_t abs = this->readPC(); uint16_t abs = this->readPC();
abs += this->readPC() << 8u; abs += this->readPC() << 8u;
uint24_t effective = this->_bus->read(abs); uint24_t effective = this->_bus.read(abs);
effective += this->_bus->read(abs + 1) << 8u; effective += this->_bus.read(abs + 1) << 8u;
return effective; return effective;
} }
@@ -146,9 +146,9 @@ namespace ComSquare::CPU
{ {
uint16_t abs = this->readPC(); uint16_t abs = this->readPC();
abs += this->readPC() << 8u; abs += this->readPC() << 8u;
uint24_t effective = this->_bus->read(abs); uint24_t effective = this->_bus.read(abs);
effective += this->_bus->read(abs + 1) << 8u; effective += this->_bus.read(abs + 1) << 8u;
effective += this->_bus->read(abs + 2) << 16u; effective += this->_bus.read(abs + 2) << 16u;
return effective; return effective;
} }
@@ -157,16 +157,16 @@ namespace ComSquare::CPU
uint24_t abs = this->readPC(); uint24_t abs = this->readPC();
abs += this->readPC() << 8u; abs += this->readPC() << 8u;
abs += this->_registers.x; abs += this->_registers.x;
uint24_t effective = this->_bus->read(abs); uint24_t effective = this->_bus.read(abs);
effective += this->_bus->read(abs + 1) << 8u; effective += this->_bus.read(abs + 1) << 8u;
return effective; return effective;
} }
uint24_t CPU::_getDirectIndirectAddr() uint24_t CPU::_getDirectIndirectAddr()
{ {
uint16_t dp = this->readPC() + this->_registers.d; uint16_t dp = this->readPC() + this->_registers.d;
uint24_t effective = this->_bus->read(dp); uint24_t effective = this->_bus.read(dp);
effective += this->_bus->read(dp + 1) << 8u; effective += this->_bus.read(dp + 1) << 8u;
effective += this->_registers.dbr << 16u; effective += this->_registers.dbr << 16u;
return effective; return effective;
} }
@@ -174,9 +174,9 @@ namespace ComSquare::CPU
uint24_t CPU::_getDirectIndirectLongAddr() uint24_t CPU::_getDirectIndirectLongAddr()
{ {
uint16_t dp = this->readPC() + this->_registers.d; uint16_t dp = this->readPC() + this->_registers.d;
uint24_t effective = this->_bus->read(dp); uint24_t effective = this->_bus.read(dp);
effective += this->_bus->read(++dp) << 8u; effective += this->_bus.read(++dp) << 8u;
effective += this->_bus->read(++dp) << 16u; effective += this->_bus.read(++dp) << 16u;
return effective; return effective;
} }

View File

@@ -3,32 +3,21 @@
// //
#include "CPU.hpp" #include "CPU.hpp"
#include "Exceptions/InvalidAddress.hpp"
#include <utility> #include "Exceptions/InvalidOpcode.hpp"
#include "Utility/Utility.hpp"
#include <iostream> #include <iostream>
#include "../Exceptions/InvalidAddress.hpp"
#include "../Exceptions/InvalidOpcode.hpp"
namespace ComSquare::CPU namespace ComSquare::CPU
{ {
CPU::CPU(std::shared_ptr<Memory::MemoryBus> bus, Cartridge::Header &cartridgeHeader) CPU::CPU(Memory::MemoryBus &bus, Cartridge::Header &cartridgeHeader)
: _bus(std::move(bus)), : _bus(bus),
_cartridgeHeader(cartridgeHeader) _cartridgeHeader(cartridgeHeader),
_dmaChannels({DMA(bus), DMA(bus), DMA(bus), DMA(bus), DMA(bus), DMA(bus), DMA(bus), DMA(bus)})
{ {
this->RESB(); 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. //! @bref The CPU's internal registers starts at $4200 and finish at $421F.
uint8_t CPU::read(uint24_t addr) uint8_t CPU::read(uint24_t addr)
@@ -214,7 +203,7 @@ namespace ComSquare::CPU
uint8_t CPU::readPC() 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++; this->_registers.pc++;
return ret; return ret;
} }
@@ -333,24 +322,24 @@ namespace ComSquare::CPU
void CPU::_push(uint8_t data) 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) void CPU::_push(uint16_t data)
{ {
this->_bus->write(this->_registers.s--, data >> 8u); this->_bus.write(this->_registers.s--, data >> 8u);
this->_bus->write(this->_registers.s--, data); this->_bus.write(this->_registers.s--, data);
} }
uint8_t CPU::_pop() uint8_t CPU::_pop()
{ {
return this->_bus->read(++this->_registers.s); return this->_bus.read(++this->_registers.s);
} }
uint16_t CPU::_pop16() uint16_t CPU::_pop16()
{ {
uint16_t value = this->_bus->read(++this->_registers.s); uint16_t value = this->_bus.read(++this->_registers.s);
value +=this->_bus->read(++this->_registers.s) << 8u; value += this->_bus.read(++this->_registers.s) << 8u;
return value; return value;
} }
@@ -363,4 +352,4 @@ namespace ComSquare::CPU
{ {
return Cpu; return Cpu;
} }
} }// namespace ComSquare::CPU

View File

@@ -2,8 +2,7 @@
// Created by anonymus-raccoon on 1/24/20. // Created by anonymus-raccoon on 1/24/20.
// //
#ifndef COMSQUARE_CPU_HPP #pragma once
#define COMSQUARE_CPU_HPP
#include "Memory/AMemory.hpp" #include "Memory/AMemory.hpp"
#include "Memory/MemoryBus.hpp" #include "Memory/MemoryBus.hpp"
@@ -12,180 +11,21 @@
#include "Memory/AMemory.hpp" #include "Memory/AMemory.hpp"
#include "Instruction.hpp" #include "Instruction.hpp"
#include "DMA/DMA.hpp" #include "DMA/DMA.hpp"
#include "CPU/Registers.hpp"
#ifdef DEBUGGER_ENABLED
#include "Debugger/RegisterViewer.hpp"
#endif
namespace ComSquare::CPU 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 //! @brief The main CPU
class CPU : public Memory::AMemory { class CPU : public Memory::AMemory
{
protected: protected:
//! @brief All the registers of the CPU //! @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). //! @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) //! @brief Is the CPU running in emulation mode (in 8bits)
bool _isEmulationMode = true; bool _isEmulationMode = true;
@@ -195,8 +35,8 @@ namespace ComSquare::CPU
bool _isWaitingForInterrupt = false; bool _isWaitingForInterrupt = false;
//! @brief The memory bus to use for read/write. //! @brief The memory bus to use for read/write.
std::shared_ptr<Memory::MemoryBus> _bus; Memory::MemoryBus &_bus;
//! @brief The cartridge header (stored for interrupt vectors.. //! @brief The cartridge header (stored for interrupt vectors..)
Cartridge::Header &_cartridgeHeader; Cartridge::Header &_cartridgeHeader;
//! @brief DMA channels witch are mapped to the bus. //! @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. //! @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(); uint24_t _getStackRelativeIndirectIndexedYAddr();
//! @brief Push 8 bits of data to the stack. //! @brief Push 8 bits of data to the stack.
void _push(uint8_t data); void _push(uint8_t data);
//! @brief Push 16 bits of data to the stack. //! @brief Push 16 bits of data to the stack.
@@ -470,7 +309,7 @@ namespace ComSquare::CPU
//! @brief All the instructions of the CPU. //! @brief All the instructions of the CPU.
//! @info Instructions are indexed by their opcode //! @info Instructions are indexed by their opcode
Instruction _instructions[0x100] = { const Instruction _instructions[0x100] = {
{&CPU::BRK, 7, "brk", AddressingMode::Immediate8bits, 2}, // 00 {&CPU::BRK, 7, "brk", AddressingMode::Immediate8bits, 2}, // 00
{&CPU::ORA, 6, "ora", AddressingMode::DirectPageIndirectIndexedByX, 2}, // 01 {&CPU::ORA, 6, "ora", AddressingMode::DirectPageIndirectIndexedByX, 2}, // 01
{&CPU::COP, 7, "cop", AddressingMode::Immediate8bits, 2}, // 02 {&CPU::COP, 7, "cop", AddressingMode::Immediate8bits, 2}, // 02
@@ -729,14 +568,20 @@ namespace ComSquare::CPU
{&CPU::SBC, 5, "sbc", AddressingMode::AbsoluteIndexedByXLong, 4}, // FF {&CPU::SBC, 5, "sbc", AddressingMode::AbsoluteIndexedByXLong, 4}, // FF
}; };
public: 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; CPU(const CPU &) = default;
//! @brief A CPU is not assignable
CPU &operator=(const CPU &) = delete; CPU &operator=(const CPU &) = delete;
//! @brief A default destructor
~CPU() override = default; ~CPU() override = default;
//! @brief This function continue to execute the Cartridge code. //! @brief This function continue to execute the Cartridge code.
//! @return The number of CPU cycles that elapsed //! @return The number of CPU cycles that elapsed
virtual unsigned update(); unsigned update();
//! @brief Read from the internal CPU register. //! @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. //! @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). //! @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). //! @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; 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. //! @brief Get the size of the data. This size can be lower than the mapped data.
//! @return The number of bytes inside this memory. //! @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) //! @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) //! @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. //! @copydoc
virtual int RESB(); int RESB();
//! @brief Is an NMI (non-maskable interrupt) requested. //! @brief Is an NMI (non-maskable interrupt) requested.
bool IsNMIRequested = false; bool IsNMIRequested = false;
@@ -768,16 +617,8 @@ namespace ComSquare::CPU
//! @brief Is an abort requested //! @brief Is an abort requested
bool IsAbortRequested = false; bool IsAbortRequested = false;
//! @brief Return true if the CPU is overloaded with debugging features. #ifdef DEBUGGER_ENABLED
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
friend Debugger::RegisterViewer; friend Debugger::RegisterViewer;
#endif #endif
}; };
} }
#endif //COMSQUARE_CPU_HPP

View File

@@ -2,18 +2,15 @@
// Created by anonymus-raccoon on 5/26/20. // Created by anonymus-raccoon on 5/26/20.
// //
#include <iostream>
#include "DMA.hpp" #include "DMA.hpp"
#include "../../Exceptions/InvalidAddress.hpp" #include "Exceptions/InvalidAddress.hpp"
namespace ComSquare::CPU namespace ComSquare::CPU
{ {
DMA::DMA(std::shared_ptr<Memory::MemoryBus> bus) : _bus(std::move(bus)) {} DMA::DMA(Memory::MemoryBus &bus)
: _bus(bus),
void DMA::setBus(std::shared_ptr<Memory::MemoryBus> bus) enabled(false)
{ {}
this->_bus = std::move(bus);
}
uint8_t DMA::read(uint8_t addr) const uint8_t DMA::read(uint8_t addr) const
{ {
@@ -68,24 +65,25 @@ namespace ComSquare::CPU
unsigned DMA::_writeOneByte(uint24_t aAddress, uint24_t bAddress) 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) { if (this->_port == 0x80) {
auto accessor = this->_bus->getAccessor(aAddress); auto accessor = this->_bus.getAccessor(aAddress);
if (accessor && accessor->getComponent() == WRam) { if (accessor && accessor->getComponent() == WRam) {
// WRAM->$2180 The write is not performed but the time is consumed anyway. // WRAM->$2180 The write is not performed but the time is consumed anyway.
if (this->_controlRegister.direction == AtoB) if (this->_controlRegister.direction == AtoB)
return 8; return 8;
// $2180->WRAM No read is performed (so only 4 master cycles are needed) but the value written is invalid. // $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; return 4;
} }
} }
if (this->_controlRegister.direction == AtoB) { if (this->_controlRegister.direction == AtoB) {
uint8_t data = this->_bus->read(aAddress); uint8_t data = this->_bus.read(aAddress);
this->_bus->write(bAddress, data); this->_bus.write(bAddress, data);
} else { } else {
uint8_t data = this->_bus->read(bAddress); uint8_t data = this->_bus.read(bAddress);
this->_bus->write(aAddress, data); this->_bus.write(aAddress, data);
} }
return 8; return 8;
} }
@@ -106,7 +104,7 @@ namespace ComSquare::CPU
return cycles; return cycles;
} }
int DMA::_getModeOffset(int index) int DMA::_getModeOffset(int index) const
{ {
switch (this->_controlRegister.mode) { switch (this->_controlRegister.mode) {
case OneToOne: case OneToOne:
@@ -127,4 +125,4 @@ namespace ComSquare::CPU
} }
return 0; return 0;
} }
} }// namespace ComSquare::CPU

View File

@@ -2,25 +2,26 @@
// Created by anonymus-raccoon on 5/26/20. // Created by anonymus-raccoon on 5/26/20.
// //
#ifndef COMSQUARE_DMA_HPP #pragma once
#define COMSQUARE_DMA_HPP
#include "Memory/MemoryBus.hpp"
#include "Models/Int24.hpp"
#include <cstdint> #include <cstdint>
#include <memory> #include <memory>
#include "../../Models/Int24.hpp"
#include "../../Memory/MemoryBus.hpp"
#ifdef DEBUGGER_ENABLED #ifdef DEBUGGER_ENABLED
#include "../../Debugger/RegisterViewer.hpp" #include "Debugger/RegisterViewer.hpp"
#endif #endif
namespace ComSquare::CPU namespace ComSquare::CPU
{ {
//! @brief Class handling all DMA/HDMA transfers (Direct Memory Access or H-Blank Direct Memory Access) //! @brief Class handling all DMA/HDMA transfers (Direct Memory Access or H-Blank Direct Memory Access)
class DMA { class DMA
{
public: public:
//! @brief The first three bytes of the DMA's control register. Used to tell how many bytes/registers there is. //! @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) //! @brief 1 byte is transferred to 1 register (write once)
OneToOne = 0b000, OneToOne = 0b000,
//! @brief 2 byte is transferred to 2 register (write once) //! @brief 2 byte is transferred to 2 register (write once)
@@ -39,63 +40,73 @@ namespace ComSquare::CPU
FourToTwoBis = 0b111 FourToTwoBis = 0b111
}; };
enum Direction { enum Direction
{
AtoB, AtoB,
BtoA BtoA
}; };
private: private:
//! @brief Write one byte using the A address, the port and the _direction. Handle special cases where no write occurs. //! @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. //! @return The number of cycles used.
unsigned _writeOneByte(uint24_t aAddress, uint24_t bAddress); 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. //! @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) //! @brief DMA Control register (various information about the transfer)
union { union
{
struct { struct {
//! @brief DMA's mode: how many bytes/registers there is, how many writes... //! @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. //! @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) //! @brief if this flag is 0: increment. Else: decrement. (The A address)
bool increment: 1; bool increment : 1;
//! @brief Two unused bites. //! @brief Two unused bites.
bool _: 2; bool _ : 2;
//! @brief The direction of the transfer. //! @brief The direction of the transfer.
Direction direction: 1; Direction direction : 1;
}; };
uint8_t raw; uint8_t raw;
} _controlRegister; } _controlRegister {};
//! @brief If this is 'xx', the register accessed will be $21xx. //! @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. //! @brief The absolute long address of the data from the A bus.
union { union
{
uint8_t bytes[3]; uint8_t bytes[3];
struct { struct {
uint16_t page; uint16_t page;
uint8_t bank; uint8_t bank;
}; };
uint24_t raw: 24; uint24_t raw : 24;
} _aAddress; } _aAddress {};
//! @brief The number of bytes to be transferred. //! @brief The number of bytes to be transferred.
union { union
{
uint8_t bytes[2]; uint8_t bytes[2];
uint16_t raw; uint16_t raw;
} _count; } _count {};
//! @brief The memory bus to use for read/write. //! @brief The memory bus to use for read/write.
std::shared_ptr<Memory::MemoryBus> _bus; Memory::MemoryBus &_bus;
public: public:
//! @brief Is this channel set to run? //! @brief Is this channel set to run?
bool enabled; 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. //! @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. //! @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); void write(uint8_t addr, uint8_t data);
//! @brief Run the DMA for x cycles //! @brief Run the DMA for x cycles
@@ -103,16 +114,18 @@ namespace ComSquare::CPU
//! @return the number of cycles taken //! @return the number of cycles taken
unsigned run(unsigned cycles); unsigned run(unsigned cycles);
DMA() = default; //! @brief Create a DMA channel with a given bus
DMA(std::shared_ptr<Memory::MemoryBus> bus); //! @param bus The memory bus to use.
explicit DMA(Memory::MemoryBus &bus);
//! @brief A DMA is copy constructable.
DMA(const DMA &) = default; 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; ~DMA() = default;
#ifdef DEBUGGER_ENABLED #ifdef DEBUGGER_ENABLED
friend Debugger::RegisterViewer; friend Debugger::RegisterViewer;
#endif #endif
}; };
} }// namespace ComSquare::CPU
#endif //COMSQUARE_DMA_HPP

View File

@@ -10,13 +10,13 @@ namespace ComSquare::CPU
{ {
int CPU::TSB(uint24_t valueAddr, AddressingMode mode) 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) if (!this->_registers.p.m)
value += this->_bus->read(valueAddr + 1) << 8u; value += this->_bus.read(valueAddr + 1) << 8u;
value |= this->_registers.a; value |= this->_registers.a;
this->_bus->write(valueAddr, value); this->_bus.write(valueAddr, value);
if (!this->_registers.p.m) 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; this->_registers.p.z = value == 0;
@@ -30,14 +30,14 @@ namespace ComSquare::CPU
int CPU::TRB(uint24_t valueAddr, AddressingMode mode) 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) 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; uint16_t newValue = value & ~this->_registers.a;
this->_bus->write(valueAddr, newValue); this->_bus.write(valueAddr, newValue);
if (!this->_registers.p.m) 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; this->_registers.p.z = (value & this->_registers.a) == 0;
@@ -52,9 +52,9 @@ namespace ComSquare::CPU
int CPU::BIT(uint24_t valueAddr, AddressingMode mode) int CPU::BIT(uint24_t valueAddr, AddressingMode mode)
{ {
unsigned negativeMask = this->_registers.p.m ? 0x80u : 0x8000u; 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) if (!this->_registers.p.m)
value += this->_bus->read(valueAddr + 1) << 8u; value += this->_bus.read(valueAddr + 1) << 8u;
if (mode != ImmediateForA) { if (mode != ImmediateForA) {
this->_registers.p.n = value & negativeMask; this->_registers.p.n = value & negativeMask;
@@ -89,18 +89,18 @@ namespace ComSquare::CPU
return 0; return 0;
} }
uint16_t value = this->_bus->read(valueAddr); uint16_t value = this->_bus.read(valueAddr);
if (!this->_registers.p.m) 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; this->_registers.p.c = value & highByte;
value <<= 1u; value <<= 1u;
this->_registers.p.n = value & highByte; this->_registers.p.n = value & highByte;
this->_registers.p.z = value == 0; this->_registers.p.z = value == 0;
this->_bus->write(valueAddr, value); this->_bus.write(valueAddr, value);
if (!this->_registers.p.m) 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; int cycles = 2 * !this->_registers.p.m;
switch (mode) { switch (mode) {
@@ -128,17 +128,17 @@ namespace ComSquare::CPU
return 0; return 0;
} }
uint16_t value = this->_bus->read(valueAddr); uint16_t value = this->_bus.read(valueAddr);
if (!this->_registers.p.m) 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; this->_registers.p.c = value & 1u;
value >>= 1u; value >>= 1u;
this->_registers.p.z = value == 0; this->_registers.p.z = value == 0;
this->_bus->write(valueAddr, value); this->_bus.write(valueAddr, value);
if (!this->_registers.p.m) 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; int cycles = 2 * !this->_registers.p.m;
switch (mode) { switch (mode) {
@@ -169,9 +169,9 @@ namespace ComSquare::CPU
return 0; return 0;
} }
uint16_t value = this->_bus->read(valueAddr); uint16_t value = this->_bus.read(valueAddr);
if (!this->_registers.p.m) 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; this->_registers.p.c = value & highByte;
value <<= 1u; value <<= 1u;
@@ -179,9 +179,9 @@ namespace ComSquare::CPU
this->_registers.p.n = value & highByte; this->_registers.p.n = value & highByte;
this->_registers.p.z = value == 0; this->_registers.p.z = value == 0;
this->_bus->write(valueAddr, value); this->_bus.write(valueAddr, value);
if (!this->_registers.p.m) 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; int cycles = 2 * !this->_registers.p.m;
switch (mode) { switch (mode) {
@@ -212,18 +212,18 @@ namespace ComSquare::CPU
return 0; return 0;
} }
uint16_t value = this->_bus->read(valueAddr); uint16_t value = this->_bus.read(valueAddr);
if (!this->_registers.p.m) 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; this->_registers.p.c = value & 1u;
value >>= 1u; value >>= 1u;
value |= oldCarry << highByteIndex; value |= oldCarry << highByteIndex;
this->_registers.p.z = value == 0; this->_registers.p.z = value == 0;
this->_bus->write(valueAddr, value); this->_bus.write(valueAddr, value);
if (!this->_registers.p.m) 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; int cycles = 2 * !this->_registers.p.m;
switch (mode) { switch (mode) {

View File

@@ -50,13 +50,13 @@ namespace ComSquare::CPU
int CPU::SEP(uint24_t valueAddr, AddressingMode) 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; return 0;
} }
int CPU::REP(uint24_t valueAddr, AddressingMode) 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) { if (this->_isEmulationMode) {
this->_registers.p.x_b = true; this->_registers.p.x_b = true;
this->_registers.p.m = true; this->_registers.p.m = true;
@@ -189,8 +189,8 @@ namespace ComSquare::CPU
int CPU::PER(uint24_t valueAddr, AddressingMode) int CPU::PER(uint24_t valueAddr, AddressingMode)
{ {
uint16_t value = this->_bus->read(valueAddr); uint16_t value = this->_bus.read(valueAddr);
value += this->_bus->read(valueAddr + 1) << 8u; value += this->_bus.read(valueAddr + 1) << 8u;
value += this->_registers.pc; value += this->_registers.pc;
this->_push(value); this->_push(value);
return 0; return 0;
@@ -226,55 +226,55 @@ namespace ComSquare::CPU
int CPU::BCC(uint24_t valueAddr, AddressingMode) int CPU::BCC(uint24_t valueAddr, AddressingMode)
{ {
if (!this->_registers.p.c) 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; return !this->_registers.p.c + this->_isEmulationMode;
} }
int CPU::BCS(uint24_t valueAddr, AddressingMode) int CPU::BCS(uint24_t valueAddr, AddressingMode)
{ {
if (this->_registers.p.c) 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; return this->_registers.p.c + this->_isEmulationMode;
} }
int CPU::BEQ(uint24_t valueAddr, AddressingMode) int CPU::BEQ(uint24_t valueAddr, AddressingMode)
{ {
if (this->_registers.p.z) 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; return this->_registers.p.z + this->_isEmulationMode;
} }
int CPU::BNE(uint24_t valueAddr, AddressingMode) int CPU::BNE(uint24_t valueAddr, AddressingMode)
{ {
if (!this->_registers.p.z) 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; return !this->_registers.p.z + this->_isEmulationMode;
} }
int CPU::BMI(uint24_t valueAddr, AddressingMode) int CPU::BMI(uint24_t valueAddr, AddressingMode)
{ {
if (this->_registers.p.n) 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; return this->_registers.p.n + this->_isEmulationMode;
} }
int CPU::BPL(uint24_t valueAddr, AddressingMode) int CPU::BPL(uint24_t valueAddr, AddressingMode)
{ {
if (!this->_registers.p.n) 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; return !this->_registers.p.n + this->_isEmulationMode;
} }
int CPU::BRA(uint24_t valueAddr, AddressingMode) 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; return this->_isEmulationMode;
} }
int CPU::BRL(uint24_t valueAddr, AddressingMode) int CPU::BRL(uint24_t valueAddr, AddressingMode)
{ {
unsigned value = this->_bus->read(valueAddr); unsigned value = this->_bus.read(valueAddr);
value += this->_bus->read(valueAddr + 1) << 8u; value += this->_bus.read(valueAddr + 1) << 8u;
this->_registers.pc += static_cast<int16_t>(value); this->_registers.pc += static_cast<int16_t>(value);
return 0; return 0;
@@ -283,14 +283,14 @@ namespace ComSquare::CPU
int CPU::BVC(uint24_t valueAddr, AddressingMode) int CPU::BVC(uint24_t valueAddr, AddressingMode)
{ {
if (!this->_registers.p.v) 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; return !this->_registers.p.v + this->_isEmulationMode;
} }
int CPU::BVS(uint24_t valueAddr, AddressingMode) int CPU::BVS(uint24_t valueAddr, AddressingMode)
{ {
if (this->_registers.p.v) 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; return this->_registers.p.v + this->_isEmulationMode;
} }

View File

@@ -9,9 +9,9 @@ namespace ComSquare::CPU
{ {
int CPU::ADC(uint24_t valueAddr, AddressingMode mode) 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) 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 negativeMask = this->_registers.p.m ? 0x80u : 0x8000u;
unsigned maxValue = this->_registers.p.m ? UINT8_MAX : UINT16_MAX; 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) int CPU::SBC(uint24_t valueAddr, AddressingMode mode)
{ {
unsigned negativeMask = this->_registers.p.m ? 0x80u : 0x8000u; 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) 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; bool oldCarry = this->_registers.p.c;
this->_registers.p.c = this->_registers.a >= value; this->_registers.p.c = this->_registers.a >= value;
@@ -94,9 +94,9 @@ namespace ComSquare::CPU
int CPU::ORA(uint24_t valueAddr, AddressingMode mode) int CPU::ORA(uint24_t valueAddr, AddressingMode mode)
{ {
unsigned negativeMask = this->_registers.p.m ? 0x80u : 0x8000u; 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) 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.a |= value;
this->_registers.p.z = this->_registers.a == 0; this->_registers.p.z = this->_registers.a == 0;
this->_registers.p.n = this->_registers.a & negativeMask; this->_registers.p.n = this->_registers.a & negativeMask;
@@ -151,9 +151,9 @@ namespace ComSquare::CPU
int CPU::CMP(uint24_t valueAddr, AddressingMode mode) int CPU::CMP(uint24_t valueAddr, AddressingMode mode)
{ {
unsigned negativeMask = this->_registers.p.m ? 0x80u : 0x8000u; 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) 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; unsigned result = this->_registers.a - value;
if (this->_registers.p.m) if (this->_registers.p.m)
result %= 0x100; result %= 0x100;
@@ -214,7 +214,7 @@ namespace ComSquare::CPU
int CPU::CPX(uint24_t valueAddr, AddressingMode mode) 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) { if (this->_registers.p.x_b) {
uint8_t x = this->_registers.x; uint8_t x = this->_registers.x;
@@ -222,7 +222,7 @@ namespace ComSquare::CPU
this->_registers.p.z = x == 0; this->_registers.p.z = x == 0;
this->_registers.p.n = x & 0x80u; this->_registers.p.n = x & 0x80u;
} else { } else {
value += this->_bus->read(valueAddr) << 8u; value += this->_bus.read(valueAddr) << 8u;
uint16_t x = this->_registers.x; uint16_t x = this->_registers.x;
x -= value; x -= value;
this->_registers.p.z = x == 0; this->_registers.p.z = x == 0;
@@ -234,7 +234,7 @@ namespace ComSquare::CPU
int CPU::CPY(uint24_t valueAddr, AddressingMode mode) 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; this->_registers.p.c = this->_registers.y >= value;
if (this->_registers.p.x_b) { if (this->_registers.p.x_b) {
@@ -243,7 +243,7 @@ namespace ComSquare::CPU
this->_registers.p.z = y == 0; this->_registers.p.z = y == 0;
this->_registers.p.n = y & 0x80u; this->_registers.p.n = y & 0x80u;
} else { } else {
value += this->_bus->read(valueAddr) << 8u; value += this->_bus.read(valueAddr) << 8u;
uint16_t y = this->_registers.y; uint16_t y = this->_registers.y;
y -= value; y -= value;
this->_registers.p.z = y == 0; this->_registers.p.z = y == 0;
@@ -255,9 +255,9 @@ namespace ComSquare::CPU
int CPU::AND(uint24_t valueAddr, AddressingMode mode) int CPU::AND(uint24_t valueAddr, AddressingMode mode)
{ {
unsigned negativeMask = this->_registers.p.m ? 0x80u : 0x8000u; 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) 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.a &= value;
this->_registers.p.n = this->_registers.a & negativeMask; this->_registers.p.n = this->_registers.a & negativeMask;
@@ -297,15 +297,15 @@ namespace ComSquare::CPU
this->_registers.ah = 0; this->_registers.ah = 0;
result = this->_registers.a; result = this->_registers.a;
} else if (!this->_registers.p.m) { } else if (!this->_registers.p.m) {
result = this->_bus->read(valueAddr); result = this->_bus.read(valueAddr);
result += this->_bus->read(valueAddr + 1) << 8u; result += this->_bus.read(valueAddr + 1) << 8u;
result = (uint16_t)(result + 1); result = (uint16_t)(result + 1);
this->_bus->write(valueAddr, result); this->_bus.write(valueAddr, result);
this->_bus->write(valueAddr + 1, result << 8u); this->_bus.write(valueAddr + 1, result << 8u);
} else { } else {
result = this->_bus->read(valueAddr); result = this->_bus.read(valueAddr);
result = (uint8_t)(result + 1); result = (uint8_t)(result + 1);
this->_bus->write(valueAddr, result); this->_bus.write(valueAddr, result);
} }
this->_registers.p.z = result == 0; this->_registers.p.z = result == 0;
@@ -337,15 +337,15 @@ namespace ComSquare::CPU
this->_registers.ah = 0; this->_registers.ah = 0;
result = this->_registers.a; result = this->_registers.a;
} else if (!this->_registers.p.m) { } else if (!this->_registers.p.m) {
result = this->_bus->read(valueAddr); result = this->_bus.read(valueAddr);
result += this->_bus->read(valueAddr + 1) << 8u; result += this->_bus.read(valueAddr + 1) << 8u;
result = (uint16_t)(result - 1); result = (uint16_t)(result - 1);
this->_bus->write(valueAddr, result); this->_bus.write(valueAddr, result);
this->_bus->write(valueAddr + 1, result << 8u); this->_bus.write(valueAddr + 1, result << 8u);
} else { } else {
result = this->_bus->read(valueAddr); result = this->_bus.read(valueAddr);
result = (uint8_t)(result - 1); result = (uint8_t)(result - 1);
this->_bus->write(valueAddr, result); this->_bus.write(valueAddr, result);
} }
this->_registers.p.z = result == 0; this->_registers.p.z = result == 0;
@@ -369,9 +369,9 @@ namespace ComSquare::CPU
int CPU::EOR(uint24_t valueAddr, AddressingMode mode) int CPU::EOR(uint24_t valueAddr, AddressingMode mode)
{ {
unsigned negativeMask = this->_registers.p.m ? 0x80u : 0x8000u; 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) 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.a ^= value;
this->_registers.p.z = this->_registers.a == 0; this->_registers.p.z = this->_registers.a == 0;
this->_registers.p.n = this->_registers.a & negativeMask; this->_registers.p.n = this->_registers.a & negativeMask;

View File

@@ -9,10 +9,10 @@ namespace ComSquare::CPU
int CPU::STA(uint24_t addr, AddressingMode mode) int CPU::STA(uint24_t addr, AddressingMode mode)
{ {
if (this->_registers.p.m) if (this->_registers.p.m)
this->_bus->write(addr, this->_registers.al); this->_bus.write(addr, this->_registers.al);
else { else {
this->_bus->write(addr, this->_registers.al); this->_bus.write(addr, this->_registers.al);
this->_bus->write(addr + 1, this->_registers.ah); this->_bus.write(addr + 1, this->_registers.ah);
} }
int cycles = !this->_registers.p.m; int cycles = !this->_registers.p.m;
@@ -34,10 +34,10 @@ namespace ComSquare::CPU
int CPU::STX(uint24_t addr, AddressingMode mode) int CPU::STX(uint24_t addr, AddressingMode mode)
{ {
if (this->_registers.p.x_b) if (this->_registers.p.x_b)
this->_bus->write(addr, this->_registers.xl); this->_bus.write(addr, this->_registers.xl);
else { else {
this->_bus->write(addr, this->_registers.xl); this->_bus.write(addr, this->_registers.xl);
this->_bus->write(addr + 1, this->_registers.xh); this->_bus.write(addr + 1, this->_registers.xh);
} }
return !this->_registers.p.x_b + (mode != Absolute && this->_registers.dl != 0); 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) int CPU::STY(uint24_t addr, AddressingMode mode)
{ {
if (this->_registers.p.x_b) if (this->_registers.p.x_b)
this->_bus->write(addr, this->_registers.yl); this->_bus.write(addr, this->_registers.yl);
else { else {
this->_bus->write(addr, this->_registers.yl); this->_bus.write(addr, this->_registers.yl);
this->_bus->write(addr + 1, this->_registers.yh); this->_bus.write(addr + 1, this->_registers.yh);
} }
return !this->_registers.p.x_b + (mode != Absolute && this->_registers.dl != 0); return !this->_registers.p.x_b + (mode != Absolute && this->_registers.dl != 0);
} }
int CPU::STZ(uint24_t addr, AddressingMode mode) int CPU::STZ(uint24_t addr, AddressingMode mode)
{ {
this->_bus->write(addr, 0x00); this->_bus.write(addr, 0x00);
if (!this->_registers.p.m) if (!this->_registers.p.m)
this->_bus->write(addr + 1, 0x00); this->_bus.write(addr + 1, 0x00);
if (mode == Absolute || mode == AbsoluteIndexedByX) if (mode == Absolute || mode == AbsoluteIndexedByX)
return !this->_registers.p.m; return !this->_registers.p.m;
return !this->_registers.p.m + this->_registers.dl != 0; return !this->_registers.p.m + this->_registers.dl != 0;
@@ -66,11 +66,11 @@ namespace ComSquare::CPU
int CPU::LDA(uint24_t addr, AddressingMode mode) int CPU::LDA(uint24_t addr, AddressingMode mode)
{ {
if (this->_registers.p.m) { 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; this->_registers.p.n = this->_registers.al & 0xF0u;
} else { } else {
this->_registers.al = this->_bus->read(addr); this->_registers.al = this->_bus.read(addr);
this->_registers.ah = this->_bus->read(addr + 1); this->_registers.ah = this->_bus.read(addr + 1);
this->_registers.p.n = this->_registers.a & 0xF000u; this->_registers.p.n = this->_registers.a & 0xF000u;
} }
this->_registers.p.z = this->_registers.a == 0x0; this->_registers.p.z = this->_registers.a == 0x0;
@@ -101,11 +101,11 @@ namespace ComSquare::CPU
int CPU::LDX(uint24_t addr, AddressingMode mode) int CPU::LDX(uint24_t addr, AddressingMode mode)
{ {
if (this->_registers.p.x_b) { 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; this->_registers.p.n = this->_registers.xl & 0xF0u;
} else { } else {
this->_registers.xl = this->_bus->read(addr); this->_registers.xl = this->_bus.read(addr);
this->_registers.xh = this->_bus->read(addr + 1); this->_registers.xh = this->_bus.read(addr + 1);
this->_registers.p.n = this->_registers.x & 0xF000u; this->_registers.p.n = this->_registers.x & 0xF000u;
} }
this->_registers.p.z = this->_registers.x == 0x0; this->_registers.p.z = this->_registers.x == 0x0;
@@ -128,11 +128,11 @@ namespace ComSquare::CPU
int CPU::LDY(uint24_t addr, AddressingMode mode) int CPU::LDY(uint24_t addr, AddressingMode mode)
{ {
if (this->_registers.p.x_b) { 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; this->_registers.p.n = this->_registers.yl & 0xF0u;
} else { } else {
this->_registers.yl = this->_bus->read(addr); this->_registers.yl = this->_bus.read(addr);
this->_registers.yh = this->_bus->read(addr + 1); this->_registers.yh = this->_bus.read(addr + 1);
this->_registers.p.n = this->_registers.y & 0xF000u; this->_registers.p.n = this->_registers.y & 0xF000u;
} }
this->_registers.p.z = this->_registers.y == 0x0; this->_registers.p.z = this->_registers.y == 0x0;

View File

@@ -160,8 +160,8 @@ namespace ComSquare::CPU
this->_registers.dbr = destBank; this->_registers.dbr = destBank;
while (this->_registers.a != 0xFFFF) { while (this->_registers.a != 0xFFFF) {
uint8_t data = this->_bus->read(srcBank << 24u | this->_registers.x); uint8_t data = this->_bus.read(srcBank << 24u | this->_registers.x);
this->_bus->write(destBank << 24u | this->_registers.y, data); this->_bus.write(destBank << 24u | this->_registers.y, data);
this->_registers.x++; this->_registers.x++;
this->_registers.y++; this->_registers.y++;
this->_registers.a--; this->_registers.a--;
@@ -177,12 +177,18 @@ namespace ComSquare::CPU
this->_registers.dbr = destBank; this->_registers.dbr = destBank;
while (this->_registers.a != 0xFFFF) { while (this->_registers.a != 0xFFFF) {
uint8_t data = this->_bus->read(srcBank << 24u | this->_registers.x); uint8_t data = this->_bus.read(srcBank << 24u | this->_registers.x);
this->_bus->write(destBank << 24u | this->_registers.y, data); this->_bus.write(destBank << 24u | this->_registers.y, data);
this->_registers.x--; this->_registers.x--;
this->_registers.y--; this->_registers.y--;
this->_registers.a--; this->_registers.a--;
} }
return 7 * length; return 7 * length;
} }
std::string CPU::getValueName(uint24_t) const
{
// TODO implement this method
return "???";
}
} }

192
sources/CPU/Registers.hpp Normal file
View 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;
};
}

View File

@@ -2,28 +2,36 @@
// Created by anonymus-raccoon on 1/27/20. // Created by anonymus-raccoon on 1/27/20.
// //
#include <sys/stat.h>
#include <cstring>
#include "Cartridge.hpp" #include "Cartridge.hpp"
#include "../Exceptions/InvalidAddress.hpp" #include "Exceptions/InvalidAction.hpp"
#include "../Exceptions/InvalidRom.hpp" #include "Exceptions/InvalidAddress.hpp"
#include "../Exceptions/InvalidAction.hpp" #include "Exceptions/InvalidRom.hpp"
#include <cstring>
#include <fstream>
#include <sys/stat.h>
namespace ComSquare::Cartridge namespace ComSquare::Cartridge
{ {
constexpr unsigned HeaderSize = 0x40u; constexpr unsigned HeaderSize = 0x40u;
Cartridge::Cartridge()
: Ram::Ram(0, Rom, "Cartridge")
{}
Cartridge::Cartridge(const std::string &romPath) Cartridge::Cartridge(const std::string &romPath)
: Ram::Ram(0, Rom, "Cartridge"), : Ram::Ram(0, Rom, "Cartridge"),
_romPath(romPath) _romPath(romPath)
{ {
if (romPath.empty()) this->loadRom(romPath);
throw InvalidRomException("Path is empty."); }
size_t size = Cartridge::getRomSize(romPath);
FILE *rom = fopen(romPath.c_str(), "rb"); void Cartridge::loadRom(const std::string &path)
{
size_t size = Cartridge::getRomSize(path);
FILE *rom = fopen(path.c_str(), "rb");
if (!rom) 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->_size = size;
this->_data = new uint8_t[size]; this->_data = new uint8_t[size];
std::memset(this->_data, 0, size); std::memset(this->_data, 0, size);
@@ -133,25 +141,25 @@ namespace ComSquare::Cartridge
continue; continue;
uint8_t resetOpCode = this->_data[info.emulationInterrupts.reset - 0x8000u]; uint8_t resetOpCode = this->_data[info.emulationInterrupts.reset - 0x8000u];
switch (resetOpCode) { switch (resetOpCode) {
case 0x18: //CLI case 0x18://CLI
case 0x78: //SEI case 0x78://SEI
case 0x4C: //JMP case 0x4C://JMP
case 0x5C: //JMP case 0x5C://JMP
case 0x20: //JSR case 0x20://JSR
case 0x22: //JSL case 0x22://JSL
case 0x9C: //STZ case 0x9C://STZ
score+= 8; score += 8;
break; break;
case 0xC2: //REP case 0xC2://REP
case 0xE2: //SEP case 0xE2://SEP
case 0xA9: //LDA case 0xA9://LDA
case 0xA2: //LDX case 0xA2://LDX
case 0xA0: //LDY case 0xA0://LDY
score += 4; score += 4;
break; break;
case 0x00: //BRK case 0x00://BRK
case 0xFF: //SBC case 0xFF://SBC
case 0xCC: //CPY case 0xCC://CPY
score -= 8; score -= 8;
break; break;
default: default:
@@ -209,4 +217,4 @@ namespace ComSquare::Cartridge
{ {
return this->_type; return this->_type;
} }
} }// namespace ComSquare::Cartridge

View File

@@ -4,23 +4,25 @@
#pragma once #pragma once
#include <string>
#include <filesystem>
#include "Memory/AMemory.hpp"
#include "Models/Int24.hpp"
#include "Memory/ARectangleMemory.hpp"
#include "InterruptVectors.hpp" #include "InterruptVectors.hpp"
#include "Memory/AMemory.hpp"
#include "Memory/ARectangleMemory.hpp"
#include "Models/Int24.hpp"
#include "Ram/Ram.hpp" #include "Ram/Ram.hpp"
#include <filesystem>
#include <string>
namespace ComSquare::Cartridge namespace ComSquare::Cartridge
{ {
enum CartridgeType { enum CartridgeType
{
Game, Game,
Audio Audio
}; };
#define ADDMAPPINGMODE(x, flag) (x = static_cast<MappingMode>(x | (flag))) #define ADDMAPPINGMODE(x, flag) (x = static_cast<MappingMode>(x | (flag)))
enum MappingMode { enum MappingMode
{
LoRom = 1u << 0u, LoRom = 1u << 0u,
HiRom = 1u << 1u, HiRom = 1u << 1u,
SlowRom = 1u << 2u, SlowRom = 1u << 2u,
@@ -33,7 +35,7 @@ namespace ComSquare::Cartridge
//! @brief The name of the game //! @brief The name of the game
std::string gameName; std::string gameName;
//! @brief The memory mapping of the ROM. //! @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). //! @brief The rom type (special information about the rom, still don't know what).
uint8_t romType = 0; uint8_t romType = 0;
//! @brief The size (in bytes) of the ram //! @brief The size (in bytes) of the ram
@@ -41,26 +43,29 @@ namespace ComSquare::Cartridge
//! @brief The size of the SRom inside the cartridge. //! @brief The size of the SRom inside the cartridge.
unsigned sramSize = 0; unsigned sramSize = 0;
//! @brief Creator license ID code. //! @brief Creator license ID code.
union { union
{
uint8_t creatorIDs[2]; uint8_t creatorIDs[2];
uint16_t creatorID = 0; uint16_t creatorID = 0;
}; };
//! @brief The version of the game //! @brief The version of the game
uint8_t version = 0; uint8_t version = 0;
//! @brief Checksum complement //! @brief Checksum complement
union { union
{
uint8_t checksumComplements[2]; uint8_t checksumComplements[2];
uint16_t checksumComplement = 0; uint16_t checksumComplement = 0;
}; };
//! @brief Checksum //! @brief Checksum
union { union
{
uint8_t checksums[2]; uint8_t checksums[2];
uint16_t checksum = 0; uint16_t checksum = 0;
}; };
//! @brief The interrupt vectors used to halt the CPU in native mode //! @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 //! @brief The interrupt vectors used to halt the CPU in emulation mode
InterruptVectors emulationInterrupts{}; InterruptVectors emulationInterrupts {};
Header() = default; Header() = default;
Header(const Header &) = default; Header(const Header &) = default;
@@ -69,7 +74,8 @@ namespace ComSquare::Cartridge
}; };
//! @brief Contains the rom's memory/instructions. //! @brief Contains the rom's memory/instructions.
class Cartridge : public Ram::Ram { class Cartridge : public Ram::Ram
{
private: private:
//! @brief The path of the currently loaded rom. //! @brief The path of the currently loaded rom.
std::string _romPath; std::string _romPath;
@@ -93,10 +99,13 @@ namespace ComSquare::Cartridge
//! @return A header struct representing the data at the memory address you passed. //! @return A header struct representing the data at the memory address you passed.
Header _mapHeader(uint32_t headerAddress); Header _mapHeader(uint32_t headerAddress);
//! @brief Current type of the cartridge //! @brief Current type of the cartridge
CartridgeType _type; CartridgeType _type = Game;
//! @brief Magic Header string of a SPC Rom //! @brief Magic Header string of a SPC Rom
static constexpr std::string_view _magicSPC = "SNES-SPC700 Sound File Data v0.30"; static constexpr std::string_view _magicSPC = "SNES-SPC700 Sound File Data v0.30";
public: public:
//! @brief A default constructor that doesn't load anything.
Cartridge();
//! @brief Load a rom from it's path. //! @brief Load a rom from it's path.
explicit Cartridge(const std::string &romPath); explicit Cartridge(const std::string &romPath);
//! @brief The cartridge can't be copied. //! @brief The cartridge can't be copied.
@@ -108,13 +117,16 @@ namespace ComSquare::Cartridge
//! @brief The header of the cartridge. //! @brief The header of the cartridge.
Header header; Header header;
//! @brief Return current type of the cartridge //! @brief Return current type of the cartridge
CartridgeType getType(); CartridgeType getType();
//! @brief Read from the rom. //! @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. //! @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. //! @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. //! @return Return the data at the address.
uint8_t read(uint24_t addr) override; uint8_t read(uint24_t addr) override;
//! @brief Write data to the rom. //! @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 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. //! @param data The data to write.
@@ -123,6 +135,11 @@ namespace ComSquare::Cartridge
//! @brief The path of the rom file //! @brief The path of the rom file
//! @return The path of the currently loaded 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

View File

@@ -2,43 +2,49 @@
// Created by anonymus-raccoon on 1/31/20. // Created by anonymus-raccoon on 1/31/20.
// //
#ifndef COMSQUARE_INTERRUPTVECTORS_HPP #pragma once
#define COMSQUARE_INTERRUPTVECTORS_HPP
#include <cinttypes>
namespace ComSquare::Cartridge namespace ComSquare::Cartridge
{ {
struct InterruptVectors { struct InterruptVectors
{
//! @brief The Co-Processor enable vector. //! @brief The Co-Processor enable vector.
union { union
{
uint8_t cop8[2]; uint8_t cop8[2];
uint16_t cop; uint16_t cop;
}; };
//! @brief The Break vector. //! @brief The Break vector.
union { union
{
uint8_t brk8[2]; uint8_t brk8[2];
uint16_t brk; uint16_t brk;
}; };
//! @brief The Abort vector. //! @brief The Abort vector.
union { union
{
uint8_t abort8[2]; uint8_t abort8[2];
uint16_t abort; uint16_t abort;
}; };
//! @brief The non-maskable interrupt (The V-Blank interrupt). //! @brief The non-maskable interrupt (The V-Blank interrupt).
union { union
{
uint8_t nmi8[2]; uint8_t nmi8[2];
uint16_t nmi; uint16_t nmi;
}; };
//! @brief The Reset vector (execution of the SNES starts with this reset vector in emulation mode). //! @brief The Reset vector (execution of the SNES starts with this reset vector in emulation mode).
union { union
{
uint8_t reset8[2]; uint8_t reset8[2];
uint16_t reset; uint16_t reset;
}; };
//! @brief The Interrupt Request vector. //! @brief The Interrupt Request vector.
union { union
{
uint8_t irq8[2]; uint8_t irq8[2];
uint16_t irq; uint16_t irq;
}; };
}; };
} }// namespace ComSquare::Cartridge
#endif //COMSQUARE_INTERRUPTVECTORS_HPP

View File

@@ -25,7 +25,7 @@ namespace ComSquare::Debugger
_painter(*this), _painter(*this),
_stackModel(this->_bus, *this), _stackModel(this->_bus, *this),
_snes(snes), _snes(snes),
_labels(this->_loadLabels(snes.cartridge->getRomPath())) _labels(this->_loadLabels(snes.cartridge.getRomPath()))
{ {
this->_window->setContextMenuPolicy(Qt::NoContextMenu); this->_window->setContextMenuPolicy(Qt::NoContextMenu);
this->_window->setAttribute(Qt::WA_QuitOnClose, false); this->_window->setAttribute(Qt::WA_QuitOnClose, false);
@@ -84,9 +84,10 @@ namespace ComSquare::Debugger
try { try {
unsigned cycles = 0; unsigned cycles = 0;
for (auto &channel : this->_dmaChannels) for (auto &channel : this->_dmaChannels) {
if (channel.enabled) if (channel.enabled)
cycles += channel.run(INT_MAX); cycles += channel.run(INT_MAX);
}
if (this->_isPaused) if (this->_isPaused)
return 0xFF; return 0xFF;
@@ -300,11 +301,11 @@ namespace ComSquare::Debugger
std::string CPUDebug::getProceededParameters() std::string CPUDebug::getProceededParameters()
{ {
uint24_t pac = this->_registers.pac; uint24_t pac = this->_registers.pac;
this->_bus->forceSilence = true; this->_bus.forceSilence = true;
Instruction instruction = this->_instructions[this->readPC()]; Instruction instruction = this->_instructions[this->readPC()];
uint24_t valueAddr = this->_getValueAddr(instruction); uint24_t valueAddr = this->_getValueAddr(instruction);
this->_registers.pac = pac; this->_registers.pac = pac;
this->_bus->forceSilence = false; this->_bus.forceSilence = false;
if (instruction.size == 1) if (instruction.size == 1)
return ""; return "";
return "[" + Utility::to_hex(valueAddr, Utility::AsmPrefix) + "]"; return "[" + Utility::to_hex(valueAddr, Utility::AsmPrefix) + "]";
@@ -316,12 +317,12 @@ namespace ComSquare::Debugger
std::string symbolPath = romPath.replace_extension(".sym"); std::string symbolPath = romPath.replace_extension(".sym");
std::ifstream sym(symbolPath); std::ifstream sym(symbolPath);
if (sym) { // if (sym) {
std::vector<Label> symLabels = WlaDx::parse(sym); // std::vector<Label> symLabels = WlaDx::parse(sym);
labels.insert(labels.end(), // labels.insert(labels.end(),
std::make_move_iterator(symLabels.begin()), // std::make_move_iterator(symLabels.begin()),
std::make_move_iterator(symLabels.end())); // std::make_move_iterator(symLabels.end()));
} // }
return labels; return labels;
} }
} }
@@ -451,7 +452,7 @@ QVariant StackModel::data(const QModelIndex &index, int role) const
return QVariant(); return QVariant();
uint16_t addr = index.row() * 2 + index.column(); uint16_t addr = index.row() * 2 + index.column();
try { 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()); return (ComSquare::Utility::to_hex(value, ComSquare::Utility::NoPrefix).c_str());
} catch (std::exception &) { } catch (std::exception &) {
return "??"; return "??";

View File

@@ -42,13 +42,13 @@ namespace ComSquare::Debugger
ctx.mFlag = true; ctx.mFlag = true;
ctx.xFlag = true; ctx.xFlag = true;
} else { } else {
uint8_t m = this->_bus->read(pc - 1, true); uint8_t m = this->_bus.read(pc - 1, true);
ctx.mFlag &= ~m & 0b00100000u; ctx.mFlag &= ~m & 0b00100000u;
ctx.xFlag &= ~m & 0b00010000u; ctx.xFlag &= ~m & 0b00010000u;
} }
} }
if (instruction.opcode == 0xE2) { // SEP 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.mFlag |= m & 0b00100000u;
ctx.xFlag |= m & 0b00010000u; ctx.xFlag |= m & 0b00010000u;
} }
@@ -69,7 +69,7 @@ namespace ComSquare::Debugger
DisassembledInstruction CPUDebug::_parseInstruction(uint24_t pc, DisassemblyContext &ctx) 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]; Instruction instruction = this->_instructions[opcode];
std::string argument = this->_getInstructionParameter(instruction, pc + 1, ctx); std::string argument = this->_getInstructionParameter(instruction, pc + 1, ctx);
return DisassembledInstruction(instruction, pc, argument, opcode); return DisassembledInstruction(instruction, pc, argument, opcode);
@@ -134,10 +134,10 @@ namespace ComSquare::Debugger
std::string CPUDebug::_getImmediateValue(uint24_t pc, bool dual) 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) if (dual)
value += this->_bus->read(pc + 1, true) << 8u; value += this->_bus.read(pc + 1, true) << 8u;
std::stringstream ss; std::stringstream ss;
ss << "#$" << std::hex << value; ss << "#$" << std::hex << value;
return ss.str(); return ss.str();
@@ -145,27 +145,27 @@ namespace ComSquare::Debugger
std::string CPUDebug::_getDirectValue(uint24_t pc) 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) 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); return Utility::to_hex(value, Utility::HexString::AsmPrefix);
} }
std::string CPUDebug::_getAbsoluteLongValue(uint24_t pc) std::string CPUDebug::_getAbsoluteLongValue(uint24_t pc)
{ {
unsigned value = this->_bus->read(pc++, true); unsigned value = this->_bus.read(pc++, true);
value += this->_bus->read(pc++, true) << 8u; value += this->_bus.read(pc++, true) << 8u;
value += this->_bus->read(pc, true) << 16u; value += this->_bus.read(pc, true) << 16u;
return Utility::to_hex(value, Utility::HexString::AsmPrefix); return Utility::to_hex(value, Utility::HexString::AsmPrefix);
} }
std::string CPUDebug::_getDirectIndexedByXValue(uint24_t pc) std::string CPUDebug::_getDirectIndexedByXValue(uint24_t pc)
{ {
unsigned value = this->_bus->read(pc, true); unsigned value = this->_bus.read(pc, true);
std::stringstream ss; std::stringstream ss;
ss << "$" << std::hex << value << ", x"; ss << "$" << std::hex << value << ", x";
@@ -174,7 +174,7 @@ namespace ComSquare::Debugger
std::string CPUDebug::_getDirectIndexedByYValue(uint24_t pc) std::string CPUDebug::_getDirectIndexedByYValue(uint24_t pc)
{ {
unsigned value = this->_bus->read(pc, true); unsigned value = this->_bus.read(pc, true);
std::stringstream ss; std::stringstream ss;
ss << "$" << std::hex << value << ", y"; ss << "$" << std::hex << value << ", y";
@@ -183,38 +183,38 @@ namespace ComSquare::Debugger
std::string CPUDebug::_getDirectIndirectValue(uint24_t pc) 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) 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) 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"; return Utility::to_hex(value, Utility::HexString::AsmPrefix) + ", x";
} }
std::string CPUDebug::_getAbsoluteIndexByYValue(uint24_t pc) 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"; return Utility::to_hex(value, Utility::HexString::AsmPrefix) + ", y";
} }
std::string CPUDebug::_getAbsoluteIndexByXLongValue(uint24_t pc) std::string CPUDebug::_getAbsoluteIndexByXLongValue(uint24_t pc)
{ {
unsigned value = this->_bus->read(pc++, true); unsigned value = this->_bus.read(pc++, true);
value += this->_bus->read(pc++, true) << 8u; value += this->_bus.read(pc++, true) << 8u;
value += this->_bus->read(pc, true) << 16u; value += this->_bus.read(pc, true) << 16u;
return Utility::to_hex(value, Utility::HexString::AsmPrefix) + ", x"; return Utility::to_hex(value, Utility::HexString::AsmPrefix) + ", x";
} }
std::string CPUDebug::_getDirectIndexedByXIndirectValue(uint24_t pc) std::string CPUDebug::_getDirectIndexedByXIndirectValue(uint24_t pc)
{ {
unsigned value = this->_bus->read(pc, true); unsigned value = this->_bus.read(pc, true);
std::stringstream ss; std::stringstream ss;
ss << "($" << std::hex << value << ", x)"; ss << "($" << std::hex << value << ", x)";
@@ -223,7 +223,7 @@ namespace ComSquare::Debugger
std::string CPUDebug::_getDirectIndirectIndexedByYValue(uint24_t pc) std::string CPUDebug::_getDirectIndirectIndexedByYValue(uint24_t pc)
{ {
unsigned value = this->_bus->read(pc, true); unsigned value = this->_bus.read(pc, true);
std::stringstream ss; std::stringstream ss;
ss << "($" << std::hex << value << "), y"; ss << "($" << std::hex << value << "), y";
@@ -232,7 +232,7 @@ namespace ComSquare::Debugger
std::string CPUDebug::_getDirectIndirectIndexedByYLongValue(uint24_t pc) std::string CPUDebug::_getDirectIndirectIndexedByYLongValue(uint24_t pc)
{ {
unsigned value = this->_bus->read(pc, true); unsigned value = this->_bus.read(pc, true);
std::stringstream ss; std::stringstream ss;
ss << "[$" << std::hex << value << "], y"; ss << "[$" << std::hex << value << "], y";
@@ -241,32 +241,32 @@ namespace ComSquare::Debugger
std::string CPUDebug::_getStackRelativeValue(uint24_t pc) 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) 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) 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) + ")"; return "(" + Utility::to_hex(value, Utility::HexString::AsmPrefix) + ")";
} }
std::string CPUDebug::_getAbsoluteIndirectLongValue(uint24_t pc) std::string CPUDebug::_getAbsoluteIndirectLongValue(uint24_t pc)
{ {
unsigned value = this->_bus->read(pc++, true); unsigned value = this->_bus.read(pc++, true);
value += this->_bus->read(pc++, true) << 8u; value += this->_bus.read(pc++, true) << 8u;
value += this->_bus->read(pc, true) << 16u; value += this->_bus.read(pc, true) << 16u;
return "(" + Utility::to_hex(value, Utility::HexString::AsmPrefix) + ")"; return "(" + Utility::to_hex(value, Utility::HexString::AsmPrefix) + ")";
} }
std::string CPUDebug::_getAbsoluteIndirectIndexedByXValue(uint24_t pc) 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)"; return "(" + Utility::to_hex(value, Utility::HexString::AsmPrefix) + ", x)";
} }
} }

View File

@@ -2,23 +2,24 @@
// Created by anonymus-raccoon on 1/27/20. // Created by anonymus-raccoon on 1/27/20.
// //
#ifndef COMSQUARE_INVALIDADDRESS_HPP #pragma once
#define COMSQUARE_INVALIDADDRESS_HPP
#include "DebuggableError.hpp"
#include <exception> #include <exception>
#include <string>
#include <ios> #include <ios>
#include <sstream> #include <sstream>
#include "DebuggableError.hpp" #include <string>
namespace ComSquare namespace ComSquare
{ {
//! @brief Exception thrown when trying to read/write to an invalid address. //! @brief Exception thrown when trying to read/write to an invalid address.
class InvalidAddress : public DebuggableError { class InvalidAddress : public DebuggableError
{
private: private:
std::string _msg; std::string _msg;
public: public:
InvalidAddress(std::string where, int32_t addr) InvalidAddress(std::string where, uint24_t addr)
{ {
std::stringstream stream; std::stringstream stream;
stream << "Could not read/write data at address: 0x" << std::hex << addr << " from " << where; 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. //! @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: private:
std::string _msg; std::string _msg;
public: public:
InvalidRectangleAddress(std::string where, int32_t addr, int16_t subaddr, int16_t start, int16_t end) 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(); } const char *what() const noexcept override { return this->_msg.c_str(); }
}; };
} }// namespace ComSquare
#endif //COMSQUARE_INVALIDADDRESS_HPP

View File

@@ -21,19 +21,4 @@ namespace ComSquare::Memory
{ {
return this->_start <= addr && addr <= this->_end; 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 "???";
}
} }

View File

@@ -26,25 +26,20 @@ namespace ComSquare::Memory
//! @param addr The absolute address (in the 24 bit bus) //! @param addr The absolute address (in the 24 bit bus)
//! @return The local address (0 refers to the first byte of this component). //! @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. //! @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. //! @brief Change starting and ending points of this mapped memory.
//! @param start The first address mapped to this component. //! @param start The first address mapped to this component.
//! @param end The last 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. //! @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); void setMemoryRegion(uint24_t start, uint24_t end);
//! @brief Return true if this component has mapped the address. //! @brief Return true if this component has mapped the address.
//! @param addr The address to check. //! @param addr The address to check.
//! @return True if this address is mapped to the component. False otherwise. //! @return True if this address is mapped to the component. False otherwise.
virtual bool hasMemoryAt(uint24_t addr) const override; [[nodiscard]] 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. //! @brief A default destructor
virtual bool isMirror() const override; ~AMemory() override = default;
//! @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;
}; };
} }

View File

@@ -4,7 +4,7 @@
#include <iostream> #include <iostream>
#include "ARectangleMemory.hpp" #include "ARectangleMemory.hpp"
#include "../Exceptions/InvalidAddress.hpp" #include "Exceptions/InvalidAddress.hpp"
namespace ComSquare::Memory namespace ComSquare::Memory
{ {
@@ -42,16 +42,6 @@ namespace ComSquare::Memory
this->_endPage = endPage; 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 std::string ARectangleMemory::getValueName(uint24_t) const
{ {
return "???"; return "???";

View File

@@ -9,7 +9,8 @@
namespace ComSquare::Memory 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). //! @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: protected:
//! @brief The first bank to map to. //! @brief The first bank to map to.
uint8_t _startBank = 0; uint8_t _startBank = 0;
@@ -19,16 +20,19 @@ namespace ComSquare::Memory
uint16_t _startPage = 0; uint16_t _startPage = 0;
//! @brief The last address of each bank to map. //! @brief The last address of each bank to map.
uint16_t _endPage = 0; uint16_t _endPage = 0;
public: public:
//! @brief Translate an absolute address to a relative address //! @brief Translate an absolute address to a relative address
//! @param addr The absolute address (in the 24 bit bus) //! @param addr The absolute address (in the 24 bit bus)
//! @return The local address (0 refers to the first byte of this component). //! @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. //! @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. //! @brief Return true if this component has mapped the address.
//! @param addr The address to check. //! @param addr The address to check.
//! @return True if this address is mapped to the component. False otherwise. //! @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. //! @brief Change starting and ending points of this mapped memory.
//! @param startBank The first bank mapped to this component. //! @param startBank The first bank mapped to this component.
//! @param endBank The last 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) //! @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. //! @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); 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 //! @brief Get the name of the data at the address
//! @param addr The address (in local space) //! @param addr The address (in local space)
virtual std::string getValueName(uint24_t addr) const override; [[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. //! @brief A default destructor.
virtual std::shared_ptr<IMemory> getMirrored() const override; ~ARectangleMemory() override = default;
virtual ~ARectangleMemory() override = default;
}; };
} }// namespace ComSquare::Memory

View File

@@ -21,36 +21,38 @@ namespace ComSquare::Memory
//! @throw This function should thrown an InvalidAddress for address that are not mapped to the component. //! @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. //! @return Return the data at the address given as parameter.
virtual uint8_t read(uint24_t addr) = 0; virtual uint8_t read(uint24_t addr) = 0;
//! @brief Write data to this component. //! @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 addr The local address to write data (0x0 should refer to the first byte of this component).
//! @param data The new data to write. //! @param data The new data to write.
//! @throw This function should thrown an InvalidAddress for address that are not mapped to the component. //! @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; virtual void write(uint24_t addr, uint8_t data) = 0;
//! @brief Return true if this component has mapped the address. //! @brief Return true if this component has mapped the address.
//! @param addr The address to check. //! @param addr The address to check.
//! @return True if this address is mapped to the component. False otherwise. //! @return True if this address is mapped to the component. False otherwise.
virtual bool hasMemoryAt(uint24_t addr) const = 0; virtual bool hasMemoryAt(uint24_t addr) const = 0;
//! @brief Translate an absolute address to a relative address //! @brief Translate an absolute address to a relative address
//! @param addr The absolute address (in the 24 bit bus) //! @param addr The absolute address (in the 24 bit bus)
//! @return The local address (0 refers to the first byte of this component). //! @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. //! @throw InvalidAddress is thrown if the address is not mapped by this component.
virtual uint24_t getRelativeAddress(uint24_t addr) const = 0; 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. //! @brief Get the size of the data. This size can be lower than the mapped data.
//! @return The number of bytes inside this memory. //! @return The number of bytes inside this memory.
virtual uint24_t getSize() const = 0; 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) //! @brief Get the name of this accessor (used for debug purpose)
virtual std::string getName() const = 0; virtual std::string getName() const = 0;
//! @brief Get the component of this accessor (used for debug purpose) //! @brief Get the component of this accessor (used for debug purpose)
virtual Component getComponent() const = 0; virtual Component getComponent() const = 0;
//! @brief Get the name of the data at the address //! @brief Get the name of the data at the address
//! @param addr The address (in local space) //! @param addr The address (in local space)
virtual std::string getValueName(uint24_t addr) const = 0; 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. //! @brief A virtual default destructor.
virtual std::shared_ptr<IMemory> getMirrored() const = 0;
virtual ~IMemory() = default; virtual ~IMemory() = default;
}; };
}; };

View File

@@ -4,43 +4,41 @@
#include <algorithm> #include <algorithm>
#include <iostream> #include <iostream>
#include "MemoryBus.hpp" #include "SNES.hpp"
#include "../SNES.hpp" #include "Memory/MemoryBus.hpp"
#include "MemoryShadow.hpp" #include "Memory/MemoryShadow.hpp"
#include "RectangleShadow.hpp" #include "Exceptions/InvalidAddress.hpp"
#include "../Exceptions/InvalidAddress.hpp"
namespace ComSquare::Memory 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()) if (it == this->_memoryAccessors.end())
return nullptr; return nullptr;
return *it; return &it->get();
} }
uint8_t MemoryBus::read(uint24_t addr) uint8_t MemoryBus::read(uint24_t addr)
{ {
std::shared_ptr<IMemory> handler = this->getAccessor(addr); IMemory *handler = this->getAccessor(addr);
if (!handler) { if (!handler) {
std::cout << "Unknown memory accessor for address $" << std::hex << addr << ". Using open bus." << std::endl; std::cout << "Unknown memory accessor for address $" << std::hex << addr << ". Using open bus." << std::endl;
return this->_openBus; return this->_openBus;
} }
uint8_t data = handler->read(handler->getRelativeAddress(addr)); uint8_t data = handler->read(handler->getRelativeAddress(addr));
this->_openBus = data; this->_openBus = data;
return data; return data;
} }
uint8_t MemoryBus::read(uint24_t addr, bool silence) uint8_t MemoryBus::peek(uint24_t addr)
{ {
if (!silence) IMemory *handler = this->getAccessor(addr);
return this->read(addr);
std::shared_ptr<IMemory> handler = this->getAccessor(addr);
if (!handler) if (!handler)
return this->_openBus; return this->_openBus;
@@ -53,7 +51,7 @@ namespace ComSquare::Memory
void MemoryBus::write(uint24_t addr, uint8_t data) void MemoryBus::write(uint24_t addr, uint8_t data)
{ {
std::shared_ptr<IMemory> handler = this->getAccessor(addr); IMemory *handler = this->getAccessor(addr);
if (!handler) { if (!handler) {
std::cout << "Unknown memory accessor for address " << std::hex << addr << ". Warning, it was a write." << std::endl; 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) void MemoryBus::_mirrorComponents(SNES &console, unsigned i)
{ {
this->_memoryAccessors.emplace_back(new Memory::RectangleShadow(console.wram, i, i, 0x0000, 0x1FFF)); this->_rectangleShadows.emplace_back(console.wram, i, i, 0x0000, 0x1FFF);
this->_memoryAccessors.emplace_back(new Memory::MemoryShadow(console.ppu, (i << 16u) + 0x2100, (i << 16u) + 0x213F)); this->_shadows.emplace_back(console.ppu, (i << 16u) + 0x2100, (i << 16u) + 0x213F);
this->_memoryAccessors.emplace_back(new Memory::MemoryShadow(console.apu, (i << 16u) + 0x2140, (i << 16u) + 0x2143)); this->_shadows.emplace_back(console.apu, (i << 16u) + 0x2140, (i << 16u) + 0x2143);
this->_memoryAccessors.emplace_back(new Memory::MemoryShadow(console.cpu, (i << 16u) + 0x4200, (i << 16u) + 0x421F)); this->_shadows.emplace_back(console.cpu, (i << 16u) + 0x4200, (i << 16u) + 0x421F);
} }
void MemoryBus::mapComponents(SNES &console) void MemoryBus::mapComponents(SNES &console)
{ {
this->_memoryAccessors.clear(); 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. // The WRam and PU registers are always mapped at the same address no matter the mapping mode.
console.wram->setMemoryRegion(0x7E, 0x7F, 0x0000, 0xFFFF); console.wram.setMemoryRegion(0x7E, 0x7F, 0x0000, 0xFFFF);
this->_memoryAccessors.push_back(console.wram); this->_memoryAccessors.emplace_back(console.wram);
console.ppu->setMemoryRegion(0x2100, 0x213F); console.ppu.setMemoryRegion(0x2100, 0x213F);
this->_memoryAccessors.push_back(console.ppu); this->_memoryAccessors.emplace_back(console.ppu);
console.apu->setMemoryRegion(0x2140, 0x2143); console.apu.setMemoryRegion(0x2140, 0x2143);
this->_memoryAccessors.push_back(console.apu); this->_memoryAccessors.emplace_back(console.apu);
console.cpu->setMemoryRegion(0x4200, 0x44FF); console.cpu.setMemoryRegion(0x4200, 0x44FF);
this->_memoryAccessors.push_back(console.cpu); this->_memoryAccessors.emplace_back(console.cpu);
// TODO implement Joys. // TODO implement Joys.
@@ -96,27 +96,27 @@ namespace ComSquare::Memory
for (uint8_t i = 0x80; i < 0xC0; i += 0x01) for (uint8_t i = 0x80; i < 0xC0; i += 0x01)
this->_mirrorComponents(console, i); this->_mirrorComponents(console, i);
if (console.cartridge->header.mappingMode & Cartridge::LoRom) { if (console.cartridge.header.mappingMode & Cartridge::LoRom) {
console.cartridge->setMemoryRegion(0x80, 0xFF, 0x8000, 0xFFFF); console.cartridge.setMemoryRegion(0x80, 0xFF, 0x8000, 0xFFFF);
this->_memoryAccessors.push_back(console.cartridge); this->_memoryAccessors.emplace_back(console.cartridge);
// Mirror on the Q1 and Q2. // 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. // 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 // 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); console.sram.setMemoryRegion(0xF0, 0xFD, 0x0000, 0x7FFF);
this->_memoryAccessors.push_back(console.sram); this->_memoryAccessors.emplace_back(console.sram);
this->_memoryAccessors.emplace_back(new Memory::RectangleShadow(console.sram, 0x70, 0x7D, 0x0000, 0x7FFF)); this->_rectangleShadows.emplace_back(console.sram, 0x70, 0x7D, 0x0000, 0x7FFF);
// TODO implement the SRam accessor for the FE/FF // TODO implement the SRam accessor for the FE/FF
} }
// TODO should implement HiRom. // TODO should implement HiRom.
}
bool MemoryBus::isDebugger() for (auto &shadow : this->_shadows)
{ this->_memoryAccessors.emplace_back(shadow);
return false; for (auto &shadow : this->_rectangleShadows)
this->_memoryAccessors.emplace_back(shadow);
} }
} }

View File

@@ -2,13 +2,14 @@
// Created by anonymus-raccoon on 1/23/20. // Created by anonymus-raccoon on 1/23/20.
// //
#ifndef COMSQUARE_MEMORYBUS_HPP #pragma once
#define COMSQUARE_MEMORYBUS_HPP
#include <cstdint>
#include <vector>
#include <memory>
#include "AMemory.hpp" #include "AMemory.hpp"
#include "RectangleShadow.hpp"
#include "MemoryShadow.hpp"
#include <cstdint>
#include <memory>
#include <vector>
namespace ComSquare namespace ComSquare
{ {
@@ -17,10 +18,16 @@ namespace ComSquare
namespace Memory namespace Memory
{ {
//! @brief The memory bus is the component responsible of mapping addresses to components address and transmitting the data. //! @brief The memory bus is the component responsible of mapping addresses to components address and transmitting the data.
class MemoryBus { class MemoryBus
{
private: 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. //! @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. //! @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. //! @param console All the components.
@@ -30,29 +37,33 @@ namespace ComSquare
//! @brief The last value read via the memory bus. //! @brief The last value read via the memory bus.
uint8_t _openBus = 0; uint8_t _openBus = 0;
public: public:
//! @brief Create a new default memory bus.
MemoryBus() = default; MemoryBus() = default;
//! @brief A memory bus is copyable.
MemoryBus(const MemoryBus &) = default; MemoryBus(const MemoryBus &) = default;
//! @brief A memory bus is assignable.
MemoryBus &operator=(const MemoryBus &) = default; MemoryBus &operator=(const MemoryBus &) = default;
//! @brief A default destructor
~MemoryBus() = default; ~MemoryBus() = default;
//! @brief Force silencing read to the bus. //! @brief Force silencing read to the bus.
bool forceSilence = false; 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. //! @brief Read data at a global address. This form allow read to be silenced.
//! @param addr The address to read from. //! @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. //! @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. //! @brief Write a data to a global address.
//! @param addr The address to write to. //! @param addr The address to write to.
//! @param data The data to write. //! @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. //! @brief Map components to the address space using the currently loaded cartridge to set the right mapping mode.
//! @param console All the components. //! @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. //! @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. //! @param addr The address you want to look for.
//! @return The components responsible for the address param or nullptr if none was found. //! @return The components responsible for the address param or nullptr if none was found.
std::shared_ptr<IMemory> getAccessor(uint24_t addr); IMemory *getAccessor(uint24_t addr);
//! @brief Return true if the Bus is overloaded with debugging features.
virtual bool isDebugger();
}; };
} }
} }
#endif //COMSQUARE_MEMORYBUS_HPP

View File

@@ -4,48 +4,46 @@
#include "MemoryShadow.hpp" #include "MemoryShadow.hpp"
#include <utility>
namespace ComSquare::Memory namespace ComSquare::Memory
{ {
MemoryShadow::MemoryShadow(std::shared_ptr<IMemory> initial, uint24_t start, uint24_t end) MemoryShadow::MemoryShadow(IMemory &initial, uint24_t start, uint24_t end)
: _initial(std::move(initial)) : _initial(initial)
{ {
this->setMemoryRegion(start, end); this->setMemoryRegion(start, end);
} }
uint8_t MemoryShadow::read(uint24_t addr) 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) 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 uint24_t MemoryShadow::getSize() const
{ {
return this->_initial->getSize(); return this->_initial.getSize();
} }
bool MemoryShadow::isMirror() const IMemory &MemoryShadow::getMirrored() const
{
return true;
}
std::shared_ptr<IMemory> MemoryShadow::getMirrored() const
{ {
return this->_initial; return this->_initial;
} }
std::string MemoryShadow::getName() const std::string MemoryShadow::getName() const
{ {
return this->_initial->getName(); return this->_initial.getName();
} }
Component MemoryShadow::getComponent() const 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);
} }
} }

View File

@@ -9,39 +9,51 @@
namespace ComSquare::Memory namespace ComSquare::Memory
{ {
class MemoryShadow : public AMemory { class MemoryShadow : public AMemory
{
private: private:
//! @brief Memory to shadow from. //! @brief Memory to shadow from.
std::shared_ptr<IMemory> _initial; IMemory &_initial;
public: public:
//! @brief Create a shadow for the memory given as parameter. //! @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(const MemoryShadow &) = default;
MemoryShadow &operator=(const MemoryShadow &) = default; //! @brief A memory shadow is not assignable.
~MemoryShadow() = default; MemoryShadow &operator=(const MemoryShadow &) = delete;
//! @brief A default destructor
~MemoryShadow() override = default;
//! @brief Read from the initial AMemory given. //! @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. //! @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. //! @throw InvalidAddress will be thrown if the address is more than the size of the initial AMemory.
//! @return Return the data at the address. //! @return Return the data at the address.
uint8_t read(uint24_t addr) override; uint8_t read(uint24_t addr) override;
//! @brief Write data to the ram. //! @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 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. //! @param data The data to write.
//! @throw InvalidAddress will be thrown if the address is more than the size of the initial AMemory. //! @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; 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. //! @brief Get the size of the data. This size can be lower than the mapped data.
//! @return The number of bytes inside this memory. //! @return The number of bytes inside this memory.
virtual uint24_t getSize() const override; [[nodiscard]] 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;
//! @brief Get the name of this accessor (used for debug purpose) //! @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) //! @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 //! @brief Return the memory accessor this accessor mirror if any
//! @return nullptr if isMirror is false, the source otherwise. //! @return nullptr if isMirror is false, the source otherwise.
std::shared_ptr<IMemory> getMirrored() const override; [[nodiscard]] IMemory &getMirrored() const;
}; };
} }

View File

@@ -3,17 +3,16 @@
// //
#include "RectangleShadow.hpp" #include "RectangleShadow.hpp"
#include <utility>
#include <iostream> #include <iostream>
namespace ComSquare::Memory namespace ComSquare::Memory
{ {
RectangleShadow::RectangleShadow(std::shared_ptr<IMemory> initial, RectangleShadow::RectangleShadow(IMemory &initial,
uint8_t startBank, uint8_t startBank,
uint8_t endBank, uint8_t endBank,
uint16_t startPage, uint16_t startPage,
uint16_t endPage) uint16_t endPage)
: _initial(std::move(initial)) : _initial(initial)
{ {
this->setMemoryRegion(startBank, endBank, startPage, endPage); this->setMemoryRegion(startBank, endBank, startPage, endPage);
} }
@@ -26,42 +25,36 @@ namespace ComSquare::Memory
uint8_t RectangleShadow::read(uint24_t addr) 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) 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; this->_bankOffset = bankOffset;
return this;
} }
uint24_t RectangleShadow::getSize() const uint24_t RectangleShadow::getSize() const
{ {
return this->_initial->getSize(); return this->_initial.getSize();
} }
bool RectangleShadow::isMirror() const IMemory &RectangleShadow::getMirrored() const
{
return true;
}
std::shared_ptr<IMemory> RectangleShadow::getMirrored() const
{ {
return this->_initial; return this->_initial;
} }
std::string RectangleShadow::getName() const std::string RectangleShadow::getName() const
{ {
return this->_initial->getName(); return this->_initial.getName();
} }
Component RectangleShadow::getComponent() const Component RectangleShadow::getComponent() const
{ {
return this->_initial->getComponent(); return this->_initial.getComponent();
} }
} }

View File

@@ -13,14 +13,21 @@ namespace ComSquare::Memory
class RectangleShadow : public ARectangleMemory { class RectangleShadow : public ARectangleMemory {
private: private:
//! @brief Memory to shadow from. //! @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. //! @brief The number of banks to add to the memory before accessing it from the initial data.
int _bankOffset = 0; int _bankOffset = 0;
public: public:
//! @brief Create a shadow for the memory given as parameter. //! @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(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; ~RectangleShadow() override = default;
//! @brief Read from the initial AMemory given. //! @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. //! @throw InvalidAddress will be thrown if the address is more than the size of the initial AMemory.
//! @return Return the data at the address. //! @return Return the data at the address.
uint8_t read(uint24_t addr) override; uint8_t read(uint24_t addr) override;
//! @brief Write data to the ram. //! @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 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. //! @param data The data to write.
//! @throw InvalidAddress will be thrown if the address is more than the size of the initial AMemory. //! @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; void write(uint24_t addr, uint8_t data) override;
//! @brief Translate an absolute address to a relative address //! @brief Translate an absolute address to a relative address
//! @param addr The absolute address (in the 24 bit bus) //! @param addr The absolute address (in the 24 bit bus)
//! @return The local address (0 refers to the first byte of this component). //! @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. //! @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. //! @brief Get the size of the data. This size can be lower than the mapped data.
//! @return The number of bytes inside this memory. //! @return The number of bytes inside this memory.
virtual uint24_t getSize() const override; [[nodiscard]] 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;
//! @brief Get the name of this accessor (used for debug purpose) //! @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) //! @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 //! @brief Return the memory accessor this accessor mirror if any
//! @return nullptr if isMirror is false, the source otherwise. //! @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). //! @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);
}; };
} }

View File

@@ -2,8 +2,7 @@
// Created by anonymus-raccoon on 3/24/20. // Created by anonymus-raccoon on 3/24/20.
// //
#ifndef COMSQUARE_COMPONENTS_HPP #pragma once
#define COMSQUARE_COMPONENTS_HPP
namespace ComSquare namespace ComSquare
{ {
@@ -19,4 +18,3 @@ namespace ComSquare
SRam = 1u << 8u, SRam = 1u << 8u,
}; };
} }
#endif //COMSQUARE_COMPONENTS_HPP

View File

@@ -6,7 +6,6 @@
#include "PPU.hpp" #include "PPU.hpp"
#include "Background.hpp" #include "Background.hpp"
#include <cmath> #include <cmath>
#include <cstring>
#include "Tile.hpp" #include "Tile.hpp"
#include "PPUUtils.hpp" #include "PPUUtils.hpp"
#include "Models/Vector2.hpp" #include "Models/Vector2.hpp"
@@ -15,7 +14,7 @@ namespace ComSquare::PPU
{ {
Background::Background(ComSquare::PPU::PPU &ppu, int backGroundNumber, bool hasPriority): Background::Background(ComSquare::PPU::PPU &ppu, int backGroundNumber, bool hasPriority):
_ppu(ppu), _ppu(ppu),
_tileMapsConfig(ppu.getBackgroundSize(backGroundNumber)), _tileMapsConfig(ppu.getBackgroundMirroring(backGroundNumber)),
_characterNbPixels(ppu.getCharacterSize(backGroundNumber)), _characterNbPixels(ppu.getCharacterSize(backGroundNumber)),
_bpp(ppu.getBPP(backGroundNumber)), _bpp(ppu.getBPP(backGroundNumber)),
_directColor(false), _directColor(false),
@@ -26,9 +25,9 @@ namespace ComSquare::PPU
_bgNumber(backGroundNumber), _bgNumber(backGroundNumber),
_tileBuffer({{{0}}}), _tileBuffer({{{0}}}),
_vram(ppu.vram), _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.setRam(this->_vram);
this->_tileRenderer.setCgram(this->_cgram); this->_tileRenderer.setCgram(this->_cgram);
} }
@@ -37,19 +36,24 @@ namespace ComSquare::PPU
{ {
uint16_t vramAddress = this->_tileMapStartAddress; uint16_t vramAddress = this->_tileMapStartAddress;
Vector2<int> offset = this->_ppu.getBgScroll(this->_bgNumber); Vector2<int> offset = this->_ppu.getBgScroll(this->_bgNumber);
this->backgroundSize.x = this->_tileMapsConfig.x * this->_characterNbPixels.x * NbCharacterWidth; this->backgroundSize.x =
this->backgroundSize.y = this->_tileMapsConfig.y * this->_characterNbPixels.y * NbCharacterHeight; 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++) { this->_drawBasicTileMap(vramAddress, offset);
if (!(i == 1 && this->_tileMapsConfig.x == 1) && !(i > 1 && this->_tileMapsConfig.y == 1)) { for (int i = 1; i < 4; i++) {
_drawBasicTileMap(vramAddress, offset);
}
vramAddress += TileMapByteSize; vramAddress += TileMapByteSize;
offset.x += NbCharacterWidth * this->_characterNbPixels.x; offset.x += NbCharacterWidth * this->_characterNbPixels.x;
if (i == 2) { if (i == 2) {
offset.x = 0; offset.x = 0;
offset.y += NbCharacterHeight * this->_characterNbPixels.y; 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); this->_tileRenderer.setBpp(this->_bpp);
} }
void Background::setTilemaps(Vector2<int> tileMaps) void Background::setTilemaps(Vector2<bool> tileMaps)
{ {
this->_tileMapsConfig = tileMaps; this->_tileMapsConfig = tileMaps;
} }

View File

@@ -31,7 +31,8 @@ namespace ComSquare::PPU
//! @brief the ppu used to get registers values (ex: bg scroll) //! @brief the ppu used to get registers values (ex: bg scroll)
ComSquare::PPU::PPU &_ppu; ComSquare::PPU::PPU &_ppu;
//! @brief The tilemap configuration nb of tileMap vertically and horizontally //! @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) //! @brief The number of pixels of a character (x: width, y:height)
Vector2<int> _characterNbPixels; Vector2<int> _characterNbPixels;
//! @brief The number of bits per pixels to currently look for each pixel //! @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) //! @brief The size of the background (x, y)
Vector2<unsigned> backgroundSize; Vector2<unsigned> backgroundSize;
//! @brief The output buffer (pixels are written on it) //! @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 //! @brief Render a background on his internal buffer
void renderBackground(); void renderBackground();
@@ -84,7 +85,7 @@ namespace ComSquare::PPU
void setBpp(int bpp); void setBpp(int bpp);
//! @brief setter for private variable _tileMaps //! @brief setter for private variable _tileMaps
//! @param tileMaps The tileMaps to set //! @param tileMaps The tileMaps to set
void setTilemaps(Vector2<int> tileMaps); void setTilemaps(Vector2<bool> tileMaps);
//! @brief Get the BackGround Number //! @brief Get the BackGround Number
//! @return the current Background number //! @return the current Background number

View File

@@ -4,19 +4,22 @@
#include <iostream> #include <iostream>
#include <bitset> #include <bitset>
#include <cstring>
#include "PPU.hpp" #include "PPU.hpp"
#include "Exceptions/NotImplementedException.hpp" #include "Exceptions/NotImplementedException.hpp"
#include "Exceptions/InvalidAddress.hpp" #include "Exceptions/InvalidAddress.hpp"
#include "Ram/Ram.hpp" #include "Ram/Ram.hpp"
#include "Models/Vector2.hpp" #include "Models/Vector2.hpp"
namespace ComSquare::PPU::Utils::Debug {
void populateEnvironment(PPU &ppu, int dumpNumber);
}
namespace ComSquare::PPU namespace ComSquare::PPU
{ {
PPU::PPU(Renderer::IRenderer &renderer): PPU::PPU(Renderer::IRenderer &renderer):
vram(std::make_shared<Ram::Ram>(VramSize, ComSquare::VRam, "VRAM")), vram(new Ram::Ram(VramSize, ComSquare::VRam, "VRAM")),
oamram(std::make_shared<Ram::Ram>(OAMRamSize, ComSquare::OAMRam, "OAMRAM")), oamram(new Ram::Ram(OAMRamSize, ComSquare::OAMRam, "OAMRAM")),
cgram(std::make_shared<Ram::Ram>(CGRamSize, ComSquare::CGRam, "CGRAM")), cgram(new Ram::Ram(CGRamSize, ComSquare::CGRam, "CGRAM")),
_renderer(renderer), _renderer(renderer),
_backgrounds{ _backgrounds{
Background(*this, 1, false), Background(*this, 1, false),
@@ -27,11 +30,13 @@ namespace ComSquare::PPU
Background(*this, 3, true), Background(*this, 3, true),
Background(*this, 4, false), Background(*this, 4, false),
Background(*this, 4, true) 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; this->_registers._isLowByte = true;
//Utils::Debug::populateEnvironment(*this, 0);
} }
uint8_t PPU::read(uint24_t addr) uint8_t PPU::read(uint24_t addr)
@@ -118,12 +123,18 @@ namespace ComSquare::PPU
case PpuRegisters::bg2sc: case PpuRegisters::bg2sc:
case PpuRegisters::bg3sc: case PpuRegisters::bg3sc:
case PpuRegisters::bg4sc: case PpuRegisters::bg4sc:
this->_registers._bgsc[addr - 0x07].raw = data; this->_registers._bgsc[addr - PpuRegisters::bg1sc].raw = data;
// update background tilemap address // update background tilemap address
this->_backgrounds[addr - 0x07].setTileMapStartAddress(this->getTileMapStartAddress(addr - 0x07 + 1)); this->_backgrounds[addr - PpuRegisters::bg1sc].setTileMapStartAddress(
this->_backgrounds[addr - 0x07 + 1].setTileMapStartAddress(this->getTileMapStartAddress(addr - 0x07 + 1)); this->getTileMapStartAddress(addr - PpuRegisters::bg1sc + 1));
this->_backgrounds[addr - 0x07].setTilemaps({this->_registers._bgsc[addr - 0x07].tilemapHorizontalMirroring, this->_registers._bgsc[addr - 0x07].tilemapVerticalMirroring}); this->_backgrounds[addr - PpuRegisters::bg1sc + 1].setTileMapStartAddress(
this->_backgrounds[addr - 0x07 + 1].setTilemaps({this->_registers._bgsc[addr - 0x07].tilemapHorizontalMirroring, this->_registers._bgsc[addr - 0x07].tilemapVerticalMirroring}); 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; break;
case PpuRegisters::bg12nba: case PpuRegisters::bg12nba:
case PpuRegisters::bg34nba: case PpuRegisters::bg34nba:
@@ -298,20 +309,21 @@ namespace ComSquare::PPU
{ {
(void)cycles; (void)cycles;
this->renderMainAndSubScreen(); this->renderMainAndSubScreen();
this->add_buffer(this->_screen, this->_subScreen); this->add_buffer(this->_screen, this->_subScreen);
this->add_buffer(this->_screen, this->_mainScreen); this->add_buffer(this->_screen, this->_mainScreen);
//this->_backgrounds[2].renderBackground(); //this->_backgrounds[2].renderBackground();
//add_buffer(this->_screen, this->_backgrounds[2].buffer); //add_buffer(this->_screen, this->_backgrounds[2].buffer);
for (unsigned long i = 0; i < 1024; i++) { for (unsigned long i = 0; i < this->_screen.size(); i++) {
for (unsigned long j = 0; j < 1024; j++) { for (unsigned long j = 0; j < this->_screen[i].size(); j++) {
this->_renderer.putPixel(j, i, this->_screen[i][j]); this->_renderer.putPixel(j, i, this->_screen[i][j]);
} }
} }
this->_renderer.drawScreen(); this->_renderer.drawScreen();
memset(this->_mainScreen, 0xFF, sizeof(this->_mainScreen)); for (auto &i : this->_mainScreen)
memset(this->_subScreen, 0xFF, sizeof(this->_subScreen)); i.fill(0XFF);
for (auto &i : this->_subScreen)
i.fill(0XFF);
} }
std::string PPU::getName() const std::string PPU::getName() const
@@ -528,12 +540,12 @@ namespace ComSquare::PPU
return baseAddress; 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.y = this->_registers._bgsc[bgNumber - 1].tilemapVerticalMirroring;
backgroundSize.x = (this->_registers._bgsc[bgNumber - 1].tilemapHorizontalMirroring) ? 2 : 1; backgroundSize.x = this->_registers._bgsc[bgNumber - 1].tilemapHorizontalMirroring;
return backgroundSize; return backgroundSize;
} }
@@ -541,9 +553,9 @@ namespace ComSquare::PPU
{ {
uint16_t colorPalette; uint16_t colorPalette;
// should only render backgrounds needed (depending of th bgMode) // should only render backgrounds needed (depending of th bgMode)
//int i = 0; int i = 0;
for (auto &_background : this->_backgrounds) { for (auto &_background : this->_backgrounds) {
//i++; i++;
_background.renderBackground(); _background.renderBackground();
} }
// TODO make a function getDefaultBgColor // TODO make a function getDefaultBgColor
@@ -551,9 +563,8 @@ namespace ComSquare::PPU
colorPalette += this->cgram->read(1) << 8U; colorPalette += this->cgram->read(1) << 8U;
uint32_t color = Utils::getRealColor(colorPalette); uint32_t color = Utils::getRealColor(colorPalette);
for (auto &array : this->_subScreen) for (auto &row : this->_subScreen)
for (auto &c : array) row.fill(color);
c = color;
// the buffer is overwrite if necessary by a new bg so the background priority is from back to front // 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 // the starting palette index isn't implemented
switch (this->_registers._bgmode.bgMode) { switch (this->_registers._bgmode.bgMode) {

View File

@@ -17,6 +17,10 @@
#define FALLTHROUGH __attribute__((fallthrough)); #define FALLTHROUGH __attribute__((fallthrough));
namespace ComSquare::PPU::Utils {
struct PpuState;
};
namespace ComSquare::PPU namespace ComSquare::PPU
{ {
static constexpr uint32_t VramSize = 65536; static constexpr uint32_t VramSize = 65536;
@@ -554,18 +558,18 @@ namespace ComSquare::PPU
std::shared_ptr<Ram::Ram> vram; std::shared_ptr<Ram::Ram> vram;
std::shared_ptr<Ram::Ram> oamram; std::shared_ptr<Ram::Ram> oamram;
std::shared_ptr<Ram::Ram> cgram; std::shared_ptr<Ram::Ram> cgram;
private: //private:
//! @brief Init ppuRegisters //! @brief Init ppuRegisters
Registers _registers{}; Registers _registers{};
Renderer::IRenderer &_renderer; Renderer::IRenderer &_renderer;
//! @brief Backgrounds buffers //! @brief Backgrounds buffers
Background _backgrounds[8]; Background _backgrounds[8];
//! @brief Main Screen buffer //! @brief Main Screen buffer
uint32_t _mainScreen[1024][1024]; std::array<std::array<uint32_t, 1024>, 1024> _mainScreen;
//! @brief Sub Screen buffer //! @brief Sub Screen buffer
uint32_t _subScreen[1024][1024]; std::array<std::array<uint32_t, 1024>, 1024> _subScreen;
//! @brief Final Screen buffer //! @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) //! @brief Used for vram read registers (0x2139 - 0x213A)
uint16_t _vramReadBuffer = 0; uint16_t _vramReadBuffer = 0;
//! @brief Struct that contain all necessary vars for the use of the registers //! @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; uint16_t getTileMapStartAddress(int bgNumber) const;
//! @brief Give the address to find the correct tileset for a given x and y //! @brief Give the address to find the correct tileset for a given x and y
uint16_t getTilesetAddress(int bgNumber) const; uint16_t getTilesetAddress(int bgNumber) const;
//! @brief Give the number of tilemaps to be rendered //! @brief Tells if the tilemap is expanded for the x and y directions
Vector2<int> getBackgroundSize(int bgNumber) const; Vector2<bool> getBackgroundMirroring(int bgNumber) const;
//! @brief Render the Main and sub screen correctly //! @brief Render the Main and sub screen correctly
void renderMainAndSubScreen(); void renderMainAndSubScreen();
//! @brief Add a bg buffer to another buffer //! @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> 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], void add_buffer(std::array<std::array<uint32_t, DEST_SIZE_Y>, DEST_SIZE_X> &bufferDest,
const uint32_t (&bufferSrc)[SRC_SIZE_Y][SRC_SIZE_X], const std::array<std::array<uint32_t, SRC_SIZE_Y>, SRC_SIZE_X> &bufferSrc,
const Vector2<int> &offset = {0, 0}) const Vector2<int> &offset = {0, 0})
{ {
// TODO use std::ranges // TODO use std::ranges
for (unsigned long i = 0; i < 1024; i++) { for (unsigned long i = 0; i < bufferSrc.size(); i++) {
for (unsigned long j = 0; j < 1024; j++) { for (unsigned long j = 0; j < bufferSrc[i].size(); j++) {
if (bufferSrc[i][j] > 0xFF) // 0xFF correspond to a black pixel with full brightness if (bufferSrc[i][j] > 0xFF) // 0xFF correspond to a black pixel with full brightness
bufferDest[i + offset.x ][j + offset.y] = bufferSrc[i][j]; bufferDest[i + offset.x ][j + offset.y] = bufferSrc[i][j];
} }
@@ -645,10 +649,11 @@ namespace ComSquare::PPU
const Registers &getWriteRegisters() const; const Registers &getWriteRegisters() const;
template <std::size_t SRC_SIZE_Y, std::size_t SRC_SIZE_X> 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}) 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 i = 0; i < buffer.size(); i++) {
for (unsigned long j = 0; j < buffer[i].size(); j++) { for (unsigned long j = 0; j < buffer[i].size(); j++) {
if (buffer[i][j] > 0xFF) // 0xFF correspond to a black pixel with full brightness if (buffer[i][j] > 0xFF) // 0xFF correspond to a black pixel with full brightness

File diff suppressed because it is too large Load Diff

View File

@@ -7,9 +7,15 @@
#include <stdint-gcc.h> #include <stdint-gcc.h>
#include <cstddef> #include <cstddef>
#include <memory>
#include <array> #include <array>
#include "Models/Vector2.hpp" #include "Models/Vector2.hpp"
namespace ComSquare::PPU
{
class PPU;
}
namespace ComSquare::PPU::Utils namespace ComSquare::PPU::Utils
{ {
@@ -72,8 +78,5 @@ namespace ComSquare::PPU::Utils
std::reverse(array.begin() + offset.x, array.begin() + offset.x + size.x); 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 #endif //COMSQUARE_PPU_UTILS_HPP

3904
sources/PPU/PpuDebug.cpp Normal file

File diff suppressed because it is too large Load Diff

19
sources/PPU/PpuDebug.hpp Normal file
View 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);
}

View File

@@ -54,25 +54,30 @@ namespace ComSquare::Renderer
{ {
try { try {
this->_snes.update(); this->_snes.update();
} catch (const DebuggableError &e) { }
#ifdef DEBUGGER_ENABLED
catch (const DebuggableError &e) {
std::cout << "Invalid rom's instruction: " << e.what() << std::endl; std::cout << "Invalid rom's instruction: " << e.what() << std::endl;
this->_snes.enableCPUDebuggingWithError(e); this->_snes.enableCPUDebuggingWithError(e);
} catch (std::exception &e) { }
#endif
catch (std::exception &e) {
std::cerr << "An error occurred: " << e.what() << std::endl; std::cerr << "An error occurred: " << e.what() << std::endl;
QApplication::quit(); QApplication::quit();
} }
} }
void QtFullSFML::reset()
{
this->_snes.cpu.RESB();
}
#ifdef DEBUGGER_ENABLED
void QtFullSFML::enableDebugCPU() void QtFullSFML::enableDebugCPU()
{ {
this->_snes.enableCPUDebugging(); this->_snes.enableCPUDebugging();
} }
void QtFullSFML::reset()
{
this->_snes.cpu->RESB();
}
void QtFullSFML::enableRamViewer() void QtFullSFML::enableRamViewer()
{ {
this->_snes.enableRamViewer(); this->_snes.enableRamViewer();
@@ -107,8 +112,9 @@ namespace ComSquare::Renderer
{ {
this->_snes.enableTileViewerDebugging(); this->_snes.enableTileViewerDebugging();
} }
#endif
QtSFMLWindow::QtSFMLWindow(unsigned int height, unsigned int width) QtSFMLWindow::QtSFMLWindow(int height, int width)
: QtSFML(&this->_window) : QtSFML(&this->_window)
{ {
this->_window.resize(width, height); this->_window.resize(width, height);
@@ -118,7 +124,7 @@ namespace ComSquare::Renderer
void QtSFMLWindow::createWindow(SNES &snes, int maxFPS) void QtSFMLWindow::createWindow(SNES &snes, int maxFPS)
{ {
QtSFML::createWindow(snes, maxFPS); QtSFML::createWindow(snes, maxFPS);
this->setWindowName(snes.cartridge->header.gameName); this->setWindowName(snes.cartridge.header.gameName);
this->_window.setCentralWidget(this->_sfWidget); this->_window.setCentralWidget(this->_sfWidget);
QMenu *file = this->_window.menuBar()->addMenu("&File"); QMenu *file = this->_window.menuBar()->addMenu("&File");
@@ -126,52 +132,52 @@ namespace ComSquare::Renderer
(void)file; (void)file;
QMenu *game = this->_window.menuBar()->addMenu("&Game"); 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); QMainWindow::connect(reset, &QAction::triggered, this->_sfWidget, &QtFullSFML::reset);
game->addAction(reset); game->addAction(reset);
#ifdef DEBUGGER_ENABLED
QMenu *debugger = this->_window.menuBar()->addMenu("&Debugger"); 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); cpuDebugger->setShortcut(Qt::Key_F1);
QMainWindow::connect(cpuDebugger, &QAction::triggered, this->_sfWidget, &QtFullSFML::enableDebugCPU); QMainWindow::connect(cpuDebugger, &QAction::triggered, this->_sfWidget, &QtFullSFML::enableDebugCPU);
debugger->addAction(cpuDebugger); debugger->addAction(cpuDebugger);
QAction *ramViewer = new QAction("Memory viewer", &this->_window); auto *ramViewer = new QAction("Memory viewer", &this->_window);
ramViewer->setShortcut(Qt::Key_F2); ramViewer->setShortcut(Qt::Key_F2);
QMainWindow::connect(ramViewer, &QAction::triggered, this->_sfWidget, &QtFullSFML::enableRamViewer); QMainWindow::connect(ramViewer, &QAction::triggered, this->_sfWidget, &QtFullSFML::enableRamViewer);
debugger->addAction(ramViewer); debugger->addAction(ramViewer);
QAction *headerViewer = new QAction("Header viewer", &this->_window); auto *headerViewer = new QAction("Header viewer", &this->_window);
headerViewer->setShortcut(Qt::Key_F3); headerViewer->setShortcut(Qt::Key_F3);
QMainWindow::connect(headerViewer, &QAction::triggered, this->_sfWidget, &QtFullSFML::enableHeaderViewer); QMainWindow::connect(headerViewer, &QAction::triggered, this->_sfWidget, &QtFullSFML::enableHeaderViewer);
debugger->addAction(headerViewer); 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); apuDebugger->setShortcut(Qt::Key_F4);
QMainWindow::connect(apuDebugger, &QAction::triggered, this->_sfWidget, &QtFullSFML::enableDebugAPU); QMainWindow::connect(apuDebugger, &QAction::triggered, this->_sfWidget, &QtFullSFML::enableDebugAPU);
debugger->addAction(apuDebugger); 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); busDebugger->setShortcut(Qt::Key_F5);
QMainWindow::connect(busDebugger, &QAction::triggered, this->_sfWidget, &QtFullSFML::enableDebugBus); QMainWindow::connect(busDebugger, &QAction::triggered, this->_sfWidget, &QtFullSFML::enableDebugBus);
debugger->addAction(busDebugger); debugger->addAction(busDebugger);
QAction *cgramDebugger = new QAction("Palette Viewer", &this->_window); auto *cgramDebugger = new QAction("Palette Viewer", &this->_window);
cgramDebugger->setShortcut(Qt::Key_F6); cgramDebugger->setShortcut(Qt::Key_F6);
QMainWindow::connect(cgramDebugger, &QAction::triggered, this->_sfWidget, &QtFullSFML::enableCgramViewer); QMainWindow::connect(cgramDebugger, &QAction::triggered, this->_sfWidget, &QtFullSFML::enableCgramViewer);
debugger->addAction(cgramDebugger); debugger->addAction(cgramDebugger);
QAction *registerDebugger = new QAction("Registers Viewer", &this->_window); auto *registerDebugger = new QAction("Registers Viewer", &this->_window);
registerDebugger->setShortcut(Qt::Key_F7); registerDebugger->setShortcut(Qt::Key_F7);
QMainWindow::connect(registerDebugger, &QAction::triggered, this->_sfWidget, &QtFullSFML::enableRegisterViewer); QMainWindow::connect(registerDebugger, &QAction::triggered, this->_sfWidget, &QtFullSFML::enableRegisterViewer);
debugger->addAction(registerDebugger); debugger->addAction(registerDebugger);
QAction *tileDebugger = new QAction("Tile Viewer", &this->_window); auto *tileDebugger = new QAction("Tile Viewer", &this->_window);
tileDebugger->setShortcut(Qt::Key_F8); tileDebugger->setShortcut(Qt::Key_F8);
QMainWindow::connect(tileDebugger, &QAction::triggered, this->_sfWidget, &QtFullSFML::enableTileViewer); QMainWindow::connect(tileDebugger, &QAction::triggered, this->_sfWidget, &QtFullSFML::enableTileViewer);
debugger->addAction(tileDebugger); debugger->addAction(tileDebugger);
#endif
this->_window.show(); this->_window.show();
} }

View File

@@ -2,16 +2,15 @@
// Created by anonymus-raccoon on 2/15/20. // Created by anonymus-raccoon on 2/15/20.
// //
#ifndef COMSQUARE_QTSFML_HPP #pragma once
#define COMSQUARE_QTSFML_HPP
#include <QtWidgets/QWidget> #include <QtWidgets/QWidget>
#include <SFML/Graphics/RenderWindow.hpp> #include <SFML/Graphics/RenderWindow.hpp>
#include <QtCore/QTimer> #include <QtCore/QTimer>
#include <QtWidgets/QMainWindow> #include <QtWidgets/QMainWindow>
#include <QtWidgets/QGridLayout> #include <QtWidgets/QGridLayout>
#include "../IRenderer.hpp" #include "Renderer/IRenderer.hpp"
#include "../SFRenderer.hpp" #include "Renderer/SFRenderer.hpp"
#include "QtWidgetSFML.hpp" #include "QtWidgetSFML.hpp"
namespace ComSquare::Renderer namespace ComSquare::Renderer
@@ -23,6 +22,7 @@ namespace ComSquare::Renderer
SNES &_snes; SNES &_snes;
void onUpdate() override; void onUpdate() override;
public: public:
#ifdef DEBUGGER_ENABLED
//! @brief Action called when clicking on the enable CPU debugger button. //! @brief Action called when clicking on the enable CPU debugger button.
void enableDebugCPU(); void enableDebugCPU();
//! @brief Action called when clicking on the enable Ram viewer button. //! @brief Action called when clicking on the enable Ram viewer button.
@@ -39,6 +39,7 @@ namespace ComSquare::Renderer
void enableRegisterViewer(); void enableRegisterViewer();
//! @brief Action called when clicking on the enable Tile viewer button //! @brief Action called when clicking on the enable Tile viewer button
void enableTileViewer(); void enableTileViewer();
#endif
//! @brief Action called when clicking on the reset button. //! @brief Action called when clicking on the reset button.
void reset(); void reset();
@@ -46,7 +47,7 @@ namespace ComSquare::Renderer
QtFullSFML(SNES &snes, QWidget* parent, const QPoint& position, const QSize& size, int frameRate = 0); QtFullSFML(SNES &snes, QWidget* parent, const QPoint& position, const QSize& size, int frameRate = 0);
QtFullSFML(const QtFullSFML &) = delete; QtFullSFML(const QtFullSFML &) = delete;
QtFullSFML &operator=(const QtFullSFML &) = delete; QtFullSFML &operator=(const QtFullSFML &) = delete;
~QtFullSFML() = default; ~QtFullSFML() override = default;
}; };
//! @brief A SFML renderer inside a QT widget. //! @brief A SFML renderer inside a QT widget.
@@ -60,7 +61,7 @@ namespace ComSquare::Renderer
public: public:
//! @brief Use this function to create the window. //! @brief Use this function to create the window.
//! @param maxFPS The number of FPS you aim to run on. //! @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. //! @brief Add a pixel to the buffer to the coordinates x, y with the color rgba.
//! @param X horizontal index. //! @param X horizontal index.
//! @param Y vertical index. //! @param Y vertical index.
@@ -76,7 +77,7 @@ namespace ComSquare::Renderer
//! @param newWindowName new title for the window. //! @param newWindowName new title for the window.
void setWindowName(std::string &newWindowName) override; void setWindowName(std::string &newWindowName) override;
//! @brief Constructor that return a SFML renderer inside a QT widget. //! @brief Constructor that return a SFML renderer inside a QT widget.
QtSFML(QWidget *parentWidget); explicit QtSFML(QWidget *parentWidget);
QtSFML(const QtSFML &) = delete; QtSFML(const QtSFML &) = delete;
QtSFML &operator=(const QtSFML &) = delete; QtSFML &operator=(const QtSFML &) = delete;
~QtSFML() = default; ~QtSFML() = default;
@@ -93,11 +94,9 @@ namespace ComSquare::Renderer
//! @brief Constructor that return a SFML renderer inside a QT window. //! @brief Constructor that return a SFML renderer inside a QT window.
//! @param height _height of the window. //! @param height _height of the window.
//! @param width _width 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(const QtSFMLWindow &) = delete;
QtSFMLWindow &operator=(const QtSFMLWindow &) = delete; QtSFMLWindow &operator=(const QtSFMLWindow &) = delete;
~QtSFMLWindow() = default; ~QtSFMLWindow() = default;
}; };
} }
#endif //COMSQUARE_QTSFML_HPP

View File

@@ -2,13 +2,11 @@
// Created by cbihan on 1/30/20. // Created by cbihan on 1/30/20.
// //
#include "SNES.hpp"
#include "SFRenderer.hpp" #include "SFRenderer.hpp"
#include <SFML/Graphics.hpp>
#include <SFML/Audio.hpp>
#include <SFML/System.hpp> #include <SFML/System.hpp>
#include <SFML/Window.hpp> #include <SFML/Window.hpp>
#include <SFML/Graphics/RenderWindow.hpp> #include <SFML/Graphics/RenderWindow.hpp>
#include "SNES.hpp"
#include <iostream> #include <iostream>
namespace ComSquare::Renderer namespace ComSquare::Renderer
@@ -29,7 +27,7 @@ namespace ComSquare::Renderer
if (icon.loadFromFile("resources/Logo.png")) if (icon.loadFromFile("resources/Logo.png"))
this->_window.setIcon(314, 314, icon.getPixelsPtr()); this->_window.setIcon(314, 314, icon.getPixelsPtr());
this->_window.setFramerateLimit(maxFPS); this->_window.setFramerateLimit(maxFPS);
this->setWindowName(snes.cartridge->header.gameName); this->setWindowName(snes.cartridge.header.gameName);
while (!this->shouldExit) { while (!this->shouldExit) {
snes.update(); snes.update();

View File

@@ -2,60 +2,72 @@
// Created by anonymus-raccoon on 1/27/20. // Created by anonymus-raccoon on 1/27/20.
// //
#include <ios>
#include <iostream>
#include "SNES.hpp" #include "SNES.hpp"
#include <ios>
#ifdef DEBUGGER_ENABLED #ifdef DEBUGGER_ENABLED
#include "Debugger/CPU/CPUDebug.hpp"
#include "Debugger/APUDebug.hpp" #include "Debugger/APUDebug.hpp"
#include "Debugger/CPU/CPUDebug.hpp"
#include "Debugger/MemoryBusDebug.hpp" #include "Debugger/MemoryBusDebug.hpp"
#include "Debugger/CGramDebug.hpp"
#include "Debugger/TileViewer/TileViewer.hpp" #include "Debugger/TileViewer/TileViewer.hpp"
#endif #endif
namespace ComSquare namespace ComSquare
{ {
SNES::SNES(const std::string &romPath, Renderer::IRenderer &renderer) : SNES::SNES(Renderer::IRenderer &renderer)
bus(std::make_shared<Memory::MemoryBus>()), : bus(),
cartridge(std::make_shared<Cartridge::Cartridge>(romPath)), cartridge(),
wram(std::make_shared<Ram::Ram>(16384, WRam, "WRam")), wram(16384, WRam, "WRam"),
sram(std::make_shared<Ram::Ram>(this->cartridge->header.sramSize, SRam, "SRam")), sram(this->cartridge.header.sramSize, SRam, "SRam"),
cpu(std::make_shared<CPU::CPU>(this->bus, cartridge->header)), cpu(this->bus, cartridge.header),
ppu(std::make_shared<PPU::PPU>(renderer)), ppu(renderer),
apu(std::make_shared<APU::APU>(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); this->bus.mapComponents(*this);
if (this->cartridge->getType() == Cartridge::Audio) if (this->cartridge.getType() == Cartridge::Audio)
this->apu->loadFromSPC(this->cartridge); this->apu.loadFromSPC(this->cartridge);
} }
void SNES::update() void SNES::update()
{ {
if (this->cartridge->getType() == Cartridge::Audio) if (this->cartridge.getType() == Cartridge::Audio) {
{ this->apu.update(0x01);
this->apu->update(0x01);
return; return;
} }
unsigned cycleCount = this->cpu->update(); unsigned cycleCount = this->cpu.update();
this->ppu->update(cycleCount); this->ppu.update(cycleCount);
this->apu->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) void SNES::enableCPUDebuggingWithError(const DebuggableError &exception)
{ {
this->enableCPUDebugging(true); this->enableCPUDebugging(true);
#ifdef DEBUGGER_ENABLED
auto cpuDebug = std::static_pointer_cast<Debugger::CPUDebug>(this->cpu); auto cpuDebug = std::static_pointer_cast<Debugger::CPUDebug>(this->cpu);
cpuDebug->showError(exception); cpuDebug->showError(exception);
#else
(void)exception;
#endif
} }
void SNES::enableCPUDebugging(bool pause) void SNES::enableCPUDebugging(bool pause)
{ {
#ifdef DEBUGGER_ENABLED
if (this->cpu->isDebugger()) { if (this->cpu->isDebugger()) {
auto cpuDebug = std::static_pointer_cast<Debugger::CPUDebug>(this->cpu); auto cpuDebug = std::static_pointer_cast<Debugger::CPUDebug>(this->cpu);
cpuDebug->focus(); cpuDebug->focus();
@@ -63,147 +75,112 @@ namespace ComSquare
cpuDebug->pause(true); cpuDebug->pause(true);
} else { } else {
this->cpu = std::make_shared<Debugger::CPUDebug>(*this->cpu, *this); 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() void SNES::disableCPUDebugging()
{ {
this->cpu = std::make_shared<CPU::CPU>(*this->cpu); this->cpu = std::make_shared<CPU::CPU>(*this->cpu);
this->bus->mapComponents(*this); this->bus.mapComponents(*this);
} }
void SNES::enableRamViewer() void SNES::enableRamViewer()
{ {
#ifdef DEBUGGER_ENABLED
if (this->_ramViewer) if (this->_ramViewer)
this->_ramViewer->focus(); this->_ramViewer->focus();
else else
this->_ramViewer = std::make_unique<Debugger::MemoryViewer>(*this, *this->bus); this->_ramViewer.emplace(*this, *this->bus);
#endif
} }
void SNES::disableRamViewer() void SNES::disableRamViewer()
{ {
#ifdef DEBUGGER_ENABLED this->_ramViewer = std::nullopt;
this->_ramViewer = nullptr;
#endif
} }
void SNES::enableHeaderViewer() void SNES::enableHeaderViewer()
{ {
#ifdef DEBUGGER_ENABLED
if (this->_headerViewer) if (this->_headerViewer)
this->_headerViewer->focus(); this->_headerViewer->focus();
else else
this->_headerViewer = std::make_unique<Debugger::HeaderViewer>(*this); this->_headerViewer.emplace(*this);
#endif
} }
void SNES::disableHeaderViewer() void SNES::disableHeaderViewer()
{ {
#ifdef DEBUGGER_ENABLED this->_headerViewer = std::nullopt;
this->_headerViewer = nullptr;
#endif
} }
void SNES::enableAPUDebugging() void SNES::enableAPUDebugging()
{ {
#ifdef DEBUGGER_ENABLED
if (this->apu->isDebugger()) if (this->apu->isDebugger())
std::static_pointer_cast<Debugger::APUDebug>(this->apu)->focus(); std::static_pointer_cast<Debugger::APUDebug>(this->apu)->focus();
else { else {
this->apu = std::make_shared<Debugger::APUDebug>(*this->apu, *this); 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() void SNES::disableAPUDebugging()
{ {
this->apu = std::make_shared<APU::APU>(*this->apu); this->apu = std::make_shared<APU::APU>(*this->apu);
this->bus->mapComponents(*this); this->bus.mapComponents(*this);
} }
void SNES::enableMemoryBusDebugging() void SNES::enableMemoryBusDebugging()
{ {
#ifdef DEBUGGER_ENABLED if (this->bus.isDebugger())
if (this->bus->isDebugger())
std::static_pointer_cast<Debugger::MemoryBusDebug>(this->bus)->focus(); std::static_pointer_cast<Debugger::MemoryBusDebug>(this->bus)->focus();
else else {
{
this->bus = std::make_shared<Debugger::MemoryBusDebug>(*this, *this->bus); this->bus = std::make_shared<Debugger::MemoryBusDebug>(*this, *this->bus);
this->cpu->setMemoryBus(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() void SNES::disableMemoryBusDebugging()
{ {
#ifdef DEBUGGER_ENABLED
this->bus = std::make_shared<Memory::MemoryBus>(*this->bus); this->bus = std::make_shared<Memory::MemoryBus>(*this->bus);
this->cpu->setMemoryBus(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() void SNES::enableCgramDebugging()
{ {
#ifdef DEBUGGER_ENABLED
if (this->_cgramViewer) if (this->_cgramViewer)
this->_cgramViewer->focus(); this->_cgramViewer->focus();
else else
this->_cgramViewer = std::make_unique<Debugger::CGramDebug>(*this, *this->ppu); this->_cgramViewer.emplace(*this, *this->ppu);
#endif
} }
void SNES::disableCgramDebugging() void SNES::disableCgramDebugging()
{ {
#ifdef DEBUGGER_ENABLED this->_cgramViewer = std::nullopt;
this->_cgramViewer = nullptr;
#endif
} }
void SNES::disableRegisterDebugging() void SNES::disableRegisterDebugging()
{ {
#ifdef DEBUGGER_ENABLED this->_registerViewer = std::nullopt;
this->_registerViewer = nullptr;
#endif
} }
void SNES::enableRegisterDebugging() void SNES::enableRegisterDebugging()
{ {
#ifdef DEBUGGER_ENABLED
if (this->_registerViewer) if (this->_registerViewer)
this->_registerViewer->focus(); this->_registerViewer->focus();
else else
this->_registerViewer = std::make_unique<Debugger::RegisterViewer>(*this); this->_registerViewer.emplace(*this);
#endif
} }
void SNES::disableTileViewerDebugging() void SNES::disableTileViewerDebugging()
{ {
#ifdef DEBUGGER_ENABLED this->_tileViewer = std::nullopt;
this->_tileViewer = nullptr;
#endif
} }
void SNES::enableTileViewerDebugging() void SNES::enableTileViewerDebugging()
{ {
#ifdef DEBUGGER_ENABLED
if (this->_tileViewer) if (this->_tileViewer)
this->_tileViewer->focus(); this->_tileViewer->focus();
else else
this->_tileViewer = std::make_unique<Debugger::TileViewer>(*this, *this->ppu); this->_tileViewer.emplace(*this, *this->ppu);
#endif
} }
}
#endif
}// namespace ComSquare

View File

@@ -2,63 +2,84 @@
// Created by anonymus-raccoon on 1/27/20. // Created by anonymus-raccoon on 1/27/20.
// //
#ifndef COMSQUARE_SNES_HPP #pragma once
#define COMSQUARE_SNES_HPP
#include "Memory/MemoryBus.hpp" #include "APU/APU.hpp"
#include "CPU/CPU.hpp" #include "CPU/CPU.hpp"
#include "Cartridge/Cartridge.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 "Exceptions/DebuggableError.hpp"
#include "Memory/MemoryBus.hpp"
#include "PPU/PPU.hpp"
#include "Ram/Ram.hpp"
#include "Renderer/IRenderer.hpp"
#include <optional>
#ifdef DEBUGGER_ENABLED #ifdef DEBUGGER_ENABLED
#include "Debugger/MemoryViewer.hpp" #include "Debugger/MemoryViewer.hpp"
#include "Debugger/HeaderViewer.hpp" #include "Debugger/HeaderViewer.hpp"
#include "Debugger/CGramDebug.hpp" #include "Debugger/CGramDebug.hpp"
#include "Debugger/RegisterViewer.hpp" #include "Debugger/RegisterViewer.hpp"
#include "Debugger/TileViewer/TileViewer.hpp" #include "Debugger/TileViewer/TileViewer.hpp"
#endif #endif
namespace ComSquare namespace ComSquare
{ {
//! @brief Container of all the components of the SNES. //! @brief Container of all the components of the SNES.
class SNES { class SNES
{
private: private:
#ifdef DEBUGGER_ENABLED #ifdef DEBUGGER_ENABLED
//! @brief The window that allow the user to view a memory. //! @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. //! @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. //! @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. //! @brief The window that allow the user to view registers.
std::unique_ptr<Debugger::RegisterViewer> _registerViewer; std::optional<Debugger::RegisterViewer> _registerViewer;
//! @brief The window that allow the user to view the cgram as tiles. //! @brief The window that allow the user to view the CGRAM as tiles.
std::unique_ptr<Debugger::TileViewer> _tileViewer; std::optional<Debugger::TileViewer> _tileViewer;
#endif #endif
public: public:
//! @brief The memory bus that map addresses to components. //! @brief The memory bus that map addresses to components.
std::shared_ptr<Memory::MemoryBus> bus; Memory::MemoryBus bus;
//! @brief Cartridge containing instructions (ROM). //! @brief Cartridge containing instructions (ROM).
std::shared_ptr<Cartridge::Cartridge> cartridge; Cartridge::Cartridge cartridge;
//! @brief Work Ram shared by all the components. //! @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. //! @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. //! @brief Central Processing Unit of the SNES.
std::shared_ptr<CPU::CPU> cpu; CPU::CPU cpu;
//! @brief Picture Processing Unit of the SNES //! @brief Picture Processing Unit of the SNES
std::shared_ptr<PPU::PPU> ppu; PPU::PPU ppu;
//! @brief Audio Processing Unit if the SNES //! @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 //! @brief Call this function to update all the components
void update(); 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. //! @brief Disable the CPU's debugging window.
void disableCPUDebugging(); void disableCPUDebugging();
//! @brief Enable the CPU's debugging window. //! @brief Enable the CPU's debugging window.
@@ -82,9 +103,9 @@ namespace ComSquare
void disableMemoryBusDebugging(); void disableMemoryBusDebugging();
//! @brief Enable the Memory Bus's debugging window. //! @brief Enable the Memory Bus's debugging window.
void enableMemoryBusDebugging(); void enableMemoryBusDebugging();
//! @brief Disable the Cgram's debugging window. //! @brief Disable the CGRAM's debugging window.
void disableCgramDebugging(); void disableCgramDebugging();
//! @brief Enable the Cgram's debugging window. //! @brief Enable the CGRAM's debugging window.
void enableCgramDebugging(); void enableCgramDebugging();
//! @brief Disable the Register's debugging window. //! @brief Disable the Register's debugging window.
void disableRegisterDebugging(); void disableRegisterDebugging();
@@ -94,13 +115,6 @@ namespace ComSquare
void disableTileViewerDebugging(); void disableTileViewerDebugging();
//! @brief Enable the TileViewer's debugging window. //! @brief Enable the TileViewer's debugging window.
void enableTileViewerDebugging(); void enableTileViewerDebugging();
#endif
//! @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;
}; };
} }// namespace ComSquare
#endif //COMSQUARE_SNES_HPP

View File

@@ -15,36 +15,53 @@ void usage(char *bin)
std::cout << "ComSquare:" << std::endl std::cout << "ComSquare:" << std::endl
<< "\tUsage: " << bin << " rom_path [options]" << std::endl << "\tUsage: " << bin << " rom_path [options]" << std::endl
<< "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-c, --cpu: \tEnable the debugger of the CPU." << std::endl
<< "\t-m, --memory: \tEnable the memory viewer panel." << 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-b, --bus: \tShow the memory bus's log." << std::endl
<< "\t-g, --cgram: \tShow the palette viewer." << 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) void parseArguments(int argc, char **argv, SNES &snes)
{ {
while (true) {
int option_index = 0; int option_index = 0;
static struct option long_options[] = { static struct option long_options[] = {
{"help", no_argument, 0, 'h'},
#ifdef DEBUGGER_ENABLED
{"cpu", no_argument, 0, 'c'}, {"cpu", no_argument, 0, 'c'},
{"apu", no_argument, 0, 'a'}, {"apu", no_argument, 0, 'a'},
{"memory", no_argument, 0, 'm'}, {"memory", no_argument, 0, 'm'},
{"header", no_argument, 0, 'h'}, {"header", no_argument, 0, 'H'},
{"bus", no_argument, 0, 'b'}, {"bus", no_argument, 0, 'b'},
{"cgram", no_argument, 0, 'g'}, {"cgram", no_argument, 0, 'g'},
{"registers", no_argument, 0, 'r'}, {"registers", no_argument, 0, 'r'},
#endif
{0, 0, 0, 0} {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) if (c == -1)
break; break;
switch (c) { switch (c) {
case 0: case 0:
usage(argv[0]); usage(argv[0]);
break; exit(2);
case 'h':
usage(argv[0]);
exit(0);
#ifdef DEBUGGER_ENABLED
case 'c': case 'c':
snes.enableCPUDebugging(); snes.enableCPUDebugging();
break; break;
@@ -66,15 +83,22 @@ void parseArguments(int argc, char **argv, SNES &snes)
case 'r': case 'r':
snes.enableRegisterDebugging(); snes.enableRegisterDebugging();
break; break;
#endif
default: default:
break; exit(2);
} }
} }
if (optind != argc - 1) {
usage(argv[0]);
exit(2);
}
snes.loadRom(argv[optind]);
} }
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
if (argc < 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) { if (argc < 2) {
usage(argv[0]); usage(argv[0]);
return 1; return 1;
} }
@@ -82,10 +106,13 @@ int main(int argc, char **argv)
QApplication::setAttribute(Qt::AA_DisableWindowContextHelpButton); QApplication::setAttribute(Qt::AA_DisableWindowContextHelpButton);
Renderer::QtSFMLWindow renderer(1100, 1100); Renderer::QtSFMLWindow renderer(1100, 1100);
try { try {
SNES snes(argv[1], renderer); // TODO remove the new once arrays are newed.
renderer.createWindow(snes, 60); auto *snes = new SNES(renderer);
parseArguments(argc, argv, snes); parseArguments(argc, argv, *snes);
return QApplication::exec(); renderer.createWindow(*snes, 60);
int ret = QApplication::exec();
delete snes;
return ret;
} }
catch(std::exception &ex) { catch(std::exception &ex) {
std::cerr << ex.what() << std::endl; std::cerr << ex.what() << std::endl;

View File

@@ -20,20 +20,20 @@ TEST_CASE("RomToVRAM DMA", "[DMA]")
// Transferring $800 bytes from ROM ($13BE00) to VRam ($2000) via DMA channel 0 // Transferring $800 bytes from ROM ($13BE00) to VRam ($2000) via DMA channel 0
// Setting VRam address (since this is an indirect write) // Setting VRam address (since this is an indirect write)
snes.bus->write(0x2115, 0b10000000); snes.bus.write(0x2115, 0b10000000);
snes.bus->write(0x2117, 0x20); snes.bus.write(0x2117, 0x20);
snes.bus->write(0x2116, 0); snes.bus.write(0x2116, 0);
snes.bus->write(0x4301, 0x18); snes.bus.write(0x4301, 0x18);
REQUIRE(snes.cpu->_dmaChannels[0]._port == 0x18); REQUIRE(snes.cpu->_dmaChannels[0]._port == 0x18);
snes.bus->write(0x4304, 0x13); snes.bus.write(0x4304, 0x13);
snes.bus->write(0x4303, 0xBE); snes.bus.write(0x4303, 0xBE);
snes.bus->write(0x4302, 0x00); snes.bus.write(0x4302, 0x00);
REQUIRE(snes.cpu->_dmaChannels[0]._aAddress.raw == 0x13BE00); REQUIRE(snes.cpu->_dmaChannels[0]._aAddress.raw == 0x13BE00);
snes.bus->write(0x4306, 0x08); snes.bus.write(0x4306, 0x08);
snes.bus->write(0x4305, 0); snes.bus.write(0x4305, 0);
REQUIRE(snes.cpu->_dmaChannels[0]._count.raw == 0x0800); 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.direction == CPU::DMA::AtoB);
REQUIRE(snes.cpu->_dmaChannels[0]._controlRegister._ == 0); REQUIRE(snes.cpu->_dmaChannels[0]._controlRegister._ == 0);
REQUIRE(snes.cpu->_dmaChannels[0]._controlRegister.increment == 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]._controlRegister.mode == CPU::DMA::TwoToTwo);
REQUIRE(snes.cpu->_dmaChannels[0].enabled == false); REQUIRE(snes.cpu->_dmaChannels[0].enabled == false);
// Enabling DMA's channel 0 // Enabling DMA's channel 0
snes.bus->write(0x420B, 1); snes.bus.write(0x420B, 1);
REQUIRE(snes.cpu->_dmaChannels[0].enabled == true); 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? // 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); auto cycles = snes.cpu->_dmaChannels[0].run(1000000);
@@ -60,11 +60,11 @@ TEST_CASE("RomToVRAM DMA", "[DMA]")
TEST_CASE("VramWrite DMA", "[DMA]") TEST_CASE("VramWrite DMA", "[DMA]")
{ {
Init() Init()
snes.bus->write(0x2117, 0x20); snes.bus.write(0x2117, 0x20);
snes.bus->write(0x2116, 0x0); snes.bus.write(0x2116, 0x0);
for (unsigned i = 0; i < 0x400; i++) { for (unsigned i = 0; i < 0x400; i++) {
snes.bus->write(0x2119, i >> 8); snes.bus.write(0x2119, i >> 8);
snes.bus->write(0x2118, i); snes.bus.write(0x2118, i);
REQUIRE(snes.ppu->_registers._vmadd.vmadd == 0x2001 + i); REQUIRE(snes.ppu->_registers._vmadd.vmadd == 0x2001 + i);
} }
for(unsigned i = 0; i < 0x400; i++) { for(unsigned i = 0; i < 0x400; i++) {
@@ -76,12 +76,12 @@ TEST_CASE("VramWrite DMA", "[DMA]")
TEST_CASE("VramWriteInvertedOrder DMA", "[DMA]") TEST_CASE("VramWriteInvertedOrder DMA", "[DMA]")
{ {
Init() Init()
snes.bus->write(0x2115, 0b10000000); snes.bus.write(0x2115, 0b10000000);
snes.bus->write(0x2117, 0x20); snes.bus.write(0x2117, 0x20);
snes.bus->write(0x2116, 0x0); snes.bus.write(0x2116, 0x0);
for (unsigned i = 0; i < 0x400; i++) { for (unsigned i = 0; i < 0x400; i++) {
snes.bus->write(0x2118, i); snes.bus.write(0x2118, i);
snes.bus->write(0x2119, i >> 8); snes.bus.write(0x2119, i >> 8);
REQUIRE(snes.ppu->_registers._vmadd.vmadd == 0x2001 + i); REQUIRE(snes.ppu->_registers._vmadd.vmadd == 0x2001 + i);
} }
for(unsigned i = 0; i < 0x400; 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 // Transferring $800 bytes from WRAM ($00) to VRam ($2000) via DMA channel 0
// Setting VRam address (since this is an indirect write) // Setting VRam address (since this is an indirect write)
snes.bus->write(0x2115, 0b10000000); snes.bus.write(0x2115, 0b10000000);
snes.bus->write(0x2117, 0); snes.bus.write(0x2117, 0);
snes.bus->write(0x2116, 0); snes.bus.write(0x2116, 0);
snes.bus->write(0x4301, 0x18); snes.bus.write(0x4301, 0x18);
REQUIRE(snes.cpu->_dmaChannels[0]._port == 0x18); REQUIRE(snes.cpu->_dmaChannels[0]._port == 0x18);
snes.bus->write(0x4304, 0x7E); snes.bus.write(0x4304, 0x7E);
snes.bus->write(0x4303, 0x00); snes.bus.write(0x4303, 0x00);
snes.bus->write(0x4302, 0x00); snes.bus.write(0x4302, 0x00);
REQUIRE(snes.cpu->_dmaChannels[0]._aAddress.raw == 0x7E0000); REQUIRE(snes.cpu->_dmaChannels[0]._aAddress.raw == 0x7E0000);
snes.bus->write(0x4306, 0x08); snes.bus.write(0x4306, 0x08);
snes.bus->write(0x4305, 0); snes.bus.write(0x4305, 0);
REQUIRE(snes.cpu->_dmaChannels[0]._count.raw == 0x0800); 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.direction == CPU::DMA::AtoB);
REQUIRE(snes.cpu->_dmaChannels[0]._controlRegister._ == 0); REQUIRE(snes.cpu->_dmaChannels[0]._controlRegister._ == 0);
REQUIRE(snes.cpu->_dmaChannels[0]._controlRegister.increment == 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]._controlRegister.mode == CPU::DMA::TwoToTwo);
REQUIRE(snes.cpu->_dmaChannels[0].enabled == false); REQUIRE(snes.cpu->_dmaChannels[0].enabled == false);
// Enabling DMA's channel 0 // Enabling DMA's channel 0
snes.bus->write(0x420B, 1); snes.bus.write(0x420B, 1);
REQUIRE(snes.cpu->_dmaChannels[0].enabled == true); 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? // 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); auto cycles = snes.cpu->_dmaChannels[0].run(1000000);

View File

@@ -15,7 +15,7 @@ using namespace ComSquare;
TEST_CASE("basicTest backgroundGetTilePixelReference", "[backgroundGetTilePixelReference]") TEST_CASE("basicTest backgroundGetTilePixelReference", "[backgroundGetTilePixelReference]")
{ {
Init() Init()
snes.bus->write(0x2100, 0b11111111); snes.bus.write(0x2100, 0b11111111);
REQUIRE(snes.ppu->_registers._inidisp.fblank == true); REQUIRE(snes.ppu->_registers._inidisp.fblank == true);
REQUIRE(snes.ppu->_registers._inidisp.brightness == 0xF); REQUIRE(snes.ppu->_registers._inidisp.brightness == 0xF);
} }

View File

@@ -14,32 +14,32 @@ using namespace ComSquare;
TEST_CASE("vram_data_read_full PPU_read_1", "[PPU_read_1]") TEST_CASE("vram_data_read_full PPU_read_1", "[PPU_read_1]")
{ {
Init() Init()
snes.bus->write(0x2115, 0b10000000); snes.bus.write(0x2115, 0b10000000);
snes.bus->write(0x2116, 0); snes.bus.write(0x2116, 0);
snes.bus->write(0x2117, 0); snes.bus.write(0x2117, 0);
snes.ppu->vram->write(0, 0b11111111); snes.ppu->vram->write(0, 0b11111111);
snes.ppu->vram->write(1, 0b11111111); snes.ppu->vram->write(1, 0b11111111);
snes.bus->write(0x2116, 0); snes.bus.write(0x2116, 0);
snes.bus->write(0x2117, 0); snes.bus.write(0x2117, 0);
uint8_t tmp = snes.bus->read(0x2139); uint8_t tmp = snes.bus.read(0x2139);
CHECK(tmp == 0b11111111); CHECK(tmp == 0b11111111);
tmp = snes.bus->read(0x213a); tmp = snes.bus.read(0x213a);
CHECK(tmp == 0b11111111); CHECK(tmp == 0b11111111);
} }
TEST_CASE("vram_data_read_half PPU_read_1", "[PPU_read_1]") TEST_CASE("vram_data_read_half PPU_read_1", "[PPU_read_1]")
{ {
Init() Init()
snes.bus->write(0x2116, 0); snes.bus.write(0x2116, 0);
snes.bus->write(0x2117, 0); snes.bus.write(0x2117, 0);
snes.ppu->vram->write(0, 0b01101001); snes.ppu->vram->write(0, 0b01101001);
snes.ppu->vram->write(1, 0b11111111); snes.ppu->vram->write(1, 0b11111111);
snes.bus->write(0x2116, 0); snes.bus.write(0x2116, 0);
snes.bus->write(0x2117, 0); snes.bus.write(0x2117, 0);
uint8_t tmp = snes.bus->read(0x2139); uint8_t tmp = snes.bus.read(0x2139);
CHECK(tmp == 0b01101001); CHECK(tmp == 0b01101001);
tmp = snes.bus->read(0x213a); tmp = snes.bus.read(0x213a);
CHECK(tmp == 0b11111111); CHECK(tmp == 0b11111111);
} }

View File

@@ -14,7 +14,7 @@ using namespace ComSquare;
TEST_CASE("inidisp_data_full_ones PPU_write", "[PPU_write]") TEST_CASE("inidisp_data_full_ones PPU_write", "[PPU_write]")
{ {
Init() Init()
snes.bus->write(0x2100, 0b11111111); snes.bus.write(0x2100, 0b11111111);
REQUIRE(snes.ppu->_registers._inidisp.fblank == true); REQUIRE(snes.ppu->_registers._inidisp.fblank == true);
REQUIRE(snes.ppu->_registers._inidisp.brightness == 0xF); 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]") TEST_CASE("inidisp_data_full_zeros PPU_write", "[PPU_write]")
{ {
Init() Init()
snes.bus->write(0x2100, 0b00000000); snes.bus.write(0x2100, 0b00000000);
REQUIRE(snes.ppu->_registers._inidisp.fblank == false); REQUIRE(snes.ppu->_registers._inidisp.fblank == false);
REQUIRE(snes.ppu->_registers._inidisp.brightness == 0x0); 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]") TEST_CASE("inidisp_data_fBlank_on_brghtness_off PPU_write", "[PPU_write]")
{ {
Init() Init()
snes.bus->write(0x2100, 0b10000000); snes.bus.write(0x2100, 0b10000000);
REQUIRE(snes.ppu->_registers._inidisp.fblank == true); REQUIRE(snes.ppu->_registers._inidisp.fblank == true);
REQUIRE(snes.ppu->_registers._inidisp.brightness == 0x0); 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]") TEST_CASE("inidisp_data_fBlank_off_brghtness_max PPU_write", "[PPU_write]")
{ {
Init() Init()
snes.bus->write(0x2100, 0b00001111); snes.bus.write(0x2100, 0b00001111);
REQUIRE(snes.ppu->_registers._inidisp.fblank == false); REQUIRE(snes.ppu->_registers._inidisp.fblank == false);
REQUIRE(snes.ppu->_registers._inidisp.brightness == 0xF); 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]") TEST_CASE("inidisp_data_fBlank_off_brghtness_half PPU_write", "[PPU_write]")
{ {
Init() Init()
snes.bus->write(0x2100, 0b00000101); snes.bus.write(0x2100, 0b00000101);
REQUIRE(snes.ppu->_registers._inidisp.fblank == false); REQUIRE(snes.ppu->_registers._inidisp.fblank == false);
REQUIRE(snes.ppu->_registers._inidisp.brightness == 0x5); 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]") TEST_CASE("obsel_111_object_size_and_all_null PPU_write", "[PPU_write]")
{ {
Init() Init()
snes.bus->write(0x2101, 0b11100000); snes.bus.write(0x2101, 0b11100000);
REQUIRE(snes.ppu->_registers._obsel.objectSize == 0b111); REQUIRE(snes.ppu->_registers._obsel.objectSize == 0b111);
REQUIRE(snes.ppu->_registers._obsel.nameSelect == 0b00); REQUIRE(snes.ppu->_registers._obsel.nameSelect == 0b00);
REQUIRE(snes.ppu->_registers._obsel.nameBaseSelect == 0b000); 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]") TEST_CASE("obsel_data_full PPU_write", "[PPU_write]")
{ {
Init() Init()
snes.bus->write(0x2101, 0b11111111); snes.bus.write(0x2101, 0b11111111);
REQUIRE(snes.ppu->_registers._obsel.objectSize == 0b111); REQUIRE(snes.ppu->_registers._obsel.objectSize == 0b111);
REQUIRE(snes.ppu->_registers._obsel.nameSelect == 0b11); REQUIRE(snes.ppu->_registers._obsel.nameSelect == 0b11);
REQUIRE(snes.ppu->_registers._obsel.nameBaseSelect == 0b111); 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]") TEST_CASE("obsel_data_full_nameselect PPU_write", "[PPU_write]")
{ {
Init() Init()
snes.bus->write(0x2101, 0b00011000); snes.bus.write(0x2101, 0b00011000);
REQUIRE(snes.ppu->_registers._obsel.objectSize == 0b000); REQUIRE(snes.ppu->_registers._obsel.objectSize == 0b000);
REQUIRE(snes.ppu->_registers._obsel.nameSelect == 0b11); REQUIRE(snes.ppu->_registers._obsel.nameSelect == 0b11);
REQUIRE(snes.ppu->_registers._obsel.nameBaseSelect == 0b000); 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]") TEST_CASE("obsel_data_full_baseselect_write", "[PPU_write]")
{ {
Init() Init()
snes.bus->write(0x2101, 0b00000111); snes.bus.write(0x2101, 0b00000111);
REQUIRE(snes.ppu->_registers._obsel.objectSize == 0b000); REQUIRE(snes.ppu->_registers._obsel.objectSize == 0b000);
REQUIRE(snes.ppu->_registers._obsel.nameSelect == 0b00); REQUIRE(snes.ppu->_registers._obsel.nameSelect == 0b00);
REQUIRE(snes.ppu->_registers._obsel.nameBaseSelect == 0b111); 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]") TEST_CASE("oamaddl_data_full PPU_write", "[PPU_write]")
{ {
Init() Init()
snes.bus->write(0x2102, 0b11111111); snes.bus.write(0x2102, 0b11111111);
REQUIRE(snes.ppu->_registers._oamadd.oamAddress == 0b011111111); REQUIRE(snes.ppu->_registers._oamadd.oamAddress == 0b011111111);
} }
TEST_CASE("oamaddh_data_full PPU_write", "[PPU_write]") TEST_CASE("oamaddh_data_full PPU_write", "[PPU_write]")
{ {
Init() Init()
snes.bus->write(0x2103, 0b11111111); snes.bus.write(0x2103, 0b11111111);
REQUIRE(snes.ppu->_registers._oamadd.objPriorityActivationBit == true); REQUIRE(snes.ppu->_registers._oamadd.objPriorityActivationBit == true);
REQUIRE(snes.ppu->_registers._oamadd.oamAddress == 0b100000000); 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]") TEST_CASE("oamaddlh_data_full PPU_write", "[PPU_write]")
{ {
Init() Init()
snes.bus->write(0x2102, 0b11111111); snes.bus.write(0x2102, 0b11111111);
snes.bus->write(0x2103, 0b11111111); snes.bus.write(0x2103, 0b11111111);
REQUIRE(snes.ppu->_registers._oamadd.objPriorityActivationBit == true); REQUIRE(snes.ppu->_registers._oamadd.objPriorityActivationBit == true);
REQUIRE(snes.ppu->_registers._oamadd.oamAddress == 0b111111111); 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]") TEST_CASE("oamaddlh_data_full_priorityBit_off PPU_write", "[PPU_write]")
{ {
Init() Init()
snes.bus->write(0x2102, 0b11111111); snes.bus.write(0x2102, 0b11111111);
snes.bus->write(0x2103, 0b01111111); snes.bus.write(0x2103, 0b01111111);
REQUIRE(snes.ppu->_registers._oamadd.objPriorityActivationBit == false); REQUIRE(snes.ppu->_registers._oamadd.objPriorityActivationBit == false);
REQUIRE(snes.ppu->_registers._oamadd.oamAddress == 0b111111111); 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]") TEST_CASE("oamaddlh_oamAdress_11_priorityBit_on PPU_write", "[PPU_write]")
{ {
Init() Init()
snes.bus->write(0x2102, 0b00001011); snes.bus.write(0x2102, 0b00001011);
snes.bus->write(0x2103, 0b10011100); snes.bus.write(0x2103, 0b10011100);
REQUIRE(snes.ppu->_registers._oamadd.objPriorityActivationBit == true); REQUIRE(snes.ppu->_registers._oamadd.objPriorityActivationBit == true);
REQUIRE(snes.ppu->_registers._oamadd.oamAddress == 11); 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]") TEST_CASE("bgmode_data_full PPU_write", "[PPU_write]")
{ {
Init() Init()
snes.bus->write(0x2105, 0b11111111); snes.bus.write(0x2105, 0b11111111);
REQUIRE(snes.ppu->_registers._bgmode.bgMode == 7); REQUIRE(snes.ppu->_registers._bgmode.bgMode == 7);
REQUIRE(snes.ppu->_registers._bgmode.characterSizeBg1 == true); REQUIRE(snes.ppu->_registers._bgmode.characterSizeBg1 == true);
REQUIRE(snes.ppu->_registers._bgmode.characterSizeBg2 == 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]") TEST_CASE("bgmode_bgmode_5_and_bg24_on PPU_write", "[PPU_write]")
{ {
Init() Init()
snes.bus->write(0x2105, 0b10100101); snes.bus.write(0x2105, 0b10100101);
REQUIRE(snes.ppu->_registers._bgmode.bgMode == 5); REQUIRE(snes.ppu->_registers._bgmode.bgMode == 5);
REQUIRE(snes.ppu->_registers._bgmode.characterSizeBg1 == false); REQUIRE(snes.ppu->_registers._bgmode.characterSizeBg1 == false);
REQUIRE(snes.ppu->_registers._bgmode.characterSizeBg2 == true); 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]") TEST_CASE("mosaic_data_full PPU_write", "[PPU_write]")
{ {
Init() Init()
snes.bus->write(0x2106, 0b11111111); snes.bus.write(0x2106, 0b11111111);
REQUIRE(snes.ppu->_registers._mosaic.affectBg1 == true); REQUIRE(snes.ppu->_registers._mosaic.affectBg1 == true);
REQUIRE(snes.ppu->_registers._mosaic.affectBg2 == true); REQUIRE(snes.ppu->_registers._mosaic.affectBg2 == true);
REQUIRE(snes.ppu->_registers._mosaic.affectBg3 == 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]") TEST_CASE("mosaic_affectbg23_w_1x1_size PPU_write", "[PPU_write]")
{ {
Init() Init()
snes.bus->write(0x2106, 0b00000110); snes.bus.write(0x2106, 0b00000110);
REQUIRE(snes.ppu->_registers._mosaic.affectBg1 == false); REQUIRE(snes.ppu->_registers._mosaic.affectBg1 == false);
REQUIRE(snes.ppu->_registers._mosaic.affectBg2 == true); REQUIRE(snes.ppu->_registers._mosaic.affectBg2 == true);
REQUIRE(snes.ppu->_registers._mosaic.affectBg3 == 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]") TEST_CASE("mosaic_affectbg14_w_2x2_size PPU_write", "[PPU_write]")
{ {
Init() Init()
snes.bus->write(0x2106, 0b00101001); snes.bus.write(0x2106, 0b00101001);
REQUIRE(snes.ppu->_registers._mosaic.affectBg1 == true); REQUIRE(snes.ppu->_registers._mosaic.affectBg1 == true);
REQUIRE(snes.ppu->_registers._mosaic.affectBg2 == false); REQUIRE(snes.ppu->_registers._mosaic.affectBg2 == false);
REQUIRE(snes.ppu->_registers._mosaic.affectBg3 == 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]") TEST_CASE("bg1sc_data_full PPU_write", "[PPU_write]")
{ {
Init() 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].tilemapAddress == 0b111111);
REQUIRE(snes.ppu->_registers._bgsc[0].tilemapHorizontalMirroring == true); REQUIRE(snes.ppu->_registers._bgsc[0].tilemapHorizontalMirroring == true);
REQUIRE(snes.ppu->_registers._bgsc[0].tilemapVerticalMirroring == 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]") TEST_CASE("bg2sc_data_full PPU_write", "[PPU_write]")
{ {
Init() 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].tilemapAddress == 0b111111);
REQUIRE(snes.ppu->_registers._bgsc[1].tilemapHorizontalMirroring == true); REQUIRE(snes.ppu->_registers._bgsc[1].tilemapHorizontalMirroring == true);
REQUIRE(snes.ppu->_registers._bgsc[1].tilemapVerticalMirroring == 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]") TEST_CASE("bg3sc_data_full PPU_write", "[PPU_write]")
{ {
Init() 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].tilemapAddress == 0b111111);
REQUIRE(snes.ppu->_registers._bgsc[2].tilemapHorizontalMirroring == true); REQUIRE(snes.ppu->_registers._bgsc[2].tilemapHorizontalMirroring == true);
REQUIRE(snes.ppu->_registers._bgsc[2].tilemapVerticalMirroring == 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]") TEST_CASE("bg4sc_data_full PPU_write", "[PPU_write]")
{ {
Init() 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].tilemapAddress == 0b111111);
REQUIRE(snes.ppu->_registers._bgsc[3].tilemapHorizontalMirroring == true); REQUIRE(snes.ppu->_registers._bgsc[3].tilemapHorizontalMirroring == true);
REQUIRE(snes.ppu->_registers._bgsc[3].tilemapVerticalMirroring == 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]") TEST_CASE("bg4sc_data_null PPU_write", "[PPU_write]")
{ {
Init() 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].tilemapAddress == 0);
REQUIRE(snes.ppu->_registers._bgsc[3].tilemapHorizontalMirroring == false); REQUIRE(snes.ppu->_registers._bgsc[3].tilemapHorizontalMirroring == false);
REQUIRE(snes.ppu->_registers._bgsc[3].tilemapVerticalMirroring == 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]") TEST_CASE("bg4sc_horizontal_off_vertical_on_random_tilemapAdress PPU_write", "[PPU_write]")
{ {
Init() 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].tilemapAddress == 0b110001);
REQUIRE(snes.ppu->_registers._bgsc[3].tilemapHorizontalMirroring == false); REQUIRE(snes.ppu->_registers._bgsc[3].tilemapHorizontalMirroring == false);
REQUIRE(snes.ppu->_registers._bgsc[3].tilemapVerticalMirroring == true); 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]") TEST_CASE("bg12nba_data_full PPU_write", "[PPU_write]")
{ {
Init() 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].baseAddressBg1a3 == 0b1111);
REQUIRE(snes.ppu->_registers._bgnba[0].baseAddressBg2a4 == 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]") TEST_CASE("bg34nba_data_full PPU_write", "[PPU_write]")
{ {
Init() 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].baseAddressBg1a3 == 0b1111);
REQUIRE(snes.ppu->_registers._bgnba[1].baseAddressBg2a4 == 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]") TEST_CASE("bg12nba_data_random_data PPU_write", "[PPU_write]")
{ {
Init() 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].baseAddressBg1a3 == 0b1010);
REQUIRE(snes.ppu->_registers._bgnba[0].baseAddressBg2a4 == 0b1010); REQUIRE(snes.ppu->_registers._bgnba[0].baseAddressBg2a4 == 0b1010);
} }

View File

@@ -14,7 +14,7 @@ using namespace ComSquare;
TEST_CASE("vmain_data_full PPU_write_2", "[PPU_write_2]") TEST_CASE("vmain_data_full PPU_write_2", "[PPU_write_2]")
{ {
Init() Init()
snes.bus->write(0x2115, 0b11111111); snes.bus.write(0x2115, 0b11111111);
REQUIRE(snes.ppu->_registers._vmain.incrementMode == true); REQUIRE(snes.ppu->_registers._vmain.incrementMode == true);
REQUIRE(snes.ppu->_registers._vmain.addressRemapping == 0b11); REQUIRE(snes.ppu->_registers._vmain.addressRemapping == 0b11);
REQUIRE(snes.ppu->_registers._vmain.incrementAmount == 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]") TEST_CASE("vmain_incrementmode_off_false_else_full PPU_write_2", "[PPU_write_2]")
{ {
Init() Init()
snes.bus->write(0x2115, 0b01111111); snes.bus.write(0x2115, 0b01111111);
REQUIRE(snes.ppu->_registers._vmain.incrementMode == false); REQUIRE(snes.ppu->_registers._vmain.incrementMode == false);
REQUIRE(snes.ppu->_registers._vmain.addressRemapping == 0b11); REQUIRE(snes.ppu->_registers._vmain.addressRemapping == 0b11);
REQUIRE(snes.ppu->_registers._vmain.incrementAmount == 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]") TEST_CASE("vmain_addressremaping_null_else_full PPU_write_2", "[PPU_write_2]")
{ {
Init() Init()
snes.bus->write(0x2115, 0b11110011); snes.bus.write(0x2115, 0b11110011);
REQUIRE(snes.ppu->_registers._vmain.incrementMode == true); REQUIRE(snes.ppu->_registers._vmain.incrementMode == true);
REQUIRE(snes.ppu->_registers._vmain.addressRemapping == 0b00); REQUIRE(snes.ppu->_registers._vmain.addressRemapping == 0b00);
REQUIRE(snes.ppu->_registers._vmain.incrementAmount == 0b11); 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]") TEST_CASE("vmain_incrementamount_null_else_full PPU_write_2", "[PPU_write_2]")
{ {
Init() Init()
snes.bus->write(0x2115, 0b11111100); snes.bus.write(0x2115, 0b11111100);
REQUIRE(snes.ppu->_registers._vmain.incrementMode == true); REQUIRE(snes.ppu->_registers._vmain.incrementMode == true);
REQUIRE(snes.ppu->_registers._vmain.addressRemapping == 0b11); REQUIRE(snes.ppu->_registers._vmain.addressRemapping == 0b11);
REQUIRE(snes.ppu->_registers._vmain.incrementAmount == 0b00); 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]") TEST_CASE("vmadd_full_data PPU_write_2", "[PPU_write_2]")
{ {
Init() Init()
snes.bus->write(0x2116, 0b11111111); snes.bus.write(0x2116, 0b11111111);
snes.bus->write(0x2117, 0b11111111); snes.bus.write(0x2117, 0b11111111);
REQUIRE(snes.ppu->_registers._vmadd.vmadd == 0b1111111111111111); REQUIRE(snes.ppu->_registers._vmadd.vmadd == 0b1111111111111111);
} }
TEST_CASE("vmadd_full_data_check_ram PPU_write_2", "[PPU_write_2]") TEST_CASE("vmadd_full_data_check_ram PPU_write_2", "[PPU_write_2]")
{ {
Init() Init()
snes.bus->write(0x2115, 0b10000000); snes.bus.write(0x2115, 0b10000000);
snes.bus->write(0x2116, 2); snes.bus.write(0x2116, 2);
snes.bus->write(0x2117, 0); snes.bus.write(0x2117, 0);
snes.bus->write(0x2118, 0xFF); snes.bus.write(0x2118, 0xFF);
snes.bus->write(0x2119, 0xFF); snes.bus.write(0x2119, 0xFF);
REQUIRE(snes.ppu->_registers._vmadd.vmadd == 3); REQUIRE(snes.ppu->_registers._vmadd.vmadd == 3);
REQUIRE(snes.ppu->vram->read(4) == 0xFF); REQUIRE(snes.ppu->vram->read(4) == 0xFF);
REQUIRE(snes.ppu->vram->read(5) == 0xF); 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]") TEST_CASE("vmadd_full_high_byte_null PPU_write_2", "[PPU_write_2]")
{ {
Init() Init()
snes.bus->write(0x2116, 0b11111111); snes.bus.write(0x2116, 0b11111111);
snes.bus->write(0x2117, 0b00000000); snes.bus.write(0x2117, 0b00000000);
REQUIRE(snes.ppu->_registers._vmadd.vmadd == 0b0000000011111111); REQUIRE(snes.ppu->_registers._vmadd.vmadd == 0b0000000011111111);
} }
TEST_CASE("vmdata_full_data PPU_write_2", "[PPU_write_2]") TEST_CASE("vmdata_full_data PPU_write_2", "[PPU_write_2]")
{ {
Init() Init()
snes.bus->write(0x2118, 0b11111111); snes.bus.write(0x2118, 0b11111111);
snes.bus->write(0x2119, 0b11111111); snes.bus.write(0x2119, 0b11111111);
REQUIRE(snes.ppu->_registers._vmdata.vmdata == 0b1111111111111111); REQUIRE(snes.ppu->_registers._vmdata.vmdata == 0b1111111111111111);
} }
TEST_CASE("vmdata_full_high_byte_null PPU_write_2", "[PPU_write_2]") TEST_CASE("vmdata_full_high_byte_null PPU_write_2", "[PPU_write_2]")
{ {
Init() Init()
snes.bus->write(0x2118, 0b11111111); snes.bus.write(0x2118, 0b11111111);
snes.bus->write(0x2119, 0b00000000); snes.bus.write(0x2119, 0b00000000);
REQUIRE(snes.ppu->_registers._vmdata.vmdata == 0b0000000011111111); REQUIRE(snes.ppu->_registers._vmdata.vmdata == 0b0000000011111111);
} }
TEST_CASE("cgadd_full_high_byte_null PPU_write_2", "[PPU_write_2]") TEST_CASE("cgadd_full_high_byte_null PPU_write_2", "[PPU_write_2]")
{ {
Init() Init()
snes.bus->write(0x2121, 0b11111111); snes.bus.write(0x2121, 0b11111111);
REQUIRE(snes.ppu->_registers._cgadd == 0b11111111); REQUIRE(snes.ppu->_registers._cgadd == 0b11111111);
REQUIRE(snes.ppu->_registers._isLowByte == true); 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]") TEST_CASE("cgdata_data_full PPU_write_2", "[PPU_write_2]")
{ {
Init() Init()
snes.bus->write(0x2121, 0x0); snes.bus.write(0x2121, 0x0);
snes.bus->write(0x2122, 0b11111111); snes.bus.write(0x2122, 0b11111111);
REQUIRE(snes.ppu->_registers._cgdata.cgdatal == 0b11111111); REQUIRE(snes.ppu->_registers._cgdata.cgdatal == 0b11111111);
REQUIRE(snes.ppu->_registers._isLowByte == false); REQUIRE(snes.ppu->_registers._isLowByte == false);
int address = snes.ppu->_registers._cgadd; 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._cgdata.cgdatah == 0b11111000);
REQUIRE(snes.ppu->_registers._isLowByte == true); REQUIRE(snes.ppu->_registers._isLowByte == true);
REQUIRE(snes.ppu->_registers._cgadd == address + 2); 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]") TEST_CASE("m7sel_data_full PPU_write_2", "[PPU_write_2]")
{ {
Init() Init()
snes.bus->write(0x211A, 0b11111111); snes.bus.write(0x211A, 0b11111111);
REQUIRE(snes.ppu->_registers._m7sel.playingFieldSize == true); REQUIRE(snes.ppu->_registers._m7sel.playingFieldSize == true);
REQUIRE(snes.ppu->_registers._m7sel.emptySpaceFill == true); REQUIRE(snes.ppu->_registers._m7sel.emptySpaceFill == true);
REQUIRE(snes.ppu->_registers._m7sel.horizontalMirroring == 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]") TEST_CASE("m7sel_data_actual PPU_write_2", "[PPU_write_2]")
{ {
Init() Init()
snes.bus->write(0x211A, 0b01111101); snes.bus.write(0x211A, 0b01111101);
REQUIRE(snes.ppu->_registers._m7sel.playingFieldSize == false); REQUIRE(snes.ppu->_registers._m7sel.playingFieldSize == false);
REQUIRE(snes.ppu->_registers._m7sel.emptySpaceFill == true); REQUIRE(snes.ppu->_registers._m7sel.emptySpaceFill == true);
REQUIRE(snes.ppu->_registers._m7sel.horizontalMirroring == 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]") TEST_CASE("w12sel_data_full PPU_write_2", "[PPU_write_2]")
{ {
Init() 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].window1InversionForBg1Bg3Obj == true);
REQUIRE(snes.ppu->_registers._wsel[0].enableWindow1ForBg1Bg3Obj == true); REQUIRE(snes.ppu->_registers._wsel[0].enableWindow1ForBg1Bg3Obj == true);
REQUIRE(snes.ppu->_registers._wsel[0].window2InversionForBg1Bg3Obj == 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]") TEST_CASE("w34sel_data_full PPU_write_2", "[PPU_write_2]")
{ {
Init() 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].window1InversionForBg1Bg3Obj == true);
REQUIRE(snes.ppu->_registers._wsel[1].enableWindow1ForBg1Bg3Obj == false); REQUIRE(snes.ppu->_registers._wsel[1].enableWindow1ForBg1Bg3Obj == false);
REQUIRE(snes.ppu->_registers._wsel[1].window2InversionForBg1Bg3Obj == true); 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]") TEST_CASE("wobjsel_data_full PPU_write_2", "[PPU_write_2]")
{ {
Init() 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].window1InversionForBg1Bg3Obj == true);
REQUIRE(snes.ppu->_registers._wsel[2].enableWindow1ForBg1Bg3Obj == false); REQUIRE(snes.ppu->_registers._wsel[2].enableWindow1ForBg1Bg3Obj == false);
REQUIRE(snes.ppu->_registers._wsel[2].window2InversionForBg1Bg3Obj == true); 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]") TEST_CASE("wbglog_data_full PPU_write_2", "[PPU_write_2]")
{ {
Init() Init()
snes.bus->write(0x212A, 0b10110001); snes.bus.write(0x212A, 0b10110001);
REQUIRE(snes.ppu->_registers._wbglog.maskLogicBg1 == 0b10); REQUIRE(snes.ppu->_registers._wbglog.maskLogicBg1 == 0b10);
REQUIRE(snes.ppu->_registers._wbglog.maskLogicBg2 == 0b11); REQUIRE(snes.ppu->_registers._wbglog.maskLogicBg2 == 0b11);
REQUIRE(snes.ppu->_registers._wbglog.maskLogicBg3 == 0b00); 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]") TEST_CASE("wobjlog_data_full PPU_write_2", "[PPU_write_2]")
{ {
Init() Init()
snes.bus->write(0x212B, 0b10110001); snes.bus.write(0x212B, 0b10110001);
REQUIRE(snes.ppu->_registers._wobjlog.maskLogicObj == 0b01); REQUIRE(snes.ppu->_registers._wobjlog.maskLogicObj == 0b01);
REQUIRE(snes.ppu->_registers._wobjlog.maskLogicColor == 0b00); 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]") TEST_CASE("tm_data_full PPU_write_2", "[PPU_write_2]")
{ {
Init() 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].enableWindowDisplayBg1 == true);
REQUIRE(snes.ppu->_registers._t[0].enableWindowDisplayBg2 == false); REQUIRE(snes.ppu->_registers._t[0].enableWindowDisplayBg2 == false);
REQUIRE(snes.ppu->_registers._t[0].enableWindowDisplayBg3 == 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]") TEST_CASE("ts_data_full PPU_write_2", "[PPU_write_2]")
{ {
Init() 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].enableWindowDisplayBg1 == false);
REQUIRE(snes.ppu->_registers._t[1].enableWindowDisplayBg2 == true); REQUIRE(snes.ppu->_registers._t[1].enableWindowDisplayBg2 == true);
REQUIRE(snes.ppu->_registers._t[1].enableWindowDisplayBg3 == 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]") TEST_CASE("tmw_data_full PPU_write_2", "[PPU_write_2]")
{ {
Init() 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].enableWindowMaskingBg1 == false);
REQUIRE(snes.ppu->_registers._tw[0].enableWindowMaskingBg2 == true); REQUIRE(snes.ppu->_registers._tw[0].enableWindowMaskingBg2 == true);
REQUIRE(snes.ppu->_registers._tw[0].enableWindowMaskingBg3 == 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]") TEST_CASE("tsw_data_full PPU_write_2", "[PPU_write_2]")
{ {
Init() 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].enableWindowMaskingBg1 == true);
REQUIRE(snes.ppu->_registers._tw[1].enableWindowMaskingBg2 == true); REQUIRE(snes.ppu->_registers._tw[1].enableWindowMaskingBg2 == true);
REQUIRE(snes.ppu->_registers._tw[1].enableWindowMaskingBg3 == false); 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]") TEST_CASE("cgwsel_data_full PPU_write_2", "[PPU_write_2]")
{ {
Init() Init()
snes.bus->write(0x2130, 0b10111001); snes.bus.write(0x2130, 0b10111001);
REQUIRE(snes.ppu->_registers._cgwsel.clipColorToBlackBeforeMath == 0b10); REQUIRE(snes.ppu->_registers._cgwsel.clipColorToBlackBeforeMath == 0b10);
REQUIRE(snes.ppu->_registers._cgwsel.preventColorMath == 0b11); REQUIRE(snes.ppu->_registers._cgwsel.preventColorMath == 0b11);
REQUIRE(snes.ppu->_registers._cgwsel.addSubscreen == false); 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]") TEST_CASE("cgadsub_data_full PPU_write_2", "[PPU_write_2]")
{ {
Init() Init()
snes.bus->write(0x2131, 0b10111001); snes.bus.write(0x2131, 0b10111001);
REQUIRE(snes.ppu->_registers._cgadsub.addSubtractSelect == true); REQUIRE(snes.ppu->_registers._cgadsub.addSubtractSelect == true);
REQUIRE(snes.ppu->_registers._cgadsub.halfColorMath == false); REQUIRE(snes.ppu->_registers._cgadsub.halfColorMath == false);
REQUIRE(snes.ppu->_registers._cgadsub.enableColorMathBackdrop == true); 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]") TEST_CASE("coldata_data_full PPU_write_2", "[PPU_write_2]")
{ {
Init() Init()
snes.bus->write(0x2132, 0b10111001); snes.bus.write(0x2132, 0b10111001);
REQUIRE(snes.ppu->_registers._coldata.blue == true); REQUIRE(snes.ppu->_registers._coldata.blue == true);
REQUIRE(snes.ppu->_registers._coldata.green == false); REQUIRE(snes.ppu->_registers._coldata.green == false);
REQUIRE(snes.ppu->_registers._coldata.red == true); 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]") TEST_CASE("setini_data_full PPU_write_2", "[PPU_write_2]")
{ {
Init() Init()
snes.bus->write(0x2133, 0b10111001); snes.bus.write(0x2133, 0b10111001);
REQUIRE(snes.ppu->_registers._setini.externalSync == true); REQUIRE(snes.ppu->_registers._setini.externalSync == true);
REQUIRE(snes.ppu->_registers._setini.mode7ExtBg == false); REQUIRE(snes.ppu->_registers._setini.mode7ExtBg == false);
REQUIRE(snes.ppu->_registers._setini.enablePseudoHiresMode == true); 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]") TEST_CASE("m7a_data_full PPU_write_2", "[PPU_write_2]")
{ {
Init() Init()
snes.bus->write(0x211B, 0b10111001); snes.bus.write(0x211B, 0b10111001);
REQUIRE(snes.ppu->_registers._m7[0].m7l == 0b10111001); REQUIRE(snes.ppu->_registers._m7[0].m7l == 0b10111001);
} }
TEST_CASE("m7c_data_low_and_high_byte PPU_write_2", "[PPU_write_2]") TEST_CASE("m7c_data_low_and_high_byte PPU_write_2", "[PPU_write_2]")
{ {
Init() Init()
snes.bus->write(0x211D, 0b10111001); snes.bus.write(0x211D, 0b10111001);
snes.bus->write(0x211D, 0b11111111); snes.bus.write(0x211D, 0b11111111);
REQUIRE(snes.ppu->_registers._m7[2].m7 == 0b1011100111111111); REQUIRE(snes.ppu->_registers._m7[2].m7 == 0b1011100111111111);
} }

View File

@@ -23,7 +23,7 @@ TEST_CASE("GetWramStart BusAccessor", "[BusAccessor]")
Init() Init()
std::shared_ptr<Memory::IMemory> accessor; std::shared_ptr<Memory::IMemory> accessor;
accessor = snes.bus->getAccessor(0x7E0000); accessor = snes.bus.getAccessor(0x7E0000);
REQUIRE(accessor.get() == snes.wram.get()); REQUIRE(accessor.get() == snes.wram.get());
} }
@@ -32,7 +32,7 @@ TEST_CASE("GetWramEnd BusAccessor", "[BusAccessor]")
Init() Init()
std::shared_ptr<Memory::IMemory> accessor; std::shared_ptr<Memory::IMemory> accessor;
accessor = snes.bus->getAccessor(0x7FFFFF); accessor = snes.bus.getAccessor(0x7FFFFF);
REQUIRE(accessor.get() == snes.wram.get()); REQUIRE(accessor.get() == snes.wram.get());
} }
@@ -41,7 +41,7 @@ TEST_CASE("GetWramMirror BusAccessor", "[BusAccessor]")
Init() Init()
std::shared_ptr<Memory::RectangleShadow> accessor; 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 != nullptr);
REQUIRE(accessor->_initial.get() == snes.wram.get()); REQUIRE(accessor->_initial.get() == snes.wram.get());
} }
@@ -51,7 +51,7 @@ TEST_CASE("GetWramMirror2 BusAccessor", "[BusAccessor]")
Init() Init()
std::shared_ptr<Memory::RectangleShadow> accessor; 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 != nullptr);
REQUIRE(accessor->_initial.get() == snes.wram.get()); REQUIRE(accessor->_initial.get() == snes.wram.get());
} }
@@ -61,7 +61,7 @@ TEST_CASE("GetWramMirror3 BusAccessor", "[BusAccessor]")
Init() Init()
std::shared_ptr<Memory::RectangleShadow> accessor; 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 != nullptr);
REQUIRE(accessor->_initial.get() == snes.wram.get()); REQUIRE(accessor->_initial.get() == snes.wram.get());
} }
@@ -69,7 +69,7 @@ TEST_CASE("GetWramMirror3 BusAccessor", "[BusAccessor]")
TEST_CASE("GetOpenBus BusAccessor", "[BusAccessor]") TEST_CASE("GetOpenBus BusAccessor", "[BusAccessor]")
{ {
Init() 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); REQUIRE(accessor.get() == nullptr);
} }
@@ -78,7 +78,7 @@ TEST_CASE("GetSramStart BusAccessor", "[BusAccessor]")
Init() Init()
std::shared_ptr<Memory::RectangleShadow> accessor; 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);
REQUIRE(accessor->_initial.get() == snes.sram.get()); REQUIRE(accessor->_initial.get() == snes.sram.get());
} }
@@ -88,7 +88,7 @@ TEST_CASE("GetSramEnd BusAccessor", "[BusAccessor]")
Init() Init()
std::shared_ptr<Memory::RectangleShadow> accessor; 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);
REQUIRE(accessor->_initial.get() == snes.sram.get()); REQUIRE(accessor->_initial.get() == snes.sram.get());
} }
@@ -98,7 +98,7 @@ TEST_CASE("GetSramMirror BusAccessor", "[BusAccessor]")
Init() Init()
std::shared_ptr<Memory::ARectangleMemory> accessor; 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()); REQUIRE(accessor.get() == snes.sram.get());
} }
@@ -107,7 +107,7 @@ TEST_CASE("GetAPUStart BusAccessor", "[BusAccessor]")
Init() Init()
std::shared_ptr<Memory::IMemory> accessor; std::shared_ptr<Memory::IMemory> accessor;
accessor = snes.bus->getAccessor(0x002140); accessor = snes.bus.getAccessor(0x002140);
REQUIRE(accessor.get() == snes.apu.get()); REQUIRE(accessor.get() == snes.apu.get());
} }
@@ -116,7 +116,7 @@ TEST_CASE("GetAPUEnd BusAccessor", "[BusAccessor]")
Init() Init()
std::shared_ptr<Memory::IMemory> accessor; std::shared_ptr<Memory::IMemory> accessor;
accessor = snes.bus->getAccessor(0x002143); accessor = snes.bus.getAccessor(0x002143);
REQUIRE(accessor.get() == snes.apu.get()); REQUIRE(accessor.get() == snes.apu.get());
} }
@@ -125,7 +125,7 @@ TEST_CASE("GetAPUMirror BusAccessor", "[BusAccessor]")
Init() Init()
std::shared_ptr<Memory::MemoryShadow> accessor; 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()); REQUIRE(accessor->_initial.get() == snes.apu.get());
} }
@@ -134,7 +134,7 @@ TEST_CASE("GetAPUMirrorFirstHalf BusAccessor", "[BusAccessor]")
Init() Init()
std::shared_ptr<Memory::MemoryShadow> accessor; 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()); REQUIRE(accessor->_initial.get() == snes.apu.get());
} }
@@ -143,7 +143,7 @@ TEST_CASE("GetCPUStart BusAccessor", "[BusAccessor]")
Init() Init()
std::shared_ptr<Memory::IMemory> accessor; std::shared_ptr<Memory::IMemory> accessor;
accessor = snes.bus->getAccessor(0x004200); accessor = snes.bus.getAccessor(0x004200);
REQUIRE(accessor.get() == snes.cpu.get()); REQUIRE(accessor.get() == snes.cpu.get());
} }
@@ -152,7 +152,7 @@ TEST_CASE("GetCPUEnd BusAccessor", "[BusAccessor]")
Init() Init()
std::shared_ptr<Memory::IMemory> accessor; std::shared_ptr<Memory::IMemory> accessor;
accessor = snes.bus->getAccessor(0x00421F); accessor = snes.bus.getAccessor(0x00421F);
REQUIRE(accessor.get() == snes.cpu.get()); REQUIRE(accessor.get() == snes.cpu.get());
} }
@@ -161,7 +161,7 @@ TEST_CASE("GetPPU1Start BusAccessor", "[BusAccessor]")
Init() Init()
std::shared_ptr<Memory::IMemory> accessor; std::shared_ptr<Memory::IMemory> accessor;
accessor = snes.bus->getAccessor(0x00213E); accessor = snes.bus.getAccessor(0x00213E);
REQUIRE(accessor.get() == snes.ppu.get()); REQUIRE(accessor.get() == snes.ppu.get());
} }
@@ -170,7 +170,7 @@ TEST_CASE("GetPPU1End BusAccessor", "[BusAccessor]")
Init() Init()
std::shared_ptr<Memory::IMemory> accessor; std::shared_ptr<Memory::IMemory> accessor;
accessor = snes.bus->getAccessor(0x00213F); accessor = snes.bus.getAccessor(0x00213F);
REQUIRE(accessor.get() == snes.ppu.get()); REQUIRE(accessor.get() == snes.ppu.get());
} }
@@ -179,7 +179,7 @@ TEST_CASE("GetCPU BusAccessor", "[BusAccessor]")
Init() Init()
std::shared_ptr<Memory::IMemory> accessor; std::shared_ptr<Memory::IMemory> accessor;
accessor = snes.bus->getAccessor(0x004212); accessor = snes.bus.getAccessor(0x004212);
REQUIRE(accessor.get() == snes.cpu.get()); REQUIRE(accessor.get() == snes.cpu.get());
} }
@@ -188,7 +188,7 @@ TEST_CASE("GetPPU1Mirror BusAccessor", "[BusAccessor]")
Init() Init()
std::shared_ptr<Memory::MemoryShadow> accessor; 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()); REQUIRE(accessor->_initial.get() == snes.ppu.get());
} }
@@ -197,7 +197,7 @@ TEST_CASE("GetCPU2Mirror BusAccessor", "[BusAccessor]")
Init() Init()
std::shared_ptr<Memory::MemoryShadow> accessor; 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()); REQUIRE(accessor->_initial.get() == snes.cpu.get());
} }
@@ -206,7 +206,7 @@ TEST_CASE("GetRomStart BusAccessor", "[BusAccessor]")
Init() Init()
std::shared_ptr<Memory::IMemory> accessor; std::shared_ptr<Memory::IMemory> accessor;
accessor = snes.bus->getAccessor(0x808000); accessor = snes.bus.getAccessor(0x808000);
REQUIRE(accessor.get() == snes.cartridge.get()); REQUIRE(accessor.get() == snes.cartridge.get());
} }
@@ -215,7 +215,7 @@ TEST_CASE("GetRomEnd BusAccessor", "[BusAccessor]")
Init() Init()
std::shared_ptr<Memory::IMemory> accessor; std::shared_ptr<Memory::IMemory> accessor;
accessor = snes.bus->getAccessor(0xFFFFFF); accessor = snes.bus.getAccessor(0xFFFFFF);
REQUIRE(accessor.get() == snes.cartridge.get()); REQUIRE(accessor.get() == snes.cartridge.get());
} }
@@ -224,7 +224,7 @@ TEST_CASE("GetRomMirror BusAccessor", "[BusAccessor]")
Init() Init()
std::shared_ptr<Memory::RectangleShadow> accessor; 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);
REQUIRE(accessor->_initial.get() == snes.cartridge.get()); REQUIRE(accessor->_initial.get() == snes.cartridge.get());
} }
@@ -234,7 +234,7 @@ TEST_CASE("GetRomMirror2 BusAccessor", "[BusAccessor]")
Init() Init()
std::shared_ptr<Memory::RectangleShadow> accessor; 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);
REQUIRE(accessor->_initial.get() == snes.cartridge.get()); REQUIRE(accessor->_initial.get() == snes.cartridge.get());
} }
@@ -244,7 +244,7 @@ TEST_CASE("GetRomMirror3 BusAccessor", "[BusAccessor]")
Init() Init()
std::shared_ptr<Memory::RectangleShadow> accessor; 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);
REQUIRE(accessor->_initial.get() == snes.cartridge.get()); REQUIRE(accessor->_initial.get() == snes.cartridge.get());
} }
@@ -254,7 +254,7 @@ TEST_CASE("Get0x0 BusAccessor", "[BusAccessor]")
Init() Init()
std::shared_ptr<Memory::RectangleShadow> accessor; 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);
REQUIRE(accessor->_initial.get() == snes.wram.get()); REQUIRE(accessor->_initial.get() == snes.wram.get());
} }
@@ -271,7 +271,7 @@ TEST_CASE("Read0x0 BusRead", "[BusRead]")
uint8_t data; uint8_t data;
snes.wram->_data[0] = 123; snes.wram->_data[0] = 123;
data = snes.bus->read(0x0); data = snes.bus.read(0x0);
REQUIRE(data == 123); REQUIRE(data == 123);
} }
@@ -280,8 +280,8 @@ TEST_CASE("Read ReadOutside", "[ReadOutside]")
Init() Init()
uint8_t data; uint8_t data;
snes.bus->_openBus = 123; snes.bus._openBus = 123;
data = snes.bus->read(0x002000); data = snes.bus.read(0x002000);
REQUIRE(data == 123); REQUIRE(data == 123);
} }
@@ -290,8 +290,8 @@ TEST_CASE("ReadOutside2 Read][Bus", "[Read][Bus]")
Init() Init()
uint8_t data; uint8_t data;
snes.bus->_openBus = 123; snes.bus._openBus = 123;
data = snes.bus->read(0xBF2FFF); data = snes.bus.read(0xBF2FFF);
REQUIRE(data == 123); REQUIRE(data == 123);
} }
@@ -300,8 +300,8 @@ TEST_CASE("ReadOutside3 Read][Bus", "[Read][Bus]")
Init() Init()
uint8_t data; uint8_t data;
snes.bus->_openBus = 123; snes.bus._openBus = 123;
data = snes.bus->read(0x127654); data = snes.bus.read(0x127654);
REQUIRE(data == 123); REQUIRE(data == 123);
} }
@@ -311,7 +311,7 @@ TEST_CASE("ReadAPU BusRead", "[BusRead]")
uint8_t data; uint8_t data;
snes.apu->_registers.port0 = 123; snes.apu->_registers.port0 = 123;
data = snes.bus->read(0x002140); data = snes.bus.read(0x002140);
REQUIRE(data == 123); REQUIRE(data == 123);
} }
@@ -321,7 +321,7 @@ TEST_CASE("ReadROM BusRead", "[BusRead]")
uint8_t data; uint8_t data;
snes.cartridge->_data[5] = 123; snes.cartridge->_data[5] = 123;
data = snes.bus->read(0x808005); data = snes.bus.read(0x808005);
REQUIRE(data == 123); REQUIRE(data == 123);
} }
@@ -331,7 +331,7 @@ TEST_CASE("ReadROMStart BusRead", "[BusRead]")
uint8_t data; uint8_t data;
snes.cartridge->_data[0] = 123; snes.cartridge->_data[0] = 123;
data = snes.bus->read(0x808000); data = snes.bus.read(0x808000);
REQUIRE(data == 123); REQUIRE(data == 123);
} }
@@ -341,7 +341,7 @@ TEST_CASE("ReadCPU BusRead", "[BusRead]")
uint8_t data; uint8_t data;
snes.cpu->_internalRegisters.wrio = 123; snes.cpu->_internalRegisters.wrio = 123;
data = snes.bus->read(0x004201); data = snes.bus.read(0x004201);
REQUIRE(data == 123); REQUIRE(data == 123);
} }
@@ -351,7 +351,7 @@ TEST_CASE("ReadPPU BusRead", "[BusRead]")
uint8_t data; uint8_t data;
snes.ppu->_registers._mpy.mpyl = 123; snes.ppu->_registers._mpy.mpyl = 123;
data = snes.bus->read(0x002134); data = snes.bus.read(0x002134);
REQUIRE(data == 123); REQUIRE(data == 123);
} }
@@ -361,7 +361,7 @@ TEST_CASE("ReadSRAM BusRead", "[BusRead]")
uint8_t data; uint8_t data;
snes.sram->_data[7] = 123; snes.sram->_data[7] = 123;
data = snes.bus->read(0x700007); data = snes.bus.read(0x700007);
REQUIRE(data == 123); REQUIRE(data == 123);
} }
@@ -371,7 +371,7 @@ TEST_CASE("ReadWRAM BusRead", "[BusRead]")
uint8_t data; uint8_t data;
snes.wram->_data[3] = 123; snes.wram->_data[3] = 123;
data = snes.bus->read(0x7E0003); data = snes.bus.read(0x7E0003);
REQUIRE(data == 123); REQUIRE(data == 123);
} }
@@ -381,7 +381,7 @@ TEST_CASE("ReadWRAM2 BusRead", "[BusRead]")
uint8_t data; uint8_t data;
snes.wram->_data[0x1010] = 123; snes.wram->_data[0x1010] = 123;
data = snes.bus->read(0x7E1010); data = snes.bus.read(0x7E1010);
REQUIRE(data == 123); REQUIRE(data == 123);
} }
@@ -392,7 +392,7 @@ TEST_CASE("ReadWRAMMirror BusRead", "[BusRead]")
uint8_t data; uint8_t data;
snes.wram->_data[0x1010] = 123; snes.wram->_data[0x1010] = 123;
data = snes.bus->read(0x1010); data = snes.bus.read(0x1010);
REQUIRE(data == 123); REQUIRE(data == 123);
} }
@@ -407,7 +407,7 @@ TEST_CASE("Write0x0 BusWrite", "[BusWrite]")
Init() Init()
try { try {
snes.bus->write(0x0, 123); snes.bus.write(0x0, 123);
} catch (std::exception &ex) { } catch (std::exception &ex) {
std::cout << ex.what() << std::endl; std::cout << ex.what() << std::endl;
} }
@@ -419,7 +419,7 @@ TEST_CASE("WriteAPU BusWrite", "[BusWrite]")
{ {
Init() Init()
snes.bus->write(0x002143, 123); snes.bus.write(0x002143, 123);
REQUIRE(snes.apu->_registers.port3 == 123); REQUIRE(snes.apu->_registers.port3 == 123);
} }
@@ -427,7 +427,7 @@ TEST_CASE("WritePPU BusWrite", "[BusWrite]")
{ {
Init() Init()
snes.bus->write(0x002106, 123); snes.bus.write(0x002106, 123);
REQUIRE(snes.ppu->_registers._mosaic.raw == 123); REQUIRE(snes.ppu->_registers._mosaic.raw == 123);
} }
@@ -435,7 +435,7 @@ TEST_CASE("WriteCPU BusWrite", "[BusWrite]")
{ {
Init() Init()
snes.bus->write(0x00420D, 123); snes.bus.write(0x00420D, 123);
REQUIRE(snes.cpu->_internalRegisters.memsel == 123); REQUIRE(snes.cpu->_internalRegisters.memsel == 123);
} }
@@ -443,14 +443,14 @@ TEST_CASE("WriteROM BusWrite", "[BusWrite]")
{ {
Init() Init()
REQUIRE_THROWS_AS(snes.bus->write(0x808005, 123), InvalidAction); REQUIRE_THROWS_AS(snes.bus.write(0x808005, 123), InvalidAction);
} }
TEST_CASE("WriteWRAM BusWrite", "[BusWrite]") TEST_CASE("WriteWRAM BusWrite", "[BusWrite]")
{ {
Init() Init()
snes.bus->write(0x7E0002, 123); snes.bus.write(0x7E0002, 123);
REQUIRE(snes.wram->_data[2] == 123); REQUIRE(snes.wram->_data[2] == 123);
} }
@@ -458,6 +458,6 @@ TEST_CASE("WriteSRAM BusWrite", "[BusWrite]")
{ {
Init() Init()
snes.bus->write(0x700009, 123); snes.bus.write(0x700009, 123);
REQUIRE(snes.sram->_data[9] == 123); REQUIRE(snes.sram->_data[9] == 123);
} }

View File

@@ -18,7 +18,7 @@
#define Init() \ #define Init() \
Renderer::NoRenderer norenderer(0, 0, 0); \ Renderer::NoRenderer norenderer(0, 0, 0); \
SNES snes("../tests/my_cartridge", norenderer); \ SNES snes(norenderer); \
snes.cartridge->_size = 100; \ snes.cartridge->_size = 100; \
delete[] snes.cartridge->_data; \ delete[] snes.cartridge->_data; \
snes.cartridge->_data = new uint8_t[snes.cartridge->_size]; \ snes.cartridge->_data = new uint8_t[snes.cartridge->_size]; \