Added handler for 0x1000 and added documentation for most functions and classes
							parent
							
								
									632873078b
								
							
						
					
					
						commit
						fce922f6c6
					
				|  | @ -7,21 +7,70 @@ | ||||||
| 
 | 
 | ||||||
| class InstructionHandler; | class InstructionHandler; | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * The main Chip8 used to emulate/interpret the Chip8 program | ||||||
|  |  */ | ||||||
| class Chip8 { | class Chip8 { | ||||||
| private: | private: | ||||||
|  |     /**
 | ||||||
|  |      * The memory of the Chip8 program | ||||||
|  |      */ | ||||||
|     unsigned char memory[0xFFF] = {}; |     unsigned char memory[0xFFF] = {}; | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * The 16 general purpose 8-bit registers, generally used to store memory addresses | ||||||
|  |      */ | ||||||
|     unsigned char v[0x10] = {}; |     unsigned char v[0x10] = {}; | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Stack of 16-bit values, used to store addresses the interpreter should return to when finished with a subroutine | ||||||
|  |      */ | ||||||
|     std::stack<unsigned short> stack{}; |     std::stack<unsigned short> stack{}; | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * The program counter which holds the currently executing address | ||||||
|  |      */ | ||||||
|     unsigned short pc; |     unsigned short pc; | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * The Display object holding information and functions used for the display | ||||||
|  |      */ | ||||||
|     Display display; |     Display display; | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * The instruction handler used to handle instructions | ||||||
|  |      */ | ||||||
|     InstructionHandler* instructionHandler; |     InstructionHandler* instructionHandler; | ||||||
| public: | public: | ||||||
|     Chip8(); |     Chip8(); | ||||||
|     ~Chip8(); |     ~Chip8(); | ||||||
|     void loadRom(const std::string&); | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Loads a rom in the memory | ||||||
|  |      * @param rom The rom to be loaded in the memory | ||||||
|  |      */ | ||||||
|  |     void loadRom(const std::string& rom); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Gets the Display object | ||||||
|  |      * @return | ||||||
|  |      */ | ||||||
|     [[nodiscard]] Display getDisplay() const; |     [[nodiscard]] Display getDisplay() const; | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Cycle to handle the next instruction | ||||||
|  |      */ | ||||||
|     void emulateCycle(); |     void emulateCycle(); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Pops a 16-bit value from the stack | ||||||
|  |      * @return a unsigned 16-bit integer | ||||||
|  |      */ | ||||||
|     [[nodiscard]] unsigned short popFromStack(); |     [[nodiscard]] unsigned short popFromStack(); | ||||||
|     void setProgramCounter(unsigned short); | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Sets the program counter (PC) to the given value | ||||||
|  |      */ | ||||||
|  |     void setProgramCounter(unsigned short value); | ||||||
| }; | }; | ||||||
| #endif //CHIP8_CHIP8_H
 | #endif //CHIP8_CHIP8_H
 | ||||||
|  |  | ||||||
|  | @ -3,12 +3,32 @@ | ||||||
| 
 | 
 | ||||||
| #include <chrono> | #include <chrono> | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * Class used to work with dates and times | ||||||
|  |  */ | ||||||
| class Date { | class Date { | ||||||
| public: | public: | ||||||
|  |     /**
 | ||||||
|  |      * Creates a new Date object with the given time_point | ||||||
|  |      * @param tp the time_point object | ||||||
|  |      */ | ||||||
|     explicit Date(std::chrono::system_clock::time_point tp); |     explicit Date(std::chrono::system_clock::time_point tp); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Gets a Date object with the current time as time_point | ||||||
|  |      * @return The Date object | ||||||
|  |      */ | ||||||
|     static Date now(); |     static Date now(); | ||||||
|     std::string to_string() const; | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Converts the time_point to a string with format "Y-%m-%d %H:%M:%S" | ||||||
|  |      * @return the formatted datetime string | ||||||
|  |      */ | ||||||
|  |     [[nodiscard]] std::string to_string() const; | ||||||
| private: | private: | ||||||
|  |     /**
 | ||||||
|  |      * The time_point to use | ||||||
|  |      */ | ||||||
|     std::chrono::system_clock::time_point tp; |     std::chrono::system_clock::time_point tp; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -6,13 +6,36 @@ | ||||||
| 
 | 
 | ||||||
| #include <SDL2/SDL.h> | #include <SDL2/SDL.h> | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * The display class used to handle drawing pixels to the SDL renderer | ||||||
|  |  */ | ||||||
| class Display { | class Display { | ||||||
| private: | private: | ||||||
|  |     /**
 | ||||||
|  |      * Flag whether the display should be redrawn | ||||||
|  |      */ | ||||||
|     bool flagRedraw = false; |     bool flagRedraw = false; | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * The 64x32-pixel monochrome display | ||||||
|  |      */ | ||||||
|     bool display[64 * 32] = {}; |     bool display[64 * 32] = {}; | ||||||
| public: | public: | ||||||
|     void draw(SDL_Renderer*); |     /**
 | ||||||
|  |      * Draws the current display to the SDL renderer | ||||||
|  |      * @param renderer the SDL renderer to draw to | ||||||
|  |      */ | ||||||
|  |     void draw(SDL_Renderer* renderer); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Gets whether the display should be redrawn | ||||||
|  |      * @return true if the display should be redrawn, false otherwise | ||||||
|  |      */ | ||||||
|     [[nodiscard]] bool needsRedraw() const; |     [[nodiscard]] bool needsRedraw() const; | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Clears the display | ||||||
|  |      */ | ||||||
|     void clear(); |     void clear(); | ||||||
| }; | }; | ||||||
| #endif //CHIP8_DISPLAY_H
 | #endif //CHIP8_DISPLAY_H
 | ||||||
|  |  | ||||||
|  | @ -1,14 +1,45 @@ | ||||||
| #ifndef CHIP8_INSTRUCTION_H | #ifndef CHIP8_INSTRUCTION_H | ||||||
| #define CHIP8_INSTRUCTION_H | #define CHIP8_INSTRUCTION_H | ||||||
|  | /**
 | ||||||
|  |  * The instruction class stores the opcode and allows easier access to the Chip8 values | ||||||
|  |  */ | ||||||
| class Instruction { | class Instruction { | ||||||
| private: | private: | ||||||
|  |     /**
 | ||||||
|  |      * The basic opcode | ||||||
|  |      */ | ||||||
|     const unsigned short opcode; |     const unsigned short opcode; | ||||||
| public: | public: | ||||||
|     explicit Instruction(unsigned short); |     explicit Instruction(unsigned short opcode); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Gets the NNN Chip8 value | ||||||
|  |      * @return | ||||||
|  |      */ | ||||||
|     [[nodiscard]] unsigned short nnn() const; |     [[nodiscard]] unsigned short nnn() const; | ||||||
|     [[nodiscard]] unsigned short n() const; | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Gets the N Chip8 value | ||||||
|  |      * @return | ||||||
|  |      */ | ||||||
|  |     [[nodiscard]] unsigned char n() const; | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Gets the KK/Byte/NN Chip8 value | ||||||
|  |      * @return | ||||||
|  |      */ | ||||||
|     [[nodiscard]] unsigned short kk() const; |     [[nodiscard]] unsigned short kk() const; | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Gets the X Chip8 value | ||||||
|  |      * @return | ||||||
|  |      */ | ||||||
|     [[nodiscard]] unsigned char x() const; |     [[nodiscard]] unsigned char x() const; | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Gets the Y Chip8 value | ||||||
|  |      * @return | ||||||
|  |      */ | ||||||
|     [[nodiscard]] unsigned char y() const; |     [[nodiscard]] unsigned char y() const; | ||||||
| }; | }; | ||||||
| #endif //CHIP8_INSTRUCTION_H
 | #endif //CHIP8_INSTRUCTION_H
 | ||||||
|  |  | ||||||
|  | @ -5,13 +5,39 @@ | ||||||
| #include "chip8.h" | #include "chip8.h" | ||||||
| #include "instruction.h" | #include "instruction.h" | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * The InstructionHandler class holds the Chip8 instruction set and all handlers | ||||||
|  |  */ | ||||||
| class InstructionHandler { | class InstructionHandler { | ||||||
| private: | private: | ||||||
|  |     /**
 | ||||||
|  |      * The typedef for the handler functions | ||||||
|  |      */ | ||||||
|     typedef void (*Handler)(Chip8&, Instruction); |     typedef void (*Handler)(Chip8&, Instruction); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Map which stores all instructions with their handler | ||||||
|  |      */ | ||||||
|     std::map<unsigned short, Handler> handlers = {}; |     std::map<unsigned short, Handler> handlers = {}; | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Handles Chip8 instruction 0x0000, as well as 0x00E0 and 0x00EE | ||||||
|  |      */ | ||||||
|     static void handle0000(Chip8&, Instruction); |     static void handle0000(Chip8&, Instruction); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Handles Chip8 instruction 0x1000 | ||||||
|  |      */ | ||||||
|  |     static void handle1000(Chip8&, Instruction); | ||||||
| public: | public: | ||||||
|     InstructionHandler(); |     InstructionHandler(); | ||||||
|     void handleInstruction(unsigned short, Chip8&, Instruction); | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Attempts to handle a chip8 instruction | ||||||
|  |      * @param instructionNumber the 16-bit value to determine the instruction | ||||||
|  |      * @param chip8 the Chip8 instance | ||||||
|  |      * @param instruction the Instruction instance | ||||||
|  |      */ | ||||||
|  |     void handleInstruction(unsigned short instructionNumber, Chip8& chip8, Instruction instruction); | ||||||
| }; | }; | ||||||
| #endif //CHIP8_INSTRUCTION_HANDLER_H
 | #endif //CHIP8_INSTRUCTION_HANDLER_H
 | ||||||
|  |  | ||||||
|  | @ -5,14 +5,26 @@ | ||||||
| #include <string> | #include <string> | ||||||
| #include "date.h" | #include "date.h" | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * The LogType of a log | ||||||
|  |  */ | ||||||
| enum LogType { | enum LogType { | ||||||
|     INFO, |     INFO, | ||||||
|     DEBUG, |     DEBUG, | ||||||
|     WARN, |     WARN, | ||||||
|     ERROR |     ERROR | ||||||
| }; | }; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * The logger class allows logging to either the output stream or the error stream | ||||||
|  |  */ | ||||||
| class Logger { | class Logger { | ||||||
| private: | private: | ||||||
|  |     /**
 | ||||||
|  |      * Converts the LogType enum to a string to display it in the log | ||||||
|  |      * @param logType the LogType enum to convert | ||||||
|  |      * @return the LogType as a string | ||||||
|  |      */ | ||||||
|     static const char* logTypeToString(LogType logType) { |     static const char* logTypeToString(LogType logType) { | ||||||
|         switch (logType) { |         switch (logType) { | ||||||
|             case LogType::INFO: |             case LogType::INFO: | ||||||
|  | @ -28,6 +40,13 @@ private: | ||||||
|         return ""; |         return ""; | ||||||
|     } |     } | ||||||
| public: | public: | ||||||
|  |     /**
 | ||||||
|  |      * Writes log to either the 'cout' or 'cerr' streams | ||||||
|  |      * | ||||||
|  |      * @tparam Args Variadic template representing any number and type of arguments that | ||||||
|  |      * @param logType The type of the log. If logType is LogType::ERROR, output to 'cerr' instead of 'cout' | ||||||
|  |      * @param args The contents of the log, this can be any number of arguments | ||||||
|  |      */ | ||||||
|     template<typename... Args> |     template<typename... Args> | ||||||
|     static void log(LogType logType, Args&&... args) { |     static void log(LogType logType, Args&&... args) { | ||||||
|         std::ostream& stream = (logType == LogType::ERROR) ? std::cerr : std::cout; |         std::ostream& stream = (logType == LogType::ERROR) ? std::cerr : std::cout; | ||||||
|  | @ -36,21 +55,45 @@ public: | ||||||
|         stream << std::endl; |         stream << std::endl; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Writes an info log to the cout stream | ||||||
|  |      * | ||||||
|  |      * @tparam Args @see self::log | ||||||
|  |      * @param args @see self::log | ||||||
|  |      */ | ||||||
|     template<typename... Args> |     template<typename... Args> | ||||||
|     static void info(Args&&... args) { |     static void info(Args&&... args) { | ||||||
|         log(LogType::INFO, std::forward<Args>(args)...); |         log(LogType::INFO, std::forward<Args>(args)...); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /**
 | ||||||
|  |     * Writes an debug log to the cout stream | ||||||
|  |      * | ||||||
|  |      * @tparam Args @see self::log | ||||||
|  |      * @param args @see self::log | ||||||
|  |      */ | ||||||
|     template<typename... Args> |     template<typename... Args> | ||||||
|     static void debug(Args&&... args) { |     static void debug(Args&&... args) { | ||||||
|         log(LogType::DEBUG, std::forward<Args>(args)...); |         log(LogType::DEBUG, std::forward<Args>(args)...); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Writes an warn log to the cout stream | ||||||
|  |      * | ||||||
|  |      * @tparam Args @see self::log | ||||||
|  |      * @param args @see self::log | ||||||
|  |      */ | ||||||
|     template<typename... Args> |     template<typename... Args> | ||||||
|     static void warn(Args&&... args) { |     static void warn(Args&&... args) { | ||||||
|         log(LogType::WARN, std::forward<Args>(args)...); |         log(LogType::WARN, std::forward<Args>(args)...); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Writes an error log to the cerr stream | ||||||
|  |      * | ||||||
|  |      * @tparam Args @see self::log | ||||||
|  |      * @param args @see self::log | ||||||
|  |      */ | ||||||
|     template<typename... Args> |     template<typename... Args> | ||||||
|     static void error(Args&&... args) { |     static void error(Args&&... args) { | ||||||
|         log(LogType::ERROR, std::forward<Args>(args)...); |         log(LogType::ERROR, std::forward<Args>(args)...); | ||||||
|  |  | ||||||
|  | @ -13,6 +13,13 @@ Chip8::~Chip8() { | ||||||
|     delete instructionHandler; |     delete instructionHandler; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * Reads all bytes from 0x200 onward and put them in the memory. | ||||||
|  |  * If the file does not exist, the program is exited. | ||||||
|  |  * | ||||||
|  |  * @param file The Chip8 rom file | ||||||
|  |  * @todo Check if the Chip8 rom file is a valid rom file | ||||||
|  |  */ | ||||||
| void Chip8::loadRom(const std::string& file) { | void Chip8::loadRom(const std::string& file) { | ||||||
|     FILE* game = fopen(("roms/" + file).c_str(), "rb"); |     FILE* game = fopen(("roms/" + file).c_str(), "rb"); | ||||||
|     if (game == nullptr) { |     if (game == nullptr) { | ||||||
|  | @ -28,12 +35,19 @@ Display Chip8::getDisplay() const { | ||||||
|     return this->display; |     return this->display; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * This emulates one cycle by getting the opcode and handling the instruction corresponding that opcode | ||||||
|  |  */ | ||||||
| void Chip8::emulateCycle() { | void Chip8::emulateCycle() { | ||||||
|     unsigned short opcode = (this->memory[this->pc] << 8 | this->memory[this->pc + 1]); |     unsigned short opcode = (this->memory[this->pc] << 8 | this->memory[this->pc + 1]); | ||||||
|     this->pc += 2; |     this->pc += 2; | ||||||
|     this->instructionHandler->handleInstruction(opcode & 0xF000, *this, Instruction(opcode)); |     this->instructionHandler->handleInstruction(opcode & 0xF000, *this, Instruction(opcode)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * Gets the value from the top of the stack, pop the top of the stack and returns the value | ||||||
|  |  * @return A 16-bit value from the stack | ||||||
|  |  */ | ||||||
| unsigned short Chip8::popFromStack() { | unsigned short Chip8::popFromStack() { | ||||||
|     unsigned short value = this->stack.top(); |     unsigned short value = this->stack.top(); | ||||||
|     this->stack.pop(); |     this->stack.pop(); | ||||||
|  |  | ||||||
|  | @ -1,5 +1,12 @@ | ||||||
| #include "../include/display.h" | #include "../include/display.h" | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * Draws the display to the SDL renderer | ||||||
|  |  * If the bool in the display is true, a white pixel will be written on that position | ||||||
|  |  * The redraw flag is set to false afterwards | ||||||
|  |  * | ||||||
|  |  * @param renderer The SDL renderer | ||||||
|  |  */ | ||||||
| void Display::draw(SDL_Renderer * renderer) { | void Display::draw(SDL_Renderer * renderer) { | ||||||
|     SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); |     SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); | ||||||
|     SDL_RenderClear(renderer); |     SDL_RenderClear(renderer); | ||||||
|  | @ -7,7 +14,7 @@ void Display::draw(SDL_Renderer * renderer) { | ||||||
| 
 | 
 | ||||||
|     for (int y = 0; y < 32; y++) { |     for (int y = 0; y < 32; y++) { | ||||||
|         for (int x = 0; x < 64; x++) { |         for (int x = 0; x < 64; x++) { | ||||||
|             if (display[(y * 64) + x] != STATE_OFF) { |             if (display[(y * 64) + x] == STATE_ON) { | ||||||
|                 SDL_Rect r; |                 SDL_Rect r; | ||||||
|                 r.x = x + 10; |                 r.x = x + 10; | ||||||
|                 r.y = y + 10; |                 r.y = y + 10; | ||||||
|  | @ -26,7 +33,10 @@ bool Display::needsRedraw() const { | ||||||
|     return this->flagRedraw; |     return this->flagRedraw; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * Clears the display by setting all pixels to false | ||||||
|  |  */ | ||||||
| void Display::clear() { | void Display::clear() { | ||||||
|     std::fill(display, display + 64 * 32, false); |     std::fill(display, display + 64 * 32, STATE_OFF); | ||||||
|     this->flagRedraw = true; |     this->flagRedraw = true; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -4,22 +4,59 @@ Instruction::Instruction(unsigned short opcode) : opcode(opcode) { | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * Gets the NNN Chip8 value, also known as the addr. | ||||||
|  |  * This is a 12-bit value, the lowest 12 bits of the instruction. | ||||||
|  |  * @return | ||||||
|  |  */ | ||||||
| unsigned short Instruction::nnn() const { | unsigned short Instruction::nnn() const { | ||||||
|     return this->opcode & 0x0FFF; |     return this->opcode & 0x0FFF; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| unsigned short Instruction::n() const { | /**
 | ||||||
|  |  * Gets the N Chip8 value, also known as the nibble. | ||||||
|  |  * This is a 4-bit value, the lowest 4 bits of the instruction. | ||||||
|  |  * @return | ||||||
|  |  */ | ||||||
|  | unsigned char Instruction::n() const { | ||||||
|     return this->opcode & 0x000F; |     return this->opcode & 0x000F; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * Gets the KK Chip8 value, also known as byte (or NN by Wikipedia). | ||||||
|  |  * The naming is inconsistent, as Wikipedia has it as NN | ||||||
|  |  * and http://devernay.free.fr/hacks/chip8/C8TECH10.HTM has it as KK (with byte as alternative name).
 | ||||||
|  |  * This is a 8-bit value, the lowest 8 bits of the instruction. | ||||||
|  |  * @return | ||||||
|  |  */ | ||||||
| unsigned short Instruction::kk() const { | unsigned short Instruction::kk() const { | ||||||
|     return this->opcode & 0x00FF; |     return this->opcode & 0x00FF; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * Gets the X Chip8 value. | ||||||
|  |  * This is a 4-bit value, the lower 4 bits of the high byte of the instruction. | ||||||
|  |  * The high byte is the second nibble. | ||||||
|  |  * Example: | ||||||
|  |  * | ||||||
|  |  * 0101 1010 1100 0011 | ||||||
|  |  * Here, the 1010 is the X value. | ||||||
|  |  * @return | ||||||
|  |  */ | ||||||
| unsigned char Instruction::x() const { | unsigned char Instruction::x() const { | ||||||
|     return (this->opcode & 0x0F00) >> 8; |     return (this->opcode & 0x0F00) >> 8; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * Gets the Y Chip8 value. | ||||||
|  |  * This is a 4-bit value, the upper 4 bits of the low byte of the instruction. | ||||||
|  |  * The low byte is the second nibble. | ||||||
|  |  * Example: | ||||||
|  |  * | ||||||
|  |  * 0101 1010 1100 0011 | ||||||
|  |  * Here, the 1100 is the Y value. | ||||||
|  |  * @return | ||||||
|  |  */ | ||||||
| unsigned char Instruction::y() const { | unsigned char Instruction::y() const { | ||||||
|     return (this->opcode & 0x00F0) >> 4; |     return (this->opcode & 0x00F0) >> 4; | ||||||
| } | } | ||||||
|  | @ -1,11 +1,19 @@ | ||||||
| #include "../include/instruction_handler.h" | #include "../include/instruction_handler.h" | ||||||
| #include "../include/logger.h" | #include "../include/logger.h" | ||||||
| #include "../include/display.h" |  | ||||||
| 
 | 
 | ||||||
| InstructionHandler::InstructionHandler() { | InstructionHandler::InstructionHandler() { | ||||||
|     this->handlers[0x0000] = handle0000; |     this->handlers[0x0000] = handle0000; | ||||||
|  |     this->handlers[0x1000] = handle1000; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * Attempts to handle the Chip8 instruction by the given instruction number. | ||||||
|  |  * If the handler doesn't exist for the instruction, an error is logged, but the program resumes. | ||||||
|  |  * | ||||||
|  |  * @param instructionNumber the 16-bit value to determine the instruction | ||||||
|  |  * @param chip8 the Chip8 instance | ||||||
|  |  * @param instruction the Instruction instance | ||||||
|  |  */ | ||||||
| void InstructionHandler::handleInstruction(unsigned short instructionNumber, Chip8& chip8, Instruction instruction) { | void InstructionHandler::handleInstruction(unsigned short instructionNumber, Chip8& chip8, Instruction instruction) { | ||||||
|     if (!this->handlers.contains(instructionNumber)) { |     if (!this->handlers.contains(instructionNumber)) { | ||||||
|         Logger::error("Unregistered instruction", instructionNumber); |         Logger::error("Unregistered instruction", instructionNumber); | ||||||
|  | @ -15,6 +23,17 @@ void InstructionHandler::handleInstruction(unsigned short instructionNumber, Chi | ||||||
|     this->handlers[instructionNumber](chip8, instruction); |     this->handlers[instructionNumber](chip8, instruction); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * Handles the 0x0000 Chip-8 instruction. | ||||||
|  |  * This handles 2 other instructions: | ||||||
|  |  * - 0x00E0 which is used to clear the screen. | ||||||
|  |  * - 0x00EE which is used to return from a subroutine. | ||||||
|  |  * | ||||||
|  |  * In older interpreters, 0x0NNN was also used to jump to a machine code at NNN, but this shouldn't be implemented. | ||||||
|  |  * | ||||||
|  |  * @param chip8 The Chip8 instance | ||||||
|  |  * @param instruction The Instruction instance | ||||||
|  |  */ | ||||||
| void InstructionHandler::handle0000(Chip8& chip8, Instruction instruction) { | void InstructionHandler::handle0000(Chip8& chip8, Instruction instruction) { | ||||||
|     switch (instruction.kk()) { |     switch (instruction.kk()) { | ||||||
|         case 0x00E0: |         case 0x00E0: | ||||||
|  | @ -26,3 +45,14 @@ void InstructionHandler::handle0000(Chip8& chip8, Instruction instruction) { | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * Handles the 0x1NNN Chip8 instruction which is used to jump to location NNN. | ||||||
|  |  * This will set the program counter to the NNN value. | ||||||
|  |  * | ||||||
|  |  * @param chip8 The Chip8 instance | ||||||
|  |  * @param instruction The Instruction instance | ||||||
|  |  */ | ||||||
|  | void InstructionHandler::handle1000(Chip8& chip8, Instruction instruction) { | ||||||
|  |     chip8.setProgramCounter(instruction.nnn()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue