nes.cpp

00001 #include "openem.h"
00002 #include "cpu/debug/cpudbg.h"
00003 #include "cpu/M65C02/M65C02.h"
00004 #include "arch/nes/ppu.h"
00005 #include "arch/nes/mmc.h"
00006 #include "arch/nes/joypad.h"
00007 #include "arch/nes/nes.h"
00008 #include <stdlib.h>
00009 #include <stdio.h>
00010 #include <string.h>
00011 
00012 void NES::pass_message(OE_MESSAGE *mes)
00013 {
00014 }
00015 
00016 void NES::dumpdebug(void)
00017 {
00018     // Dump the 6502's debug list
00019     CPU_DEBUG_LIST *dlist = &m6502.dbg.list;
00020     char *tr;
00021     dlist->seek_first();
00022     if (dlist->getcur() == NULL) return;
00023     printf("\n");
00024     for (;;) {
00025         tr = m6502.debug_str((CPU_M65C02_DEBUG_STATE *)dlist->getcur()->cstate);
00026         printf("\n%s",tr);
00027         free(tr);
00028         dlist->seek_next();
00029         if (dlist->getcur() == dlist->getlast()) { break; }
00030     }
00031     dlist->clear(); 
00032 }
00033 
00034 NES *curnes;
00035 // 0x2000-0x3FFF
00036 void writereg(void *ref, dword addr, byte data)
00037 {
00038     curnes->ppu.writereg(addr,data);
00039 }
00040 
00041 byte readreg(void *ref, dword addr)
00042 {
00043     return curnes->ppu.readreg(addr);
00044 }
00045 
00046 // Generic read/write
00047 void write8(void *ref, dword addr, byte data)
00048 {
00049 }
00050 
00051 byte read8(void *ref, dword addr)
00052 {
00053     return 0;
00054 }
00055 
00056 
00057 // 0x4000-0x5FFF
00058 void writeodd(void *ref, dword addr, byte data)
00059 {
00060     if (addr == 0x4014)
00061         curnes->ppu.writereg(addr,data);
00062     if (addr == 0x4016)
00063         curnes->jpad1.writereg(data);
00064     if (addr == 0x4017)
00065         curnes->jpad2.writereg(data);
00066 }
00067 
00068 byte readodd(void *ref, dword addr)
00069 {
00070     if (addr == 0x4016)
00071         return curnes->jpad1.readreg();
00072     if (addr == 0x4017)
00073         return curnes->jpad2.readreg();
00074     return 0;
00075 }
00076 
00077 // 0x8000-0xFFFF
00078 void writerom(void *ref, dword addr, byte data)
00079 {
00080 }
00081 
00082 void NES::reset(void)
00083 {
00084     m6502.reset();
00085 }
00086 
00087 // Draw a frame!
00088 void NES::doframe(void)
00089 {
00090     curnes = this;
00091     // Start the frame
00092     ppu.start_frame();
00093     uint32 i;
00094     // Do all scanlines
00095     for (i = 0; i < 262; i++) {
00096         ppu.set_scanline(i);
00097         m6502.NMI = ppu.NMI;
00098         m6502.cycle(114);       // About 114 cycles per line (113.9, but yeah...)
00099         ppu.draw_scanline(i);
00100     }
00101     // Now end the ppu's frame
00102     ppu.end_frame();
00103 }
00104 
00105 int NES::load_rom(char *fill)
00106 {
00107     FILE *fil = 0;
00108     char *yo;
00109     int er = 0;
00110     byte *curbank;
00111     byte mnum;
00112 
00113     yo = (char *)malloc(100);
00114 
00115     fil = fopen(fill,"rb");
00116     if (!fil) { printf("nofileopen"); er = -1; goto efunc; }
00117 
00118     // Get the NES format descriptor
00119     fread(yo,1,4,fil);
00120     if ((*yo != 'N') && (*(yo+1) != 'E') && (*(yo+2) != 'S') && (*(yo+3) != 0x1A)) { printf("wrongfiletype"); er = -2; goto efunc; }
00121 
00122     // Get the number of ROM and VROM banks, then allocate them!
00123     fread(yo,1,2,fil);
00124     numrombanks = *yo;
00125     numvrombanks = *(yo+1);
00126 
00127     romb = (byte *)malloc(0x4000 * numrombanks);
00128     vromb = (byte *)malloc(0x2000 * numvrombanks);
00129 
00130     // Setup mirroring and stuff!
00131     fread(yo,1,2,fil);
00132     if (*yo & 1) { ppu.mirrormode = MIRROR_VERTICAL; } else { ppu.mirrormode = MIRROR_HORIZONTAL; }
00133     if (*yo & 2) { sram = true; } else { sram = false; }
00134     if (*yo & 8) { ppu.mirrormode = MIRROR_FOURWAY; }
00135 
00136     mnum = (((*yo) >> 4) << 4) | (*(yo+1));
00137 
00138     // 8 blank bytes
00139     fread(yo,1,8,fil);
00140 
00141     // Now load program rom
00142     curbank = romb;
00143     int i;
00144     for (i = 0; i < numrombanks; i++) {
00145         fread(curbank,1,0x4000,fil);
00146         curbank += 0x4000;
00147     }
00148 
00149     // Now the vrom...
00150     curbank = vromb;
00151     for (i = 0; i < numvrombanks; i++) {
00152         fread(curbank,1,0x2000,fil);
00153         curbank += 0x2000;
00154     }
00155 
00156     // Now map the memory!!!
00157     curbank = romb;
00158     if (numrombanks == 1) {
00159         // 0xC000... mirrors 0x8000-0xC000
00160         //for (i = 0x80; i < 0xC0; i++) { memp[i] = memp[i+0x40] = curbank; curbank += 0x0100; }
00161         memcpy((mem+0x8000),romb,0x4000);
00162         memcpy((mem+0xC000),romb,0x4000);
00163     }
00164     else {
00165         // 0x8000 and 0xC000 are diff.
00166         //for (i = 0x80; i < 0x100; i++) { memp[i] = curbank; curbank += 0x100; }
00167         memcpy((mem+0x8000),romb,0x4000);
00168         memcpy((mem+0xC000),(romb+0x4000),0x4000);
00169     }
00170 
00171     if (numvrombanks == 1) {
00172         memcpy(ppu.vram,vromb,0x2000);
00173     }
00174 
00175     ppu.setmapper();
00176 
00177 efunc:
00178     if (fil) fclose(fil);
00179     free(yo);
00180     return er;
00181 }
00182 
00183 void NES::init(void)
00184 {
00185     // Setup the M6502
00186     m6502.init();                                   // Init it
00187     m6502.set_mode(M65C02_MODE_2A03, false);        // Set it to be a regular 2A03 w/ no nonstandard-op support
00188 
00189     // Set up the joyapds
00190     jpad1.set_type(0, NESJTYPE_REGULAR, 1);         // Joypad 1: regular, connected
00191     jpad2.set_type(1, NESJTYPE_REGULAR, 0);         // Joypad 2: regular, not connected
00192     // Reserve 64k of memory
00193     mem = (byte *)malloc(65536);
00194     ppu.mem = mem;
00195     ppu.init();
00196     ppu.mycpu = &m6502;
00197 
00198     curnes = this;                                  // Set memory functions to work for this
00199     romloaded = false;
00200     vromyes = false;
00201 
00202     // Set up memory mapping
00203     m6502.mem.create_pagetable(256,256);    // 256 pages of 256 bytes each
00204     dword i;
00205 
00206     // Internal RAM mirrored 4 times, read/writeable
00207     oe_pagetable_ptrtable *calls = m6502.mem.calls;
00208     OE_PT_FLAG *flags = m6502.mem.flags;
00209     byte *mptr = mem;
00210     byte **e = (byte **)m6502.mem.mem;
00211     // This doens't need a call table
00212     for (i = 0; i < 0x08; i++) {
00213         *flags = *(flags+8) = *(flags+16) = *(flags+24) = (OE_PT_FLAG_READABLE | OE_PT_FLAG_WRITEABLE);
00214         *e = *(e+8) = *(e+16) = *(e+24) = mptr;
00215         calls->rm8 = (calls+8)->rm8 = (calls+16)->rm8 = (calls+24)->rm8 = &read8;
00216         calls->wm8 = (calls+8)->wm8 = (calls+16)->wm8 = (calls+24)->wm8 = &write8;
00217         mptr+=256;
00218         e++;
00219         flags++;
00220         calls++;
00221     }
00222 
00223     // mptr, flags, and calls are at 0x07 now. We want them at 0x20.
00224     flags = (m6502.mem.flags+0x20);
00225     mptr = (mem+(256*0x20));
00226     e = (byte **)(m6502.mem.mem + 0x20);
00227     calls = (m6502.mem.calls+0x20);
00228     // 0x2000 -  0x3FFF: memory-mapped regs every 8 bytes. So, we call regwrite.
00229     for (i = 0x20; i < 0x40; i++) {
00230         *flags = 0;                 // We want it to call the function on read AND write
00231         *e = mptr;                  // Setup what area of memory it is - even though it will NEVER be accessed
00232         calls->rm8 = &readreg;      // Setup call table
00233         calls->wm8 = &writereg;     // Setup call table
00234         mptr+=256;
00235         e++;
00236         flags++;
00237         calls++;
00238     }
00239 
00240     // 0x4000-0x5FFF: Funky stuff
00241     for (i = 0x40; i< 0x60; i++) {
00242         *flags = 0;
00243         *e = mptr;
00244         calls->rm8 = &readodd;
00245         calls->wm8 = &writeodd;
00246         mptr+=256;
00247         e++;
00248         flags++;
00249         calls++;
00250     }
00251 
00252     // 0x6000-0x7FFF: SRAM, but for now let's have it access CPU main memory
00253     for (i = 0x60; i< 0x80; i++) {
00254         *flags = OE_PT_FLAG_READABLE | OE_PT_FLAG_WRITEABLE;
00255         *e = mptr;
00256         calls->rm8 = &read8;
00257         calls->wm8 = &write8;
00258         mptr+=256;
00259         e++;
00260         flags++;
00261         calls++;
00262     }
00263 
00264     // 0x8000-0xFFFF: ROM cartridge. Set it readable (main memory for now - mapper will fix later), but set up the writerom function.
00265     for (i = 0x80; i< 0x100; i++) {
00266         *flags = OE_PT_FLAG_READABLE;
00267         *e = mptr;
00268         calls->rm8 = &read8;
00269         calls->wm8 = &writerom;
00270         mptr+=256;
00271         e++;
00272         flags++;
00273         calls++;
00274     }
00275 
00276     // Setup MMC
00277     mmc.myppu = &ppu;
00278 
00279     // Setup memory writes
00280 //  m6502.read_mem8 = readmem;
00281 //  m6502.write_mem8 = writemem;
00282 }
00283 
00284 void NES::uninit(void)
00285 {
00286     free(mem);
00287     if (vromyes) free(vromb);
00288     if (romloaded) free(romb);
00289     ppu.uninit();
00290 }

Generated on Sat Sep 9 03:50:44 2006 for Openem APIs by  doxygen 1.4.7