~groovestomp/gsnes

674f2642b2552acf4fc467d9adcb663f3c3c5043 — GrooveStomp 1 year, 5 months ago 78fc0c6
Cleaned up several errors after running with Valgrind
7 files changed, 107 insertions(+), 77 deletions(-)

M cpu.c
M graphics.c
M input.c
M input.h
M main.c
M ppu.c
M sprite.c
M cpu.c => cpu.c +47 -39
@@ 5,7 5,7 @@

  File: cpu.c
  Created: 2019-10-16
  Updated: 2019-11-30
  Updated: 2019-12-01
  Author: Aaron Oman
  Notice: GNU AGPLv3 License



@@ 1405,10 1405,10 @@ uint8_t XXX(struct cpu *cpu) {


char **CpuDebugStateInit(struct cpu *cpu, int *numLines) {
        char **debug = (char **)malloc(sizeof(char *) * 7);
        char **debug = (char **)calloc(7, sizeof(char *));

        debug[0] = "        N V - B D I Z C";
        debug[1] = malloc(strlen("status: 1 1 - 1 1 1 1 1") + 1);
        debug[1] = calloc(strlen("status: 1 1 - 1 1 1 1 1") + 1, sizeof(char));

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


@@ 1424,19 1424,19 @@ char **CpuDebugStateInit(struct cpu *cpu, int *numLines) {

        #pragma GCC diagnostic pop

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

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

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

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

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

        *numLines = 7;


@@ 1449,21 1449,23 @@ void CpuDebugStateDeinit(char **debug) {
                return;

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

        free(debug);
}

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

        self->text = malloc(length);
        self->text = calloc(length + 1, sizeof(char));
        if (NULL == self->text) {
                free(self);
                DebugInstructionDeinit(self);
                return NULL;
        }



@@ 1498,7 1500,7 @@ struct disassembly *DisassemblyInit(struct cpu *cpu, uint16_t start, uint16_t st
        disassembly->count = stop - start;
        disassembly->map = (struct debug_instruction **)calloc(disassembly->count, sizeof(struct debug_instruction *));
        if (NULL == disassembly->map) {
                free(disassembly);
                DisassemblyDeinit(disassembly);
                return NULL;
        }



@@ 1509,104 1511,105 @@ struct disassembly *DisassemblyInit(struct cpu *cpu, uint16_t start, uint16_t st
        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.
                uint8_t hexBufLen = 5; // Space for terminating null.
                char hex_buf[hexBufLen];
                memset(hex_buf, 0, hexBufLen);
                uint16_t textLen = hexBufLen; // Size adjusts as we construct string below.

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

                // Prefix instruction with address.
                HexToString(addr, 4, hex_buf, hex_buf_len);
                text_len += 3; // Adding $, <colon> and <space>
                snprintf(text, text_len, "$%s: ", hex_buf);
                strncpy(text_cpy, text, strnlen(text, text_len) + 1);
                HexToString(addr, 4, hex_buf, hexBufLen);
                textLen += 3; // Adding $, <colon> and <space>
                snprintf(text, textLen, "$%s: ", hex_buf);
                strncpy(text_cpy, text, strnlen(text, textLen) + 1);

                // Get the readable name of the instruction.
                uint8_t opcode = BusRead(cpu->bus, addr, true);
                instruction = instruction_map[opcode];
                addr++;
                text_len += 4; // instruction.name is 3 chars, plus an extra space.
                snprintf(text, text_len, "%s%s ", text_cpy, instruction.name); //<--
                strncpy(text_cpy, text, strnlen(text, text_len));
                textLen += 4; // instruction.name is 3 chars, plus an extra space.
                snprintf(text, textLen, "%s%s ", text_cpy, instruction.name); //<--
                strncpy(text_cpy, text, strnlen(text, textLen));

                if (IMP == instruction.address) {
                        snprintf(text, 256, "%s {IMP}", text_cpy);
                } else if (IMM == instruction.address) {
                        value = BusRead(cpu->bus, addr, true);
                        addr++;
                        HexToString(value, 2, hex_buf, hex_buf_len);
                        HexToString(value, 2, hex_buf, hexBufLen);
                        snprintf(text, 256, "%s#$%s {IMM}", text_cpy, hex_buf);
                } else if (ZP0 == instruction.address) {
                        lo = BusRead(cpu->bus, addr, true);
                        addr++;
                        hi = 0x00;
                        HexToString(lo, 2, hex_buf, hex_buf_len);
                        HexToString(lo, 2, hex_buf, hexBufLen);
                        snprintf(text, 256, "%s$%s {ZP0}", text_cpy, hex_buf);
                } else if (ZPX == instruction.address) {
                        lo = BusRead(cpu->bus, addr, true);
                        addr++;
                        hi = 0x00;
                        HexToString(lo, 2, hex_buf, hex_buf_len);
                        HexToString(lo, 2, hex_buf, hexBufLen);
                        snprintf(text, 256, "%s$%s, X {ZPX}", text_cpy, hex_buf);
                } else if (ZPY == instruction.address) {
                        lo = BusRead(cpu->bus, addr, true);
                        addr++;
                        hi = 0x00;
                        HexToString(lo, 2, hex_buf, hex_buf_len);
                        HexToString(lo, 2, hex_buf, hexBufLen);
                        snprintf(text, 256, "%s$%s, Y {ZPY}", text_cpy, hex_buf);
                } else if (IZX == instruction.address) {
                        lo = BusRead(cpu->bus, addr, true);
                        addr++;
                        hi = 0x00;
                        HexToString(lo, 2, hex_buf, hex_buf_len);
                        HexToString(lo, 2, hex_buf, hexBufLen);
                        snprintf(text, 256, "%s($%s, X) {IZX}", text_cpy, hex_buf);
                } else if (IZY == instruction.address) {
                        lo = BusRead(cpu->bus, addr, true);
                        addr++;
                        hi = 0x00;
                        HexToString(lo, 2, hex_buf, hex_buf_len);
                        HexToString(lo, 2, hex_buf, hexBufLen);
                        snprintf(text, 256, "%s($%s, Y) {IZY}", text_cpy, hex_buf);
                } else if (ABS == instruction.address) {
                        lo = BusRead(cpu->bus, addr, true);
                        addr++;
                        hi = BusRead(cpu->bus, addr, true);
                        addr++;
                        HexToString((uint16_t)(hi << 8) | lo, 4, hex_buf, hex_buf_len);
                        HexToString((uint16_t)(hi << 8) | lo, 4, hex_buf, hexBufLen);
                        snprintf(text, 256, "%s$%s {ABS}", text_cpy, hex_buf);
                } else if (ABX == instruction.address) {
                        lo = BusRead(cpu->bus, addr, true);
                        addr++;
                        hi = BusRead(cpu->bus, addr, true);
                        addr++;
                        HexToString((uint16_t)(hi << 8) | lo, 4, hex_buf, hex_buf_len);
                        HexToString((uint16_t)(hi << 8) | lo, 4, hex_buf, hexBufLen);
                        snprintf(text, 256, "%s$%s, X {ABX}", text_cpy, hex_buf);
                } else if (ABY == instruction.address) {
                        lo = BusRead(cpu->bus, addr, true);
                        addr++;
                        hi = BusRead(cpu->bus, addr, true);
                        addr++;
                        HexToString((uint16_t)(hi << 8) | lo, 4, hex_buf, hex_buf_len);
                        HexToString((uint16_t)(hi << 8) | lo, 4, hex_buf, hexBufLen);
                        snprintf(text, 256, "%s$%s, Y {ABY}", text_cpy, hex_buf);
                } else if (IND == instruction.address) {
                        lo = BusRead(cpu->bus, addr, true);
                        addr++;
                        hi = BusRead(cpu->bus, addr, true);
                        addr++;
                        HexToString((uint16_t)(hi << 8) | lo, 4, hex_buf, hex_buf_len);
                        HexToString((uint16_t)(hi << 8) | lo, 4, hex_buf, hexBufLen);
                        snprintf(text, 256, "%s($%s) {IND}", text_cpy, hex_buf);
                } else if (REL == instruction.address) {
                        value = BusRead(cpu->bus, addr, true);
                        addr++;
                        HexToString(value, 2, hex_buf, hex_buf_len);
                        HexToString(value, 2, hex_buf, hexBufLen);

                        char hex_buf2[5];
                        HexToString(addr + (int8_t)value, 4, hex_buf2, hex_buf_len);
                        HexToString(addr + (int8_t)value, 4, hex_buf2, hexBufLen);
                        snprintf(text, 256, "%s$%s [$%s] {REL}", text_cpy, hex_buf, hex_buf2);
                }

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



@@ 1621,6 1624,11 @@ void DisassemblyDeinit(struct disassembly *disassembly) {
        }

        if (NULL != disassembly->map) {
                for (int i = 0; i < disassembly->count; i++) {
                        if (NULL != disassembly->map[i]) {
                                DebugInstructionDeinit(disassembly->map[i]);
                        }
                }
                free(disassembly->map);
        }


M graphics.c => graphics.c +1 -1
@@ 277,7 277,6 @@ void GraphicsDrawLine(struct graphics *graphics, int x1, int y1, int x2, int y2,

void GraphicsInitText(struct graphics *graphics, unsigned char *ttfBuffer) {
        if (NULL == ttfBuffer) {
                // TODO: error handling
                return;
        }



@@ 312,6 311,7 @@ void GraphicsDrawText(struct graphics *graphics, int x, int y, char *string, int
                                GraphicsPutPixel(graphics, x + xOffset + (w + x0), y - (h + y0), color);
                        }
                }
                free(bitmap);
        }
}


M input.c => input.c +25 -23
@@ 4,7 4,7 @@

  File: input.c
  Created: 2019-06-21
  Updated: 2019-11-26
  Updated: 2019-12-01
  Author: Aaron Oman
  Notice: GNU GPLv3 License



@@ 13,6 13,7 @@
  conditions; See LICENSE for details.
 ******************************************************************************/
//! \file input.c
#include <stdlib.h> // calloc, free
#include <string.h> // memset

#include "SDL2/SDL.h"


@@ 27,40 28,34 @@ struct input {
        SDL_Event event;
        int isQuitPressed;
        struct button_state *keyStates;
        bool *keyStatesNew;
        bool *keyStatesOld;
        bool *keyPressesThisFrame; // boolmap of pressed keys.
        bool *keyPressesLastFrame; // boolmap of pressed keys.
};

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

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

        input->keyStates = (struct button_state *)calloc(KEY_COUNT, sizeof(struct button_state));
        if (NULL == input->keyStates) {
                InputDeinit(input);
                return NULL;
        }

        input->keyStatesNew = (bool *)calloc(KEY_COUNT, sizeof(bool));
        if (NULL == input->keyStatesNew) {
        input->keyPressesThisFrame = (bool *)calloc(KEY_COUNT, sizeof(bool));
        if (NULL == input->keyPressesThisFrame) {
                InputDeinit(input);
                return NULL;
        }

        input->keyStatesOld = (bool *)calloc(KEY_COUNT, sizeof(bool));
        if (NULL == input->keyStatesOld) {
        input->keyPressesLastFrame = (bool *)calloc(KEY_COUNT, sizeof(bool));
        if (NULL == input->keyPressesLastFrame) {
                InputDeinit(input);
                return NULL;
        }

        for (int i = 0; i <= KEY_COUNT; i++) {
                input->keyStates[i] = (struct button_state){ 0 };
        }

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



@@ 74,11 69,11 @@ void InputDeinit(struct input *input) {
        if (NULL != input->keyStates)
                free(input->keyStates);

        if (NULL != input->keyStatesNew)
                free(input->keyStatesNew);
        if (NULL != input->keyPressesThisFrame)
                free(input->keyPressesThisFrame);

        if (NULL != input->keyStatesOld)
                free(input->keyStatesOld);
        if (NULL != input->keyPressesLastFrame)
                free(input->keyPressesLastFrame);

        free(input);
}


@@ 89,22 84,29 @@ void InputProcess(struct input *input) {

        for (enum input_key_enum i = KEY_A; i < KEY_COUNT; i++) {
                int sdlScancode = MapToSdlEnum(i);
                input->keyStatesNew[i] = input->sdlKeyStates[sdlScancode];
                input->keyPressesThisFrame[i] = input->sdlKeyStates[sdlScancode];

                if (input->keyStatesNew[i] == input->keyStatesOld[i]) {
                // The key is not in a _changed_ state - if it was held, it is
                // still held; if it was not, it is still not.
                if (input->keyPressesThisFrame[i] == input->keyPressesLastFrame[i]) {
                        input->keyStates[i].pressed = false;
                        input->keyStates[i].released = false;
                        continue;
                }

                if (input->keyStatesNew[i]) {
                // The key has _changed_ state.

                // Pressed
                if (input->keyPressesThisFrame[i]) {
                        input->keyStates[i].pressed = !input->keyStates[i].held;
                        input->keyStates[i].held = true;
                } else {
                }
                // Released
                else {
                        input->keyStates[i].released = true;
                        input->keyStates[i].held = false;
                }
                input->keyStatesOld[i] = input->keyStatesNew[i];
                input->keyPressesLastFrame[i] = input->keyPressesThisFrame[i];
        }

        while (SDL_PollEvent(&input->event)) {

M input.h => input.h +1 -1
@@ 4,7 4,7 @@

  File: input.h
  Created: 2019-07-21
  Updated: 2019-11-26
  Updated: 2019-12-01
  Author: Aaron Oman
  Notice: GNU GPLv3 License


M main.c => main.c +3 -3
@@ 137,11 137,11 @@ void Init() {
void DrawCpuState(int x, int y) {
        GraphicsDrawText(graphics, x, y, "CPU State", FONT_HEADER_SCALE, 0x000000FF);
        int numLines = 0;
        char **cpu_state = CpuDebugStateInit(cpu, &numLines);
        char **cpuState = CpuDebugStateInit(cpu, &numLines);
        for (int i = 0; i < numLines; i++) {
                GraphicsDrawText(graphics, x, (y - 15) - (18 * i), cpu_state[i], FONT_SCALE, 0x000000FF);
                GraphicsDrawText(graphics, x, (y - 15) - (18 * i), cpuState[i], FONT_SCALE, 0x000000FF);
        }
        CpuDebugStateDeinit(cpu_state);
        CpuDebugStateDeinit(cpuState);
}

void DrawDisassembly(struct disassembly *disassembly, int x, int y, int numLines) {

M ppu.c => ppu.c +28 -8
@@ 4,7 4,7 @@

  File: ppu.c
  Created: 2019-11-03
  Updated: 2019-11-29
  Updated: 2019-12-01
  Author: Aaron Oman
  Notice: GNU AGPLv3 License



@@ 117,7 117,7 @@ struct ppu {
};

struct ppu *PpuInit() {
        struct ppu *ppu = (struct ppu *)malloc(sizeof(struct ppu));
        struct ppu *ppu = (struct ppu *)calloc(1, sizeof(struct ppu));
        if (NULL == ppu) {
                return NULL;
        }


@@ 322,7 322,19 @@ void PpuDeinit(struct ppu *ppu) {
        if (NULL != ppu->patternTableSprites) {
                SpriteDeinit(ppu->patternTableSprites[0]);
                SpriteDeinit(ppu->patternTableSprites[1]);
                free(ppu->nameTableSprites);
                free(ppu->patternTableSprites);
        }

        if (NULL != ppu->screen) {
                SpriteDeinit(ppu->screen);
        }

        if (NULL != ppu->paletteTables) {
                free(ppu->paletteTables);
        }

        if (NULL != ppu->palette) {
                free(ppu->palette);
        }

        free(ppu);


@@ 858,6 870,9 @@ void PpuWriteViaCpu(struct ppu *ppu, uint16_t addr, uint8_t data) {
uint8_t PpuReadViaCpu(struct ppu *ppu, uint16_t addr, bool readOnly) {
        uint8_t data = 0x00;

        // Reading from PPU registers can affect their contents so this read
        // only option is used for examining the state of the PPU without
        // changing its state. This is really only used in debug mode.
        if (readOnly) {
                switch(addr) {
                        case 0x0000: // Control


@@ 887,7 902,12 @@ uint8_t PpuReadViaCpu(struct ppu *ppu, uint16_t addr, bool readOnly) {
                        case 0x0007: // PPU Data
                                break;
                }
        } else { // Not ReadOnly
        }

        // These are the live PPU registers that repsond to being read from in
	// various ways. Note that not all the registers are capable of being
	// read from so they just return 0x00
        else { // Not ReadOnly
                switch (addr) {
                        case 0x000: // Control - Not Readable
                                break;


@@ 920,7 940,7 @@ uint8_t PpuReadViaCpu(struct ppu *ppu, uint16_t addr, bool readOnly) {
                        case 0x006: // PPU Address - Not Readable
                                break;

                        case 0x007: // PPU Data TODO
                        case 0x007: // PPU Data
                                // Normal reads are delayed by one cycle, so read the
                                // buffer, then refresh the buffer.
                                data = ppu->dataBuffer;


@@ 962,13 982,13 @@ struct sprite *PpuGetPatternTable(struct ppu *ppu, uint8_t i, uint8_t palette) {
                                // Each pixel is 2 bits, stored in two separate bit planes.
                                // Each bit plane is 64 bits, which means the LSb
                                // and MSb are always 64 bits (8 bytes) apart.
                                uint8_t tileLsb = PpuRead(ppu, i * CHR_ROM + byteOffset + row + 0);
                                uint8_t tileMsb = PpuRead(ppu, i * CHR_ROM + byteOffset + row + 8);
                                uint8_t tileLsb = PpuRead(ppu, i * CHR_ROM + byteOffset + row + 0x0000);
                                uint8_t tileMsb = PpuRead(ppu, i * CHR_ROM + byteOffset + row + 0x0008);

                                // We read 8 bits worth of data, now we iterate
                                // through each column of the current row.
                                for (int col = 0; col < 8; col++) {
                                        uint8_t pixel = (tileLsb & 0x01) + (tileMsb& 0x01);
                                        uint8_t pixel = (tileLsb & 0x01) + (tileMsb & 0x01);

                                        // Shift each byte right one bit so the
                                        // next iteration works on the next

M sprite.c => sprite.c +2 -2
@@ 14,14 14,14 @@
  conditions; See LICENSE for details.
******************************************************************************/
//! \file sprite.c
#include <stdlib.h> // malloc, free
#include <stdlib.h> // calloc, free
#include <math.h> // fmin

#include "sprite.h"
#include "color.h"

struct sprite *SpriteInit(unsigned int width, unsigned int height) {
        struct sprite *sprite = (struct sprite *)malloc(sizeof(struct sprite));
        struct sprite *sprite = (struct sprite *)calloc(1, sizeof(struct sprite));
        if (NULL == sprite) {
                return NULL;
        }