~groovestomp/gsnes

99bb14a0e5c2cdc0f46bc4d7cc817d819123b79a — GrooveStomp 1 year, 6 months ago 34a7bb8
Basic emulation running now.

- Keyboard inputs are hooked up properly.
- A simulation loop has been implemented.
- Replace snake_case struct attributes with camelCase.
19 files changed, 591 insertions(+), 291 deletions(-)

M bus.c
M bus.h
M cart.c
M cart.h
M color.c
M color.h
M cpu.c
M cpu.h
M input.c
M input.h
M main.c
M mapper.h
M mapper000.c
M mapper000.h
M ppu.c
M ppu.h
M sprite.c
M sprite.h
M util.h
M bus.c => bus.c +17 -21
@@ 8,7 8,7 @@
  Author: Aaron Oman
  Notice: GNU AGPLv3 License

  Based off of: One Lone Coder NES Emulator Copyright (C) 2018 Javidx9
  Based off of: One Lone Coder NES Emulator Copyright (C) 2019 Javidx9
  This program comes with ABSOLUTELY NO WARRANTY.
  This is free software, and you are welcome to redistribute it under certain
  conditions; See LICENSE for details.


@@ 25,19 25,21 @@ struct bus {
        struct cpu *cpu;
        struct ppu *ppu;
        struct cart *cart;
        uint8_t *cpu_ram; // Dummy RAM for prototyping
        uint32_t tick_count;
        uint8_t *cpuRam; // Dummy RAM for prototyping
        uint32_t tickCount;
};

struct bus *BusInit(struct cpu *cpu) {
struct bus *BusInit(struct cpu *cpu, struct ppu *ppu) {
        struct bus *bus = (struct bus *)malloc(sizeof(struct bus));

        bus->cpu_ram = (uint8_t *)malloc(64 * 1024);
        bus->cpuRam = (uint8_t *)malloc(64 * 1024);
        for (int i = 0; i < 64 * 1024; i++) {
                bus->cpu_ram[i] = 0x00;
                bus->cpuRam[i] = 0x00;
        }

        bus->cpu = cpu;
        bus->ppu = ppu;

        return bus;
}



@@ 46,8 48,8 @@ void BusDeinit(struct bus *bus) {
                return;
        }

        if (NULL != bus->cpu_ram) {
                free(bus->cpu_ram);
        if (NULL != bus->cpuRam) {
                free(bus->cpuRam);
        }

        free(bus);


@@ 55,13 57,13 @@ void BusDeinit(struct bus *bus) {

void BusWrite(struct bus *bus, uint16_t addr, uint8_t data) {
        if (addr >= 0x0000 && addr <= 0xFFFF) {
                bus->cpu_ram[addr] = data;
                bus->cpuRam[addr] = data;
        }
}

uint8_t BusRead(struct bus *bus, uint16_t addr) {
        if (addr >= 0x0000 && addr <= 0xFFFF) {
                return bus->cpu_ram[addr];
                return bus->cpuRam[addr];
        }

        return 0x00;


@@ 73,24 75,18 @@ void BusAttachCart(struct bus *bus, struct cart *cart) {
}

void BusReset(struct bus *bus) {
        //CartReset(bus->cart);
        CpuReset(bus->cpu);
        bus->tick_count = 0;
        PpuReset(bus->ppu);
        bus->tickCount = 0;
}

//! \brief Increment the system by the fastest clock tick
//!
//! The running frequency is determined by the fastest clock in the system - in
//! this case, the PPU.  Every other clock is some fraction slower than the PPU,
//! so we compute a modulus every cycle to determine when to increment other
//! clocks.
//!
//! \param[in,out] bus
void BusTick(struct bus *bus) {
        PpuTick(bus->ppu);

        if (0 == (bus->tick_count % 3)) {
        if (0 == (bus->tickCount % 3)) {
                CpuTick(bus->cpu);
        }

        bus->tick_count++;
        bus->tickCount++;
}

M bus.h => bus.h +16 -2
@@ 8,7 8,7 @@
  Author: Aaron Oman
  Notice: GNU AGPLv3 License

  Based off of: One Lone Coder NES Emulator Copyright (C) 2018 Javidx9
  Based off of: One Lone Coder NES Emulator Copyright (C) 2019 Javidx9
  This program comes with ABSOLUTELY NO WARRANTY.
  This is free software, and you are welcome to redistribute it under certain
  conditions; See LICENSE for details.


@@ 21,9 21,10 @@

struct cpu;
struct bus;
struct ppu;

struct bus *
BusInit(struct cpu *cpu);
BusInit(struct cpu *cpu, struct ppu *ppu);

void
BusDeinit(struct bus *bus);


@@ 34,4 35,17 @@ BusWrite(struct bus *bus, uint16_t addr, uint8_t data);
uint8_t
BusRead(struct bus *bus, uint16_t addr);

void
BusReset(struct bus *bus);

//! \brief Increment the system by the fastest clock tick
//!
//! The running frequency is determined by the fastest clock in the system - in
//! this case, the PPU.  Every other clock is some fraction slower than the PPU,
//! so we compute a modulus every cycle to determine when to increment other
//! clocks.
//!
//! \param[in,out] bus
void BusTick(struct bus *bus);

#endif // BUS_VERSION

M cart.c => cart.c +8 -8
@@ 8,11 8,12 @@
  Author: Aaron Oman
  Notice: GNU AGPLv3 License

  Based off of: One Lone Coder NES Emulator Copyright (C) 2018 Javidx9
  Based off of: One Lone Coder NES Emulator Copyright (C) 2019 Javidx9
  This program comes with ABSOLUTELY NO WARRANTY.
  This is free software, and you are welcome to redistribute it under certain
  conditions; See LICENSE for details.
 ******************************************************************************/
//! \file cart.c
#include <stdint.h>
#include <stdio.h> // fopen
#include <stdbool.h> // bool


@@ 22,7 23,6 @@
#include "util.h"
#include "mapper.h"
#include "mapper000.h"
//! \file cart.c

struct cart {
        uint8_t mapper_id;


@@ 130,21 130,21 @@ struct cart *CartInit(char *filename) {

        cart->is_image_valid = true;
        fclose(f);

        return cart;
}

void CartDeinit(struct cart *cart) {
        if (NULL == cart) {
        if (NULL == cart)
                return;
        }

        if (NULL != cart->chr_mem) {
        if (NULL != cart->chr_mem)
                free(cart->chr_mem);
        }

        if (NULL != cart->prg_mem) {
        if (NULL != cart->prg_mem)
                free(cart->prg_mem);
        }

        free(cart);
}

bool CartCpuRead(struct cart *cart, uint16_t addr, uint8_t *data) {

M cart.h => cart.h +3 -3
@@ 8,17 8,17 @@
  Author: Aaron Oman
  Notice: GNU AGPLv3 License

  Based off of: One Lone Coder NES Emulator Copyright (C) 2018 Javidx9
  Based off of: One Lone Coder NES Emulator Copyright (C) 2019 Javidx9
  This program comes with ABSOLUTELY NO WARRANTY.
  This is free software, and you are welcome to redistribute it under certain
  conditions; See LICENSE for details.
 ******************************************************************************/
//! \file cart.h
#include <stdint.h>
#include <stdbool.h>
//! \file cart.h

#ifndef CART_VERSION
#define CART_VERSION "0.1.0"
#define CART_VERSION "0.1-gsnes"

struct cart;


M color.c => color.c +0 -2
@@ 8,12 8,10 @@
  Author: Aaron Oman
  Notice: GNU GPLv3 License

  Based off of: One Lone Coder Console Game Engine Copyright (C) 2018 Javidx9
  This program comes with ABSOLUTELY NO WARRANTY.
  This is free software, and you are welcome to redistribute it under certain
  conditions; See LICENSE for details.
 ******************************************************************************/

//! \file color.c

#include "color.h"

M color.h => color.h +1 -4
@@ 8,14 8,10 @@
  Author: Aaron Oman
  Notice: GNU GPLv3 License

  Based off of: One Lone Coder Console Game Engine Copyright (C) 2018 Javidx9
  This program comes with ABSOLUTELY NO WARRANTY.
  This is free software, and you are welcome to redistribute it under certain
  conditions; See LICENSE for details.
  Notice: Creative Commons Attribution 4.0 International License (CC-BY 4.0)
 ******************************************************************************/
#include <stdint.h>

//! \file color.h
//! This interface attempts to provide an intuitive wrapper around "raw"
//! unsigned integer colors.


@@ 23,6 19,7 @@
//! An unsigned integer color is packed 32-bit value consisting of 4 pixel
//! elements: RGBA.  These elements are stored as written: RGBA, or, visually
//! mapped as hex symbols: RRGGBBAA.
#include <stdint.h>

#ifndef COLOR_VERSION
#define COLOR_VERSION "0.2-gsnes" //!< include guard

M cpu.c => cpu.c +172 -138
@@ 9,11 9,12 @@
  Author: Aaron Oman
  Notice: GNU AGPLv3 License

  Based off of: olcNES Copyright (C) 2018 Javidx9
  Based off of: olcNES Copyright (C) 2019 Javidx9
  This program comes with ABSOLUTELY NO WARRANTY.
  This is free software, and you are welcome to redistribute it under certain
  conditions; See LICENSE for details.
 ******************************************************************************/
//! \file cpu.c
#include <stdbool.h> // bool
#include <stdio.h> // snprintf
#include <stdlib.h> // malloc, free


@@ 22,8 23,6 @@
#include "cpu.h"
#include "bus.h"

//! \file cpu.c

// Addressing Modes
uint8_t ABS(struct cpu *cpu);
uint8_t ABX(struct cpu *cpu);


@@ 92,11 91,11 @@ struct cpu {
        uint8_t status; //!< Status Register

        uint8_t fetched; //!< Any data fetched for the current instruction
        uint16_t addr_abs;
        uint16_t addr_rel;
        uint16_t addrAbs;
        uint16_t addrRel;
        uint8_t opcode; //!< Opcode for the currently executing instruction
        uint8_t cycles; //!< How many cycles the current instruction takes
        uint32_t tick_count;
        uint32_t tickCount;
};

enum status_flags {


@@ 122,11 121,11 @@ struct cpu *CpuInit() {
        cpu->pc = 0x0000;
        cpu->status = 0x00;

        cpu->addr_abs = 0x0000;
        cpu->addr_rel = 0x00;
        cpu->addrAbs = 0x0000;
        cpu->addrRel = 0x00;
        cpu->opcode = 0x00;
        cpu->cycles = 0;
        cpu->tick_count = 0;
        cpu->tickCount = 0;
}

void CpuDeinit(struct cpu *cpu) {


@@ 152,7 151,7 @@ static void SetFlag(struct cpu *cpu, enum status_flags f, bool v) {

static uint8_t Fetch(struct cpu* cpu) {
        if (!(instruction_map[cpu->opcode].address == IMP)) {
                cpu->fetched = BusRead(cpu->bus, cpu->addr_abs);
                cpu->fetched = BusRead(cpu->bus, cpu->addrAbs);
        }

        return cpu->fetched;


@@ 178,10 177,14 @@ void CpuTick(struct cpu *cpu) {
                cpu->cycles += (need_more_cycles_1 & need_more_cycles_2);
        }

        cpu->tick_count++;
        cpu->tickCount++;
        cpu->cycles--;
}

int CpuIsComplete(struct cpu *cpu) {
        return (0 == cpu->cycles);
}

void CpuReset(struct cpu *cpu) {
        cpu->a = 0;
        cpu->x = 0;


@@ 189,14 192,14 @@ void CpuReset(struct cpu *cpu) {
        cpu->sp = 0xFD;
        cpu->status = 0x00 | U;

        cpu->addr_abs = 0xFFFC;
        uint16_t lo = BusRead(cpu->bus, cpu->addr_abs + 0);
        uint16_t hi = BusRead(cpu->bus, cpu->addr_abs + 1);
        cpu->addrAbs = 0xFFFC;
        uint16_t lo = BusRead(cpu->bus, cpu->addrAbs + 0);
        uint16_t hi = BusRead(cpu->bus, cpu->addrAbs + 1);

        cpu->pc = (hi << 8) | lo;

        cpu->addr_rel = 0x0000;
        cpu->addr_abs = 0x0000;
        cpu->addrRel = 0x0000;
        cpu->addrAbs = 0x0000;
        cpu->fetched = 0x00;

        cpu->cycles = 8;


@@ 215,9 218,9 @@ void Irq(struct cpu *cpu) {
                BusWrite(cpu->bus, 0x0100 + cpu->sp, cpu->status);
                cpu->sp--;

                cpu->addr_abs = 0xFFFE;
                uint16_t lo = BusRead(cpu->bus, cpu->addr_abs + 0);
                uint16_t hi = BusRead(cpu->bus, cpu->addr_abs + 1);
                cpu->addrAbs = 0xFFFE;
                uint16_t lo = BusRead(cpu->bus, cpu->addrAbs + 0);
                uint16_t hi = BusRead(cpu->bus, cpu->addrAbs + 1);
                cpu->pc = (hi << 8) | lo;

                cpu->cycles = 7;


@@ 236,9 239,9 @@ void Nmi(struct cpu *cpu) {
        BusWrite(cpu->bus, 0x0100 + cpu->sp, cpu->status);
        cpu->sp--;

        cpu->addr_abs = 0xFFFA;
        uint16_t lo = BusRead(cpu->bus, cpu->addr_abs + 0);
        uint16_t hi = BusRead(cpu->bus, cpu->addr_abs + 1);
        cpu->addrAbs = 0xFFFA;
        uint16_t lo = BusRead(cpu->bus, cpu->addrAbs + 0);
        uint16_t hi = BusRead(cpu->bus, cpu->addrAbs + 1);
        cpu->pc = (hi << 8) | lo;

        cpu->cycles = 8;


@@ 313,7 316,7 @@ uint8_t ABS(struct cpu *cpu) {
        uint16_t hi = BusRead(cpu->bus, cpu->pc);
        cpu->pc++;

        cpu->addr_abs = (hi << 8) | lo;
        cpu->addrAbs = (hi << 8) | lo;

        return 0;
}


@@ 327,12 330,12 @@ uint8_t ABX(struct cpu *cpu) {
        uint16_t hi = BusRead(cpu->bus, cpu->pc);
        cpu->pc++;

        cpu->addr_abs = (hi << 8) | lo;
        cpu->addr_abs += cpu->x;
        cpu->addrAbs = (hi << 8) | lo;
        cpu->addrAbs += cpu->x;

        // If the memory page has changed, then this addressing mode may take
        // another clock cycle to execute.
        if ((cpu->addr_abs & 0xFF00) != (hi << 8))
        if ((cpu->addrAbs & 0xFF00) != (hi << 8))
                return 1;
        else
                return 0;


@@ 347,12 350,12 @@ uint8_t ABY(struct cpu *cpu) {
        uint16_t hi = BusRead(cpu->bus, cpu->pc);
        cpu->pc++;

        cpu->addr_abs = (hi << 8) | lo;
        cpu->addr_abs += cpu->y;
        cpu->addrAbs = (hi << 8) | lo;
        cpu->addrAbs += cpu->y;

        // If the memory page has changed, then this addressing mode may take
        // another clock cycle to execute.
        if ((cpu->addr_abs & 0xFF00) != (hi << 8))
        if ((cpu->addrAbs & 0xFF00) != (hi << 8))
                return 1;
        else
                return 0;


@@ 366,7 369,7 @@ uint8_t ABY(struct cpu *cpu) {
//! \param[in,out] cpu
//! \return 0 This addressing mode will take no additional cycles
uint8_t IMM(struct cpu *cpu) {
        cpu->addr_abs = cpu->pc++;
        cpu->addrAbs = cpu->pc++;
        return 0;
}



@@ 405,9 408,9 @@ uint8_t IND(struct cpu *cpu) {
        uint16_t ptr = (ptr_hi << 8) | ptr_lo;

        if (ptr_lo == 0x00FF) { // Simulate page boundary hardware bug
                cpu->addr_abs = (BusRead(cpu->bus, ptr & 0xFF00) << 8) | BusRead(cpu->bus, ptr + 0);
                cpu->addrAbs = (BusRead(cpu->bus, ptr & 0xFF00) << 8) | BusRead(cpu->bus, ptr + 0);
        } else { // Behave normally
                cpu->addr_abs = (BusRead(cpu->bus, ptr + 1) << 8) | BusRead(cpu->bus, ptr + 0);
                cpu->addrAbs = (BusRead(cpu->bus, ptr + 1) << 8) | BusRead(cpu->bus, ptr + 0);
        }

        return 0;


@@ 429,7 432,7 @@ uint8_t IZX(struct cpu *cpu) {
        uint16_t lo = BusRead(cpu->bus, offset & 0x00FF);
        uint16_t hi = BusRead(cpu->bus, (offset +  1) & 0x00FF);

        cpu->addr_abs = (hi << 8) | lo;
        cpu->addrAbs = (hi << 8) | lo;

        return 0;
}


@@ 454,10 457,10 @@ uint8_t IZY(struct cpu *cpu) {
        uint16_t lo = BusRead(cpu->bus, t & 0x00FF);
        uint16_t hi = BusRead(cpu->bus, (t + 1) & 0x00FF);

        cpu->addr_abs = (hi << 8) | lo;
        cpu->addr_abs += cpu->y;
        cpu->addrAbs = (hi << 8) | lo;
        cpu->addrAbs += cpu->y;

        if ((cpu->addr_abs & 0xFF00) != (hi << 8))
        if ((cpu->addrAbs & 0xFF00) != (hi << 8))
                return 1;
        else
                return 0;


@@ 472,7 475,7 @@ uint8_t IZY(struct cpu *cpu) {
//! \param[in,out] cpu
//! \return 0 This addressing mode will take no additional cycles
uint8_t REL(struct cpu *cpu) {
        cpu->addr_rel = BusRead(cpu->bus, cpu->pc);
        cpu->addrRel = BusRead(cpu->bus, cpu->pc);
        cpu->pc++;

        // REL involves signed values for jumps.


@@ 483,10 486,10 @@ uint8_t REL(struct cpu *cpu) {

        // Check if the leading bit of this byte is a 1, indicating a negative
        // number.
        if (cpu->addr_rel & 0x80) {
                // If addr_rel is negative, then sign-extend the address to the
        if (cpu->addrRel & 0x80) {
                // If addrRel is negative, then sign-extend the address to the
                // full 16-bits so the addition works out.
                cpu->addr_rel |= 0xFF00;
                cpu->addrRel |= 0xFF00;
        }

        return 0;


@@ 500,9 503,9 @@ uint8_t REL(struct cpu *cpu) {
//! \param[in,out] cpu
//! \return 0 This addressing mode will take no additional cycles
uint8_t ZP0(struct cpu *cpu) {
        cpu->addr_abs = BusRead(cpu->bus, cpu->pc);
        cpu->addrAbs = BusRead(cpu->bus, cpu->pc);
        cpu->pc++;
        cpu->addr_abs &= 0x00FF;
        cpu->addrAbs &= 0x00FF;
        return 0;
}



@@ 514,9 517,9 @@ uint8_t ZP0(struct cpu *cpu) {
//! \param[in,out] cpu
//! \return 0 This addressing mode will take no additional cycles
uint8_t ZPX(struct cpu *cpu) {
        cpu->addr_abs = BusRead(cpu->bus, cpu->pc) + cpu->x;
        cpu->addrAbs = BusRead(cpu->bus, cpu->pc) + cpu->x;
        cpu->pc++;
        cpu->addr_abs &= 0x00FF;
        cpu->addrAbs &= 0x00FF;
        return 0;
}



@@ 528,9 531,9 @@ uint8_t ZPX(struct cpu *cpu) {
//! \param[in,out] cpu
//! \return 0 This addressing mode will take no additional cycles
uint8_t ZPY(struct cpu *cpu) {
        cpu->addr_abs = BusRead(cpu->bus, cpu->pc) + cpu->y;
        cpu->addrAbs = BusRead(cpu->bus, cpu->pc) + cpu->y;
        cpu->pc++;
        cpu->addr_abs &= 0x00FF;
        cpu->addrAbs &= 0x00FF;
        return 0;
}



@@ 566,7 569,7 @@ uint8_t ASL(struct cpu *cpu) {
        if (instruction_map[cpu->opcode].address == IMP) {
                cpu->a = tmp & 0x00FF;
        } else {
                BusWrite(cpu->bus, cpu->addr_abs, tmp & 0x00FF);
                BusWrite(cpu->bus, cpu->addrAbs, tmp & 0x00FF);
        }

        return 0;


@@ 582,16 585,16 @@ uint8_t BCC(struct cpu *cpu) {
        if (GetFlag(cpu, C) == 0) {
                // Branch instructions implicitly increment clock cycles.
                cpu->cycles++;
                cpu->addr_abs = cpu->pc + cpu->addr_rel;
                cpu->addrAbs = cpu->pc + cpu->addrRel;

                // If the memory page is different, then incur another clock
                // cycle.
                if ((cpu->addr_abs & 0xFF00) != (cpu->pc & 0xFF00)) {
                if ((cpu->addrAbs & 0xFF00) != (cpu->pc & 0xFF00)) {
                        cpu->cycles++;
                }

                // Set the program counter.
                cpu->pc = cpu->addr_abs;
                cpu->pc = cpu->addrAbs;
        }

        return 0;


@@ 607,16 610,16 @@ uint8_t BCS(struct cpu *cpu) {
        if (GetFlag(cpu, C) == 1) {
                // Branch instructions implicitly increment clock cycles.
                cpu->cycles++;
                cpu->addr_abs = cpu->pc + cpu->addr_rel;
                cpu->addrAbs = cpu->pc + cpu->addrRel;

                // If the memory page is different, then incur another clock
                // cycle.
                if ((cpu->addr_abs & 0xFF00) != (cpu->pc & 0xFF00)) {
                if ((cpu->addrAbs & 0xFF00) != (cpu->pc & 0xFF00)) {
                        cpu->cycles++;
                }

                // Set the program counter.
                cpu->pc = cpu->addr_abs;
                cpu->pc = cpu->addrAbs;
        }

        return 0;


@@ 632,16 635,16 @@ uint8_t BEQ(struct cpu *cpu) {
        if (GetFlag(cpu, Z) == 1) {
                // Branch instructions implicitly increment clock cycles.
                cpu->cycles++;
                cpu->addr_abs = cpu->pc + cpu->addr_rel;
                cpu->addrAbs = cpu->pc + cpu->addrRel;

                // If the memory page is different, then incur another clock
                // cycle.
                if ((cpu->addr_abs & 0xFF00) != (cpu->pc & 0xFF00)) {
                if ((cpu->addrAbs & 0xFF00) != (cpu->pc & 0xFF00)) {
                        cpu->cycles++;
                }

                // Set the program counter.
                cpu->pc = cpu->addr_abs;
                cpu->pc = cpu->addrAbs;
        }

        return 0;


@@ 669,13 672,13 @@ uint8_t BIT(struct cpu *cpu) {
uint8_t BMI(struct cpu *cpu) {
        if (GetFlag(cpu, N) == 1) {
                cpu->cycles++;
                cpu->addr_abs = cpu->pc + cpu->addr_rel;
                cpu->addrAbs = cpu->pc + cpu->addrRel;

                if ((cpu->addr_abs & 0xFF00) != (cpu->pc & 0xFF00)) {
                if ((cpu->addrAbs & 0xFF00) != (cpu->pc & 0xFF00)) {
                        cpu->cycles++;
                }

                cpu->pc = cpu->addr_abs;
                cpu->pc = cpu->addrAbs;
        }
        return 0;
}


@@ 689,13 692,13 @@ uint8_t BMI(struct cpu *cpu) {
uint8_t BNE(struct cpu *cpu) {
        if (GetFlag(cpu, Z) == 0) {
                cpu->cycles++;
                cpu->addr_abs = cpu->pc + cpu->addr_rel;
                cpu->addrAbs = cpu->pc + cpu->addrRel;

                if ((cpu->addr_abs & 0xFF00) != (cpu->pc & 0xFF00)) {
                if ((cpu->addrAbs & 0xFF00) != (cpu->pc & 0xFF00)) {
                        cpu->cycles++;
                }

                cpu->pc = cpu->addr_abs;
                cpu->pc = cpu->addrAbs;
        }
        return 0;
}


@@ 709,13 712,13 @@ uint8_t BNE(struct cpu *cpu) {
uint8_t BPL(struct cpu *cpu) {
        if (GetFlag(cpu, N) == 0) {
                cpu->cycles++;
                cpu->addr_abs = cpu->pc + cpu->addr_rel;
                cpu->addrAbs = cpu->pc + cpu->addrRel;

                if ((cpu->addr_abs & 0xFF00) != (cpu->pc & 0xFF00)) {
                if ((cpu->addrAbs & 0xFF00) != (cpu->pc & 0xFF00)) {
                        cpu->cycles++;
                }

                cpu->pc = cpu->addr_abs;
                cpu->pc = cpu->addrAbs;
        }
        return 0;
}


@@ 753,13 756,13 @@ uint8_t BRK(struct cpu*cpu) {
uint8_t BVC(struct cpu *cpu) {
        if (GetFlag(cpu, V) == 0) {
                cpu->cycles++;
                cpu->addr_abs = cpu->pc + cpu->addr_rel;
                cpu->addrAbs = cpu->pc + cpu->addrRel;

                if ((cpu->addr_abs & 0xFF00) != (cpu->pc & 0xFF00)) {
                if ((cpu->addrAbs & 0xFF00) != (cpu->pc & 0xFF00)) {
                        cpu->cycles++;
                }

                cpu->pc = cpu->addr_abs;
                cpu->pc = cpu->addrAbs;
        }
        return 0;
}


@@ 773,13 776,13 @@ uint8_t BVC(struct cpu *cpu) {
uint8_t BVS(struct cpu *cpu) {
        if (GetFlag(cpu, V) == 1) {
                cpu->cycles++;
                cpu->addr_abs = cpu->pc + cpu->addr_rel;
                cpu->addrAbs = cpu->pc + cpu->addrRel;

                if ((cpu->addr_abs & 0xFF00) != (cpu->pc & 0xFF00)) {
                if ((cpu->addrAbs & 0xFF00) != (cpu->pc & 0xFF00)) {
                        cpu->cycles++;
                }

                cpu->pc = cpu->addr_abs;
                cpu->pc = cpu->addrAbs;
        }
        return 0;
}


@@ 880,7 883,7 @@ uint8_t CPY(struct cpu *cpu) {
uint8_t DEC(struct cpu *cpu) {
        uint8_t fetched = Fetch(cpu);
        uint16_t tmp = fetched - 1;
        BusWrite(cpu->bus, cpu->addr_abs, tmp & 0x00FF);
        BusWrite(cpu->bus, cpu->addrAbs, tmp & 0x00FF);

        SetFlag(cpu, Z, (tmp & 0x00FF) == 0x0000);
        SetFlag(cpu, N, tmp & 0x0080);


@@ 944,7 947,7 @@ uint8_t EOR(struct cpu *cpu) {
uint8_t INC(struct cpu *cpu) {
        uint8_t fetched = Fetch(cpu);
        uint16_t tmp = fetched + 1;
        BusWrite(cpu->bus, cpu->addr_abs, tmp & 0x00FF);
        BusWrite(cpu->bus, cpu->addrAbs, tmp & 0x00FF);

        SetFlag(cpu, Z, (tmp & 0x00FF) == 0x0000);
        SetFlag(cpu, N, tmp & 0x0080);


@@ 988,7 991,7 @@ uint8_t INY(struct cpu *cpu) {
//! \param[in,out] cpu
//! \return 0 This instruction will take no additional cycles
uint8_t JMP(struct cpu *cpu) {
        cpu->pc = cpu->addr_abs;
        cpu->pc = cpu->addrAbs;
        return 0;
}



@@ 1007,7 1010,7 @@ uint8_t JSR(struct cpu *cpu) {
        BusWrite(cpu->bus, 0x0100 + cpu->sp, cpu->pc & 0x00FF);
        cpu->sp--;

        cpu->pc = cpu->addr_abs;
        cpu->pc = cpu->addrAbs;
        return 0;
}



@@ 1070,7 1073,7 @@ uint8_t LSR(struct cpu *cpu) {
        if (instruction_map[cpu->opcode].address == IMP)
                cpu->a = tmp & 0x00FF;
        else
                BusWrite(cpu->bus, cpu->addr_abs, tmp & 0x00FF);
                BusWrite(cpu->bus, cpu->addrAbs, tmp & 0x00FF);

        return 0;
}


@@ 1180,7 1183,7 @@ uint8_t ROL(struct cpu *cpu) {
        if (instruction_map[cpu->opcode].address == IMP)
                cpu->a = tmp & 0x00FF;
        else
                BusWrite(cpu->bus, cpu->addr_abs, tmp & 0x00FF);
                BusWrite(cpu->bus, cpu->addrAbs, tmp & 0x00FF);

        return 0;



@@ 1200,7 1203,7 @@ uint8_t ROR(struct cpu *cpu) {
        if (instruction_map[cpu->opcode].address == IMP)
                cpu->a = tmp & 0x00FF;
        else
                BusWrite(cpu->bus, cpu->addr_abs, tmp & 0x00FF);
                BusWrite(cpu->bus, cpu->addrAbs, tmp & 0x00FF);

        return 0;
}


@@ 1279,7 1282,7 @@ uint8_t SEI(struct cpu *cpu) {
//! \param[in,out] cpu
//! \return 0 This instruction will take no additional cycles
uint8_t STA(struct cpu *cpu) {
        BusWrite(cpu->bus, cpu->addr_abs, cpu->a);
        BusWrite(cpu->bus, cpu->addrAbs, cpu->a);
        return 0;
}



@@ 1290,7 1293,7 @@ uint8_t STA(struct cpu *cpu) {
//! \param[in,out] cpu
//! \return 0 This instruction will take no additional cycles
uint8_t STX(struct cpu *cpu) {
        BusWrite(cpu->bus, cpu->addr_abs, cpu->x);
        BusWrite(cpu->bus, cpu->addrAbs, cpu->x);
        return 0;
}



@@ 1301,7 1304,7 @@ uint8_t STX(struct cpu *cpu) {
//! \param[in,out] cpu
//! \return 0 This instruction will take no additional cycles
uint8_t STY(struct cpu *cpu) {
        BusWrite(cpu->bus, cpu->addr_abs, cpu->y);
        BusWrite(cpu->bus, cpu->addrAbs, cpu->y);
        return 0;
}



@@ 1409,21 1412,65 @@ void ToHexString(uint32_t n, uint8_t d, char *buf, uint8_t size) {
        buf[d] = '\0';
}

void DebugInstructionMapDeinit(struct debug_instruction_map *map) {
        if (NULL == map) {

//-- Debug Structures ----------------------------------------------------------


char **CpuDebugStateInit(struct cpu *cpu) {
        char **debug = (char **)malloc(sizeof(char *) * 7);

        debug[0] = "        N V - B D I Z C";
        debug[1] = malloc(strlen("status: 1 1 - 1 1 1 1 1") + 1);
        sprintf(debug[1], "Status: %d %d - %d %d %d %d %d",
                GetFlag(cpu, N),
                GetFlag(cpu, V),
                GetFlag(cpu, B),
                GetFlag(cpu, D),
                GetFlag(cpu, I),
                GetFlag(cpu, Z),
                GetFlag(cpu, C));

        debug[2] = malloc(strlen("pc: $0000") + 1);
        sprintf(debug[2], "PC: $%04X", cpu->pc);

        debug[3] = malloc(strlen("a:  $00") + 1);
        sprintf(debug[3], "A:  $%02X", cpu->a);

        debug[4] = malloc(strlen("x:  $00") + 1);
        sprintf(debug[4], "X:  $%02X", cpu->x);

        debug[5] = malloc(strlen("y:  $00") + 1);
        sprintf(debug[5], "Y:  $%02X", cpu->y);

        debug[6] = malloc(strlen("sp: $0000") + 1);
        sprintf(debug[6], "SP: $%04X", cpu->sp);

        return debug;
}

void CpuDebugStateDeinit(char **debug) {
        if (NULL == debug)
                return;
        }

        if (NULL != map->map) {
                free(map->map);
        for (int i = 1; i < 7; i++) {
                if (NULL == debug[i])
                        continue;
                free(debug[i]);
        }

        free(map);
}

struct debug_instruction *DebugInstructionInit(uint16_t address, char *string, int length) {
        struct debug_instruction *self = (struct debug_instruction *)malloc(sizeof(struct debug_instruction));
        if (NULL == self) {
                return NULL;
        }

        self->text = malloc(length);
        if (NULL == self->text) {
                free(self);
                return NULL;
        }

        strncpy(self->text, string, length);
        return self;
}


@@ 1440,32 1487,36 @@ void DebugInstructionDeinit(struct debug_instruction *self) {
        free(self);
}

int CpuIsComplete(struct cpu *cpu) {
        return (0 == cpu->cycles);
}

struct debug_instruction_map *CpuDisassemble(struct cpu *cpu, uint16_t start, uint16_t stop) {
struct disassembly *DisassemblyInit(struct cpu *cpu, uint16_t start, uint16_t stop) {
        int addr = start;
        uint8_t value = 0x00;
        uint8_t lo = 0x00;
        uint8_t hi = 0x00;
        uint16_t line_addr = 0;

        struct debug_instruction_map *debug_map = (struct debug_instruction_map *)malloc(sizeof(struct debug_instruction_map));
        debug_map->count = stop - start;
        debug_map->map = (struct debug_instruction **)malloc(sizeof(struct debug_instruction *) * debug_map->count);
        struct disassembly *disassembly = (struct disassembly *)malloc(sizeof(struct disassembly));
        if (NULL == disassembly) {
                return NULL;
        }

        char text[256] = { 0 };
        char text_cpy[256] = { 0 };
        uint8_t hex_buf_len = 5; // Space for terminating null.
        char hex_buf[hex_buf_len];
        uint16_t text_len = hex_buf_len; // Size adjusts as we construct string below.
        disassembly->count = stop - start;
        disassembly->map = (struct debug_instruction **)calloc(disassembly->count, sizeof(struct debug_instruction *));
        if (NULL == disassembly->map) {
                free(disassembly);
                return NULL;
        }

        #pragma GCC diagnostic push
        #pragma GCC diagnostic ignored "-Wformat-truncation"

        int i = 0;
        while (addr <= stop) {
                char text[256] = { 0 };
                char text_cpy[256] = { 0 };
                uint8_t hex_buf_len = 5; // Space for terminating null.
                char hex_buf[hex_buf_len];
                uint16_t text_len = hex_buf_len; // Size adjusts as we construct string below.

                text_len = hex_buf_len; // Size adjusts as we construct string below.
                line_addr = addr;
                struct instruction instruction;


@@ 1559,54 1610,37 @@ struct debug_instruction_map *CpuDisassemble(struct cpu *cpu, uint16_t start, ui
                        snprintf(text, 256, "%s$%s [$%s] {REL}", text_cpy, hex_buf, hex_buf2);
                }

                debug_map->map[i] = DebugInstructionInit(line_addr, text, strnlen(text, 256));
                disassembly->map[i] = DebugInstructionInit(line_addr, text, strnlen(text, 256));
                i++;
        }

        #pragma GCC diagnostic pop

        return debug_map;
        return disassembly;
}

char **CpuDebugState(struct cpu *cpu) {
        char **debug = (char **)malloc(sizeof(char *) * 7);

        debug[0] = "        N V - B D I Z C";
        debug[1] = malloc(strlen("status: 1 1 - 1 1 1 1 1") + 1);
        sprintf(debug[1], "Status: %d %d - %d %d %d %d %d",
                GetFlag(cpu, N),
                GetFlag(cpu, V),
                GetFlag(cpu, B),
                GetFlag(cpu, D),
                GetFlag(cpu, I),
                GetFlag(cpu, Z),
                GetFlag(cpu, C));

        debug[2] = malloc(strlen("pc: $0000") + 1);
        sprintf(debug[2], "PC: $%04X", cpu->pc);

        debug[3] = malloc(strlen("a:  $00") + 1);
        sprintf(debug[3], "A:  $%02X", cpu->a);

        debug[4] = malloc(strlen("x:  $00") + 1);
        sprintf(debug[4], "X:  $%02X", cpu->x);

        debug[5] = malloc(strlen("y:  $00") + 1);
        sprintf(debug[5], "Y:  $%02X", cpu->y);
void DisassemblyDeinit(struct disassembly *disassembly) {
        if (NULL == disassembly) {
                return;
        }

        debug[6] = malloc(strlen("sp: $0000") + 1);
        sprintf(debug[6], "SP: $%04X", cpu->sp);
        if (NULL != disassembly->map) {
                free(disassembly->map);
        }

        return debug;
        free(disassembly);
}

void CpuDebugStateDeinit(char **debug) {
        if (NULL == debug)
                return;
int DisassemblyFindPc(struct disassembly *disassembly, struct cpu *cpu) {
        if (NULL == disassembly) return -1;
        if (NULL == cpu) return -1;

        for (int i = 1; i < 7; i++) {
                if (NULL == debug[i])
                        continue;
                free(debug[i]);
        for (int i = 0; i < disassembly->count; i++) {
                if (NULL == disassembly || NULL == disassembly->map || NULL == disassembly->map[i]) continue;

                unsigned long parsed = strtoul(&disassembly->map[i]->text[1], NULL, 16);
                if ((uint16_t)parsed == cpu->pc) return i;
        }

        return -1;
}

M cpu.h => cpu.h +18 -13
@@ 8,14 8,13 @@
  Author: Aaron Oman
  Notice: GNU AGPLv3 License

  Based off of: One Lone Coder NES Emulator Copyright (C) 2018 Javidx9
  Based off of: One Lone Coder NES Emulator Copyright (C) 2019 Javidx9
  This program comes with ABSOLUTELY NO WARRANTY.
  This is free software, and you are welcome to redistribute it under certain
  conditions; See LICENSE for details.
 ******************************************************************************/
#include <stdint.h>

//! \file cpu.h
#include <stdint.h>

#ifndef CPU_VERSION
#define CPU_VERSION "0.1.0"


@@ 38,15 37,24 @@ CpuReset(struct cpu *cpu);
void
CpuTick(struct cpu *cpu);

int
CpuIsComplete(struct cpu *cpu);

//-- Debug ---------------------------------------------------------------------

char **
CpuDebugStateInit(struct cpu *cpu);

void
CpuDebugStateDeinit(char **debug);

struct debug_instruction {
        uint16_t address;
        char *text;
        int text_length;
};

struct debug_instruction_map {
struct disassembly {
        struct debug_instruction **map;
        int count;
};


@@ 54,16 62,13 @@ struct debug_instruction_map {
void
DebugInstructionDeinit(struct debug_instruction *inst);

void
DebugInstructionMapDeinit(struct debug_instruction_map *map);

struct debug_instruction_map *
CpuDisassemble(struct cpu *cpu, uint16_t start, uint16_t stop);

char **
CpuDebugState(struct cpu *cpu);
struct disassembly *
DisassemblyInit(struct cpu *cpu, uint16_t start, uint16_t stop);

void
CpuDebugStateDeinit(char **debug);
DisassemblyDeinit(struct disassembly *disassembly);

int
DisassemblyFindPc(struct disassembly *disassembly, struct cpu *cpu);

#endif // CPU_VERSION

M input.c => input.c +127 -1
@@ 1,5 1,5 @@
/******************************************************************************
  GrooveStomp's Text Renderer
  GrooveStomp's NES Emulator
  Copyright (c) 2019 Aaron Oman (GrooveStomp)

  File: input.c


@@ 28,8 28,22 @@ struct input {

struct input *InputInit() {
        struct input *input = (struct input *)malloc(sizeof(struct input));
        if (NULL == input) {
                return NULL;
        }

        memset(input, 0, sizeof(struct input));

        /* input->keyStates = (struct input_key *)calloc(KEY_MAX + 1, sizeof(struct input_key)); */
        /* if (NULL == input) { */
        /*         free(input); */
        /*         return NULL; */
        /* } */

        /* for (int i = 0; i <= KEY_MAX; i++) { */
        /*         *input->keyStates[i] = { 0 }; */
        /* } */

        input->sdlKeyStates = SDL_GetKeyboardState(NULL);
        input->isQuitPressed = 0;



@@ 45,6 59,7 @@ void InputDeinit(struct input *input) {

void InputProcess(struct input *input) {
        input->isQuitPressed = 0;
        SDL_PumpEvents(); // Update sdlKeyState;

        while (SDL_PollEvent(&input->event)) {
                switch (input->event.type) {


@@ 68,3 83,114 @@ void InputProcess(struct input *input) {
int InputIsQuitRequested(struct input *input) {
        return input->isQuitPressed;
}

int MapToSdlEnum(enum input_key_enum e) {
        switch(e) {
                case KEY_A:
                        return SDL_SCANCODE_A;
                case KEY_B:
                        return SDL_SCANCODE_B;
                case KEY_C:
                        return SDL_SCANCODE_C;
                case KEY_D:
                        return SDL_SCANCODE_D;
                case KEY_E:
                        return SDL_SCANCODE_E;
                case KEY_F:
                        return SDL_SCANCODE_F;
                case KEY_G:
                        return SDL_SCANCODE_G;
                case KEY_H:
                        return SDL_SCANCODE_H;
                case KEY_I:
                        return SDL_SCANCODE_I;
                case KEY_J:
                        return SDL_SCANCODE_J;
                case KEY_K:
                        return SDL_SCANCODE_K;
                case KEY_L:
                        return SDL_SCANCODE_L;
                case KEY_M:
                        return SDL_SCANCODE_M;
                case KEY_N:
                        return SDL_SCANCODE_N;
                case KEY_O:
                        return SDL_SCANCODE_O;
                case KEY_P:
                        return SDL_SCANCODE_P;
                case KEY_Q:
                        return SDL_SCANCODE_Q;
                case KEY_R:
                        return SDL_SCANCODE_R;
                case KEY_S:
                        return SDL_SCANCODE_S;
                case KEY_T:
                        return SDL_SCANCODE_T;
                case KEY_U:
                        return SDL_SCANCODE_U;
                case KEY_V:
                        return SDL_SCANCODE_V;
                case KEY_W:
                        return SDL_SCANCODE_W;
                case KEY_X:
                        return SDL_SCANCODE_X;
                case KEY_Y:
                        return SDL_SCANCODE_Y;
                case KEY_Z:
                        return SDL_SCANCODE_Z;
                case KEY_LEFT:
                        return SDL_SCANCODE_LEFT;
                case KEY_RIGHT:
                        return SDL_SCANCODE_RIGHT;
                case KEY_UP:
                        return SDL_SCANCODE_UP;
                case KEY_DOWN:
                        return SDL_SCANCODE_DOWN;
                case KEY_ENTER:
                        return SDL_SCANCODE_RETURN;
                case KEY_ESC:
                        return SDL_SCANCODE_ESCAPE;
                case KEY_SPACE:
                        return SDL_SCANCODE_SPACE;
                case KEY_1:
                        return SDL_SCANCODE_1;
                case KEY_2:
                        return SDL_SCANCODE_2;
                case KEY_3:
                        return SDL_SCANCODE_3;
                case KEY_4:
                        return SDL_SCANCODE_4;
                case KEY_5:
                        return SDL_SCANCODE_5;
                case KEY_6:
                        return SDL_SCANCODE_6;
                case KEY_7:
                        return SDL_SCANCODE_7;
                case KEY_8:
                        return SDL_SCANCODE_8;
                case KEY_9:
                        return SDL_SCANCODE_9;
                case KEY_0:
                        return SDL_SCANCODE_0;
                case KEY_LSHIFT:
                        return SDL_SCANCODE_LSHIFT;
                case KEY_RSHIFT:
                        return SDL_SCANCODE_RSHIFT;
                case KEY_LCTRL:
                        return SDL_SCANCODE_LCTRL;
                case KEY_RCTRL:
                        return SDL_SCANCODE_RCTRL;
                default:
                        return -1;
        };
        return -1;
}

unsigned int InputIsKeyPressed(struct input *input, enum input_key_enum e) {
        int i = MapToSdlEnum(e);
        if (i < 0) {
                return 0;
        }

        return input->sdlKeyStates[i];
}

M input.h => input.h +53 -0
@@ 45,4 45,57 @@ InputProcess(struct input *input);
int
InputIsQuitRequested(struct input *input);

enum input_key_enum {
        KEY_A = 0,
        KEY_B,
        KEY_C,
        KEY_D,
        KEY_E,
        KEY_F,
        KEY_G,
        KEY_H,
        KEY_I,
        KEY_J,
        KEY_K,
        KEY_L,
        KEY_M,
        KEY_N,
        KEY_O,
        KEY_P,
        KEY_Q,
        KEY_R,
        KEY_S,
        KEY_T,
        KEY_U,
        KEY_V,
        KEY_W,
        KEY_X,
        KEY_Y,
        KEY_Z,
        KEY_LEFT,
        KEY_RIGHT,
        KEY_UP,
        KEY_DOWN,
        KEY_ENTER,
        KEY_ESC,
        KEY_LSHIFT,
        KEY_RSHIFT,
        KEY_LCTRL,
        KEY_RCTRL,
        KEY_SPACE,
        KEY_1,
        KEY_2,
        KEY_3,
        KEY_4,
        KEY_5,
        KEY_6,
        KEY_7,
        KEY_8,
        KEY_9,
        KEY_0
};

unsigned int
InputIsKeyPressed(struct input *input, enum input_key_enum e);

#endif // INPUT_VERSION

M main.c => main.c +103 -49
@@ 8,13 8,13 @@
  Author: Aaron Oman
  Notice: GNU AGPLv3 License

  Based off of: One Lone Coder NES Emulator Copyright (C) 2018 Javidx9
  Based off of: One Lone Coder NES Emulator Copyright (C) 2019 Javidx9
  This program comes with ABSOLUTELY NO WARRANTY.
  This is free software, and you are welcome to redistribute it under certain
  conditions; See LICENSE for details.
 ******************************************************************************/
//! \file main.c
#include <time.h> // nanosleep
#include <time.h> // struct timespec, clock_gettime
#include <stdlib.h> // strtoul, exit
#include <string.h> // strlen
#include <stdio.h> // printf


@@ 24,14 24,8 @@
#include "ppu.h"
#include "graphics.h"
#include "input.h"

//! \brief convert from seconds to nanoseconds
//!
//! Used to make it easier to understand the value being passed to nanosleep()
//!
//! \param x number of seconds
//! \return x as nanoseconds
#define S_TO_NS(x) (x) * 1000000000
#include "util.h"
#include "color.h"

// Load Program (assembled at https://www.masswerk.at/6502/assembler.html)
/*


@@ 90,7 84,13 @@ void Init() {
                Deinit(1);
        }

        bus = BusInit(cpu);
        ppu = PpuInit();
        if (NULL == ppu) {
                fprintf(stderr, "Couldn't initialize ppu");
                Deinit(1);
        }

        bus = BusInit(cpu, ppu);
        if (NULL == bus) {
                fprintf(stderr, "Couldn't initialize bus");
                Deinit(1);


@@ 125,8 125,8 @@ void Init() {
        }

        fseek(ttf_file, 0, SEEK_SET);
        size_t objs_read = fread(font_buffer, 1, fsize, ttf_file);
        if (ferror(ttf_file)) {
        size_t objsRead = fread(font_buffer, 1, fsize, ttf_file);
        if (objsRead != 1 && ferror(ttf_file)) {
                perror("fread() failed");
                fclose(ttf_file);
                Deinit(1);


@@ 147,9 147,40 @@ void LoadRom(struct bus *bus, char *data) {
        }
}

void DrawCpuState(int x, int y) {
        GraphicsDrawText(graphics, x, y, "CPU State", 25, 0x000000FF);
        char **cpu_state = CpuDebugStateInit(cpu);
        for (int i = 0; i < 7; i++) {
                GraphicsDrawText(graphics, x, (y - 20) - (18 * i), cpu_state[i], 15, 0x000000FF);
        }
        CpuDebugStateDeinit(cpu_state);
}

void DrawDisassembly(struct disassembly *disassembly, int x, int y, int numLines) {
        GraphicsDrawText(graphics, x, y, "Disassembly", 25, 0x000000FF);

        int pc = DisassemblyFindPc(disassembly, cpu);

        int halfLines = (int)(0.5f * (float)numLines);
        int min = pc - halfLines;
        if (min < 0 || min > 0xFFFF) min = 0;

        int max = pc + halfLines;
        if (max > 0xFFFF || max < 0) max = 0xFFFF;

        for (int i = min; i < max; i++) {
                if (NULL == disassembly || NULL == disassembly->map || NULL == disassembly->map[i]) {
                        GraphicsDrawLine(graphics, x, (y - 25) - (9 * i), x + 100, (y - 15) - (9 * i), ColorBlack.rgba);
                } else if (i == pc) {
                        GraphicsDrawText(graphics, x, (y - 25) - (18 * i), disassembly->map[i]->text, 15, ColorBlue.rgba);
                } else {
                        GraphicsDrawText(graphics, x, (y - 25) - (18 * i), disassembly->map[i]->text, 15, ColorBlack.rgba);
                }
        }
}

int main(int argc, char **argv) {
        Init();
        struct timespec sleep = { .tv_sec = 0, .tv_nsec = S_TO_NS(0.0333) };

        CpuConnectBus(cpu, bus);
        LoadRom(bus, program);


@@ 159,53 190,76 @@ int main(int argc, char **argv) {
        BusWrite(bus, 0xFFFD, 0x80);

        // Disassemble
        struct debug_instruction_map *map = CpuDisassemble(cpu, 0x0000, 0x000F);

        // TODO: Render text for disassembly in while loop below
        /* for (int i = 0; i < map->count; i++) { */
        /*         printf("map{%p}", (void *)map); */
        /*         if (NULL != map) { */
        /*                 printf("->map{%p}", (void *)map->map); */

        /*                 if (NULL != map->map) { */
        /*                         printf("[i]{%p}", (void *)map->map[i]); */

        /*                         if (NULL != map->map[i]) { */
        /*                                 printf("->text{%s}", map->map[i]->text); */
        /*                         } */
        /*                 } */
        /*         } */
        /*         printf("\n"); */
        /* } */

        int running = 1;
        while (running) {
        struct disassembly *disassembly = DisassemblyInit(cpu, 0x0000, 0x00FF);

        struct timespec frameEnd;
        struct timespec frameStart;
        clock_gettime(CLOCK_REALTIME, &frameStart);

        double residualTime = 0.0;
        int isEmulating = 1;
        int isRunning = 1;
        while (isRunning) {
                clock_gettime(CLOCK_REALTIME, &frameEnd);
                double elapsedTime = S_AS_MS(frameEnd.tv_sec - frameStart.tv_sec);
                elapsedTime += NS_AS_MS(frameEnd.tv_nsec - frameStart.tv_nsec);

                GraphicsBegin(graphics);
                GraphicsClearScreen(graphics, 0xFFFFFFFF);
                GraphicsDrawLine(graphics, 801, 0, 801, 800, 0x000000FF);

                GraphicsDrawText(graphics, 805, 780, "CPU State", 25, 0x000000FF);
                char **cpu_state = CpuDebugState(cpu);
                for (int i = 0; i < 7; i++) {
                        GraphicsDrawText(graphics, 805, 760 - (18 * i), cpu_state[i], 15, 0x000000FF);
                if (isEmulating) {
                        if (0.0f < residualTime) {
                                residualTime -= elapsedTime;
                        } else {
                                residualTime += (1.0 / 60.0) - elapsedTime;
                                do { BusTick(bus); } while (!PpuIsFrameComplete(ppu));
                                PpuResetFrameCompletion(ppu);
                        }
                } else {
                        // Emulate code step-by-step.
                        if (InputIsKeyPressed(input, KEY_C)) {
                                // Tick enough times to execute a whole CPU instruction.
                                do { BusTick(bus); } while (!CpuIsComplete(cpu));

                                // The CPU clock runs slower than system clock,
                                // so it may be incomplete for additional system
                                // clock cycles. Drain those out.
                                do { BusTick(bus); } while (CpuIsComplete(cpu));
                        }

                        // Emulate one whole frame.
                        if (InputIsKeyPressed(input, KEY_F)) {
                                // Clock enough times to draw a single frame.
                                do { BusTick(bus); } while (!PpuIsFrameComplete(ppu));

                                // Use residual clock cycles to complete the
                                // current instruction.
                                do { BusTick(bus); } while (!CpuIsComplete(cpu));

                                // Reset frame completion flag.
                                PpuResetFrameCompletion(ppu);
                        }
                }
                CpuDebugStateDeinit(cpu_state);

                GraphicsDrawLine(graphics, 801, 630, 1200, 630, 0x000000FF);
                InputProcess(input);
                isRunning = !InputIsQuitRequested(input);

                GraphicsEnd(graphics);
                if (InputIsKeyPressed(input, KEY_SPACE)) isEmulating = !isEmulating;
                if (InputIsKeyPressed(input, KEY_R)) BusReset(bus);

                // TODO: Hookup input with progressing emulation
                InputProcess(input);
                running = !InputIsQuitRequested(input);
                GraphicsDrawLine(graphics, 811, 0, 811, 800, 0x000000FF);
                DrawCpuState(820, 775);

                nanosleep(&sleep, NULL);
                GraphicsDrawLine(graphics, 811, 630, 1200, 630, 0x000000FF);
                DrawDisassembly(disassembly, 820, 600, 25);

                GraphicsEnd(graphics);
        }

        DebugInstructionMapDeinit(map);
        DisassemblyDeinit(disassembly);

        // Reset
        CpuReset(cpu);
        BusReset(bus);

        Deinit(0);
        return 0;

M mapper.h => mapper.h +2 -2
@@ 8,13 8,13 @@
  Author: Aaron Oman
  Notice: GNU AGPLv3 License

  Based off of: One Lone Coder NES Emulator Copyright (C) 2018 Javidx9
  Based off of: One Lone Coder NES Emulator Copyright (C) 2019 Javidx9
  This program comes with ABSOLUTELY NO WARRANTY.
  This is free software, and you are welcome to redistribute it under certain
  conditions; See LICENSE for details.
 ******************************************************************************/
#include <stdint.h>
//! \file mapper.h
#include <stdint.h>

typedef bool (*map_cpu_read_fn)(void *interface, uint16_t addr, uint32_t *mapped_addr);


M mapper000.c => mapper000.c +2 -2
@@ 8,15 8,15 @@
  Author: Aaron Oman
  Notice: GNU AGPLv3 License

  Based off of: One Lone Coder NES Emulator Copyright (C) 2018 Javidx9
  Based off of: One Lone Coder NES Emulator Copyright (C) 2019 Javidx9
  This program comes with ABSOLUTELY NO WARRANTY.
  This is free software, and you are welcome to redistribute it under certain
  conditions; See LICENSE for details.
 ******************************************************************************/
//! \file mapper000.c
#include <stdlib.h> // malloc, free

#include "mapper000.h"
//! \file mapper000.c

struct mapper000 {
        uint8_t prg_banks;

M mapper000.h => mapper000.h +2 -2
@@ 8,14 8,14 @@
  Author: Aaron Oman
  Notice: GNU AGPLv3 License

  Based off of: One Lone Coder NES Emulator Copyright (C) 2018 Javidx9
  Based off of: One Lone Coder NES Emulator Copyright (C) 2019 Javidx9
  This program comes with ABSOLUTELY NO WARRANTY.
  This is free software, and you are welcome to redistribute it under certain
  conditions; See LICENSE for details.
 ******************************************************************************/
//! \file mapper000.h
#include <stdint.h>
#include <stdbool.h>
//! \file mapper000.h

struct mapper000;


M ppu.c => ppu.c +48 -35
@@ 8,46 8,47 @@
  Author: Aaron Oman
  Notice: GNU AGPLv3 License

  Based off of: One Lone Coder NES Emulator Copyright (C) 2018 Javidx9
  Based off of: One Lone Coder NES Emulator Copyright (C) 2019 Javidx9
  This program comes with ABSOLUTELY NO WARRANTY.
  This is free software, and you are welcome to redistribute it under certain
  conditions; See LICENSE for details.
 ******************************************************************************/
//! \file ppu.c
#include <stdlib.h> // malloc, free
#include <stdbool.h> // bool
#include <stdio.h>

#include "ppu.h"
#include "cart.h"
#include "color.h"
#include "sprite.h"
//! \file ppu.c

struct ppu {
        struct cart *cart;

        bool is_frame_complete;
        bool isFrameComplete;
        int16_t scanline; //!< Which row on the screen we are computing.
        int16_t cycle; //!< Which column on the screen we are computing.

        uint8_t **name_tables; //[2][1024];
        uint8_t **pattern_tables; //[2][4096];
        uint8_t *palette_tables; //[32];
        uint8_t **nameTables; //[2][1024];
        uint8_t **patternTables; //[2][4096];
        uint8_t *paletteTables; //[32];

        struct color *palette;
        struct sprite *screen;
        struct sprite **name_table_sprites;
        struct sprite **pattern_table_sprites;
        struct sprite **nameTableSprites;
        struct sprite **patternTableSprites;

        union {
                struct {
                        uint8_t grayscale : 1;
                        uint8_t render_background_left : 1;
                        uint8_t render_sprites_left : 1;
                        uint8_t render_background : 1;
                        uint8_t render_sprites : 1;
                        uint8_t enhance_red : 1;
                        uint8_t enhance_green : 1;
                        uint8_t enhance_blue : 1;
                        uint8_t renderBackgroundLeft : 1;
                        uint8_t renderSpritesLeft : 1;
                        uint8_t renderBackground : 1;
                        uint8_t renderSprites : 1;
                        uint8_t enhanceRed : 1;
                        uint8_t enhanceGreen : 1;
                        uint8_t enhanceBlue : 1;
                };
                uint8_t reg;



@@ 60,7 61,7 @@ struct ppu *PpuInit() {
                return NULL;
        }

        ppu->palette = (struct color *)malloc(sizeof(struct color) * 0x40);
        ppu->palette = (struct color *)calloc(0x40, sizeof(struct color));
        if (NULL == ppu->palette) {
                PpuDeinit(ppu);
                return NULL;


@@ 72,32 73,32 @@ struct ppu *PpuInit() {
                return NULL;
        }

        ppu->name_tables = (uint8_t **)calloc(2, 1024);
        if (NULL == ppu->name_tables) {
        ppu->nameTables = (uint8_t **)calloc(2, 1024);
        if (NULL == ppu->nameTables) {
                PpuDeinit(ppu);
                return NULL;
        }

        ppu->pattern_tables = (uint8_t **)calloc(2, 4096);
        if (NULL == ppu->pattern_tables) {
        ppu->patternTables = (uint8_t **)calloc(2, 4096);
        if (NULL == ppu->patternTables) {
                PpuDeinit(ppu);
                return NULL;
        }

        ppu->palette_tables = (uint8_t *)calloc(32, 1);
        if (NULL == ppu->palette_tables) {
        ppu->paletteTables = (uint8_t *)calloc(32, 1);
        if (NULL == ppu->paletteTables) {
                PpuDeinit(ppu);
                return NULL;
        }

        ppu->name_table_sprites = (struct sprite **)malloc(sizeof(struct sprite *) * 2);
        ppu->name_table_sprites[0] = SpriteInit(256, 240);
        ppu->name_table_sprites[1] = SpriteInit(256, 240);
        ppu->nameTableSprites = (struct sprite **)calloc(2, sizeof(struct sprite *));
        ppu->nameTableSprites[0] = SpriteInit(256, 240);
        ppu->nameTableSprites[1] = SpriteInit(256, 240);
        // TODO: Error handling

        ppu->pattern_table_sprites = (struct sprite **)malloc(sizeof(struct sprite *) * 2);
        ppu->pattern_table_sprites[0] = SpriteInit(128, 128);
        ppu->pattern_table_sprites[1] = SpriteInit(128, 128);
        ppu->patternTableSprites = (struct sprite **)calloc(2, sizeof(struct sprite *));
        ppu->patternTableSprites[0] = SpriteInit(128, 128);
        ppu->patternTableSprites[1] = SpriteInit(128, 128);
        // TODO: Error handling

        ppu->palette[0x00] = ColorInitInts(84, 84, 84, 255);


@@ 189,7 190,7 @@ void PpuAttachCart(struct ppu *ppu, struct cart *cart) {
//! Advance the pixel right one pixel on the current row, or to the start of the
//! next row if we've reached the screen edge.
//! When the ppu has reached the end of the screen entirely, set
//! is_frame_complete to true.
//! isFrameComplete to true.
//!
//! \param[in,out] ppu
void PpuTick(struct ppu *ppu) {


@@ 206,13 207,13 @@ void PpuTick(struct ppu *ppu) {

                if (261 < ppu->scanline) {
                        ppu->scanline = -1;
                        ppu->is_frame_complete = true;
                        ppu->isFrameComplete = true;
                }
        }
}

struct sprite *PpuGetPatternTable(struct ppu *ppu, uint8_t i) {
        return ppu->pattern_table_sprites[i];
        return ppu->patternTableSprites[i];
}

uint8_t PpuRead(struct ppu *ppu, uint16_t addr) {


@@ 223,7 224,7 @@ uint8_t PpuRead(struct ppu *ppu, uint16_t addr) {
        } else if (addr >= 0x0000 && addr <= 0x1FFF) { // Pattern Memory.
                // MSB determines which table.
                uint16_t pattern_index = (addr & 0x1000) >> 12;
                data = ppu->pattern_tables[pattern_index][addr & 0x0FFF];
                data = ppu->patternTables[pattern_index][addr & 0x0FFF];
        } else if (addr >= 0x2000 && addr <= 0x2FFF) {
        } else if (addr >= 0x3000 && addr <= 0x3FFF) { // Palette Memory.
                addr &= 0x001F; // Mask the bottom 5 bits.


@@ 233,7 234,7 @@ uint8_t PpuRead(struct ppu *ppu, uint16_t addr) {
                if (addr == 0x0014) addr = 0x0004;
                if (addr == 0x0018) addr = 0x0008;
                if (addr == 0x001C) addr = 0x000C;
                data = ppu->palette_tables[addr] & (ppu->mask.grayscale ? 0x30 : 0x3F);
                data = ppu->paletteTables[addr] & (ppu->mask.grayscale ? 0x30 : 0x3F);
        }

        return data;


@@ 249,7 250,7 @@ void PpuWrite(struct ppu *ppu, uint16_t addr, uint8_t data) {

                // MSB determines which table.
                uint16_t pattern_index = (addr & 0x1000) >> 12;
                ppu->pattern_tables[pattern_index][addr & 0x0FFF] = data;
                ppu->patternTables[pattern_index][addr & 0x0FFF] = data;
        } else if (addr >= 0x2000 && addr <= 0x2FFF) {
        } else if (addr >= 0x3000 && addr <= 0x3FFF) { // Palette Memory.
                addr &= 0x001F; // Mask the bottom 5 bits.


@@ 259,7 260,7 @@ void PpuWrite(struct ppu *ppu, uint16_t addr, uint8_t data) {
                if (addr == 0x0014) addr = 0x0004;
                if (addr == 0x0018) addr = 0x0008;
                if (addr == 0x001C) addr = 0x000C;
                ppu->palette_tables[addr] = data;
                ppu->paletteTables[addr] = data;
        }
}



@@ 278,3 279,15 @@ struct color *GetColorFromPaletteRam(struct ppu *ppu, uint8_t palette, uint8_t p
        // "& 0x3F" Stops read past the bounds of ppu->palette.
        return &ppu->palette[PpuRead(ppu, addr) & 0x3F];
}

void PpuReset(struct ppu *ppu) {
        // TODO PpuReset()
}

int PpuIsFrameComplete(struct ppu *ppu) {
        return ppu->isFrameComplete;
}

void PpuResetFrameCompletion(struct ppu *ppu) {
        ppu->isFrameComplete = false;
}

M ppu.h => ppu.h +11 -2
@@ 8,14 8,14 @@
  Author: Aaron Oman
  Notice: GNU AGPLv3 License

  Based off of: One Lone Coder NES Emulator Copyright (C) 2018 Javidx9
  Based off of: One Lone Coder NES Emulator Copyright (C) 2019 Javidx9
  This program comes with ABSOLUTELY NO WARRANTY.
  This is free software, and you are welcome to redistribute it under certain
  conditions; See LICENSE for details.
 ******************************************************************************/
//! \file ppu.h
#ifndef PPU_VERSION
#define PPU_VERSION "0.1.0"
//! \file ppu.h

struct ppu;
struct cart;


@@ 32,4 32,13 @@ PpuAttachCart(struct ppu *ppu, struct cart *cart);
void
PpuTick(struct ppu *ppu);

void
PpuReset(struct ppu *ppu);

int
PpuIsFrameComplete(struct ppu *ppu);

void
PpuResetFrameCompletion(struct ppu *ppu);

#endif // PPU_VERSION

M sprite.c => sprite.c +2 -2
@@ 8,17 8,17 @@
  Author: Aaron Oman
  Notice: GNU AGPLv3 License

  Based off of: One Lone Coder NES Emulator Copyright (C) 2018 Javidx9
  Based off of: One Lone Coder NES Emulator Copyright (C) 2019 Javidx9
  This program comes with ABSOLUTELY NO WARRANTY.
  This is free software, and you are welcome to redistribute it under certain
  conditions; See LICENSE for details.
******************************************************************************/
//! \file sprite.c
#include <stdlib.h> // malloc, free
#include <math.h> // fmin

#include "sprite.h"
#include "color.h"
//! \file sprite.c

struct sprite {
        struct color *pixels;

M sprite.h => sprite.h +2 -2
@@ 8,13 8,13 @@
  Author: Aaron Oman
  Notice: GNU AGPLv3 License

  Based off of: One Lone Coder NES Emulator Copyright (C) 2018 Javidx9
  Based off of: One Lone Coder NES Emulator Copyright (C) 2019 Javidx9
  This program comes with ABSOLUTELY NO WARRANTY.
  This is free software, and you are welcome to redistribute it under certain
  conditions; See LICENSE for details.
 ******************************************************************************/
#include <stdint.h>
//! \file sprite.h
#include <stdint.h>

struct sprite;
struct color;

M util.h => util.h +4 -3
@@ 8,20 8,21 @@
  Author: Aaron Oman
  Notice: GNU AGPLv3 License

  Based off of: One Lone Coder NES Emulator Copyright (C) 2018 Javidx9
  Based off of: One Lone Coder NES Emulator Copyright (C) 2019 Javidx9
  This program comes with ABSOLUTELY NO WARRANTY.
  This is free software, and you are welcome to redistribute it under certain
  conditions; See LICENSE for details.
 ******************************************************************************/
#include <stdint.h>
//! \file util.h
#include <stdint.h>

#ifndef UTIL_VERSION
#define UTIL_VERSION "0.1.0"
#define UTIL_VERSION "0.1-gsnes"

#define S_AS_MS(x) (x) * 1000.0 //!< Convert seconds to milliseconds
#define NS_AS_MS(x) (x) / 1000000.0 //!< Convert nanoseconds to milliseconds
#define MS_AS_NS(x) (x) * 1000000.0 //!< Convert milliseconds to nanoseconds
#define S_AS_NS(x) (x) * 1000000000 //!< Convert seconds to nanoseconds
#define HZ_AS_MS(x) (1.0 / (x)) * 1000.0 //!< Convert hertz to milliseconds per frame

#define B_AS_KB(x) (x) * (1.0 / 1024)