Skip to content

Instantly share code, notes, and snippets.

@gucchan22
Last active August 29, 2015 14:09
Show Gist options
  • Save gucchan22/1b21a47ae3f3380223cc to your computer and use it in GitHub Desktop.
Save gucchan22/1b21a47ae3f3380223cc to your computer and use it in GitHub Desktop.
#include <iostream>
#include <string>
#include <stdio.h>
#include <stdint.h>
#include <SDL2/SDL.h>
#define __DEBUG_FLAG__ 1
class INESParser {
const char *rom_path;
uint8_t *prg_rom = NULL;
uint8_t *chr_rom = NULL;
unsigned int prg_rom_size, chr_rom_size, prg_rom_page, chr_rom_page;
bool vertical_mirroring, horizontal_mirroring;
bool mapper_no; // 0-fixed
enum MirroringType { vertical, horizontal };
public:
explicit INESParser(const char *path) : rom_path(path) {}
~INESParser() { release(); }
void release() {
if(prg_rom) {
delete []prg_rom;
prg_rom = NULL;
}
if(chr_rom) {
delete []chr_rom;
chr_rom = NULL;
}
}
void parse() {
release();
FILE *rom_ptr = fopen(rom_path, "rb");
unsigned char signature[4], tmp_o, tmp_t;
fread(signature, 4, 1, rom_ptr);
if(memcmp(signature, "NES\x1A", 4) == 0) {
fread(&prg_rom_page, 1, 1, rom_ptr);
fread(&chr_rom_page, 1, 1, rom_ptr);
prg_rom_size = prg_rom_page * 0x4000;
chr_rom_size = chr_rom_page * 0x2000;
fread(&tmp_o, 1, 1, rom_ptr); // PPU Flag-0
fread(&tmp_t, 1, 1, rom_ptr); // PPU Flag-1
mapper_no = (tmp_o >> 4) | (tmp_t & 0xf0);
vertical_mirroring = (tmp_o & 1) == 1 ? true : false;
horizontal_mirroring = !vertical_mirroring;
prg_rom = new uint8_t[prg_rom_size];
chr_rom = new uint8_t[chr_rom_size];
fclose(rom_ptr);
//std::cout << "PRG:" << prg_rom_size << "Bytes, CHR:" << chr_rom_size << std::endl;
}
}
void inspect() {
std::cout << "ROM(*.nes) Information:\nMapper:0" << std::endl;
std::cout << "Mirroring:" << (this->getMirroringType() == vertical ? "Vertical" : "Horzontal") << std::endl;
std::cout << "PRG-ROM Size:" << (this->getPrgRomSize() / 1024) << "KB" << std::endl;
std::cout << "CHR-ROM Size:" << (this->getChrRomSize() / 1024) << "KB" << std::endl;
}
uint8_t *getPrgRom() { return prg_rom; }
uint8_t *getChrRom() { return chr_rom; }
MirroringType getMirroringType() { return this->vertical_mirroring ? vertical : horizontal; }
bool is_sram_enable() { return false; }
int mapper_number() { return mapper_no; }
unsigned int getPrgRomSize() { return prg_rom_size; }
unsigned int getChrRomSize() { return chr_rom_size; }
unsigned int getPrgRomPage() { return prg_rom_page; }
unsigned int getChrRomPage() { return chr_rom_page; }
};
uint32_t rgb888[65] = {
0x6b6b6b, 0x001084, 0x08008c, 0x42007b, 0x63005a, 0x6b0010, 0x600000, 0x4f3500,
0x314e18, 0x005a21, 0x215a10, 0x085242, 0x003973, 0x000000, 0x000000, 0x000000,
0xa5a5a5, 0x0042c6, 0x4229ce, 0x6b00bd, 0x942994, 0x9c1042, 0x9c3900, 0x845e21,
0x5f7b21, 0x2d8c29, 0x188e10, 0x2e8663, 0x29739c, 0x000000, 0x000000, 0x000000,
0xefefef, 0x5a8cff, 0x7b6bff, 0xa55aff, 0xd64aff, 0xe7639c, 0xde7b52, 0xce9c29,
0xadb531, 0x7bce31, 0x5ace52, 0x4ac694, 0x4ab5ce, 0x525252, 0x000000, 0x000000,
0xefefef, 0xadc6ff, 0xbdbdff, 0xceb5ff, 0xe7b5ff, 0xf9bbdf, 0xf7c6b5, 0xdec69c,
0xd6d694, 0xc6e79c, 0xb5e7ad, 0xade7c6, 0xaddee7, 0xadadad, 0x000000, 0x000000
};
class RAM {
uint8_t ram_memory[0x800];
public:
explicit RAM() {}
~RAM() {}
uint8_t read(uint16_t addr) const { return ram_memory[addr & 0x07ff]; }
void write(uint16_t addr, uint8_t v) { ram_memory[addr & 0x07ff] = v; }
};
class VM {
RAM& ram;
public:
explicit VM(RAM &nes_ram, const std::string &rom_path) : ram(nes_ram) {
INESParser rom_parser = INESParser(rom_path.c_str());
rom_parser.parse();
}
~VM() {}
uint8_t read_u8(uint16_t addr) {
switch(addr & 0xf000) {
case 0x0000: return ram.read(addr); // RAM Read Access
}
return 0x0000;
}
uint16_t read_u16(uint16_t addr) { return (read_u8(addr) | (read_u8(addr + 1) << 8)); }
void write(uint16_t addr, uint8_t v) {}
};
class RNESGraphics {
SDL_Window *window;
SDL_Renderer *renderer;
SDL_Texture *texture;
const char *window_title;
public:
explicit RNESGraphics(const std::string& wtitle) : window_title(wtitle.c_str()) {
SDL_CreateWindowAndRenderer(256, 240, 0, &window, &renderer);
SDL_SetWindowTitle(window, window_title);
SDL_RendererInfo info;
SDL_GetRendererInfo(renderer,&info);
texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGB888, SDL_TEXTUREACCESS_STREAMING, 256, 240);
}
~RNESGraphics() {
SDL_DestroyTexture(texture);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
}
void executeRendering(uint8_t (&gbuff)[240][256], const uint8_t paletteMask) {
SDL_Event ev;
while(SDL_PollEvent(&ev)) {
if(ev.type == SDL_QUIT) exit(0);
}
uint32_t *line;
uint8_t *line8;
int pitch;
SDL_LockTexture(texture, NULL, reinterpret_cast<void**>(&line8), &pitch);
for(int y = 0; y < 240; y++) {
line = reinterpret_cast<uint32_t*>(line8);
for(int x = 0; x < 256; x++) line[x] = rgb888[gbuff[y][x] & paletteMask];
line8 += pitch;
}
SDL_UnlockTexture(texture);
SDL_RenderClear(renderer);
SDL_Rect rect;
rect.x = 0;
rect.w = 256;
rect.h = 240;
SDL_RenderCopy(renderer, texture, &rect, NULL);
SDL_RenderPresent(renderer);
}
};
class RNESController {
uint8_t keyState;
public:
explicit RNESController() : keyState(0) {}
~RNESController() {}
void onVblank() {
const uint8_t *keyBoardState = SDL_GetKeyboardState(NULL);
SDL_Scancode scancodes[] = {
SDL_SCANCODE_UP, SDL_SCANCODE_DOWN, SDL_SCANCODE_LEFT, SDL_SCANCODE_RIGHT,
SDL_SCANCODE_A, SDL_SCANCODE_B, SDL_SCANCODE_T, SDL_SCANCODE_S,
};
for(int i = 0; i < 8; i++) {
if(keyBoardState[scancodes[i]]) keyState |= i;
}
}
bool isPressed(int index) { return ((keyState >> index) & 1) == 1; }
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment