Plan 9 from Bell Labs’s /usr/web/sources/contrib/aiju/nes/main.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


#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();
	}
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.