From 53532ca44fd960b13e6f2b749c6150d316ace97c Mon Sep 17 00:00:00 2001 From: AnonymusRaccoon Date: Fri, 31 Jan 2020 15:48:10 +0100 Subject: [PATCH] Adding a scoring system for the header address --- CMakeLists.txt | 2 +- sources/Cartridge/Cartridge.cpp | 80 +++++++++++++++++++++----- sources/Cartridge/Cartridge.hpp | 26 +++++++-- sources/Cartridge/InterruptVectors.hpp | 44 ++++++++++++++ 4 files changed, 134 insertions(+), 18 deletions(-) create mode 100644 sources/Cartridge/InterruptVectors.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index fa72c08..bf8236d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -79,7 +79,7 @@ add_executable(ComSquare sources/Renderer/SFRenderer.hpp sources/Renderer/SFRenderer.cpp sources/Exceptions/InvalidAction.hpp -) + sources/Cartridge/InterruptVectors.hpp) target_link_libraries(ComSquare sfml-graphics diff --git a/sources/Cartridge/Cartridge.cpp b/sources/Cartridge/Cartridge.cpp index 8051e69..3b224eb 100644 --- a/sources/Cartridge/Cartridge.cpp +++ b/sources/Cartridge/Cartridge.cpp @@ -59,6 +59,54 @@ namespace ComSquare::Cartridge throw InvalidAction("Witting to the ROM is not allowed."); } + Header Cartridge::_mapHeader(uint32_t headerAddress) + { + Header head; + headerAddress -= 0xC0u; + + ADDMAPPINGMODE(head.mappingMode, this->_data[headerAddress + 0xD5u] & 0x10u ? FastRom : SlowRom); + ADDMAPPINGMODE(head.mappingMode, this->_data[headerAddress + 0xD5u] & 0x1u ? HiRom : LoRom); + if (this->_data[headerAddress + 0xD5u] & 0x2u || this->_data[headerAddress + 0xD5u] & 0x4u) + ADDMAPPINGMODE(head.mappingMode, ExRom); + head.romType = this->_data[headerAddress + 0xD6u]; + head.romSize = 0x400u << this->_data[headerAddress + 0xD7u]; + head.sramSize = 0x400u << this->_data[headerAddress + 0xD8u]; + head.creatorIDs[0] = this->_data[headerAddress + 0xD9u]; + head.creatorIDs[1] = this->_data[headerAddress + 0xDAu]; + head.version = this->_data[headerAddress + 0xDBu]; + head.checksumComplements[0] = this->_data[headerAddress + 0xDCu]; + head.checksumComplements[1] = this->_data[headerAddress + 0xDDu]; + head.checksums[0] = this->_data[headerAddress + 0xDEu]; + head.checksums[1] = this->_data[headerAddress + 0xDFu]; + + head.nativeInterrupts.cop8[0] = this->_data[headerAddress + 0xE4u]; + head.nativeInterrupts.cop8[1] = this->_data[headerAddress + 0xE5u]; + head.nativeInterrupts.brk8[0] = this->_data[headerAddress + 0xE6u]; + head.nativeInterrupts.brk8[1] = this->_data[headerAddress + 0xE7u]; + head.nativeInterrupts.abort8[0] = this->_data[headerAddress + 0xE8u]; + head.nativeInterrupts.abort8[1] = this->_data[headerAddress + 0xE9u]; + head.nativeInterrupts.nmi8[0] = this->_data[headerAddress + 0xEAu]; + head.nativeInterrupts.nmi8[1] = this->_data[headerAddress + 0xEBu]; + head.nativeInterrupts.reset8[0] = this->_data[headerAddress + 0xECu]; + head.nativeInterrupts.reset8[1] = this->_data[headerAddress + 0xEDu]; + head.nativeInterrupts.irq8[0] = this->_data[headerAddress + 0xEEu]; + head.nativeInterrupts.irq8[1] = this->_data[headerAddress + 0xEFu]; + + head.emulationInterrupts.cop8[0] = this->_data[headerAddress + 0xF4u]; + head.emulationInterrupts.cop8[1] = this->_data[headerAddress + 0xF5u]; + head.emulationInterrupts.abort8[0] = this->_data[headerAddress + 0xF8u]; + head.emulationInterrupts.abort8[1] = this->_data[headerAddress + 0xF9u]; + head.emulationInterrupts.nmi8[0] = this->_data[headerAddress + 0xFAu]; + head.emulationInterrupts.nmi8[1] = this->_data[headerAddress + 0xFBu]; + head.emulationInterrupts.reset8[0] = this->_data[headerAddress + 0xFCu]; + head.emulationInterrupts.reset8[1] = this->_data[headerAddress + 0xFDu]; + head.emulationInterrupts.brk8[0] = this->_data[headerAddress + 0xFEu]; + head.emulationInterrupts.brk8[1] = this->_data[headerAddress + 0xFFu]; + head.emulationInterrupts.irq8[0] = this->_data[headerAddress + 0xFEu]; + head.emulationInterrupts.irq8[1] = this->_data[headerAddress + 0xFFu]; + return head; + } + uint32_t Cartridge::_getHeaderAddress() { uint32_t address[] = {0x7FC0, 0xFFC0, 0x81C0, 0x101C0}; @@ -68,7 +116,23 @@ namespace ComSquare::Cartridge for (uint32_t addr : address) { int score = 0; - // TODO Implement a scoring system for the address here. + if (addr + 0x32u >= this->_size) + continue; + + Header info = this->_mapHeader(addr); + if (info.romType <= 0x8u) + score++; + if (info.romSize < 0x400u << 0x10u) + score++; + if (info.sramSize < 0x400u << 0x08u) + score++; + if (info.checksum + info.checksumComplement == 0xFFFF && info.checksum != 0 && info.checksumComplement != 0) + score += 8; + + if (info.emulationInterrupts.reset <= 0x8000u) // The reset vector is the first thing called by the SNES so It must execute the code inside the ROM (the rom starts at 0x8000). + continue; + + if (score > bestScore) { bestScore = score; bestAddress = addr; @@ -79,23 +143,13 @@ namespace ComSquare::Cartridge bool Cartridge::_loadHeader() { - unsigned headerAddress = this->_getHeaderAddress(); + uint32_t headerAddress = this->_getHeaderAddress(); + this->header = this->_mapHeader(headerAddress); char name[22]; std::memcpy(name, &this->_data[headerAddress], 21); name[21] = '\0'; this->header.gameName = std::string(name); - ADDMAPPINGMODE(this->_data[headerAddress + 21] & 0x10u ? FastRom : SlowRom); - ADDMAPPINGMODE(this->_data[headerAddress + 21] & 0x1u ? HiRom : LoRom); - if (this->_data[headerAddress + 21] & 0x2u || this->_data[headerAddress + 210] & 0x4u) - ADDMAPPINGMODE(ExRom); - this->header.romType = this->_data[headerAddress + 22]; - this->header.romSize = 0x400u << this->_data[headerAddress + 23]; - this->header.sramSize = 0x400u << this->_data[headerAddress + 24]; - this->header.creatorID = this->_data[headerAddress + 25]; - this->header.version = this->_data[headerAddress + 27]; - this->header.checksumComplement = this->_data[headerAddress + 28]; - this->header.checksum = this->_data[headerAddress + 29]; return headerAddress & 0x200u; } } \ No newline at end of file diff --git a/sources/Cartridge/Cartridge.hpp b/sources/Cartridge/Cartridge.hpp index 2572b08..192f0a8 100644 --- a/sources/Cartridge/Cartridge.hpp +++ b/sources/Cartridge/Cartridge.hpp @@ -9,10 +9,11 @@ #include "../Memory/IMemory.hpp" #include "../Models/Ints.hpp" #include "../Memory/IRectangleMemory.hpp" +#include "InterruptVectors.hpp" namespace ComSquare::Cartridge { - #define ADDMAPPINGMODE(flag) (this->header.mappingMode = static_cast(this->header.mappingMode | (flag))) + #define ADDMAPPINGMODE(x, flag) (x = static_cast(x | (flag))) enum MappingMode { LoRom = 1u << 0u, HiRom = 1u << 1u, @@ -34,13 +35,26 @@ namespace ComSquare::Cartridge //! @brief The size of the SRom inside the cartridge. unsigned sramSize; //! @brief Creator license ID code. - uint8_t creatorID; + union { + uint8_t creatorIDs[2]; + uint16_t creatorID; + }; //! @brief The version of the game uint8_t version; //! @brief Checksum complement - uint8_t checksumComplement; + union { + uint8_t checksumComplements[2]; + uint16_t checksumComplement; + }; //! @brief Checksum - uint8_t checksum; + union { + uint8_t checksums[2]; + uint16_t checksum; + }; + //! @brief The interrupt vectors used to halt the CPU in native mode + InterruptVectors nativeInterrupts; + //! @brief The interrupt vectors used to halt the CPU in emulation mode + InterruptVectors emulationInterrupts; }; //! @brief Contains the rom's memory/instructions. @@ -61,6 +75,10 @@ namespace ComSquare::Cartridge //! @brief Get the address of the header. //! @return The address of this cartridge header. uint32_t _getHeaderAddress(); + //! @brief Parse the memory to get a readable header. + //! @param headerAddress The address you want to parse. + //! @return A header struct representing the data at the memory address you passed. + Header _mapHeader(uint32_t headerAddress); public: //! @brief Load a rom from it's path. explicit Cartridge(const std::string &romPath); diff --git a/sources/Cartridge/InterruptVectors.hpp b/sources/Cartridge/InterruptVectors.hpp new file mode 100644 index 0000000..bd745bf --- /dev/null +++ b/sources/Cartridge/InterruptVectors.hpp @@ -0,0 +1,44 @@ +// +// Created by anonymus-raccoon on 1/31/20. +// + +#ifndef COMSQUARE_INTERRUPTVECTORS_HPP +#define COMSQUARE_INTERRUPTVECTORS_HPP + +namespace ComSquare::Cartridge +{ + struct InterruptVectors { + //! @brief The Co-Processor enable vector. + union { + uint8_t cop8[2]; + uint16_t cop; + }; + //! @brief The Break vector. + union { + uint8_t brk8[2]; + uint16_t brk; + }; + //! @brief The Abort vector. + union { + uint8_t abort8[2]; + uint16_t abort; + }; + //! @brief The non-maskable interrupt (The V-Blank interrupt). + 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 { + uint8_t reset8[2]; + uint16_t reset; + }; + //! @brief The Interrupt Request vector. + union { + uint8_t irq8[2]; + uint16_t irq; + }; + }; +} + +#endif //COMSQUARE_INTERRUPTVECTORS_HPP