Skip to content

Instantly share code, notes, and snippets.

@justinmeiners
Created June 16, 2019 05:30
Show Gist options
  • Save justinmeiners/23951d31501ada97a9e0b4676d6fc01b to your computer and use it in GitHub Desktop.
Save justinmeiners/23951d31501ada97a9e0b4676d6fc01b to your computer and use it in GitHub Desktop.
/* Created By: Justin Meiners (2012)
This is the only worthwhile piece a project I wrote in 2012. I got interested in emulation after watching
[Bisqwit's video](https://www.youtube.com/watch?v=y71lli8MS8s)
It was interesting to learn about how the cartridge data is organized
and how the graphics are stored.
I didn't get very far into the actual emulation, as the CPU has tons of instructions
with slightly different variations and I didn't understand computer architecture at the time.
Bisqwit's method is the best I have seen for handling the tedious instructions. I didn't use C++
so I attempted to combine logical parts with a set of macros.
Resources:
http://fms.komkon.org/EMUL8/HOWTO.html#LABH
http://www.z80.info
http://en.wikipedia.org/wiki/Picture_Processing_Unit
http://sadistech.com/nesromtool/romdoc.html
http://nesdev.icequake.net/NES%20emulation%20discussion.txt
http://opcode-defined.quora.com/How-NES-Graphics-Work-Sprites-and-Palettes
http://www.atarimax.com/jindroush.atari.org/aopc.html#BRK
http://www.thealmightyguru.com/Games/Hacking/Wiki/index.php?title=6502_Opcodes
http://wiki.nesdev.com/w/index.php/NMI
*/
/* 16 kb */
#define ROM_BANK_SIZE 16384
/* 8 kb */
#define VROM_BANK_SIZE 8192
/* 2 kb */
#define RAM_SIZE 2048
ypedef struct
{
u8 romBankCount; /* prg */
u8 vromBankCount; /* char */
u8* ROM;
u8* VROM;
} GamePack_t;
void GamePack_InitWithFile(GamePack_t* pack, const char* path)
{
FILE* file = fopen(path, "rb");
/* header NES 16 bytes */
assert(fgetc(file) == 'N');
assert(fgetc(file) == 'E');
assert(fgetc(file) == 'S');
assert(fgetc(file) == '\32');
/* how many banks of ROM and VROM in cartridge? */
pack->romBankCount = fgetc(file);
pack->vromBankCount = fgetc(file);
fseek(file, 10, SEEK_CUR);
/* allocate and read ROM and VROM */
pack->ROM = malloc(pack->romBankCount * ROM_BANK_SIZE);
pack->VROM = malloc(pack->vromBankCount * VROM_BANK_SIZE);
fread(pack->ROM, ROM_BANK_SIZE, pack->romBankCount, file);
fread(pack->VROM, VROM_BANK_SIZE, pack->vromBankCount, file);
fclose(file);
}
// the images this spat out hand incorrect colors
// because they are depdendant on the color pallete
// which is set dynamically.
// It is still fun to extract the sprites form a ROM yourself!
typedef struct
{
u8 r;
u8 g;
u8 b;
u8 a;
} Pix_t;
void GamePack_VROMDump(GamePack_t* pack)
{
char header[18]={0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
header[12] = 8 & 0xFF;
header[13] = (8 >> 8) & 0xFF;
header[14] = (8) & 0xFF;
header[15] = (8 >> 8) & 0xFF;
header[16] = 32;
char bgPallete[3];
bgPallete[0] = pack->VROM[0x3f00];
bgPallete[1] = pack->VROM[0x3f01];
bgPallete[2] = pack->VROM[0x3f02];
char spritePallete[3];
spritePallete[0] = pack->VROM[0x3f11];
spritePallete[1] = pack->VROM[0x3f12];
spritePallete[2] = pack->VROM[0x3f13];
int i = 0;
int vc = 0;
for (i = 0; i < (VROM_BANK_SIZE / 16); i ++)
{
char file[128];
sprintf(file, "spr_%i.tga", i);
FILE* f = fopen(file, "wb");
fwrite(header, sizeof(header), 1, f);
u8* channel1 = pack->VROM + vc;
vc += 8;
u8* channel2 = pack->VROM + vc;
vc += 8;
Pix_t sprite[64];
int x;
int y;
for (y = 0; y < 8; y ++)
{
for (x = 0; x < 8; x ++)
{
int ind = (7 - x) * 8 + (7 - y);
u8 chan1Val = (channel1[x] & (1 << y)) != 0;
u8 chan2Val = (channel2[x] & (1 << y)) != 0;
u8 pixValue = chan1Val | (chan2Val << 1);
sprite[ind].r = (pixValue == 1) * 255;
sprite[ind].g = (pixValue == 2) * 255;
sprite[ind].b = (pixValue == 3) * 255;
sprite[ind].a = (pixValue != 0) * 255;
}
}
fwrite(sprite, 8 * 8, sizeof(Pix_t), f);
fclose(f);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment