~groovestomp/gsgb

9179fdaac82b59ad54d4a140cb9ce01141e9a6e9 — Aaron Oman 5 months ago 371260c
Formatting, video component and bugfix

- Added video component.
- Re-indented cpu_impl.cpp.
- Re-indented cpu.hpp.
- Reformatted huge descriptive text block in cpu.hpp.
- Fixed a major bug where 16-bit registers were endian-incorrect.
- Improved debug output.
9 files changed, 700 insertions(+), 514 deletions(-)

M CHANGELIST
M Makefile
M src/bus.cpp
M src/bus.hpp
M src/cpu.hpp
M src/cpu_impl.cpp
M src/main.cpp
A src/video.cpp
A src/video.hpp
M CHANGELIST => CHANGELIST +6 -0
@@ 1,4 1,10 @@
2021-01-04
- Added video component.
- Re-indented cpu_impl.cpp.

2021-01-02
- Re-indented cpu.hpp.
- Reformatted huge descriptive text block in cpu.hpp.
- Fixed a major bug where 16-bit registers were endian-incorrect.
- Improved debug output.


M Makefile => Makefile +2 -2
@@ 1,7 1,7 @@
#******************************************************************************
# File: Makefile
# Created: 2019-06-27
# Updated: 2020-12-23
# Updated: 2021-01-04
# Package: gsgb
# Creator: Aaron Oman (GrooveStomp)
# Homepage: https://git.sr.ht/~groovestomp/gsgb/


@@ 15,7 15,7 @@ LIBS    = $(shell sdl2-config --libs) -lSDL2main
CFLAGS  = -std=c++17 -fno-exceptions -pedantic -Wall

SRC_DEP   =
SRC       = src/main.cpp src/cpu.cpp src/bus.cpp src/operand.cpp src/cartridge.cpp src/mbc.cpp
SRC       = src/main.cpp src/cpu.cpp src/bus.cpp src/operand.cpp src/cartridge.cpp src/mbc.cpp src/video.cpp
OBJFILES  = $(patsubst %.cpp,%.o,$(SRC))
LINTFILES = $(patsubst %.cpp,__%.cpp,$(SRC)) $(patsubst %.cpp,_%.cpp,$(SRC))


M src/bus.cpp => src/bus.cpp +11 -7
@@ 1,7 1,7 @@
/******************************************************************************
 * File: bus.cpp
 * Created: 2019-09-07
 * Updated: 2020-12-30
 * Updated: 2021-01-04
 * Package: gsgb
 * Creator: Aaron Oman (GrooveStomp)
 * Homepage: https://git.sr.ht/~groovestomp/gsgb/


@@ 15,6 15,7 @@
#include "bus.hpp"
#include "cpu.hpp"
#include "cartridge.hpp"
#include "video.hpp"

namespace gs {



@@ 68,14 69,10 @@ namespace gs {
        Bus::Bus() {
                cart = nullptr;
                cpu = nullptr;
                video = nullptr;

                // RAM starts at 0xC000
                memory = new uint8_t[8 * 1024];
                // Video memory starts at 0x8000
                videoMemory = new uint8_t[8 * 1024];

                // Alternatively, 0x8800-0x97FF
                bgTileMap = &videoMemory[0x8000]; //!< Up to 0x8FFF

                // Set boot state.
                write(RegBOOT, 0x0);


@@ 84,13 81,14 @@ namespace gs {
        }

        Bus::~Bus() {
                delete[] videoMemory;
                delete[] memory;
        }

        void Bus::write(uint16_t ptr, uint8_t value) {
                if (cart != nullptr && cart->write(ptr, value)) {
                        return;
                } else if (video != nullptr && video->write(ptr, value)) {
                        return;
                }

                switch (ptr) {


@@ 127,6 125,8 @@ namespace gs {
                uint8_t value;
                if (cart != nullptr && cart->read(ptr, value)) {
                        return value;
                } else if (video != nullptr && video->read(ptr, value)) {
                        return value;
                }

                switch (ptr) {


@@ 157,6 157,10 @@ namespace gs {
                cpu->attach(this);
        }

        void Bus::attach(Video *video) {
                this->video = video;
        }

        //! \see https://gbdev.io/pandocs/#power-up-sequence
        void Bus::reset() {
                cpu->reset();

M src/bus.hpp => src/bus.hpp +4 -5
@@ 1,7 1,7 @@
/******************************************************************************
 * File: bus.hpp
 * Created: 2019-08-30
 * Updated: 2020-12-28
 * Updated: 2021-01-04
 * Package: gsgb
 * Creator: Aaron Oman (GrooveStomp)
 * Homepage: https://git.sr.ht/~groovestomp/gsgb/


@@ 17,14 17,14 @@
namespace gs {
        class Cpu;
        class Cartridge;
        class Video;

        class Bus {
        private:
                uint8_t *memory;
                uint8_t *videoMemory; //!< 256x256
                uint8_t *videoDisplay; //!< 160x144
                Cpu *cpu;
                Cartridge *cart;
                Video *video;

        public:
                struct {


@@ 33,8 33,6 @@ namespace gs {
                        uint8_t sc; // serial control
                } memRegisters;

                uint8_t *bgTileMap; //!< Tiles to be displayed.

                Bus();
                ~Bus();



@@ 43,6 41,7 @@ namespace gs {

                void attach(Cartridge *cart);
                void attach(Cpu *cpu);
                void attach(Video *video);
                void reset();
        };


M src/cpu.hpp => src/cpu.hpp +93 -88
@@ 8,6 8,9 @@
 * Copyright 2019 - 2021, Aaron Oman and the gsgb contributors
 * SPDX-License-Identifier: AGPL-3.0-only
 ******************************************************************************/
//! \file cpu.hpp
//! \see http://marc.rawer.de/Gameboy/Docs/GBCPUman.pdf
//! \see http://z80.info/zip/z80Cpu_um.pdf

/*
  Flags:


@@ 19,103 22,105 @@
  Z: Zero Flag
  S: Sign Flag

The Carry Flag (C) is set or cleared depending on the operation being performed. For
ADD Instructions that generate a Carry, and for SUB Instructions that generate a Borrow,
the Carry Flag is set. The Carry Flag is reset by an ADD Instruction that does not generate
a Carry, and by a SUB Instruction that does not generate a Borrow. This saved Carry facil-
itates software routines for extended precision arithmetic. Additionally, the DAA instruc-
tion sets the Carry Flag if the conditions for making the decimal adjustment are met.
For the RLA, RRA, RLS, and RRS Instructions, the Carry bit is used as a link between the
least-significant byte (LSB) and the most-significant byte (MSB) for any register or mem-
ory location. During the RLCA, RLC, and SLA Instructions, the Carry flag contains the
final value shifted out of bit 7 of any register or memory location. During the RRCA,
RRC, SRA, and SRL Instructions, the Carry flag contains the final value shifted out of bit
0 of any register or memory location.
For the logical Instructions AND, OR, and XOR, the Carry flag is reset.
The Carry flag can also be set by the Set Carry Flag (SCF) Instruction and complemented
by the Compliment Carry Flag (CCF) Instruction. (See p82 of Z80 CPU User Manual.)

The Half Carry Flag (H) is set (1) or cleared (0) depending on the Carry and Borrow status
between bits 3 and 4 of an 8-bit arithmetic operation. This flag is used by the Decimal
Adjust Accumulator (DAA) Instruction to correct the result of a packed BCD add or sub-
tract operation. The H Flag is set (1) or cleared (0) as shown:

| H Flag | Add                                 | Subtract                    |
|--------+-------------------------------------+-----------------------------|
|      1 | A Carry occurs from bit 3 to bit 4  | A Borrow from bit 4 occurs  |
|      0 | No Carry occurs from bit 3 to bit 4 | No Borrow from bit 4 occurs |

(See p82 of Z80 CPU User Manual.)
  The Carry Flag (C) is set or cleared depending on the operation being
  performed. For ADD Instructions that generate a Carry, and for SUB
  Instructions that generate a Borrow, the Carry Flag is set. The Carry Flag is
  reset by an ADD Instruction that does not generate a Carry, and by a SUB
  Instruction that does not generate a Borrow. This saved Carry facil- itates
  software routines for extended precision arithmetic. Additionally, the DAA
  instruc- tion sets the Carry Flag if the conditions for making the decimal
  adjustment are met.  For the RLA, RRA, RLS, and RRS Instructions, the Carry
  bit is used as a link between the least-significant byte (LSB) and the
  most-significant byte (MSB) for any register or mem- ory location. During the
  RLCA, RLC, and SLA Instructions, the Carry flag contains the final value
  shifted out of bit 7 of any register or memory location. During the RRCA, RRC,
  SRA, and SRL Instructions, the Carry flag contains the final value shifted out
  of bit 0 of any register or memory location.

  For the logical Instructions AND, OR, and XOR, the Carry flag is reset.  The
  Carry flag can also be set by the Set Carry Flag (SCF) Instruction and
  complemented by the Compliment Carry Flag (CCF) Instruction. (See p82 of Z80
  CPU User Manual.)

  The Half Carry Flag (H) is set (1) or cleared (0) depending on the Carry and
  Borrow status between bits 3 and 4 of an 8-bit arithmetic operation. This flag
  is used by the Decimal Adjust Accumulator (DAA) Instruction to correct the
  result of a packed BCD add or sub- tract operation. The H Flag is set (1) or
  cleared (0) as shown:

  | H Flag | Add                                 | Subtract                    |
  |--------+-------------------------------------+-----------------------------|
  |      1 | A Carry occurs from bit 3 to bit 4  | A Borrow from bit 4 occurs  |
  |      0 | No Carry occurs from bit 3 to bit 4 | No Borrow from bit 4 occurs |

  (See p82 of Z80 CPU User Manual.)
*/

#ifndef CPU_VERSION
#define CPU_VERSION "0.1.0" //!< include guard

#include <memory>
#include <cstdint>

namespace gs {

//! \file cpu.hpp
//! \see http://marc.rawer.de/Gameboy/Docs/GBCPUman.pdf
//! \see http://z80.info/zip/z80Cpu_um.pdf

class Bus;
class Instruction;

class Cpu {
public:
        Cpu();
        ~Cpu();

        void instructionFetch();
        void instructionExecute();
        char *instructionDesc();

        void flagSet(uint8_t, uint8_t);
        void flagSet(char, uint8_t);
        uint8_t flagGet(char);
        uint8_t flagGet(uint8_t);

        void attach(Bus *bus);
        void reset();

        void dumpState();

        union {
                struct r8_type {
                        uint8_t C;
                        uint8_t B;
                        uint8_t E;
                        uint8_t D;
                        uint8_t L;
                        uint8_t H;

                        // Special purpose accumulator and flag.
                        uint8_t F;
                        uint8_t A;
                } r8;
                struct r16_type {
                        uint16_t BC;
                        uint16_t DE;
                        uint16_t HL;
                        uint16_t AF; // Special purpose accumulator and flag.
                } r16;
        } registers;

        // Special purpose registers
        uint8_t R; //!< memory refresh
        uint16_t PC; //!< program counter
        uint16_t SP; //!< stack pointer
        uint16_t I; //!< interrupt vector

        uint16_t opcode = 0x0;

private:
        friend class Instruction;
        class Impl;
        Bus *bus;
        Impl *impl;
};
        class Bus;
        class Instruction;

        class Cpu {
        public:
                Cpu();
                ~Cpu();

                void instructionFetch();
                void instructionExecute();
                char *instructionDesc();

                void flagSet(uint8_t, uint8_t);
                void flagSet(char, uint8_t);
                uint8_t flagGet(char);
                uint8_t flagGet(uint8_t);

                void attach(Bus *bus);
                void reset();

                void dumpState();

                union {
                        struct r8_type {
                                uint8_t C;
                                uint8_t B;
                                uint8_t E;
                                uint8_t D;
                                uint8_t L;
                                uint8_t H;

                                // Special purpose accumulator and flag.
                                uint8_t F;
                                uint8_t A;
                        } r8;
                        struct r16_type {
                                uint16_t BC;
                                uint16_t DE;
                                uint16_t HL;
                                uint16_t AF; // Special purpose accumulator and flag.
                        } r16;
                } registers;

                // Special purpose registers
                uint8_t R; //!< memory refresh
                uint16_t PC; //!< program counter
                uint16_t SP; //!< stack pointer
                uint16_t I; //!< interrupt vector

                uint16_t opcode = 0x0;

        private:
                friend class Instruction;
                class Impl;
                Bus *bus;
                Impl *impl;
        };

} // namespace gs


M src/cpu_impl.cpp => src/cpu_impl.cpp +411 -411
@@ 1,7 1,7 @@
/******************************************************************************
 * File: cpu_impl.cpp
 * Created: 2019-09-07
 * Updated: 2020-12-23
 * Updated: 2021-01-04
 * Package: gsgb
 * Creator: Aaron Oman (GrooveStomp)
 * Homepage: https://git.sr.ht/~groovestomp/gsgb/


@@ 19,426 19,426 @@

namespace gs {

class Bus;
class Operand;
class Instruction;
        class Bus;
        class Operand;
        class Instruction;

class Cpu::Impl {
public:
        Impl(Cpu *cpu);
        ~Impl();
        class Cpu::Impl {
        public:
                Impl(Cpu *cpu);
                ~Impl();

        void InitInstructionMap();
                void InitInstructionMap();

        // Load operations
        void LD();
        void LDD();
        void LDI();
        void LDH();
        void LDHL();
                // Load operations
                void LD();
                void LDD();
                void LDI();
                void LDH();
                void LDHL();

        // Arithmetic/logic operations
        void PUSH();
        void POP();
        void ADD8();
        void ADC8();
        void SUB8();
        void SBC8();
        void AND();
        void OR();
        void XOR();
        void CP();
        void INC8();
        void DEC8();
        void ADD16();
        void INC16();
        void DEC16();
                // Arithmetic/logic operations
                void PUSH();
                void POP();
                void ADD8();
                void ADC8();
                void SUB8();
                void SBC8();
                void AND();
                void OR();
                void XOR();
                void CP();
                void INC8();
                void DEC8();
                void ADD16();
                void INC16();
                void DEC16();

        // Miscellaneous operations
        void SWAP();
        void DAA();
        void CPL();
        void CCF();
        void SCF();
        void NOP();
        void HALT();
        void STOP();
        void DI();
        void EI();
                // Miscellaneous operations
                void SWAP();
                void DAA();
                void CPL();
                void CCF();
                void SCF();
                void NOP();
                void HALT();
                void STOP();
                void DI();
                void EI();

        // Rotate and shift operations
        void RLCA();
        void RLA();
        void RRCA();
        void RRA();
        void RLC();
        void RL();
        void RRC();
        void RR();
        void SLA();
        void SRA();
        void SRL();
                // Rotate and shift operations
                void RLCA();
                void RLA();
                void RRCA();
                void RRA();
                void RLC();
                void RL();
                void RRC();
                void RR();
                void SLA();
                void SRA();
                void SRL();

        // Bit operations
        void BIT();
        void SET();
        void RES();
                // Bit operations
                void BIT();
                void SET();
                void RES();

        void JP(); // Jump
        void JR(); // Jump
        void CALL(); // Call
        void RST(); // Restart
        void RET(); // Return
        void RETI(); // Return, enabling interrupts
                void JP(); // Jump
                void JR(); // Jump
                void CALL(); // Call
                void RST(); // Restart
                void RET(); // Return
                void RETI(); // Return, enabling interrupts

        // Instance variables
        Cpu *cpu;
        Bus *bus;
        bool halted = false;
        bool waitForButtonPress = false;
        bool interruptsDisabled = false;
        bool interruptsDisabledRequested = false;
        bool interruptsEnabledRequested = false;
                // Instance variables
                Cpu *cpu;
                Bus *bus;
                bool halted = false;
                bool waitForButtonPress = false;
                bool interruptsDisabled = false;
                bool interruptsDisabledRequested = false;
                bool interruptsEnabledRequested = false;

        // Variables and functions to assist in emulation
        std::shared_ptr<Operand> operand1;
        std::shared_ptr<Operand> operand2;
        std::shared_ptr<Instruction> instruction = nullptr;
        std::map<int,Instruction> instructionMap;
                // Variables and functions to assist in emulation
                std::shared_ptr<Operand> operand1;
                std::shared_ptr<Operand> operand2;
                std::shared_ptr<Instruction> instruction = nullptr;
                std::map<int,Instruction> instructionMap;

        // Opcodes
        void Op_0000();
        void Op_0001();
        void Op_0002();
        void Op_0003();
        void Op_0004();
        void Op_0005();
        void Op_0006();
        void Op_0007();
        void Op_0008();
        void Op_0009();
        void Op_000A();
        void Op_000B();
        void Op_000C();
        void Op_000D();
        void Op_000E();
        void Op_000F();
        void Op_0011();
        void Op_0012();
        void Op_0013();
        void Op_0014();
        void Op_0015();
        void Op_0016();
        void Op_0017();
        void Op_0018();
        void Op_0019();
        void Op_001A();
        void Op_001B();
        void Op_001C();
        void Op_001D();
        void Op_001E();
        void Op_001F();
        void Op_0020();
        void Op_0021();
        void Op_0022();
        void Op_0023();
        void Op_0024();
        void Op_0025();
        void Op_0026();
        void Op_0027();
        void Op_0028();
        void Op_0029();
        void Op_002A();
        void Op_002B();
        void Op_002C();
        void Op_002D();
        void Op_002E();
        void Op_002F();
        void Op_0030();
        void Op_0031();
        void Op_0032();
        void Op_0033();
        void Op_0034();
        void Op_0035();
        void Op_0036();
        void Op_0037();
        void Op_0038();
        void Op_0039();
        void Op_003A();
        void Op_003B();
        void Op_003C();
        void Op_003D();
        void Op_003E();
        void Op_003F();
        void Op_0040();
        void Op_0041();
        void Op_0042();
        void Op_0043();
        void Op_0044();
        void Op_0045();
        void Op_0046();
        void Op_0047();
        void Op_0048();
        void Op_0049();
        void Op_004A();
        void Op_004B();
        void Op_004C();
        void Op_004D();
        void Op_004E();
        void Op_004F();
        void Op_0050();
        void Op_0051();
        void Op_0052();
        void Op_0053();
        void Op_0054();
        void Op_0055();
        void Op_0056();
        void Op_0057();
        void Op_0058();
        void Op_0059();
        void Op_005A();
        void Op_005B();
        void Op_005C();
        void Op_005D();
        void Op_005E();
        void Op_005F();
        void Op_0060();
        void Op_0061();
        void Op_0062();
        void Op_0063();
        void Op_0064();
        void Op_0065();
        void Op_0066();
        void Op_0067();
        void Op_0068();
        void Op_0069();
        void Op_006A();
        void Op_006B();
        void Op_006C();
        void Op_006D();
        void Op_006E();
        void Op_006F();
        void Op_0070();
        void Op_0071();
        void Op_0072();
        void Op_0073();
        void Op_0074();
        void Op_0075();
        void Op_0076();
        void Op_0077();
        void Op_0078();
        void Op_0079();
        void Op_007A();
        void Op_007B();
        void Op_007C();
        void Op_007D();
        void Op_007E();
        void Op_007F();
        void Op_0080();
        void Op_0081();
        void Op_0082();
        void Op_0083();
        void Op_0084();
        void Op_0085();
        void Op_0086();
        void Op_0087();
        void Op_0088();
        void Op_0089();
        void Op_008A();
        void Op_008B();
        void Op_008C();
        void Op_008D();
        void Op_008E();
        void Op_008F();
        void Op_0090();
        void Op_0091();
        void Op_0092();
        void Op_0093();
        void Op_0094();
        void Op_0095();
        void Op_0096();
        void Op_0097();
        void Op_0098();
        void Op_0099();
        void Op_009A();
        void Op_009B();
        void Op_009C();
        void Op_009D();
        void Op_009E();
        void Op_009F();
        void Op_00A0();
        void Op_00A1();
        void Op_00A2();
        void Op_00A3();
        void Op_00A4();
        void Op_00A5();
        void Op_00A6();
        void Op_00A7();
        void Op_00A8();
        void Op_00A9();
        void Op_00AA();
        void Op_00AB();
        void Op_00AC();
        void Op_00AD();
        void Op_00AE();
        void Op_00AF();
        void Op_00B0();
        void Op_00B1();
        void Op_00B2();
        void Op_00B3();
        void Op_00B4();
        void Op_00B5();
        void Op_00B6();
        void Op_00B7();
        void Op_00B8();
        void Op_00B9();
        void Op_00BA();
        void Op_00BB();
        void Op_00BC();
        void Op_00BD();
        void Op_00BE();
        void Op_00BF();
        void Op_00C0();
        void Op_00C1();
        void Op_00C2();
        void Op_00C3();
        void Op_00C4();
        void Op_00C5();
        void Op_00C6();
        void Op_00C7();
        void Op_00C8();
        void Op_00C9();
        void Op_00CA();
        void Op_00CC();
        void Op_00CD();
        void Op_00CE();
        void Op_00CF();
        void Op_00D0();
        void Op_00D1();
        void Op_00D2();
        void Op_00D4();
        void Op_00D5();
        void Op_00D6();
        void Op_00D7();
        void Op_00D8();
        void Op_00D9();
        void Op_00DA();
        void Op_00DC();
        void Op_00DF();
        void Op_00E0();
        void Op_00E1();
        void Op_00E2();
        void Op_00E5();
        void Op_00E6();
        void Op_00E7();
        void Op_00E8();
        void Op_00E9();
        void Op_00EA();
        void Op_00EE();
        void Op_00EF();
        void Op_00F0();
        void Op_00F1();
        void Op_00F2();
        void Op_00F3();
        void Op_00F5();
        void Op_00F6();
        void Op_00F7();
        void Op_00F8();
        void Op_00F9();
        void Op_00FA();
        void Op_00FB();
        void Op_00FE();
        void Op_00FF();
        void Op_1000();
        void Op_CB00();
        void Op_CB01();
        void Op_CB02();
        void Op_CB03();
        void Op_CB04();
        void Op_CB05();
        void Op_CB06();
        void Op_CB07();
        void Op_CB08();
        void Op_CB09();
        void Op_CB0A();
        void Op_CB0B();
        void Op_CB0C();
        void Op_CB0D();
        void Op_CB0E();
        void Op_CB0F();
        void Op_CB10();
        void Op_CB11();
        void Op_CB12();
        void Op_CB13();
        void Op_CB14();
        void Op_CB15();
        void Op_CB16();
        void Op_CB17();
        void Op_CB18();
        void Op_CB19();
        void Op_CB1A();
        void Op_CB1B();
        void Op_CB1C();
        void Op_CB1D();
        void Op_CB1E();
        void Op_CB1F();
        void Op_CB20();
        void Op_CB21();
        void Op_CB22();
        void Op_CB23();
        void Op_CB24();
        void Op_CB25();
        void Op_CB26();
        void Op_CB27();
        void Op_CB28();
        void Op_CB29();
        void Op_CB2A();
        void Op_CB2B();
        void Op_CB2C();
        void Op_CB2D();
        void Op_CB2E();
        void Op_CB2F();
        void Op_CB30();
        void Op_CB31();
        void Op_CB32();
        void Op_CB33();
        void Op_CB34();
        void Op_CB35();
        void Op_CB36();
        void Op_CB37();
        void Op_CB38();
        void Op_CB39();
        void Op_CB3A();
        void Op_CB3B();
        void Op_CB3C();
        void Op_CB3D();
        void Op_CB3E();
        void Op_CB3F();
        void Op_CB40();
        void Op_CB41();
        void Op_CB42();
        void Op_CB43();
        void Op_CB44();
        void Op_CB45();
        void Op_CB46();
        void Op_CB47();
        void Op_CB80();
        void Op_CB81();
        void Op_CB82();
        void Op_CB83();
        void Op_CB84();
        void Op_CB85();
        void Op_CB86();
        void Op_CB87();
        void Op_CBC0();
        void Op_CBC1();
        void Op_CBC2();
        void Op_CBC3();
        void Op_CBC4();
        void Op_CBC5();
        void Op_CBC6();
        void Op_CBC7();
        void Op_CBC8();
};
                // Opcodes
                void Op_0000();
                void Op_0001();
                void Op_0002();
                void Op_0003();
                void Op_0004();
                void Op_0005();
                void Op_0006();
                void Op_0007();
                void Op_0008();
                void Op_0009();
                void Op_000A();
                void Op_000B();
                void Op_000C();
                void Op_000D();
                void Op_000E();
                void Op_000F();
                void Op_0011();
                void Op_0012();
                void Op_0013();
                void Op_0014();
                void Op_0015();
                void Op_0016();
                void Op_0017();
                void Op_0018();
                void Op_0019();
                void Op_001A();
                void Op_001B();
                void Op_001C();
                void Op_001D();
                void Op_001E();
                void Op_001F();
                void Op_0020();
                void Op_0021();
                void Op_0022();
                void Op_0023();
                void Op_0024();
                void Op_0025();
                void Op_0026();
                void Op_0027();
                void Op_0028();
                void Op_0029();
                void Op_002A();
                void Op_002B();
                void Op_002C();
                void Op_002D();
                void Op_002E();
                void Op_002F();
                void Op_0030();
                void Op_0031();
                void Op_0032();
                void Op_0033();
                void Op_0034();
                void Op_0035();
                void Op_0036();
                void Op_0037();
                void Op_0038();
                void Op_0039();
                void Op_003A();
                void Op_003B();
                void Op_003C();
                void Op_003D();
                void Op_003E();
                void Op_003F();
                void Op_0040();
                void Op_0041();
                void Op_0042();
                void Op_0043();
                void Op_0044();
                void Op_0045();
                void Op_0046();
                void Op_0047();
                void Op_0048();
                void Op_0049();
                void Op_004A();
                void Op_004B();
                void Op_004C();
                void Op_004D();
                void Op_004E();
                void Op_004F();
                void Op_0050();
                void Op_0051();
                void Op_0052();
                void Op_0053();
                void Op_0054();
                void Op_0055();
                void Op_0056();
                void Op_0057();
                void Op_0058();
                void Op_0059();
                void Op_005A();
                void Op_005B();
                void Op_005C();
                void Op_005D();
                void Op_005E();
                void Op_005F();
                void Op_0060();
                void Op_0061();
                void Op_0062();
                void Op_0063();
                void Op_0064();
                void Op_0065();
                void Op_0066();
                void Op_0067();
                void Op_0068();
                void Op_0069();
                void Op_006A();
                void Op_006B();
                void Op_006C();
                void Op_006D();
                void Op_006E();
                void Op_006F();
                void Op_0070();
                void Op_0071();
                void Op_0072();
                void Op_0073();
                void Op_0074();
                void Op_0075();
                void Op_0076();
                void Op_0077();
                void Op_0078();
                void Op_0079();
                void Op_007A();
                void Op_007B();
                void Op_007C();
                void Op_007D();
                void Op_007E();
                void Op_007F();
                void Op_0080();
                void Op_0081();
                void Op_0082();
                void Op_0083();
                void Op_0084();
                void Op_0085();
                void Op_0086();
                void Op_0087();
                void Op_0088();
                void Op_0089();
                void Op_008A();
                void Op_008B();
                void Op_008C();
                void Op_008D();
                void Op_008E();
                void Op_008F();
                void Op_0090();
                void Op_0091();
                void Op_0092();
                void Op_0093();
                void Op_0094();
                void Op_0095();
                void Op_0096();
                void Op_0097();
                void Op_0098();
                void Op_0099();
                void Op_009A();
                void Op_009B();
                void Op_009C();
                void Op_009D();
                void Op_009E();
                void Op_009F();
                void Op_00A0();
                void Op_00A1();
                void Op_00A2();
                void Op_00A3();
                void Op_00A4();
                void Op_00A5();
                void Op_00A6();
                void Op_00A7();
                void Op_00A8();
                void Op_00A9();
                void Op_00AA();
                void Op_00AB();
                void Op_00AC();
                void Op_00AD();
                void Op_00AE();
                void Op_00AF();
                void Op_00B0();
                void Op_00B1();
                void Op_00B2();
                void Op_00B3();
                void Op_00B4();
                void Op_00B5();
                void Op_00B6();
                void Op_00B7();
                void Op_00B8();
                void Op_00B9();
                void Op_00BA();
                void Op_00BB();
                void Op_00BC();
                void Op_00BD();
                void Op_00BE();
                void Op_00BF();
                void Op_00C0();
                void Op_00C1();
                void Op_00C2();
                void Op_00C3();
                void Op_00C4();
                void Op_00C5();
                void Op_00C6();
                void Op_00C7();
                void Op_00C8();
                void Op_00C9();
                void Op_00CA();
                void Op_00CC();
                void Op_00CD();
                void Op_00CE();
                void Op_00CF();
                void Op_00D0();
                void Op_00D1();
                void Op_00D2();
                void Op_00D4();
                void Op_00D5();
                void Op_00D6();
                void Op_00D7();
                void Op_00D8();
                void Op_00D9();
                void Op_00DA();
                void Op_00DC();
                void Op_00DF();
                void Op_00E0();
                void Op_00E1();
                void Op_00E2();
                void Op_00E5();
                void Op_00E6();
                void Op_00E7();
                void Op_00E8();
                void Op_00E9();
                void Op_00EA();
                void Op_00EE();
                void Op_00EF();
                void Op_00F0();
                void Op_00F1();
                void Op_00F2();
                void Op_00F3();
                void Op_00F5();
                void Op_00F6();
                void Op_00F7();
                void Op_00F8();
                void Op_00F9();
                void Op_00FA();
                void Op_00FB();
                void Op_00FE();
                void Op_00FF();
                void Op_1000();
                void Op_CB00();
                void Op_CB01();
                void Op_CB02();
                void Op_CB03();
                void Op_CB04();
                void Op_CB05();
                void Op_CB06();
                void Op_CB07();
                void Op_CB08();
                void Op_CB09();
                void Op_CB0A();
                void Op_CB0B();
                void Op_CB0C();
                void Op_CB0D();
                void Op_CB0E();
                void Op_CB0F();
                void Op_CB10();
                void Op_CB11();
                void Op_CB12();
                void Op_CB13();
                void Op_CB14();
                void Op_CB15();
                void Op_CB16();
                void Op_CB17();
                void Op_CB18();
                void Op_CB19();
                void Op_CB1A();
                void Op_CB1B();
                void Op_CB1C();
                void Op_CB1D();
                void Op_CB1E();
                void Op_CB1F();
                void Op_CB20();
                void Op_CB21();
                void Op_CB22();
                void Op_CB23();
                void Op_CB24();
                void Op_CB25();
                void Op_CB26();
                void Op_CB27();
                void Op_CB28();
                void Op_CB29();
                void Op_CB2A();
                void Op_CB2B();
                void Op_CB2C();
                void Op_CB2D();
                void Op_CB2E();
                void Op_CB2F();
                void Op_CB30();
                void Op_CB31();
                void Op_CB32();
                void Op_CB33();
                void Op_CB34();
                void Op_CB35();
                void Op_CB36();
                void Op_CB37();
                void Op_CB38();
                void Op_CB39();
                void Op_CB3A();
                void Op_CB3B();
                void Op_CB3C();
                void Op_CB3D();
                void Op_CB3E();
                void Op_CB3F();
                void Op_CB40();
                void Op_CB41();
                void Op_CB42();
                void Op_CB43();
                void Op_CB44();
                void Op_CB45();
                void Op_CB46();
                void Op_CB47();
                void Op_CB80();
                void Op_CB81();
                void Op_CB82();
                void Op_CB83();
                void Op_CB84();
                void Op_CB85();
                void Op_CB86();
                void Op_CB87();
                void Op_CBC0();
                void Op_CBC1();
                void Op_CBC2();
                void Op_CBC3();
                void Op_CBC4();
                void Op_CBC5();
                void Op_CBC6();
                void Op_CBC7();
                void Op_CBC8();
        };

} // namespace gs

M src/main.cpp => src/main.cpp +4 -1
@@ 1,7 1,7 @@
/******************************************************************************
 * File: main.cpp
 * Created: 2019-08-29
 * Updated: 2020-12-31
 * Updated: 2021-01-04
 * Package: gsgb
 * Creator: Aaron Oman (GrooveStomp)
 * Homepage: https://git.sr.ht/~groovestomp/gsgb/


@@ 16,6 16,7 @@
#include "bus.hpp"
#include "cpu.hpp"
#include "cartridge.hpp"
#include "video.hpp"

using namespace std;
using namespace gs;


@@ 24,6 25,7 @@ int main(int argc, char *argv[]) {
        Cpu cpu;
        Cartridge *cart = nullptr;
        Bus gb;
        Video video;

        ifstream stream("data/cpu_instrs/individual/03-op sp,hl.gb", ios::in | ios::binary | ios::ate);
        if (stream.is_open()) {


@@ 42,6 44,7 @@ int main(int argc, char *argv[]) {

        gb.attach(&cpu);
        gb.attach(cart);
        gb.attach(&video);
        gb.reset();

        vector<char> buf;

A src/video.cpp => src/video.cpp +91 -0
@@ 0,0 1,91 @@
/******************************************************************************
 * File: video.cpp
 * Created: 2021-01-04
 * Updated: 2021-01-04
 * Package: gsgb
 * Creator: Aaron Oman (GrooveStomp)
 * Homepage: https://git.sr.ht/~groovestomp/gsgb/
 * Copyright 2019 - 2021, Aaron Oman and the gsgb contributors
 * SPDX-License-Identifier: AGPL-3.0-only
 ******************************************************************************/
//! \file video.cpp

#include "video.hpp"

namespace gs {

        bool Video::write(uint16_t addr, uint8_t value) {
                if (addr >= 0x8000 && addr <= 0x9FFF) {
                        uint16_t addr2 = addr - 0x8000;
                        vram[addr2] = value;
                        return true;

                } else if (addr >= 0xFE00 && addr <= 0xFE9F) {
                        uint16_t addr2 = addr - 0xFE00;
                        oam[addr2] = value;
                        return true;
                }

                switch (addr) {
                        case 0xFF40:
                                lcdc = value;
                                return true;

                        case 0xFF42:
                                scrolly = value;
                                return true;

                        case 0xFF43:
                                scrollx = value;
                                return true;

                        case 0xFF4A:
                                wndposy = value;
                                return true;

                        case 0xFF4B:
                                wndposx = value;
                                return true;
                }

                return false;
        }

        bool Video::read(uint16_t addr, uint8_t &value) {
                if (addr >= 0x8000 && addr <= 0x9FFF) {
                        uint16_t addr2 = addr - 0x8000;
                        value = vram[addr2];
                        return true;

                } else if (addr >= 0xFE00 && addr <= 0xFE9F) {
                        uint16_t addr2 = addr - 0xFE00;
                        value = oam[addr2];
                        return true;
                }

                switch (addr) {
                        case 0xFF40:
                                value = lcdc;
                                return true;

                        case 0xFF42:
                                value = scrolly;
                                return true;

                        case 0xFF43:
                                value = scrollx;
                                return true;

                        case 0xFF4A:
                                value = wndposy;
                                return true;

                        case 0xFF4B:
                                value = wndposx;
                                return true;
                }

                return false;
        }

} // namespace gs

A src/video.hpp => src/video.hpp +78 -0
@@ 0,0 1,78 @@
/******************************************************************************
 * File: video.hpp
 * Created: 2021-01-04
 * Updated: 2021-01-04
 * Package: gsgb
 * Creator: Aaron Oman (GrooveStomp)
 * Homepage: https://git.sr.ht/~groovestomp/gsgb/
 * Copyright 2019 - 2021, Aaron Oman and the gsgb contributors
 * SPDX-License-Identifier: AGPL-3.0-only
 ******************************************************************************/
//! \file video.hpp
#ifndef VIDEO_VERSION
#define VIDEO_VERSION "0.1.0" //!< include guard

#include <cstdint>

namespace gs {

        /*
          Background Tile Map:
          32 rows of 32bytes
          32 x 32 tiles
          each byte is the number of a tile to show
          LCDC register specifies which Tile Data Table is in use.

          Tile Data Tables:
          $8000 - $8FFF Foreground (Sprites)
           > 0 - 255
          $8800 - $97FF Background
           > -128 - 127 (0 is $9000)

          Object Attribute Memory (OAM):
          $FE00 - $FE9F
          40 4-byte blocks, each representing a sprite.
        */


        /*
#
FF40 - LCD Control Register

LCDC is the main LCD Control register. Its bits toggle what elements are displayed on the screen, and how.
Bit 	Name 	Usage notes
7 	LCD Display Enable 	0=Off, 1=On
6 	Window Tile Map Display Select 	0=9800-9BFF, 1=9C00-9FFF
5 	Window Display Enable 	0=Off, 1=On
4 	BG & Window Tile Data Select 	0=8800-97FF, 1=8000-8FFF
3 	BG Tile Map Display Select 	0=9800-9BFF, 1=9C00-9FFF
2 	OBJ (Sprite) Size 	0=Off, 1=On
1 	OBJ (Sprite) Display Enable 	0=Off, 1=On
0 	BG/Window Display/Priority
         */

        // $8000 - $A000 is VRAM
        class Video {
        public:
                // $8000 - $8FFF sprite data table
                // $8800 - $97FF bg data table
                // $9800 - $98FF tile map 1
                // $9C99 - $9FFF tile map 2
                uint8_t vram[8 * 1024];
                uint8_t oam[40 * 4]; // $FE00 - $FE9F

                uint8_t lcdc;
                uint8_t scrollx;
                uint8_t scrolly;
                uint8_t wndposx;
                uint8_t wndposy;

                bool write(uint16_t addr, uint8_t value);
                bool read(uint16_t addr, uint8_t &value);
        private:
                // TODO: X window stuff here.
        };

} // namespace gs

#endif // VIDEO_VERSION