fixed mem access violation

This commit is contained in:
Lauchmelder 2021-10-24 13:47:11 +02:00
parent 2b71e3e0d2
commit 56c9dfbe6e
8 changed files with 188 additions and 64 deletions

View file

@ -7,7 +7,7 @@
#include "ppu.h" #include "ppu.h"
#include "cartridge.h" #include "cartridge.h"
struct Bus* createBus() struct Bus* createBus(SDL_Renderer* renderer)
{ {
struct Bus* bus = (struct Bus*)malloc(sizeof(struct Bus)); struct Bus* bus = (struct Bus*)malloc(sizeof(struct Bus));
if (bus == NULL) if (bus == NULL)
@ -40,6 +40,7 @@ struct Bus* createBus()
bus->cpu = createCPU(bus); bus->cpu = createCPU(bus);
// Create PPU and attack it // Create PPU and attack it
bus->screen = renderer;
bus->ppu = createPPU(bus); bus->ppu = createPPU(bus);
bus->masterClockTimer = 0; bus->masterClockTimer = 0;

View file

@ -2,6 +2,7 @@
#define _BUS_H_ #define _BUS_H_
#include "types.h" #include "types.h"
#include <SDL.h>
struct CPU; struct CPU;
struct PPU; struct PPU;
@ -18,10 +19,12 @@ struct Bus
struct Cartridge* cartridge; struct Cartridge* cartridge;
Byte masterClockTimer; Byte masterClockTimer;
SDL_Renderer* screen;
}; };
// Sets up the Bus, allocates memory and creates devices // Sets up the Bus, allocates memory and creates devices
struct Bus* createBus(); struct Bus* createBus(SDL_Renderer* renderer);
// Destroys the bus, cleans up memory and destroys devices on the Bus // Destroys the bus, cleans up memory and destroys devices on the Bus
void destroyBus(struct Bus* bus); void destroyBus(struct Bus* bus);

View file

@ -4,33 +4,6 @@
#include "bus.h" #include "bus.h"
struct INES_Header
{
Byte nestext[4];
Byte prg_rom_size;
Byte chr_rom_size;
struct
{
Byte mirror : 1;
Byte battery : 1;
Byte trainer : 1;
Byte ignore_mirror : 1;
Byte mapper_lower_nibble : 4;
} Flags6;
struct
{
Byte vs : 1;
Byte playchoice : 1;
Byte nes20 : 2;
Byte mapper_upper_nibble : 4;
} Flags7;
Byte prg_ram_size;
Byte unused[7];
};
struct Cartridge* createCartridge(struct Bus* parent, const char* filepath) struct Cartridge* createCartridge(struct Bus* parent, const char* filepath)
{ {
struct Cartridge* cartridge = (struct Cartridge*)malloc(sizeof(struct Cartridge)); struct Cartridge* cartridge = (struct Cartridge*)malloc(sizeof(struct Cartridge));
@ -42,25 +15,24 @@ struct Cartridge* createCartridge(struct Bus* parent, const char* filepath)
FILE* fp = fopen(filepath, "rb"); FILE* fp = fopen(filepath, "rb");
struct INES_Header header; fread(&cartridge->header, sizeof(cartridge->header), 1, fp);
fread(&header, sizeof(header), 1, fp);
cartridge->prg_rom = (Byte*)malloc(0x4000 * (size_t)header.prg_rom_size); cartridge->prg_rom = (Byte*)malloc(0x4000 * (size_t)cartridge->header.prg_rom_size);
if (cartridge->prg_rom == NULL) if (cartridge->prg_rom == NULL)
{ {
fprintf(stderr, "Failed to allocate PRG memory for cartridge, aborting.\n"); fprintf(stderr, "Failed to allocate PRG memory for cartridge, aborting.\n");
exit(1); exit(1);
} }
cartridge->chr_rom = (Byte*)malloc(0x2000 * (size_t)header.chr_rom_size); cartridge->chr_rom = (Byte*)malloc(0x2000 * (size_t)cartridge->header.chr_rom_size);
if (cartridge->chr_rom == NULL) if (cartridge->chr_rom == NULL)
{ {
fprintf(stderr, "Failed to allocate CHR memory for cartridge, aborting.\n"); fprintf(stderr, "Failed to allocate CHR memory for cartridge, aborting.\n");
exit(1); exit(1);
} }
fread(cartridge->prg_rom, 0x4000, header.prg_rom_size, fp); fread(cartridge->prg_rom, 0x4000, cartridge->header.prg_rom_size, fp);
fread(cartridge->chr_rom, 0x2000, header.chr_rom_size, fp); fread(cartridge->chr_rom, 0x2000, cartridge->header.chr_rom_size, fp);
cartridge->bus = parent; cartridge->bus = parent;
return cartridge; return cartridge;

View file

@ -7,6 +7,33 @@ struct Bus;
struct Cartridge struct Cartridge
{ {
struct
{
Byte nestext[4];
Byte prg_rom_size;
Byte chr_rom_size;
struct
{
Byte mirror : 1;
Byte battery : 1;
Byte trainer : 1;
Byte ignore_mirror : 1;
Byte mapper_lower_nibble : 4;
} Flags6;
struct
{
Byte vs : 1;
Byte playchoice : 1;
Byte nes20 : 2;
Byte mapper_upper_nibble : 4;
} Flags7;
Byte prg_ram_size;
Byte unused[7];
} header;
Byte* prg_rom; Byte* prg_rom;
Byte* chr_rom; Byte* chr_rom;

View file

@ -189,7 +189,7 @@ void fetch(struct CPU* cpu)
void execute(struct CPU* cpu) void execute(struct CPU* cpu)
{ {
// LOG_BUS(cpu->bus); LOG_BUS(cpu->bus);
switch (cpu->currentOpcode->op) switch (cpu->currentOpcode->op)
{ {
@ -425,7 +425,7 @@ void execute(struct CPU* cpu)
cpu->y--; cpu->y--;
cpu->status.negative = ((cpu->y & 0x80) == 0x80); cpu->status.negative = ((cpu->y & 0x80) == 0x80);
cpu->status.zero = (cpu->y == 0x80); cpu->status.zero = (cpu->y == 0x00);
} break; } break;
case EOR: case EOR:

View file

@ -1,4 +1,5 @@
#include "bus.h" #include "bus.h"
#include "ppu.h"
#include <stdio.h> #include <stdio.h>
#include <SDL.h> #include <SDL.h>
@ -21,7 +22,7 @@ int main(int argc, char** argv)
exit(1); exit(1);
} }
struct Bus* bus = createBus(); struct Bus* bus = createBus(renderer);
SDL_Event event; SDL_Event event;
int running = 1; int running = 1;
@ -43,12 +44,36 @@ int main(int argc, char** argv)
} }
} }
doFrame(bus); doFrame(bus);
SDL_SetRenderDrawColor(renderer, 20, 0, 20, 0);
SDL_RenderClear(renderer);
SDL_Texture* tableTexture = getPatternTableTexture(bus->ppu, 0);
SDL_Rect target = { 10, 10, 256, 256 };
SDL_RenderCopy(renderer, tableTexture, NULL, &target);
tableTexture = getPatternTableTexture(bus->ppu, 1);
target.x = 256 + 10 + 10;
SDL_RenderCopy(renderer, tableTexture, NULL, &target);
tableTexture = getNameTableTexture(bus->ppu, 0);
target.x = 10;
target.y = 256 + 10 + 10;
SDL_RenderCopy(renderer, tableTexture, NULL, &target);
tableTexture = getNameTableTexture(bus->ppu, 1);
target.x = 256 + 10 + 10;
SDL_RenderCopy(renderer, tableTexture, NULL, &target);
SDL_RenderPresent(renderer);
} }
destroyBus(bus); destroyBus(bus);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit(); SDL_Quit();
return 0; return 0;

View file

@ -4,6 +4,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <memory.h> #include <memory.h>
#include "bus.h" #include "bus.h"
#include "cartridge.h"
struct PPU* createPPU(struct Bus* parent) struct PPU* createPPU(struct Bus* parent)
{ {
@ -16,29 +17,39 @@ struct PPU* createPPU(struct Bus* parent)
ppu->bus = parent; ppu->bus = parent;
ppu->patternTables[0] = (Byte*)malloc(0x1000 * 2);
if (ppu->patternTables[0] == NULL)
{
fprintf(stderr, "Failed to allocate memory for PPU pattern tables.\n");
exit(1);
}
memset(ppu->patternTables[0], 0, 0x1000 * 2);
for (int i = 0; i < 2; i++) for (int i = 0; i < 2; i++)
{ {
ppu->patternTables[i] = (Byte*)malloc(0x1000); ppu->patternTables[i] = ppu->patternTables[0] + ((size_t)0x1000 * i);
if (ppu->patternTables[i] == NULL) ppu->patternTableTextures[i] = SDL_CreateTexture(parent->screen, SDL_PIXELFORMAT_RGB332, SDL_TEXTUREACCESS_STREAMING, 64, 64);
{
fprintf(stderr, "Failed to allocate memory for PPU pattern table #%d object.\n", i);
exit(1);
}
memset(ppu->patternTables[i], 0, 0x1000);
} }
for (int i = 0; i < 4; i++)
ppu->nameTables[0] = (Byte*)malloc(0x0400 * 2);
if (ppu->nameTables[0] == NULL)
{ {
ppu->nametables[i] = (Byte*)malloc(0x0400); fprintf(stderr, "Failed to allocate memory for PPU nameTables.\n");
if (ppu->nametables[i] == NULL) exit(1);
{
fprintf(stderr, "Failed to allocate memory for PPU nametable #%d object.\n", i);
exit(1);
}
memset(ppu->nametables[i], 0, 0x0400);
} }
memset(ppu->nameTables[0], 0, 0x0400 * 2);
for (int i = 0; i < 2; i++)
{
ppu->nameTables[i] = ppu->nameTables[0] + ((size_t)0x0400 * i);
ppu->nameTableTextures[i] = SDL_CreateTexture(parent->screen, SDL_PIXELFORMAT_RGB332, SDL_TEXTUREACCESS_STREAMING, 32, 32);
}
ppu->paletteIndexes = (Byte*)malloc(0x20); ppu->paletteIndexes = (Byte*)malloc(0x20);
if (ppu->paletteIndexes == NULL) if (ppu->paletteIndexes == NULL)
@ -47,6 +58,8 @@ struct PPU* createPPU(struct Bus* parent)
exit(1); exit(1);
} }
ppu->oam = (Byte*)malloc(0x100); ppu->oam = (Byte*)malloc(0x100);
if (ppu->oam == NULL) if (ppu->oam == NULL)
{ {
@ -54,6 +67,9 @@ struct PPU* createPPU(struct Bus* parent)
exit(1); exit(1);
} }
ppu->mirroring = parent->cartridge->header.Flags6.mirror;
ppu->ppuCtrl.raw = 0b00000000; ppu->ppuCtrl.raw = 0b00000000;
ppu->ppuMask.raw = 0b00000000; ppu->ppuMask.raw = 0b00000000;
ppu->ppuStatus.raw = 0b10100000; ppu->ppuStatus.raw = 0b10100000;
@ -64,7 +80,7 @@ struct PPU* createPPU(struct Bus* parent)
ppu->scrollWriteTarget = 0; ppu->scrollWriteTarget = 0;
ppu->ppuAddress.raw = 0x00; ppu->ppuAddress.raw = 0x00;
ppu->ppuAddressWriteTarget = 0; ppu->ppuAddressWriteTarget = 1;
ppu->x = 0; ppu->x = 0;
ppu->y = 0; ppu->y = 0;
@ -76,10 +92,14 @@ void destroyPPU(struct PPU* ppu)
{ {
free(ppu->oam); free(ppu->oam);
free(ppu->paletteIndexes); free(ppu->paletteIndexes);
for(int i = 0; i < 4; i++)
free(ppu->nametables[i]);
for (int i = 0; i < 2; i++) for (int i = 0; i < 2; i++)
free(ppu->patternTables[i]); SDL_DestroyTexture(ppu->nameTableTextures[i]);
free(ppu->nameTables[0]);
for (int i = 0; i < 2; i++)
SDL_DestroyTexture(ppu->patternTableTextures[i]);
free(ppu->patternTables[0]);
free(ppu); free(ppu);
} }
@ -106,8 +126,31 @@ Byte ppuRead(struct PPU* ppu, Word addr)
break; break;
case 0x2007: case 0x2007:
val = ppu->nametables[ppu->ppuAddress.raw & 0x2000][ppu->ppuAddress.raw & 0x1FFF]; {
if (ppu->ppuAddress.raw < 0x2000)
{
val = ppu->patternTables[0][ppu->ppuAddress.raw];
}
else if (0x2000 <= ppu->ppuAddress.raw && ppu->ppuAddress.raw < 0x3F00)
{
Word effectiveAddress = ppu->ppuAddress.raw;
effectiveAddress &= ~(0x0400 + ppu->mirroring * 0x0400);
if (effectiveAddress >= 0x2800)
effectiveAddress -= 0x0400;
val = ppu->nameTables[0][(effectiveAddress - 0x2000) & 0x0FFF];
}
else if (0x3F00 <= ppu->ppuAddress.raw && ppu->ppuAddress.raw < 0x4000)
{
val = ppu->paletteIndexes[(ppu->ppuAddress.raw - 0x3F00) & 0x1F];
}
else
{
fprintf(stderr, "PPU access violation at $%04X", ppu->ppuAddress.raw);
exit(1);
}
ppu->ppuAddress.raw += ppu->ppuCtrl.increment; ppu->ppuAddress.raw += ppu->ppuCtrl.increment;
}
break; break;
default: default:
@ -144,9 +187,32 @@ void ppuWrite(struct PPU* ppu, Word addr, Byte val)
break; break;
case 0x2007: case 0x2007:
ppu->nametables[ppu->ppuAddress.raw & 0x2000][ppu->ppuAddress.raw & 0x1FFF] = val; {
ppu->ppuAddress.raw += ppu->ppuCtrl.increment; if (ppu->ppuAddress.raw < 0x2000)
{
ppu->patternTables[0][ppu->ppuAddress.raw] = val;
}
else if(0x2000 <= ppu->ppuAddress.raw && ppu->ppuAddress.raw < 0x3F00)
{
Word effectiveAddress = ppu->ppuAddress.raw;
effectiveAddress &= ~(0x0400 + ppu->mirroring * 0x0400);
if (effectiveAddress >= 0x2800)
effectiveAddress -= 0x0400;
ppu->nameTables[0][(effectiveAddress - 0x2000) & 0x0FFF] = val;
}
else if (0x3F00 <= ppu->ppuAddress.raw && ppu->ppuAddress.raw < 0x4000)
{
ppu->paletteIndexes[(ppu->ppuAddress.raw - 0x3F00) & 0x1F] = val;
}
else
{
fprintf(stderr, "PPU access violation at $%04X", ppu->ppuAddress.raw);
exit(1);
}
ppu->ppuAddress.raw += (ppu->ppuCtrl.increment == 0 ? 1 : 32);
break; break;
}
default: default:
fprintf(stderr, "Write access violation at PPU register: $%04X", addr); fprintf(stderr, "Write access violation at PPU register: $%04X", addr);
@ -169,3 +235,25 @@ int tickPPU(struct PPU* ppu)
return (ppu->x == 0 && ppu->y == 0); return (ppu->x == 0 && ppu->y == 0);
} }
SDL_Texture* getPatternTableTexture(struct PPU* ppu, int index)
{
SDL_Texture* target = ppu->patternTableTextures[index];
int pitch;
void* pixels;
SDL_LockTexture(target, NULL, &pixels, &pitch);
SDL_memcpy(pixels, ppu->patternTables[index], 0x1000);
SDL_UnlockTexture(target);
return target;
}
SDL_Texture* getNameTableTexture(struct PPU* ppu, int index)
{
SDL_Texture* target = ppu->nameTableTextures[index];
int pitch;
void* pixels;
SDL_LockTexture(target, NULL, &pixels, &pitch);
SDL_memcpy(pixels, ppu->nameTables[index], 0x0400);
SDL_UnlockTexture(target);
return target;
}

View file

@ -77,7 +77,12 @@ struct PPU
Byte oamdma; Byte oamdma;
Byte* patternTables[2]; Byte* patternTables[2];
Byte* nametables[4]; SDL_Texture* patternTableTextures[2];
Byte* nameTables[2];
SDL_Texture* nameTableTextures[2];
Byte mirroring;
Byte* paletteIndexes; Byte* paletteIndexes;
union union
@ -106,4 +111,7 @@ void ppuWrite(struct PPU* ppu, Word addr, Byte val);
int tickPPU(struct PPU* ppu); int tickPPU(struct PPU* ppu);
SDL_Texture* getPatternTableTexture(struct PPU* ppu, int index);
SDL_Texture* getNameTableTexture(struct PPU* ppu, int index);
#endif // _PPU_H_ #endif // _PPU_H_