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

View File

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

View File

@@ -390,12 +390,16 @@ namespace ComSquare::APU
//! @brief Get the component of this accessor (used for debug purpose)
Component getComponent() const override;
//! @brief Get the name of the data at the address
//! @param addr The address (in local space)
[[nodiscard]] std::string getValueName(uint24_t addr) const override;
//! @brief Get the size of the data. This size can be lower than the mapped data.
//! @return The number of bytes inside this memory.
uint24_t getSize() const override;
//! @brief Parses rom data to uploads directly into RAM and corresponding registers
void loadFromSPC(const std::shared_ptr<Cartridge::Cartridge>& cartridge);
void loadFromSPC(Cartridge::Cartridge &cartridge);
//! @brief This function execute the instructions received until the maximum number of cycles is reached.
//! @return The number of cycles that elapsed.

View File

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

View File

@@ -2,10 +2,9 @@
// Created by Melefo on 27/02/2020.
//
#ifndef COMSQUARE_IPL_HPP
#define COMSQUARE_IPL_HPP
#pragma once
#include "../../Memory/AMemory.hpp"
#include "Memory/AMemory.hpp"
namespace ComSquare::APU::IPL
{
@@ -31,15 +30,12 @@ namespace ComSquare::APU::IPL
public:
//! @brief Create the rom with its value.
explicit IPL(Component, std::string iplName);
//! @brief The rom can't be copied.
IPL(const IPL &) = delete;
//! @brief The rom can't be assigned.
IPL &operator=(IPL &) = delete;
//! @brief Destructor that free the rom.
~IPL();
//! @brief A default destructor
~IPL() override = default;
//! @brief Read data from the component using the same method as the basic IMemory.
//! @param addr The global 24 bits address. This method is responsible of mapping to the component's read.
@@ -55,14 +51,16 @@ namespace ComSquare::APU::IPL
//! @brief Get the size of the data. This size can be lower than the mapped data.
//! @return The number of bytes inside this memory.
uint24_t getSize() const override;
[[nodiscard]] uint24_t getSize() const override;
//! @brief Get the name of this accessor (used for debug purpose)
std::string getName() const override;
[[nodiscard]] std::string getName() const override;
//! @brief Get the component of this accessor (used for debug purpose)
Component getComponent() const override;
[[nodiscard]] Component getComponent() const override;
//! @brief Get the name of the data at the address
//! @param addr The address (in local space)
[[nodiscard]] std::string getValueName(uint24_t addr) const override;
};
}
#endif //COMSQUARE_IPL_HPP

View File

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

View File

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

View File

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

View File

@@ -2,8 +2,7 @@
// Created by anonymus-raccoon on 1/24/20.
//
#ifndef COMSQUARE_CPU_HPP
#define COMSQUARE_CPU_HPP
#pragma once
#include "Memory/AMemory.hpp"
#include "Memory/MemoryBus.hpp"
@@ -12,180 +11,21 @@
#include "Memory/AMemory.hpp"
#include "Instruction.hpp"
#include "DMA/DMA.hpp"
#include "CPU/Registers.hpp"
#ifdef DEBUGGER_ENABLED
#include "Debugger/RegisterViewer.hpp"
#endif
namespace ComSquare::CPU
{
//! @brief Struct containing registers for the main CPU.
struct Registers {
//! @brief The Accumulator
union {
struct {
uint8_t al;
uint8_t ah;
};
uint16_t a;
};
//! @brief The Data Bank Register;
uint8_t dbr;
//! @brief The Direct Page register;
union {
struct {
uint8_t dl;
uint8_t dh;
};
uint16_t d;
};
union {
struct {
//! @brief The Program Counter;
union {
struct {
uint8_t pcl;
uint8_t pch;
};
uint16_t pc;
};
//! @brief The Program Bank Register;
uint8_t pbr;
};
//! @brief The current Program Address Counter (does not exist in a snes but is useful here).
uint24_t pac;
};
//! @brief The Stack pointer
union {
struct {
uint8_t sl;
uint8_t sh;
};
uint16_t s;
};
//! @brief The X index register
union {
struct {
uint8_t xl;
uint8_t xh;
};
uint16_t x;
};
//! @brief The Y index register
union {
struct {
uint8_t yl;
uint8_t yh;
};
uint16_t y;
};
//! @brief The Processor status register;
union {
struct {
//! @brief The Carry flag
bool c : 1;
//! @brief The Zero flag
bool z : 1;
//! @brief The Interrupt request disable flag
bool i : 1;
//! @brief The Decimal mode flag
bool d : 1;
//! @brief The indeX register width flag (in native mode only) - 0 = 16 bits mode, 1 = 8 bits mode OR the Break flag (in emulation mode only)
bool x_b : 1;
//! @brief The accumulator and Memory width flag (in native mode only) - 0 = 16 bits mode, 1 = 8 bits mode.
bool m : 1;
//! @brief The oVerflow flag
bool v : 1;
//! @brief The Negative flag
bool n : 1;
};
uint8_t flags;
} p;
};
//! @brief Struct containing internal registers of the CPU.
struct InternalRegisters
{
//! @brief Interrupt Enable Register
uint8_t nmitimen;
//! @brief IO Port Write Register
uint8_t wrio;
//! @brief Multiplicand Register A
uint8_t wrmpya;
//! @brief Multiplicand Register B
uint8_t wrmpyb;
//! @brief Divisor & Dividend Registers (A - Low)
uint8_t wrdivl;
//! @brief Divisor & Dividend Registers (A - High)
uint8_t wrdivh;
//! @brief Divisor & Dividend Registers (B)
uint8_t wrdivb;
//! @brief IRQ Timer Registers (Horizontal - Low)
uint8_t htimel;
//! @brief IRQ Timer Registers (Horizontal - High)
uint8_t htimeh;
//! @brief IRQ Timer Registers (Vertical - Low)
uint8_t vtimel;
//! @brief IRQ Timer Registers (Vertical - High)
uint8_t vtimeh;
//! @brief HDMA Enable Register
uint8_t hdmaen;
//! @brief ROM Speed Register
uint8_t memsel;
//! @brief Interrupt Flag Registers
uint8_t rdnmi;
//! @brief Interrupt Flag Registers - TimeUp
uint8_t timeup;
//! @brief PPU Status Register
uint8_t hvbjoy;
//! @brief IO Port Read Register
uint8_t rdio;
//! @brief Divide Result Registers (can sometimes be used as multiplication result register) - LOW
uint8_t rddivl;
//! @brief Divide Result Registers (can sometimes be used as multiplication result register) - HIGH
uint8_t rddivh;
//! @brief Multiplication Result Registers (can sometimes be used as divide result register) - LOW
uint8_t rdmpyl;
//! @brief Multiplication Result Registers (can sometimes be used as divide result register) - HIGH
uint8_t rdmpyh;
//! @brief Controller Port Data Registers (Pad 1 - Low)
uint8_t joy1l;
//! @brief Controller Port Data Registers (Pad 1 - High)
uint8_t joy1h;
//! @brief Controller Port Data Registers (Pad 2 - Low)
uint8_t joy2l;
//! @brief Controller Port Data Registers (Pad 2 - High)
uint8_t joy2h;
//! @brief Controller Port Data Registers (Pad 3 - Low)
uint8_t joy3l;
//! @brief Controller Port Data Registers (Pad 3 - High)
uint8_t joy3h;
//! @brief Controller Port Data Registers (Pad 4 - Low)
uint8_t joy4l;
//! @brief Controller Port Data Registers (Pad 4 - High)
uint8_t joy4h;
};
//! @brief The main CPU
class CPU : public Memory::AMemory {
class CPU : public Memory::AMemory
{
protected:
//! @brief All the registers of the CPU
Registers _registers{};
Registers _registers {};
//! @brief Internal registers of the CPU (accessible from the bus via addr $4200 to $421F).
InternalRegisters _internalRegisters{};
InternalRegisters _internalRegisters {};
//! @brief Is the CPU running in emulation mode (in 8bits)
bool _isEmulationMode = true;
@@ -195,8 +35,8 @@ namespace ComSquare::CPU
bool _isWaitingForInterrupt = false;
//! @brief The memory bus to use for read/write.
std::shared_ptr<Memory::MemoryBus> _bus;
//! @brief The cartridge header (stored for interrupt vectors..
Memory::MemoryBus &_bus;
//! @brief The cartridge header (stored for interrupt vectors..)
Cartridge::Header &_cartridgeHeader;
//! @brief DMA channels witch are mapped to the bus.
@@ -250,7 +90,6 @@ namespace ComSquare::CPU
//! @brief The <8-bit exp> is added to S and combined with DBR to form the base address. Y is added to the base address to form the effective address.
uint24_t _getStackRelativeIndirectIndexedYAddr();
//! @brief Push 8 bits of data to the stack.
void _push(uint8_t data);
//! @brief Push 16 bits of data to the stack.
@@ -470,7 +309,7 @@ namespace ComSquare::CPU
//! @brief All the instructions of the CPU.
//! @info Instructions are indexed by their opcode
Instruction _instructions[0x100] = {
const Instruction _instructions[0x100] = {
{&CPU::BRK, 7, "brk", AddressingMode::Immediate8bits, 2}, // 00
{&CPU::ORA, 6, "ora", AddressingMode::DirectPageIndirectIndexedByX, 2}, // 01
{&CPU::COP, 7, "cop", AddressingMode::Immediate8bits, 2}, // 02
@@ -729,14 +568,20 @@ namespace ComSquare::CPU
{&CPU::SBC, 5, "sbc", AddressingMode::AbsoluteIndexedByXLong, 4}, // FF
};
public:
explicit CPU(std::shared_ptr<Memory::MemoryBus> bus, Cartridge::Header &cartridgeHeader);
//! @brief Construct a new generic CPU.
//! @param bus The memory bus to use to transfer data.
//! @param cartridgeHeader The header used to know interrupts, main entry point etc...
CPU(Memory::MemoryBus &bus, Cartridge::Header &cartridgeHeader);
//! @brief A default copy constructor
CPU(const CPU &) = default;
//! @brief A CPU is not assignable
CPU &operator=(const CPU &) = delete;
//! @brief A default destructor
~CPU() override = default;
//! @brief This function continue to execute the Cartridge code.
//! @return The number of CPU cycles that elapsed
virtual unsigned update();
unsigned update();
//! @brief Read from the internal CPU register.
//! @param addr The address to read from. The address 0x0 should refer to the first byte of the register.
//! @throw InvalidAddress will be thrown if the address is more than $1F (the number of register).
@@ -748,18 +593,22 @@ namespace ComSquare::CPU
//! @throw InvalidAddress will be thrown if the address is more than $1F (the number of register).
void write(uint24_t addr, uint8_t data) override;
//! @brief Get the name of the data at the address
//! @param addr The address (in local space)
[[nodiscard]] std::string getValueName(uint24_t addr) const override;
//! @brief Get the size of the data. This size can be lower than the mapped data.
//! @return The number of bytes inside this memory.
uint24_t getSize() const override;
[[nodiscard]] uint24_t getSize() const override;
//! @brief Get the name of this accessor (used for debug purpose)
std::string getName() const override;
[[nodiscard]] std::string getName() const override;
//! @brief Get the component of this accessor (used for debug purpose)
Component getComponent() const override;
[[nodiscard]] Component getComponent() const override;
//! @brief Reset interrupt - Called on boot and when the reset button is pressed.
virtual int RESB();
//! @copydoc
int RESB();
//! @brief Is an NMI (non-maskable interrupt) requested.
bool IsNMIRequested = false;
@@ -768,16 +617,8 @@ namespace ComSquare::CPU
//! @brief Is an abort requested
bool IsAbortRequested = false;
//! @brief Return true if the CPU is overloaded with debugging features.
virtual bool isDebugger() const;
//! @brief Change the memory bus used by the CPU.
virtual void setMemoryBus(std::shared_ptr<Memory::MemoryBus> bus);
#ifdef DEBUGGER_ENABLED
#ifdef DEBUGGER_ENABLED
friend Debugger::RegisterViewer;
#endif
#endif
};
}
#endif //COMSQUARE_CPU_HPP

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -21,19 +21,4 @@ namespace ComSquare::Memory
{
return this->_start <= addr && addr <= this->_end;
}
bool AMemory::isMirror() const
{
return false;
}
std::shared_ptr<IMemory> AMemory::getMirrored() const
{
return nullptr;
}
std::string AMemory::getValueName(uint24_t) const
{
return "???";
}
}

View File

@@ -26,25 +26,20 @@ namespace ComSquare::Memory
//! @param addr The absolute address (in the 24 bit bus)
//! @return The local address (0 refers to the first byte of this component).
//! @throw InvalidAddress is thrown if the address is not mapped by this component.
virtual uint24_t getRelativeAddress(uint24_t addr) const override;
[[nodiscard]] uint24_t getRelativeAddress(uint24_t addr) const override;
//! @brief Change starting and ending points of this mapped memory.
//! @param start The first address mapped to this component.
//! @param end The last address mapped to this component.
//! @warning The start/end address should be a continuous range. You can't map address 0x0 and 0x2 but not 0x1. To do that, use two AMemory.
void setMemoryRegion(uint24_t start, uint24_t end);
//! @brief Return true if this component has mapped the address.
//! @param addr The address to check.
//! @return True if this address is mapped to the component. False otherwise.
virtual bool hasMemoryAt(uint24_t addr) const override;
//! @brief Check if this memory is a mirror or not.
//! @return True if this memory is a mirror. False otherwise.
virtual bool isMirror() const override;
//! @brief Get the name of the data at the address
//! @param addr The address (in local space)
virtual std::string getValueName(uint24_t addr) const override;
//! @brief Return the memory accessor this accessor mirror if any
//! @return nullptr if isMirror is false, the source otherwise.
virtual std::shared_ptr<IMemory> getMirrored() const override;
virtual ~AMemory() override = default;
[[nodiscard]] bool hasMemoryAt(uint24_t addr) const override;
//! @brief A default destructor
~AMemory() override = default;
};
}

View File

@@ -4,7 +4,7 @@
#include <iostream>
#include "ARectangleMemory.hpp"
#include "../Exceptions/InvalidAddress.hpp"
#include "Exceptions/InvalidAddress.hpp"
namespace ComSquare::Memory
{
@@ -42,16 +42,6 @@ namespace ComSquare::Memory
this->_endPage = endPage;
}
bool ARectangleMemory::isMirror() const
{
return false;
}
std::shared_ptr<IMemory> ARectangleMemory::getMirrored() const
{
return nullptr;
}
std::string ARectangleMemory::getValueName(uint24_t) const
{
return "???";

View File

@@ -9,7 +9,8 @@
namespace ComSquare::Memory
{
//! @brief Base memory class to map non continuous rectangle to the memory. (A rectangle that spam across more than one bank but that does not start at $0000 or end at $FFFF).
class ARectangleMemory : public IMemory {
class ARectangleMemory : public IMemory
{
protected:
//! @brief The first bank to map to.
uint8_t _startBank = 0;
@@ -19,16 +20,19 @@ namespace ComSquare::Memory
uint16_t _startPage = 0;
//! @brief The last address of each bank to map.
uint16_t _endPage = 0;
public:
//! @brief Translate an absolute address to a relative address
//! @param addr The absolute address (in the 24 bit bus)
//! @return The local address (0 refers to the first byte of this component).
//! @throw InvalidAddress is thrown if the address is not mapped by this component.
virtual uint24_t getRelativeAddress(uint24_t addr) const override;
[[nodiscard]] uint24_t getRelativeAddress(uint24_t addr) const override;
//! @brief Return true if this component has mapped the address.
//! @param addr The address to check.
//! @return True if this address is mapped to the component. False otherwise.
bool hasMemoryAt(uint24_t addr) const override;
[[nodiscard]] bool hasMemoryAt(uint24_t addr) const override;
//! @brief Change starting and ending points of this mapped memory.
//! @param startBank The first bank mapped to this component.
//! @param endBank The last bank mapped to this component.
@@ -36,15 +40,12 @@ namespace ComSquare::Memory
//! @param endPage The end page mapped to this component (every mapped banks will have this pages lower than this mapped)
//! @warning The start/end address should be a rectangle. To mirror memory, use the MemoryShadow class and not this one.
void setMemoryRegion(uint8_t startBank, uint8_t endBank, uint16_t startPage, uint16_t endPage);
//! @brief Check if this memory is a mirror or not.
//! @return True if this memory is a mirror. False otherwise.
virtual bool isMirror() const override;
//! @brief Get the name of the data at the address
//! @param addr The address (in local space)
virtual std::string getValueName(uint24_t addr) const override;
//! @brief Return the memory accessor this accessor mirror if any
//! @return nullptr if isMirror is false, the source otherwise.
virtual std::shared_ptr<IMemory> getMirrored() const override;
virtual ~ARectangleMemory() override = default;
[[nodiscard]] std::string getValueName(uint24_t addr) const override;
//! @brief A default destructor.
~ARectangleMemory() override = default;
};
}
}// namespace ComSquare::Memory

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

View File

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

View File

@@ -2,13 +2,14 @@
// Created by anonymus-raccoon on 1/23/20.
//
#ifndef COMSQUARE_MEMORYBUS_HPP
#define COMSQUARE_MEMORYBUS_HPP
#pragma once
#include <cstdint>
#include <vector>
#include <memory>
#include "AMemory.hpp"
#include "RectangleShadow.hpp"
#include "MemoryShadow.hpp"
#include <cstdint>
#include <memory>
#include <vector>
namespace ComSquare
{
@@ -17,10 +18,16 @@ namespace ComSquare
namespace Memory
{
//! @brief The memory bus is the component responsible of mapping addresses to components address and transmitting the data.
class MemoryBus {
class MemoryBus
{
private:
//! @brief The list of components registered inside the bus. Every components that can read/write to a public address should be in this vector.
std::vector<std::shared_ptr<IMemory>> _memoryAccessors;
std::vector<std::reference_wrapper<IMemory>> _memoryAccessors;
//! @brief The list of simple memory shadows that are used to map duplicated zones of memory.
std::vector<MemoryShadow> _shadows = {};
//! @brief The list of rectangle memory shadows that are used to map duplicated zones of memory.
std::vector<RectangleShadow> _rectangleShadows = {};
//! @brief WRam, CPU, PPU & APU registers are mirrored to all banks of Q1 & Q3. This function is used for the mirroring.
//! @param console All the components.
@@ -30,29 +37,33 @@ namespace ComSquare
//! @brief The last value read via the memory bus.
uint8_t _openBus = 0;
public:
//! @brief Create a new default memory bus.
MemoryBus() = default;
//! @brief A memory bus is copyable.
MemoryBus(const MemoryBus &) = default;
//! @brief A memory bus is assignable.
MemoryBus &operator=(const MemoryBus &) = default;
//! @brief A default destructor
~MemoryBus() = default;
//! @brief Force silencing read to the bus.
bool forceSilence = false;
//! @brief Read data at a global address.
//! @param addr The address to read from.
//! @return The value that the component returned for this address. If the address was mapped to ram, it simply returned the value. If the address was mapped to a register the component returned the register.
virtual uint8_t read(uint24_t addr);
//! @brief Read data at a global address. This form allow read to be silenced.
//! @param addr The address to read from.
//! @param silence Disable login to the memory bus's debugger (if enabled). Should only be used by other debuggers. This also won't affect the open bus.
//! @throws InvalidAddress If the address is not mapped to the bus, this exception is thrown.
//! @return The value that the component returned for this address. If the address was mapped to ram, it simply returned the value. If the address was mapped to a register the component returned the register.
virtual uint8_t read(uint24_t addr, bool silence);
uint8_t read(uint24_t addr);
//! @brief This as the same purpose as a read but it does not change the open bus and won't throw an exception.
//! @param addr The address to read from.
//! @return The value that the component returned for this address. If the address was mapped to ram, it simply returned the value. If the address was mapped to a register the component returned the register.
uint8_t peek(uint24_t addr);
//! @brief Write a data to a global address.
//! @param addr The address to write to.
//! @param data The data to write.
virtual void write(uint24_t addr, uint8_t data);
void write(uint24_t addr, uint8_t data);
//! @brief Map components to the address space using the currently loaded cartridge to set the right mapping mode.
//! @param console All the components.
@@ -61,13 +72,7 @@ namespace ComSquare
//! @brief Helper function to get the components that is responsible of read/write at an address.
//! @param addr The address you want to look for.
//! @return The components responsible for the address param or nullptr if none was found.
std::shared_ptr<IMemory> getAccessor(uint24_t addr);
//! @brief Return true if the Bus is overloaded with debugging features.
virtual bool isDebugger();
IMemory *getAccessor(uint24_t addr);
};
}
}
#endif //COMSQUARE_MEMORYBUS_HPP

View File

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

View File

@@ -9,39 +9,51 @@
namespace ComSquare::Memory
{
class MemoryShadow : public AMemory {
class MemoryShadow : public AMemory
{
private:
//! @brief Memory to shadow from.
std::shared_ptr<IMemory> _initial;
IMemory &_initial;
public:
//! @brief Create a shadow for the memory given as parameter.
MemoryShadow(std::shared_ptr<IMemory> initial, uint24_t start, uint24_t end);
//! @param initial The memory to shadow
//! @param start The start position of the initial memory to shadow.
//! @param end The end position of the initial memory to shadow.
MemoryShadow(IMemory &initial, uint24_t start, uint24_t end);
//! @brief A memory shadow is copy constructable
MemoryShadow(const MemoryShadow &) = default;
MemoryShadow &operator=(const MemoryShadow &) = default;
~MemoryShadow() = default;
//! @brief A memory shadow is not assignable.
MemoryShadow &operator=(const MemoryShadow &) = delete;
//! @brief A default destructor
~MemoryShadow() override = default;
//! @brief Read from the initial AMemory given.
//! @param addr The address to read from. The address 0x0 should refer to the first byte of the initial AMemory.
//! @throw InvalidAddress will be thrown if the address is more than the size of the initial AMemory.
//! @return Return the data at the address.
uint8_t read(uint24_t addr) override;
//! @brief Write data to the ram.
//! @param addr The address to write to. The address 0x0 should refer to the first byte of the initial AMemory.
//! @param data The data to write.
//! @throw InvalidAddress will be thrown if the address is more than the size of the initial AMemory.
void write(uint24_t addr, uint8_t data) override;
//! @brief Get the size of the data. This size can be lower than the mapped data.
//! @return The number of bytes inside this memory.
virtual uint24_t getSize() const override;
//! @brief Check if this memory is a mirror or not.
//! @return True if this memory is a mirror. False otherwise.
bool isMirror() const override;
[[nodiscard]] uint24_t getSize() const override;
//! @brief Get the name of this accessor (used for debug purpose)
std::string getName() const override;
[[nodiscard]] std::string getName() const override;
//! @brief Get the component of this accessor (used for debug purpose)
Component getComponent() const override;
[[nodiscard]] Component getComponent() const override;
//! @brief Get the name of the data at the address
//! @param addr The address (in local space)
[[nodiscard]] std::string getValueName(uint24_t addr) const override;
//! @brief Return the memory accessor this accessor mirror if any
//! @return nullptr if isMirror is false, the source otherwise.
std::shared_ptr<IMemory> getMirrored() const override;
[[nodiscard]] IMemory &getMirrored() const;
};
}

View File

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

View File

@@ -13,14 +13,21 @@ namespace ComSquare::Memory
class RectangleShadow : public ARectangleMemory {
private:
//! @brief Memory to shadow from.
std::shared_ptr<IMemory> _initial;
IMemory &_initial;
//! @brief The number of banks to add to the memory before accessing it from the initial data.
int _bankOffset = 0;
public:
//! @brief Create a shadow for the memory given as parameter.
explicit RectangleShadow(std::shared_ptr<IMemory> initial, uint8_t startBank, uint8_t endBank, uint16_t startPage, uint16_t endPage);
//! @param startBank The starting bank of the memory to shadow.
//! @param endBank The ending bank of the memory to shadow
//! @param startPage The starting page of the memory to shadow
//! @param endPage The ending page of the memory to shadow
RectangleShadow(IMemory &initial, uint8_t startBank, uint8_t endBank, uint16_t startPage, uint16_t endPage);
//! @brief A rectangle shadow is copy constructable.
RectangleShadow(const RectangleShadow &) = default;
RectangleShadow &operator=(const RectangleShadow &) = default;
//! @brrief A rectangle shadow is not assignable
RectangleShadow &operator=(const RectangleShadow &) = delete;
//! @brief A default destructor.
~RectangleShadow() override = default;
//! @brief Read from the initial AMemory given.
@@ -28,31 +35,34 @@ namespace ComSquare::Memory
//! @throw InvalidAddress will be thrown if the address is more than the size of the initial AMemory.
//! @return Return the data at the address.
uint8_t read(uint24_t addr) override;
//! @brief Write data to the ram.
//! @param addr The address to write to. The address 0x0 should refer to the first byte of the initial AMemory.
//! @param data The data to write.
//! @throw InvalidAddress will be thrown if the address is more than the size of the initial AMemory.
void write(uint24_t addr, uint8_t data) override;
//! @brief Translate an absolute address to a relative address
//! @param addr The absolute address (in the 24 bit bus)
//! @return The local address (0 refers to the first byte of this component).
//! @throw InvalidAddress is thrown if the address is not mapped by this component.
uint24_t getRelativeAddress(uint24_t addr) const override;
[[nodiscard]] uint24_t getRelativeAddress(uint24_t addr) const override;
//! @brief Get the size of the data. This size can be lower than the mapped data.
//! @return The number of bytes inside this memory.
virtual uint24_t getSize() const override;
//! @brief Check if this memory is a mirror or not.
//! @return True if this memory is a mirror. False otherwise.
bool isMirror() const override;
[[nodiscard]] uint24_t getSize() const override;
//! @brief Get the name of this accessor (used for debug purpose)
std::string getName() const override;
[[nodiscard]] std::string getName() const override;
//! @brief Get the component of this accessor (used for debug purpose)
Component getComponent() const override;
[[nodiscard]] Component getComponent() const override;
//! @brief Return the memory accessor this accessor mirror if any
//! @return nullptr if isMirror is false, the source otherwise.
std::shared_ptr<IMemory> getMirrored() const override;
[[nodiscard]] IMemory &getMirrored() const;
//! @brief Set the number of bank this component do not shadow. Referring to the first byte of this component will refer to the first byte of the bank at (bankOffset + start of initial memory).
RectangleShadow *setBankOffset(int bankOffset);
void setBankOffset(int bankOffset);
};
}

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

3904
sources/PPU/PpuDebug.cpp Normal file

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

View File

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

View File

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

View File

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

View File

@@ -2,63 +2,84 @@
// Created by anonymus-raccoon on 1/27/20.
//
#ifndef COMSQUARE_SNES_HPP
#define COMSQUARE_SNES_HPP
#pragma once
#include "Memory/MemoryBus.hpp"
#include "APU/APU.hpp"
#include "CPU/CPU.hpp"
#include "Cartridge/Cartridge.hpp"
#include "Ram/Ram.hpp"
#include "PPU/PPU.hpp"
#include "APU/APU.hpp"
#include "Renderer/IRenderer.hpp"
#include "Exceptions/DebuggableError.hpp"
#include "Memory/MemoryBus.hpp"
#include "PPU/PPU.hpp"
#include "Ram/Ram.hpp"
#include "Renderer/IRenderer.hpp"
#include <optional>
#ifdef DEBUGGER_ENABLED
#include "Debugger/MemoryViewer.hpp"
#include "Debugger/HeaderViewer.hpp"
#include "Debugger/CGramDebug.hpp"
#include "Debugger/RegisterViewer.hpp"
#include "Debugger/TileViewer/TileViewer.hpp"
#include "Debugger/MemoryViewer.hpp"
#include "Debugger/HeaderViewer.hpp"
#include "Debugger/CGramDebug.hpp"
#include "Debugger/RegisterViewer.hpp"
#include "Debugger/TileViewer/TileViewer.hpp"
#endif
namespace ComSquare
{
//! @brief Container of all the components of the SNES.
class SNES {
class SNES
{
private:
#ifdef DEBUGGER_ENABLED
//! @brief The window that allow the user to view a memory.
std::unique_ptr<Debugger::MemoryViewer> _ramViewer;
std::optional<Debugger::MemoryViewer> _ramViewer;
//! @brief The window that allow the user to view the cartridge's header.
std::unique_ptr<Debugger::HeaderViewer> _headerViewer;
std::optional<Debugger::HeaderViewer> _headerViewer;
//! @brief The window that allow the user to view the CGRAM.
std::unique_ptr<Debugger::CGramDebug> _cgramViewer;
std::optional<Debugger::CGramDebug> _cgramViewer;
//! @brief The window that allow the user to view registers.
std::unique_ptr<Debugger::RegisterViewer> _registerViewer;
//! @brief The window that allow the user to view the cgram as tiles.
std::unique_ptr<Debugger::TileViewer> _tileViewer;
std::optional<Debugger::RegisterViewer> _registerViewer;
//! @brief The window that allow the user to view the CGRAM as tiles.
std::optional<Debugger::TileViewer> _tileViewer;
#endif
public:
//! @brief The memory bus that map addresses to components.
std::shared_ptr<Memory::MemoryBus> bus;
Memory::MemoryBus bus;
//! @brief Cartridge containing instructions (ROM).
std::shared_ptr<Cartridge::Cartridge> cartridge;
Cartridge::Cartridge cartridge;
//! @brief Work Ram shared by all the components.
std::shared_ptr<Ram::Ram> wram;
Ram::Ram wram;
//! @brief Save Ram residing inside the Cartridge in a real SNES.
std::shared_ptr<Ram::Ram> sram;
Ram::Ram sram;
//! @brief Central Processing Unit of the SNES.
std::shared_ptr<CPU::CPU> cpu;
CPU::CPU cpu;
//! @brief Picture Processing Unit of the SNES
std::shared_ptr<PPU::PPU> ppu;
PPU::PPU ppu;
//! @brief Audio Processing Unit if the SNES
std::shared_ptr<APU::APU> apu;
APU::APU apu;
//! @brief Create all the components using a common memory bus for all of them.
//! @param renderer The renderer to use.
explicit SNES(Renderer::IRenderer &renderer);
//! @brief Create all the components using a common memory bus for all of them and load a rom
//! @param ramPath The rom to load.
//! @param renderer The renderer to use.
SNES(const std::string &ramPath, Renderer::IRenderer &renderer);
//! @brief A SNES is not copyable.
SNES(const SNES &) = delete;
//! @brief A SNES can't be assigned
SNES &operator=(const SNES &) = delete;
//! @brief A default destructor.
~SNES() = default;
//! @brief Call this function to update all the components
void update();
//! @brief Load the rom at the given path
//! @param rom The path of the rom.
//! @throws InvalidRomException If the rom is invalid, this exception is thrown.
void loadRom(const std::string& path);
#ifdef DEBUGGER_ENABLED
//! @brief Disable the CPU's debugging window.
void disableCPUDebugging();
//! @brief Enable the CPU's debugging window.
@@ -82,9 +103,9 @@ namespace ComSquare
void disableMemoryBusDebugging();
//! @brief Enable the Memory Bus's debugging window.
void enableMemoryBusDebugging();
//! @brief Disable the Cgram's debugging window.
//! @brief Disable the CGRAM's debugging window.
void disableCgramDebugging();
//! @brief Enable the Cgram's debugging window.
//! @brief Enable the CGRAM's debugging window.
void enableCgramDebugging();
//! @brief Disable the Register's debugging window.
void disableRegisterDebugging();
@@ -94,13 +115,6 @@ namespace ComSquare
void disableTileViewerDebugging();
//! @brief Enable the TileViewer's debugging window.
void enableTileViewerDebugging();
//! @brief Create all the components using a common memory bus for all of them.
SNES(const std::string &ramPath, Renderer::IRenderer &renderer);
SNES(const SNES &) = delete;
SNES &operator=(const SNES &) = delete;
~SNES() = default;
#endif
};
}
#endif //COMSQUARE_SNES_HPP
}// namespace ComSquare

View File

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

View File

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

View File

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

View File

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

View File

@@ -14,7 +14,7 @@ using namespace ComSquare;
TEST_CASE("inidisp_data_full_ones PPU_write", "[PPU_write]")
{
Init()
snes.bus->write(0x2100, 0b11111111);
snes.bus.write(0x2100, 0b11111111);
REQUIRE(snes.ppu->_registers._inidisp.fblank == true);
REQUIRE(snes.ppu->_registers._inidisp.brightness == 0xF);
}
@@ -22,7 +22,7 @@ TEST_CASE("inidisp_data_full_ones PPU_write", "[PPU_write]")
TEST_CASE("inidisp_data_full_zeros PPU_write", "[PPU_write]")
{
Init()
snes.bus->write(0x2100, 0b00000000);
snes.bus.write(0x2100, 0b00000000);
REQUIRE(snes.ppu->_registers._inidisp.fblank == false);
REQUIRE(snes.ppu->_registers._inidisp.brightness == 0x0);
}
@@ -30,7 +30,7 @@ TEST_CASE("inidisp_data_full_zeros PPU_write", "[PPU_write]")
TEST_CASE("inidisp_data_fBlank_on_brghtness_off PPU_write", "[PPU_write]")
{
Init()
snes.bus->write(0x2100, 0b10000000);
snes.bus.write(0x2100, 0b10000000);
REQUIRE(snes.ppu->_registers._inidisp.fblank == true);
REQUIRE(snes.ppu->_registers._inidisp.brightness == 0x0);
}
@@ -38,7 +38,7 @@ TEST_CASE("inidisp_data_fBlank_on_brghtness_off PPU_write", "[PPU_write]")
TEST_CASE("inidisp_data_fBlank_off_brghtness_max PPU_write", "[PPU_write]")
{
Init()
snes.bus->write(0x2100, 0b00001111);
snes.bus.write(0x2100, 0b00001111);
REQUIRE(snes.ppu->_registers._inidisp.fblank == false);
REQUIRE(snes.ppu->_registers._inidisp.brightness == 0xF);
}
@@ -46,7 +46,7 @@ TEST_CASE("inidisp_data_fBlank_off_brghtness_max PPU_write", "[PPU_write]")
TEST_CASE("inidisp_data_fBlank_off_brghtness_half PPU_write", "[PPU_write]")
{
Init()
snes.bus->write(0x2100, 0b00000101);
snes.bus.write(0x2100, 0b00000101);
REQUIRE(snes.ppu->_registers._inidisp.fblank == false);
REQUIRE(snes.ppu->_registers._inidisp.brightness == 0x5);
}
@@ -54,7 +54,7 @@ TEST_CASE("inidisp_data_fBlank_off_brghtness_half PPU_write", "[PPU_write]")
TEST_CASE("obsel_111_object_size_and_all_null PPU_write", "[PPU_write]")
{
Init()
snes.bus->write(0x2101, 0b11100000);
snes.bus.write(0x2101, 0b11100000);
REQUIRE(snes.ppu->_registers._obsel.objectSize == 0b111);
REQUIRE(snes.ppu->_registers._obsel.nameSelect == 0b00);
REQUIRE(snes.ppu->_registers._obsel.nameBaseSelect == 0b000);
@@ -63,7 +63,7 @@ TEST_CASE("obsel_111_object_size_and_all_null PPU_write", "[PPU_write]")
TEST_CASE("obsel_data_full PPU_write", "[PPU_write]")
{
Init()
snes.bus->write(0x2101, 0b11111111);
snes.bus.write(0x2101, 0b11111111);
REQUIRE(snes.ppu->_registers._obsel.objectSize == 0b111);
REQUIRE(snes.ppu->_registers._obsel.nameSelect == 0b11);
REQUIRE(snes.ppu->_registers._obsel.nameBaseSelect == 0b111);
@@ -72,7 +72,7 @@ TEST_CASE("obsel_data_full PPU_write", "[PPU_write]")
TEST_CASE("obsel_data_full_nameselect PPU_write", "[PPU_write]")
{
Init()
snes.bus->write(0x2101, 0b00011000);
snes.bus.write(0x2101, 0b00011000);
REQUIRE(snes.ppu->_registers._obsel.objectSize == 0b000);
REQUIRE(snes.ppu->_registers._obsel.nameSelect == 0b11);
REQUIRE(snes.ppu->_registers._obsel.nameBaseSelect == 0b000);
@@ -81,7 +81,7 @@ TEST_CASE("obsel_data_full_nameselect PPU_write", "[PPU_write]")
TEST_CASE("obsel_data_full_baseselect_write", "[PPU_write]")
{
Init()
snes.bus->write(0x2101, 0b00000111);
snes.bus.write(0x2101, 0b00000111);
REQUIRE(snes.ppu->_registers._obsel.objectSize == 0b000);
REQUIRE(snes.ppu->_registers._obsel.nameSelect == 0b00);
REQUIRE(snes.ppu->_registers._obsel.nameBaseSelect == 0b111);
@@ -90,14 +90,14 @@ TEST_CASE("obsel_data_full_baseselect_write", "[PPU_write]")
TEST_CASE("oamaddl_data_full PPU_write", "[PPU_write]")
{
Init()
snes.bus->write(0x2102, 0b11111111);
snes.bus.write(0x2102, 0b11111111);
REQUIRE(snes.ppu->_registers._oamadd.oamAddress == 0b011111111);
}
TEST_CASE("oamaddh_data_full PPU_write", "[PPU_write]")
{
Init()
snes.bus->write(0x2103, 0b11111111);
snes.bus.write(0x2103, 0b11111111);
REQUIRE(snes.ppu->_registers._oamadd.objPriorityActivationBit == true);
REQUIRE(snes.ppu->_registers._oamadd.oamAddress == 0b100000000);
}
@@ -105,8 +105,8 @@ TEST_CASE("oamaddh_data_full PPU_write", "[PPU_write]")
TEST_CASE("oamaddlh_data_full PPU_write", "[PPU_write]")
{
Init()
snes.bus->write(0x2102, 0b11111111);
snes.bus->write(0x2103, 0b11111111);
snes.bus.write(0x2102, 0b11111111);
snes.bus.write(0x2103, 0b11111111);
REQUIRE(snes.ppu->_registers._oamadd.objPriorityActivationBit == true);
REQUIRE(snes.ppu->_registers._oamadd.oamAddress == 0b111111111);
}
@@ -114,8 +114,8 @@ TEST_CASE("oamaddlh_data_full PPU_write", "[PPU_write]")
TEST_CASE("oamaddlh_data_full_priorityBit_off PPU_write", "[PPU_write]")
{
Init()
snes.bus->write(0x2102, 0b11111111);
snes.bus->write(0x2103, 0b01111111);
snes.bus.write(0x2102, 0b11111111);
snes.bus.write(0x2103, 0b01111111);
REQUIRE(snes.ppu->_registers._oamadd.objPriorityActivationBit == false);
REQUIRE(snes.ppu->_registers._oamadd.oamAddress == 0b111111111);
}
@@ -123,8 +123,8 @@ TEST_CASE("oamaddlh_data_full_priorityBit_off PPU_write", "[PPU_write]")
TEST_CASE("oamaddlh_oamAdress_11_priorityBit_on PPU_write", "[PPU_write]")
{
Init()
snes.bus->write(0x2102, 0b00001011);
snes.bus->write(0x2103, 0b10011100);
snes.bus.write(0x2102, 0b00001011);
snes.bus.write(0x2103, 0b10011100);
REQUIRE(snes.ppu->_registers._oamadd.objPriorityActivationBit == true);
REQUIRE(snes.ppu->_registers._oamadd.oamAddress == 11);
}
@@ -132,7 +132,7 @@ TEST_CASE("oamaddlh_oamAdress_11_priorityBit_on PPU_write", "[PPU_write]")
TEST_CASE("bgmode_data_full PPU_write", "[PPU_write]")
{
Init()
snes.bus->write(0x2105, 0b11111111);
snes.bus.write(0x2105, 0b11111111);
REQUIRE(snes.ppu->_registers._bgmode.bgMode == 7);
REQUIRE(snes.ppu->_registers._bgmode.characterSizeBg1 == true);
REQUIRE(snes.ppu->_registers._bgmode.characterSizeBg2 == true);
@@ -144,7 +144,7 @@ TEST_CASE("bgmode_data_full PPU_write", "[PPU_write]")
TEST_CASE("bgmode_bgmode_5_and_bg24_on PPU_write", "[PPU_write]")
{
Init()
snes.bus->write(0x2105, 0b10100101);
snes.bus.write(0x2105, 0b10100101);
REQUIRE(snes.ppu->_registers._bgmode.bgMode == 5);
REQUIRE(snes.ppu->_registers._bgmode.characterSizeBg1 == false);
REQUIRE(snes.ppu->_registers._bgmode.characterSizeBg2 == true);
@@ -156,7 +156,7 @@ TEST_CASE("bgmode_bgmode_5_and_bg24_on PPU_write", "[PPU_write]")
TEST_CASE("mosaic_data_full PPU_write", "[PPU_write]")
{
Init()
snes.bus->write(0x2106, 0b11111111);
snes.bus.write(0x2106, 0b11111111);
REQUIRE(snes.ppu->_registers._mosaic.affectBg1 == true);
REQUIRE(snes.ppu->_registers._mosaic.affectBg2 == true);
REQUIRE(snes.ppu->_registers._mosaic.affectBg3 == true);
@@ -167,7 +167,7 @@ TEST_CASE("mosaic_data_full PPU_write", "[PPU_write]")
TEST_CASE("mosaic_affectbg23_w_1x1_size PPU_write", "[PPU_write]")
{
Init()
snes.bus->write(0x2106, 0b00000110);
snes.bus.write(0x2106, 0b00000110);
REQUIRE(snes.ppu->_registers._mosaic.affectBg1 == false);
REQUIRE(snes.ppu->_registers._mosaic.affectBg2 == true);
REQUIRE(snes.ppu->_registers._mosaic.affectBg3 == true);
@@ -178,7 +178,7 @@ TEST_CASE("mosaic_affectbg23_w_1x1_size PPU_write", "[PPU_write]")
TEST_CASE("mosaic_affectbg14_w_2x2_size PPU_write", "[PPU_write]")
{
Init()
snes.bus->write(0x2106, 0b00101001);
snes.bus.write(0x2106, 0b00101001);
REQUIRE(snes.ppu->_registers._mosaic.affectBg1 == true);
REQUIRE(snes.ppu->_registers._mosaic.affectBg2 == false);
REQUIRE(snes.ppu->_registers._mosaic.affectBg3 == false);
@@ -189,7 +189,7 @@ TEST_CASE("mosaic_affectbg14_w_2x2_size PPU_write", "[PPU_write]")
TEST_CASE("bg1sc_data_full PPU_write", "[PPU_write]")
{
Init()
snes.bus->write(0x2107, 0b11111111);
snes.bus.write(0x2107, 0b11111111);
REQUIRE(snes.ppu->_registers._bgsc[0].tilemapAddress == 0b111111);
REQUIRE(snes.ppu->_registers._bgsc[0].tilemapHorizontalMirroring == true);
REQUIRE(snes.ppu->_registers._bgsc[0].tilemapVerticalMirroring == true);
@@ -198,7 +198,7 @@ TEST_CASE("bg1sc_data_full PPU_write", "[PPU_write]")
TEST_CASE("bg2sc_data_full PPU_write", "[PPU_write]")
{
Init()
snes.bus->write(0x2108, 0b11111111);
snes.bus.write(0x2108, 0b11111111);
REQUIRE(snes.ppu->_registers._bgsc[1].tilemapAddress == 0b111111);
REQUIRE(snes.ppu->_registers._bgsc[1].tilemapHorizontalMirroring == true);
REQUIRE(snes.ppu->_registers._bgsc[1].tilemapVerticalMirroring == true);
@@ -207,7 +207,7 @@ TEST_CASE("bg2sc_data_full PPU_write", "[PPU_write]")
TEST_CASE("bg3sc_data_full PPU_write", "[PPU_write]")
{
Init()
snes.bus->write(0x2109, 0b11111111);
snes.bus.write(0x2109, 0b11111111);
REQUIRE(snes.ppu->_registers._bgsc[2].tilemapAddress == 0b111111);
REQUIRE(snes.ppu->_registers._bgsc[2].tilemapHorizontalMirroring == true);
REQUIRE(snes.ppu->_registers._bgsc[2].tilemapVerticalMirroring == true);
@@ -216,7 +216,7 @@ TEST_CASE("bg3sc_data_full PPU_write", "[PPU_write]")
TEST_CASE("bg4sc_data_full PPU_write", "[PPU_write]")
{
Init()
snes.bus->write(0x210A, 0b11111111);
snes.bus.write(0x210A, 0b11111111);
REQUIRE(snes.ppu->_registers._bgsc[3].tilemapAddress == 0b111111);
REQUIRE(snes.ppu->_registers._bgsc[3].tilemapHorizontalMirroring == true);
REQUIRE(snes.ppu->_registers._bgsc[3].tilemapVerticalMirroring == true);
@@ -225,7 +225,7 @@ TEST_CASE("bg4sc_data_full PPU_write", "[PPU_write]")
TEST_CASE("bg4sc_data_null PPU_write", "[PPU_write]")
{
Init()
snes.bus->write(0x210A, 0b00000000);
snes.bus.write(0x210A, 0b00000000);
REQUIRE(snes.ppu->_registers._bgsc[3].tilemapAddress == 0);
REQUIRE(snes.ppu->_registers._bgsc[3].tilemapHorizontalMirroring == false);
REQUIRE(snes.ppu->_registers._bgsc[3].tilemapVerticalMirroring == false);
@@ -234,7 +234,7 @@ TEST_CASE("bg4sc_data_null PPU_write", "[PPU_write]")
TEST_CASE("bg4sc_horizontal_off_vertical_on_random_tilemapAdress PPU_write", "[PPU_write]")
{
Init()
snes.bus->write(0x210A, 0b11000110);
snes.bus.write(0x210A, 0b11000110);
REQUIRE(snes.ppu->_registers._bgsc[3].tilemapAddress == 0b110001);
REQUIRE(snes.ppu->_registers._bgsc[3].tilemapHorizontalMirroring == false);
REQUIRE(snes.ppu->_registers._bgsc[3].tilemapVerticalMirroring == true);
@@ -243,7 +243,7 @@ TEST_CASE("bg4sc_horizontal_off_vertical_on_random_tilemapAdress PPU_write", "[P
TEST_CASE("bg12nba_data_full PPU_write", "[PPU_write]")
{
Init()
snes.bus->write(0x210B, 0b11111111);
snes.bus.write(0x210B, 0b11111111);
REQUIRE(snes.ppu->_registers._bgnba[0].baseAddressBg1a3 == 0b1111);
REQUIRE(snes.ppu->_registers._bgnba[0].baseAddressBg2a4 == 0b1111);
}
@@ -251,7 +251,7 @@ TEST_CASE("bg12nba_data_full PPU_write", "[PPU_write]")
TEST_CASE("bg34nba_data_full PPU_write", "[PPU_write]")
{
Init()
snes.bus->write(0x210C, 0b11111111);
snes.bus.write(0x210C, 0b11111111);
REQUIRE(snes.ppu->_registers._bgnba[1].baseAddressBg1a3 == 0b1111);
REQUIRE(snes.ppu->_registers._bgnba[1].baseAddressBg2a4 == 0b1111);
}
@@ -259,7 +259,7 @@ TEST_CASE("bg34nba_data_full PPU_write", "[PPU_write]")
TEST_CASE("bg12nba_data_random_data PPU_write", "[PPU_write]")
{
Init()
snes.bus->write(0x210B, 0b10101010);
snes.bus.write(0x210B, 0b10101010);
REQUIRE(snes.ppu->_registers._bgnba[0].baseAddressBg1a3 == 0b1010);
REQUIRE(snes.ppu->_registers._bgnba[0].baseAddressBg2a4 == 0b1010);
}

View File

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

View File

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

View File

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