#include <u.h>
#include <libc.h>
#include <draw.h>
#include "6502.h"
#include "nes.h"
#include "ppu.h"
#include "mmc1.h"
// LSB first: A, B, Select, Start, Up, Down, Left, Right
int buttons = (1<<20), buttoni = 0;
int pr = 0;
byte cpureg[32];
int readhandler(int addr) {
if(addr >= 0x2000 && addr <= 0x2007) return ppuread(addr);
if(addr == 0x4016 || addr == 0x4017) {
if(buttoni >= 32) return 1;
return ((buttons >> (buttoni++)) & 1);
}
if(addr >= 0x4000 && addr <= 0x4017) return cpureg[addr - 0x4000];
sysfatal("read from non-present address %.4x", addr & 0xffff);
return 0;
}
void writehandler(int val, int addr) {
if(addr >= 0x2000 && addr <= 0x2007) ppuwrite(addr, val);
else if(addr >= 0x8000) mmc1write(addr, val);
else if(addr == 0x4014) oamfill(val & 0xff);
else if(addr == 0x4016) {
if((val & 0xFF) == 0) buttoni = 0;
}
else if(addr >= 0x4000 && addr <= 0x4017)
cpureg[addr - 0x4000] = val & 0xff;
else sysfatal("write of %.2x to non-present address %.4x", val & 0xff, addr & 0xffff);
}
void printreg(void) {
char* s = disasm(mem+regPC);
fprint(2, "A %.2x X %.2x Y %.2x P %.2x S %.2x PC %.4x (%.2x) [%c%c%c%c%c%c%c] %s\n",
regA, regX, regY, regP, regS, regPC, mem[regPC],
(regP & (1<<7)) ? 'N' : ' ',
(regP & (1<<6)) ? 'V' : ' ',
(regP & (1<<4)) ? 'B' : ' ',
(regP & (1<<3)) ? 'D' : ' ',
(regP & (1<<2)) ? 'I' : ' ',
(regP & (1<<1)) ? 'Z' : ' ',
(regP & (1<<0)) ? 'C' : ' ',
s
);
free(s);
}
void undefined(void) {
fprint(2, "undefined opcode\n");
regPC--;
printreg();
regPC++;
exits("undefined opcode");
}
NESHeader header;
byte mapper;
char** prg = 0, ** chr = 0;
void loadrom(char* file) {
int i;
int f = open(file, OREAD);
if(!f) sysfatal("can't open %s: %r\n", file);
char magic[4];
read(f, magic, 4);
if(strncmp(magic, "NES\x1A", 4)) sysfatal("invalid rom");
read(f, &header.nprg, 1);
read(f, &header.nchr, 1);
read(f, &header.flags6, 1);
read(f, &header.nram, 1);
read(f, &header.flags7, 1);
char pad[7];
read(f, pad, 7);
print("%d * 16 KB PRG ROM, %d * 8 KB CHR ROM\n", header.nprg, header.nchr);
if(header.flags6 & (1<<2)) seek(f, 512, 1);
mapper = (header.flags6 >> 4) | (header.flags7 & 0xF0);
if(mapper > 1) sysfatal("mapper %d unsupported\n", mapper);
prg = calloc(sizeof(char*), header.nprg);
for(i=0;i<header.nprg;i++) {
prg[i] = calloc(0x4000, 1);
read(f, prg[i], 0x4000);
}
if(header.nchr) {
chr = calloc(sizeof(char*), header.nchr);
for(i=0;i<header.nchr;i++) {
chr[i] = calloc(0x4000, 1);
read(f, chr[i], 0x4000);
}
}
close(f);
memcpy(mem + 0x8000, prg[0], 0x4000);
memcpy(mem + 0xC000, prg[header.nprg - 1], 0x4000);
memset(memt, 3, 2048);
f = open("nes.sav", OREAD);
if(f) {
read(f, mem + 0x6000, 8192);
close(f);
}
memset(memt + 0x6000, 3, 8192);
memset(memt + 0x8000, 1, 0x8000);
regPC = *(word*) (mem + 0xFFFC);
}
void save() {
int f = create("nes.sav", OWRITE | OTRUNC, 0666);
write(f, mem + 0x6000, 8192);
close(f);
}
void drawpixel(int x, int y, int c) {
}
int frames = 0;
void updatedisplay() {
frames++;
}
/*
void alhandler() {
char buf[512];
snprintf(buf, 511, "%d FPS", frames);
SDL_WM_SetCaption(buf, buf);
}
*/
int main(int argc, char** argv) {
if(argc < 2)
sysfatal("%s ROM\n", *argv);
// alarm(1);
// signal(SIGALRM, alhandler);
newwindow("-dx 256 -dy 240");
initdraw(0, 0, "NES emulator");
loadrom(argv[1]);
// pr = 1;
while(1) {
if(pr) printreg();
step();
ppuadvance();
}
}
|