mercredi 25 novembre 2015

Access violation writing location. (C++)

been trying to tackle this problem for a while now, with nothing working. Hopefully, you guys have some useful suggestions. The program itself is a Chip-8 interpreter that I called "Chocolate Chip", for some reason.

Debugged using Visual Studio 2015, Exception thrown at 0x00B02E36 in Chocolate Chip.exe: 0xC0000005: Access violation writing location 0x00B0CF90. The issue occurs on line 296 below. (You should be able to find it.)

#include "def.h"

using namespace std;

bool loadROM()
{
printf("Loading rom...\n");

// Open file
FILE * pFile = fopen("C:\\Users\\Ethan\\Documents\\invaders.c8", "rb");
if (pFile == NULL)
{
    fputs("File error", stderr);
    return false;
}

// Check file size
fseek(pFile, 0, SEEK_END);
long lSize = ftell(pFile);
rewind(pFile);
printf("Filesize: %d\n", (int)lSize);

// Allocate memory to contain the whole file
char * buffer = (char*)malloc(sizeof(char) * lSize);
if (buffer == NULL)
{
    fputs("Memory error", stderr);
    return false;
}

// Copy the file into the buffer
size_t result = fread(buffer, 1, lSize, pFile);
if (result != lSize)
{
    fputs("Reading error", stderr);
    return false;
}

// Copy buffer to Chip8 memory
if ((4096 - 512) > lSize)
{
    for (int i = 0; i < lSize; ++i)
        memory[i + 512] = buffer[i];
}
else
    printf("Error: ROM too big for memory");

// Close file, free buffer
fclose(pFile);
free(buffer);

return true;
}

int emuCPU()
{
if (loadC == 0)
{
    loadROM();
    loadC = 1;
}

opcode = memory[pc] << 8 | memory[pc + 1];

switch (opcode & 0xF000)
{
#pragma region Opcode starting with 0x0

case 0x0000:
    switch (opcode & 0x000F)
    {
    case 0x0000: //Clear screen
        for (int a = 1; a < 32 * 64; a++)
        {
            display[a] = 0;
        }
        drawFlag = 1;

        break;

    case 0x000E: //Return from subroutine
        sp--;
        pc = stack[sp];
        pc += 2;
        break;
    }
    break;
#pragma endregion

#pragma region Opcode starting with 0x1
case 0x1000: //Jumps to address NNN.
    pc = opcode & 0x0FFF;
    break;
#pragma endregion

#pragma region Opcode starting with 0x2
case 0x2000: //Calls subroutine at NNN
    sp++;
    stack[sp] = pc;
    pc = opcode & 0x0FFF;
    break;
#pragma endregion

#pragma region Opcode starting with 0x3
case 0x3000: //Skips the next instruction if vX equals NN
    if (v[(opcode & 0x0F00) >> 8] == (opcode & 0x00FF))
    {
        pc += 4;
    }

    else
    {
        pc += 2;
    }
    break;
#pragma endregion

#pragma region Opcode starting with 0x4
case 0x4000: //Skips the next instruction if vX doesn't equal NN
    if (v[(opcode & 0x0F00) >> 8] != (opcode & 0x00FF))
    {
        pc += 4;
    }

    else
    {
        pc += 2;
    }
    break;
#pragma endregion

#pragma region Opcode starting with 0x5
case 0x5000: //Skips the next instruction if vX equals vY
    if (v[(opcode & 0x0F00) >> 8] == v[(opcode & 0x00F0) >> 4])
    {
        pc += 4;
    }

    else
    {
        pc += 2;
    }
    break;
#pragma endregion

#pragma region Opcode starting with 0x6
case 0x6000: //Sets vX to NN
    v[(opcode & 0x0F00) >> 8] = opcode & 0x00FF;
    pc += 2;
    break;
#pragma endregion

#pragma region Opcode starting with 0x7
case 0x7000: //Adds NN to vX
    v[(opcode & 0x0F00) >> 8] += 0x00FF;
    pc += 2;
    break;
#pragma endregion

#pragma region Opcode starting with 0x8
case 0x8000:
    switch (opcode & 0x000F)
    {
    case 0x0000: //Sets vX to the value of vY
        v[(opcode & 0x0F00) >> 8] = v[(opcode & 0x00F0) >> 4];
        pc += 2;
        break;

    case 0x0001: //Sets vX to vX or vY
        v[(opcode & 0x0F00) >> 8] |= v[(opcode & 0x00F0) >> 4];
        pc += 2;
        break;

    case 0x0002: //Sets vX to vX and vY
        v[(opcode & 0x0F00) >> 8] &= v[(opcode & 0x00F0) >> 4];
        pc += 2;
        break;

    case 0x0003: //Sets vX to vX xor vY
        v[(opcode & 0x0F00) >> 8] ^= v[(opcode & 0x00F0) >> 4];
        pc += 2;
        break;

    case 0x0004: //Adds vY to vX. 
                 //vF is set to 1 when there's a carry, and to 0 when there isn't
        v[(opcode & 0x0F00) >> 8] += v[(opcode & 0x00F0) >> 4];
        if (v[(opcode & 0x00F0) >> 4] > (0xFF - v[(opcode & 0x0F00) >> 8]))
        {
            v[0xF] = 1;
        }
        else
        {
            v[0xF] = 0;
        }
        pc += 2;
        break;

    case 0x0005: //VY is subtracted from VX. 
                 //VF is set to 0 when there's a borrow, and 1 when there isn't.
        v[(opcode & 0x0F00) >> 8] -= v[(opcode & 0x00F0) >> 4];
        if (v[(opcode & 0x00F0) >> 4] > (0xFF - v[(opcode & 0x0F00) >> 8]))
        {
            v[0xF] = 0;
        }
        else
        {
            v[0xF] = 1;
        }
        pc += 2;
        break;

    case 0x0006: //Shifts VX right by one.
        v[0xF] = v[(opcode & 0x0F00) >> 8] & 0x1;
        v[(opcode & 0x0F00) >> 8] >> 1;

        pc += 2;
        break;

    case 0x0007: //Sets VX to VY minus VX. 
                 //VF is set to 0 when there's a borrow, and 1 when there isn't.
        if (v[(opcode & 0x00F0) >> 4] < v[(opcode & 0x0F00) >> 8])
        {
            v[0xF] = 0;
        }
        else
        {
            v[0xF] = 1;
        }
        v[(opcode & 0x0F00) >> 8] = v[(opcode & 0x00F0) >> 4] - v[(opcode & 0x0F00) >> 8];

        pc += 2;
        break;

    case 0x000E: //Shifts VX left by one. V
                 //F is set to the value of the most significant bit of VX before the shift
        v[0xF] = v[(opcode & 0x0F00) >> 8] >> 7;
        v[(opcode & 0x0F00) >> 8] <<= 1;
        pc += 2;
        break;
    }
    break;
#pragma endregion

#pragma region Opcode starting with 0x9
case 0x9000: //Skips the next instruction if VX doesn't equal VY
    if (v[(opcode & 0x0F00) >> 8] != (v[(opcode & 0x0F00) >> 4]))
    {
        pc += 4;
    }

    else
    {
        pc += 2;
    }
    break;
#pragma endregion

#pragma region Opcode starting with 0xA
case 0xA000: //Sets I to the address NNN
    I = opcode & 0x0FFF;
    pc += 2;
    break;
#pragma endregion

#pragma region Opcode starting with 0xB
case 0xB000: //Jumps to the address NNN plus V0
    pc = (opcode & 0x0FFF) + v[0];
    break;
#pragma endregion

#pragma region Opcode starting with 0xC
case 0xC000: //Sets VX to the result of a bitwise and operation on a random number and NN
    v[(opcode & 0x0F00) >> 8] = (rand() % 0xFF) & (opcode & 0x00FF);
    pc += 2;
    break;
#pragma endregion

#pragma region Opcode starting with 0xD
case 0xD000: //Sprites stored in memory at location in index register (I), 8bits wide.
    x = v[(opcode & 0x0F00) >> 8];
    y = v[(opcode & 0x00F0) >> 4];
    height = opcode & 0x000F;

    v[0xF] = 0;
    for (int a = 0; a < height; a++) //Draws sprite at vX and vY
    {
        pixel = memory[I + a];
        for (int b = 0; b < 8; b++)
        {
            if ((pixel & (0x80 >> b)) != 0)
            {
                if (display[(x + b + ((y + a) * 64))] == 1)
                {
                    v[0xF] = 1;
                }
            ->display[x + b + ((y + a) * 64)] ^= 1;<- STOPSHERESTOPSHERESTOPS
            }
        }
    }

    drawFlag = 1;
    pc += 2;
    break;
#pragma endregion

#pragma region Opcode starting with 0xE
case 0xE000:
    switch (opcode & 0x00FF)
    {
    case 0x009E: //Skips the next instruction if the key stored in VX is pressed
        if (keys[v[(opcode & 0x0F00) >> 8]] != 0)
        {
            pc += 4;
        }
        else
        {
            pc += 2;
        }
        break;

    case 0x00A1: //Skips the next instruction if the key stored in VX isn't pressed
        if (keys[v[(opcode & 0x0F00) >> 8]] == 0)
        {
            pc += 4;
        }
        else
        {
            pc += 2;
        }
        break;
    }
    break;
#pragma endregion

#pragma region Opcode starting with 0xF
case 0xF000:
    switch (opcode & 0x00FF)
    {
    case 0x0007: //Sets VX to the value of the delay timer
        v[(opcode & 0x0F00) >> 8] = dt;
        pc += 2;
        break;

    case 0x000A: //A key press is awaited, and then stored in VX
        keyPress = 0;

        for (int a = 0; a < 16; a++)
        {
            if (keys[a] != 0)
            {
                v[(opcode & 0x0F00) >> 8] = a;
                keyPress = 1;
            }
        }
        break;

    case 0x0015: //Sets the delay timer to VX
        dt = v[(opcode & 0x0F00) >> 8];
        pc += 2;
        break;

    case 0x0018: //Sets the sound timer to VX
        st = v[(opcode & 0x0F00) >> 8];
        pc += 2;
        break;

    case 0x001E: //Adds VX to I
        I += v[(opcode & 0x0F00) >> 8];
        if (I > 0xFFF)
        {
            v[0xF] = 1;
        }
        else
        {
            v[0xF] = 0;
        }
        pc += 2;
        break;

    case 0x0029: //Sets I to the location of the sprite for the character in VX
        I = v[(opcode & 0x0F00) >> 8] * 0x5;
        pc += 2;
        break;

    case 0x0033: //Stores the Binary-coded decimal representation of VX
        memory[I] = v[(opcode & 0x0F00) >> 8] / 100;
        memory[I + 1] = (v[(opcode & 0x0F00) >> 8] / 10) % 10;
        memory[I + 2] = (v[(opcode & 0x0F00) >> 8] % 100) % 10;
        pc += 2;
        break;

    case 0x0055: //Stores V0 to VX in memory starting at address I
        for (int a = 0; a <= ((opcode & 0x0F00) >> 8); a++)
        {
            memory[I + a] = v[a];
        }
        I += ((opcode & 0x0F00) >> 8) + 1;
        pc += 2;
        break;

    case 0x0065: //Fills V0 to VX with values from memory starting at address I
        for (int a = 0; a <= ((opcode & 0x0F00) >> 8); a++)
        {
            v[a] = memory[I + a];
        }
        I += ((opcode & 0x0F00) >> 8) + 1;
        pc += 2;
        break;
    }
    break;
#pragma endregion

    if (dt > 0)
    {
        dt--;
    }

    if (st > 0)
    {
        st--;
    }

}
}

void main()
{
while (true)
{
    emuCPU();

    cout << hex << "OPCODE: " << opcode << endl;
    cout << "Draw: " << drawFlag;
    cout << hex << x << endl;
    cout << hex << y << endl;

    Sleep(100);

    }
}

I would like to apologize for how terrible the formatting is, that was forced by StackOverflow's code editor. These discrepancies are not in the actual code.

Again, I am sorry for how long the code is. Kinda sucks.

Aucun commentaire:

Enregistrer un commentaire