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