let me show you my code:MottZilla wrote:There are many ways to do various parts of the emulator. Using a ReadMem type function to handle reading is one way. And yes your example seems correct.
I'm not sure what you mean about large blocks of memory.
Code: Select all
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
#include <conio2.h>
#include <string.h>
// DECLARACION DE DEFINES
#define LD_IMM(REG) REG = mem[++pc]; pc++; z_flag = !(REG); n_flag = REG & 0x80
#define LD_ABS(REG) REG = ReadMem((mem[pc + 2] << 8) | mem[pc + 1]); pc += 3; z_flag = !(REG); n_flag = REG & 0x80
#define LD_ZP(REG) REG = ReadMem((mem[++pc] << 8) | 0x00); pc++; z_flag = !(REG); n_flag = REG & 0x80
#define LD_ABSIND(REG,IND) REG = ReadMem(((mem[pc + 2] << 8) | mem[pc + 1]) + IND); pc += 3; z_flag = !(REG); n_flag = REG & 0x80
#define ST_ABS(REG) WriteMem((mem[pc + 2] << 8) | mem[pc + 1],REG); pc += 3;
#define IN(REG) REG++; pc++; z_flag = !(REG); n_flag = REG & 0x80
#define CP_IMM(REG) if(REG < mem[++pc]) { n_flag = 1; z_flag = c_flag = 0; }; \
if(REG == mem[pc]) { n_flag = 0; z_flag = c_flag = 1; }; \
if(REG > mem[pc]) { n_flag = z_flag = 0; c_flag = 1; };\
pc++;
#define BRANCH(FLAG,VALUE) pc += 2; if(FLAG == VALUE) { pc--; (mem[pc] > 0x7f) ? pc -= (~mem[pc] & 0x00ff) : pc += (mem[pc] & 0x00ff); }
// DECLARACION DE FUNCIONES
static inline unsigned char ReadMem(int addr);
static inline void WriteMem(int addr,int value);
static inline void WritePPU(int value);
// DECLARACION DE VARIABLES GLOBALES
unsigned char *mem,*ROM,*VRAM;
unsigned int pc;
// INICIO DEL PROGRAMA PRINCIPAL
int main(void)
{
int tecla;
char romname[50];
FILE *romfile;
unsigned long int ciclos_cpu;
int z_flag,n_flag,c_flag;
int acc,x,y;
int opcode;
int RomBanks16kb;
unsigned int InitPC;
const char tabla_ciclos_cpu[256] = // Vector que almacena los ciclos usados por cada opcode
{
7,6,2,8,3,3,5,5,3,2,2,2,4,4,6,6,2,5,2,8,4,4,6,6,2,4,2,7,5,5,7,7,
6,6,2,8,3,3,5,5,4,2,2,2,4,4,6,6,2,5,2,8,4,4,6,6,2,4,2,7,
5,5,7,7,6,6,2,8,3,3,5,5,3,2,2,2,3,4,6,6,2,5,2,8,4,4,6,6,2,4,2,7,
5,5,7,7,6,6,2,8,3,3,5,5,4,2,2,2,5,4,6,6,2,5,2,8,4,4,6,6,
2,4,2,7,5,5,7,7,2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,2,6,2,6,4,4,4,4,
2,5,2,5,5,5,5,5,2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,2,5,2,5,
4,4,4,4,2,4,2,5,4,4,4,4,2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6,2,5,2,8,
4,4,6,6,2,4,2,7,5,5,7,7,2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6,
2,5,2,8,4,4,6,6,2,4,2,7,5,5,7,7
};
clrscr();
strcpy(romname,"demo.nes");
romfile = fopen(romname,"rb");
mem = (unsigned char *)malloc(0x10000);
VRAM = (unsigned char *)malloc(0x4000);
memset(mem,0,0x10000);
memset(VRAM,0,0x4000);
fseek(romfile,16,0);
fread(&mem[0x8000],1,0x4000,romfile);
fseek(romfile,16,0);
fread(&mem[0xc000],1,0x4000,romfile);
fseek(romfile,16400,0);
fread(VRAM,1,0x2000,romfile);
fclose(romfile);
InitPC = (mem[0xfffd] << 8) | mem[0xfffc];
pc = InitPC;
acc = x = y = ciclos_cpu = 0;
for(;;)
{
opcode = mem[pc];
switch(opcode)
{
// LDx IMMEDIATE
case 0xa9: LD_IMM(acc); break;
case 0xa2: LD_IMM(x); break;
case 0xa0: LD_IMM(y); break;
// LDx ABSOLUTE
case 0xad: LD_ABS(acc); break;
case 0xae: LD_ABS(x); break;
case 0xac: LD_ABS(y); break;
// LDx ZERO PAGE
case 0xa5: LD_ZP(acc); break;
case 0xa6: LD_ZP(x); break;
case 0xa4: LD_ZP(y); break;
// LDx ABSOLUTE INDEXED
case 0xbd: LD_ABSIND(acc,x); break;
case 0xb9: LD_ABSIND(acc,y); break;
case 0xbe: LD_ABSIND(x,y); break;
case 0xbc: LD_ABSIND(y,x); break;
// STx ABSOLUTE
case 0x8d: ST_ABS(acc); break;
case 0x8e: ST_ABS(x); break;
case 0x8c: ST_ABS(y); break;
// INx IMPLIED
case 0xe8: IN(x); break;
case 0xc8: IN(y); break;
// CPx IMMEDIATE
case 0xc9: CP_IMM(y); break;
case 0xe0: CP_IMM(x); break;
case 0xc0: CP_IMM(y); break;
// BRANCH RELATIVE
case 0xd0: BRANCH(z_flag,0); break;
case 0xf0: BRANCH(z_flag,1); break;
case 0x90: BRANCH(c_flag,0); break;
case 0xb0: BRANCH(c_flag,1); break;
case 0x10: BRANCH(n_flag,0); break;
case 0x30: BRANCH(n_flag,1); break;
default:
printf("%X: %X\n",pc,mem[pc]);
pc++;
break;
}
ciclos_cpu = tabla_ciclos_cpu[opcode];
while(kbhit())
{
tecla = getch();
if(tecla == 27) { free(mem); free(ROM); exit(0); }
}
}
free(mem);
free(ROM);
return 0;
}
static inline unsigned char ReadMem(int addr)
{
unsigned char temp2002,temp2007;
if(addr < 0x2000) return mem[addr];
else
{
switch(addr)
{
case 0x2002:
temp2002 = VRAM[addr];
VRAM[addr] &= 0x7f; // Ponemos el bit 7 a 0
VRAM[0x2005] = VRAM[0x2006] = 0;
return temp2002;
break;
case 0x2004:
return VRAM[0x2003];
break;
case 0x2007:
temp2007 = VRAM[0x2007];
(VRAM[0x2000] & 0x4) == 0 ? VRAM[0x2006]++ : VRAM[0x2006] += 32;
return temp2007;
break;
}
}
return 0;
}
static inline void WriteMem(int addr,int value)
{
int temp2006;
static int PrimeraLectura = 1; // Valor 1 si es la primera lectura, 0 lo contrario
switch(addr)
{
case 0x2000:
case 0x2001:
VRAM[addr] = value;
break;
case 0x2006:
if(PrimeraLectura == 1)
{
temp2006 = mem[pc + 1] << 8;
PrimeraLectura = 0;
}
else
{
temp2006 |= mem[pc + 1];
PrimeraLectura = 1;
}
break;
case 0x2007:
if((VRAM[0x2002] & 0x10) == 1) break;
else WritePPU(value);
break;
}
return;
}
static inline void WritePPU(int value)
{
return;
}