1 #include 2 #include 3 #include 4 #include 5 6 #include 7 #include 8 9 /* NESEMU1 : EMULATOR FOR THE NINTENDO ENTERTAINMENT SYSTEM (R) ARCHITECTURE */ 10 /* Written by and copyright (C) 2011 Joel Yliluoma - http://iki.fi/bisqwit/ */ 11 /* Trademarks are owned by their respective owners. Lawyers love tautologies. */ 12 13 static const char* inputfn = "input.fmv"; 14 15 // Integer types 16 typedef uint_least32_t u32; 17 typedef uint_least16_t u16; 18 typedef uint_least8_t u8; 19 typedef int_least8_t s8; 20 21 // Bitfield utilities 22 template 23 struct RegBit 24 { 25 T data; 26 enum { mask = (1u << nbits) - 1u }; 27 template 28 RegBit& operator=(T2 val) 29 { 30 data = (data & ~(mask << bitno)) | ((nbits > 1 ? val & mask : !!val) << bitno); 31 return *this; 32 } 33 operator unsigned() const { return (data >> bitno) & mask; } 34 RegBit& operator++ () { return *this = *this + 1; } 35 unsigned operator++ (int) { unsigned r = *this; ++*this; return r; } 36 }; 37 38 namespace IO 39 { 40 SDL_Surface *s; 41 void Init() 42 { 43 SDL_Init(SDL_INIT_VIDEO); 44 SDL_InitSubSystem(SDL_INIT_VIDEO); 45 s = SDL_SetVideoMode(256, 240, 32,0); 46 signal(SIGINT, SIG_DFL); 47 } 48 49 void PutPixel(unsigned px,unsigned py, unsigned pixel, int offset) 50 { 51 // The input value is a NES color index (with de-emphasis bits). 52 // We need RGB values. To produce a RGB value, we emulate the NTSC circuitry. 53 // For most part, this process is described at: 54 // http://wiki.nesdev.com/w/index.php/NTSC_video 55 // Incidentally, this code is shorter than a table of 64*8 RGB values. 56 static unsigned palette[3][64][512] = {}, prev=~0u; 57 // Caching the generated colors 58 if(prev == ~0u) 59 for(int o=0; o<3; ++o) 60 for(int u=0; u<3; ++u) 61 for(int p0=0; p0<512; ++p0) 62 for(int p1=0; p1<64; ++p1) 63 { 64 // Calculate the luma and chroma by emulating the relevant circuits: 65 auto s = "\372\273\32\305\35\311I\330D\357}\13D!}N"; 66 int y=0, i=0, q=0; 67 for(int p=0; p<12; ++p) // 12 samples of NTSC signal constitute a color. 68 { 69 // Sample either the previous or the current pixel. 70 int r = (p+o*4)%12, pixel = r < 8-u*2 ? p0 : p1; // Use pixel=p0 to disable artifacts. 71 // Decode the color index. 72 int c = pixel%16, l = c<0xE ? pixel/4 & 12 : 4, e=p0/64; 73 // NES NTSC modulator (square wave between up to four voltage levels): 74 int b = 40 + s[(c > 12*((c+8+p)%12 < 6)) + 2*!(0451326 >> p/2*3 & e) + l]; 75 // Ideal TV NTSC demodulator: 76 y += b; 77 i += b * int(std::cos(M_PI * p / 6) * 5909); 78 q += b * int(std::sin(M_PI * p / 6) * 5909); 79 } 80 // Convert the YIQ color into RGB 81 auto gammafix = [=](float f) { return f <= 0.f ? 0.f : std::pow(f, 2.2f / 1.8f); }; 82 auto clamp = [](int v) { return v>255 ? 255 : v; }; 83 // Store color at subpixel precision 84 if(u==2) palette[o][p1][p0] += 0x10000*clamp(255 * gammafix(y/1980.f + i* 0.947f/9e6f + q* 0.624f/9e6f)); 85 if(u==1) palette[o][p1][p0] += 0x00100*clamp(255 * gammafix(y/1980.f + i*-0.275f/9e6f + q*-0.636f/9e6f)); 86 if(u==0) palette[o][p1][p0] += 0x00001*clamp(255 * gammafix(y/1980.f + i*-1.109f/9e6f + q* 1.709f/9e6f)); 87 } 88 // Store the RGB color into the frame buffer. 89 ((u32*) s->pixels) [py * 256 + px] = palette[offset][prev%64][pixel]; 90 prev = pixel; 91 } 92 void FlushScanline(unsigned py) 93 { 94 if(py == 239) SDL_Flip(s); 95 } 96 97 int joy_current[2]={0,0}, joy_next[2]={0,0}, joypos[2]={0,0}; 98 void JoyStrobe(unsigned v) 99 { 100 if(v) { joy_current[0] = joy_next[0]; joypos[0]=0; } 101 if(v) { joy_current[1] = joy_next[1]; joypos[1]=0; } 102 } 103 u8 JoyRead(unsigned idx) 104 { 105 static const u8 masks[8] = {0x20,0x10,0x40,0x80,0x04,0x08,0x02,0x01}; 106 return ((joy_current[idx] & masks[joypos[idx]++ & 7]) ? 1 : 0); 107 } 108 } 109 110 namespace GamePak 111 { 112 std::vector ROM, VRAM(0x2000); 113 unsigned mappernum; 114 const unsigned VROM_Granularity = 0x0400, VROM_Pages = 0x2000 / VROM_Granularity; 115 const unsigned ROM_Granularity = 0x2000, ROM_Pages = 0x10000 / ROM_Granularity; 116 unsigned char NRAM[0x1000], PRAM[0x2000]; 117 unsigned char* banks[ROM_Pages] = {}; 118 unsigned char* Vbanks[VROM_Pages] = {}; 119 unsigned char *Nta[4] = { NRAM+0x0000, NRAM+0x0400, NRAM+0x0000, NRAM+0x0400 }; 120 121 template& r, unsigned granu> 122 static void SetPages(unsigned size, unsigned baseaddr, unsigned index) 123 { 124 for(unsigned v = r.size() + index * size, 125 p = baseaddr / granu; 126 p < (baseaddr + size) / granu && p < npages; 127 ++p, v += granu) 128 b[p] = &r[v % r.size()]; 129 } 130 auto& SetROM = SetPages< ROM_Pages, banks, ROM, ROM_Granularity>; 131 auto& SetVROM = SetPages; 132 133 u8 Access(unsigned addr, u8 value, bool write) 134 { 135 if(write && addr >= 0x8000 && mappernum == 7) // e.g. Rare games 136 { 137 SetROM(0x8000, 0x8000, (value&7)); 138 Nta[0] = Nta[1] = Nta[2] = Nta[3] = &NRAM[0x400 * ((value>>4)&1)]; 139 } 140 if(write && addr >= 0x8000 && mappernum == 2) // e.g. Rockman, Castlevania 141 { 142 SetROM(0x4000, 0x8000, value); 143 } 144 if(write && addr >= 0x8000 && mappernum == 3) // e.g. Kage, Solomon's Key 145 { 146 value &= Access(addr,0,false); // Simulate bus conflict 147 SetVROM(0x2000, 0x0000, (value&3)); 148 } 149 if(write && addr >= 0x8000 && mappernum == 1) // e.g. Rockman 2, Simon's Quest 150 { 151 static u8 regs[4]={0x0C,0,0,0}, counter=0, cache=0; 152 if(value & 0x80) { regs[0]=0x0C; goto configure; } 153 cache |= (value&1) << counter; 154 if(++counter == 5) 155 { 156 regs[ (addr>>13) & 3 ] = value = cache; 157 configure: 158 cache = counter = 0; 159 static const u8 sel[4][4] = { {0,0,0,0}, {1,1,1,1}, {0,1,0,1}, {0,0,1,1} }; 160 for(unsigned m=0; m<4; ++m) Nta[m] = &NRAM[0x400 * sel[regs[0]&3][m]]; 161 SetVROM(0x1000, 0x0000, ((regs[0]&16) ? regs[1] : ((regs[1]&~1)+0))); 162 SetVROM(0x1000, 0x1000, ((regs[0]&16) ? regs[2] : ((regs[1]&~1)+1))); 163 switch( (regs[0]>>2)&3 ) 164 { 165 case 0: case 1: 166 SetROM(0x8000, 0x8000, (regs[3] & 0xE) / 2); 167 break; 168 case 2: 169 SetROM(0x4000, 0x8000, 0); 170 SetROM(0x4000, 0xC000, (regs[3] & 0xF)); 171 break; 172 case 3: 173 SetROM(0x4000, 0x8000, (regs[3] & 0xF)); 174 SetROM(0x4000, 0xC000, ~0); 175 break; 176 } 177 } 178 } 179 if( (addr >> 13) == 3 ) return PRAM[addr & 0x1FFF ]; 180 return banks[ (addr / ROM_Granularity) % ROM_Pages] [addr % ROM_Granularity]; 181 } 182 void Init() 183 { 184 SetVROM(0x2000, 0x0000, 0); 185 for(unsigned v=0; v<4; ++v) SetROM(0x4000, v*0x4000, v==3 ? -1 : 0); 186 } 187 } 188 189 namespace CPU /* CPU: Ricoh RP2A03 (based on MOS6502, almost the same as in Commodore 64) */ 190 { 191 u8 RAM[0x800]; 192 bool reset=true, nmi=false, nmi_edge_detected=false, intr=false; 193 194 template u8 MemAccess(u16 addr, u8 v=0); 195 u8 RB(u16 addr) { return MemAccess<0>(addr); } 196 u8 WB(u16 addr,u8 v) { return MemAccess<1>(addr, v); } 197 void tick(); 198 } 199 200 namespace PPU /* Picture Processing Unit */ 201 { 202 union regtype // PPU register file 203 { 204 u32 value; 205 // Reg0 (write) // Reg1 (write) // Reg2 (read) 206 RegBit<0,8,u32> sysctrl; RegBit< 8,8,u32> dispctrl; RegBit<16,8,u32> status; 207 RegBit<0,2,u32> BaseNTA; RegBit< 8,1,u32> Grayscale; RegBit<21,1,u32> SPoverflow; 208 RegBit<2,1,u32> Inc; RegBit< 9,1,u32> ShowBG8; RegBit<22,1,u32> SP0hit; 209 RegBit<3,1,u32> SPaddr; RegBit<10,1,u32> ShowSP8; RegBit<23,1,u32> InVBlank; 210 RegBit<4,1,u32> BGaddr; RegBit<11,1,u32> ShowBG; // Reg3 (write) 211 RegBit<5,1,u32> SPsize; RegBit<12,1,u32> ShowSP; RegBit<24,8,u32> OAMaddr; 212 RegBit<6,1,u32> SlaveFlag; RegBit<11,2,u32> ShowBGSP; RegBit<24,2,u32> OAMdata; 213 RegBit<7,1,u32> NMIenabled; RegBit<13,3,u32> EmpRGB; RegBit<26,6,u32> OAMindex; 214 } reg; 215 // Raw memory data as read&written by the game 216 u8 palette[32], OAM[256]; 217 // Decoded sprite information, used & changed during each scanline 218 struct { u8 sprindex, y, index, attr, x; u16 pattern; } OAM2[8], OAM3[8]; 219 220 union scrolltype 221 { 222 RegBit<3,16,u32> raw; // raw VRAM address (16-bit) 223 RegBit<0, 8,u32> xscroll; // low 8 bits of first write to 2005 224 RegBit<0, 3,u32> xfine; // low 3 bits of first write to 2005 225 RegBit<3, 5,u32> xcoarse; // high 5 bits of first write to 2005 226 RegBit<8, 5,u32> ycoarse; // high 5 bits of second write to 2005 227 RegBit<13,2,u32> basenta; // nametable index (copied from 2000) 228 RegBit<13,1,u32> basenta_h; // horizontal nametable index 229 RegBit<14,1,u32> basenta_v; // vertical nametable index 230 RegBit<15,3,u32> yfine; // low 3 bits of second write to 2005 231 RegBit<11,8,u32> vaddrhi; // first write to 2006 (with high 2 bits set to zero) 232 RegBit<3, 8,u32> vaddrlo; // second write to 2006 233 } scroll, vaddr; 234 235 unsigned pat_addr, sprinpos, sproutpos, sprrenpos, sprtmp; 236 u16 tileattr, tilepat, ioaddr; 237 u32 bg_shift_pat, bg_shift_attr; 238 239 int scanline=241, x=0, scanline_end=341, VBlankState=0, cycle_counter=0; 240 int read_buffer=0, open_bus=0, open_bus_decay_timer=0; 241 bool even_odd_toggle=false, offset_toggle=false; 242 243 /* Memory mapping: Convert PPU memory address into a reference to relevant data */ 244 u8& mmap(int i) 245 { 246 i &= 0x3FFF; 247 if(i >= 0x3F00) { if(i%4==0) i &= 0x0F; return palette[i & 0x1F]; } 248 if(i < 0x2000) return GamePak::Vbanks[(i / GamePak::VROM_Granularity) % GamePak::VROM_Pages] 249 [ i % GamePak::VROM_Granularity]; 250 return GamePak::Nta[ (i>>10)&3][i&0x3FF]; 251 } 252 // External I/O: read or write 253 u8 Access(u16 index, u8 v, bool write) 254 { 255 auto RefreshOpenBus = [&](u8 v) { return open_bus_decay_timer = 77777, open_bus = v; }; 256 u8 res = open_bus; 257 if(write) RefreshOpenBus(v); 258 switch(index) // Which port from $200x? 259 { 260 case 0: if(write) { reg.sysctrl = v; scroll.basenta = reg.BaseNTA; } break; 261 case 1: if(write) { reg.dispctrl = v; } break; 262 case 2: if(write) break; 263 res = reg.status | (open_bus & 0x1F); 264 reg.InVBlank = false; // Reading $2002 clears the vblank flag. 265 offset_toggle = false; // Also resets the toggle for address updates. 266 if(VBlankState != -5) 267 VBlankState = 0; // This also may cancel the setting of InVBlank. 268 break; 269 case 3: if(write) reg.OAMaddr = v; break; // Index into Object Attribute Memory 270 case 4: if(write) OAM[reg.OAMaddr++] = v; // Write or read the OAM (sprites). 271 else res = RefreshOpenBus(OAM[reg.OAMaddr] & (reg.OAMdata==2 ? 0xE3 : 0xFF)); 272 break; 273 case 5: if(!write) break; // Set background scrolling offset 274 if(offset_toggle) { scroll.yfine = v & 7; scroll.ycoarse = v >> 3; } 275 else { scroll.xscroll = v; } 276 offset_toggle = !offset_toggle; 277 break; 278 case 6: if(!write) break; // Set video memory position for reads/writes 279 if(offset_toggle) { scroll.vaddrlo = v; vaddr.raw = (unsigned) scroll.raw; } 280 else { scroll.vaddrhi = v & 0x3F; } 281 offset_toggle = !offset_toggle; 282 break; 283 case 7: 284 res = read_buffer; 285 u8& t = mmap(vaddr.raw); // Access the video memory. 286 if(write) res = t = v; 287 else { if((vaddr.raw & 0x3F00) == 0x3F00) // palette? 288 res = read_buffer = (open_bus & 0xC0) | (t & 0x3F); 289 read_buffer = t; } 290 RefreshOpenBus(res); 291 vaddr.raw = vaddr.raw + (reg.Inc ? 32 : 1); // The address is automatically updated. 292 break; 293 } 294 return res; 295 } 296 void rendering_tick() 297 { 298 bool tile_decode_mode = 0x10FFFF & (1u << (x/16)); // When x is 0..255, 320..335 299 300 // Each action happens in two steps: 1) select memory address; 2) receive data and react on it. 301 switch(x % 8) 302 { 303 case 2: // Point to attribute table 304 ioaddr = 0x23C0 + 0x400*vaddr.basenta + 8*(vaddr.ycoarse/4) + (vaddr.xcoarse/4); 305 if(tile_decode_mode) break; // Or nametable, with sprites. 306 case 0: // Point to nametable 307 ioaddr = 0x2000 + (vaddr.raw & 0xFFF); 308 // Reset sprite data 309 if(x == 0) { sprinpos = sproutpos = 0; if(reg.ShowSP) reg.OAMaddr = 0; } 310 if(!reg.ShowBG) break; 311 // Reset scrolling (vertical once, horizontal each scanline) 312 if(x == 304 && scanline == -1) vaddr.raw = (unsigned) scroll.raw; 313 if(x == 256) { vaddr.xcoarse = (unsigned)scroll.xcoarse; 314 vaddr.basenta_h = (unsigned)scroll.basenta_h; 315 sprrenpos = 0; } 316 break; 317 case 1: 318 if(x == 337 && scanline == -1 && even_odd_toggle && reg.ShowBG) scanline_end = 340; 319 // Name table access 320 pat_addr = 0x1000*reg.BGaddr + 16*mmap(ioaddr) + vaddr.yfine; 321 if(!tile_decode_mode) break; 322 // Push the current tile into shift registers. 323 // The bitmap pattern is 16 bits, while the attribute is 2 bits, repeated 8 times. 324 bg_shift_pat = (bg_shift_pat >> 16) + 0x00010000 * tilepat; 325 bg_shift_attr = (bg_shift_attr >> 16) + 0x55550000 * tileattr; 326 break; 327 case 3: 328 // Attribute table access 329 if(tile_decode_mode) 330 { 331 tileattr = (mmap(ioaddr) >> ((vaddr.xcoarse&2) + 2*(vaddr.ycoarse&2))) & 3; 332 // Go to the next tile horizontally (and switch nametable if it wraps) 333 if(!++vaddr.xcoarse) { vaddr.basenta_h = 1-vaddr.basenta_h; } 334 // At the edge of the screen, do the same but vertically 335 if(x==251 && !++vaddr.yfine && ++vaddr.ycoarse == 30) 336 { vaddr.ycoarse = 0; vaddr.basenta_v = 1-vaddr.basenta_v; } 337 } 338 else if(sprrenpos < sproutpos) 339 { 340 // Select sprite pattern instead of background pattern 341 auto& o = OAM3[sprrenpos]; // Sprite to render on next scanline 342 memcpy(&o, &OAM2[sprrenpos], sizeof(o)); 343 unsigned y = (scanline) - o.y; 344 if(o.attr & 0x80) y ^= (reg.SPsize ? 15 : 7); 345 pat_addr = 0x1000 * (reg.SPsize ? (o.index & 0x01) : reg.SPaddr); 346 pat_addr += 0x10 * (reg.SPsize ? (o.index & 0xFE) : (o.index & 0xFF)); 347 pat_addr += (y&7) + (y&8)*2; 348 } 349 break; 350 // Pattern table bytes 351 case 5: 352 tilepat = mmap(pat_addr|0); 353 break; 354 case 7: // Interleave the bits of the two pattern bytes 355 unsigned p = tilepat | (mmap(pat_addr|8) << 8); 356 p = (p&0xF00F) | ((p&0x0F00)>>4) | ((p&0x00F0)<<4); 357 p = (p&0xC3C3) | ((p&0x3030)>>2) | ((p&0x0C0C)<<2); 358 p = (p&0x9999) | ((p&0x4444)>>1) | ((p&0x2222)<<1); 359 tilepat = p; 360 // When decoding sprites, save the sprite graphics and move to next sprite 361 if(!tile_decode_mode && sprrenpos < sproutpos) 362 OAM3[sprrenpos++].pattern = tilepat; 363 break; 364 } 365 // Find which sprites are visible on next scanline (TODO: implement crazy 9-sprite malfunction) 366 switch(x>=64 && x<256 && x%2 ? (reg.OAMaddr++ & 3) : 4) 367 { 368 default: 369 // Access OAM (object attribute memory) 370 sprtmp = OAM[reg.OAMaddr]; 371 break; 372 case 0: 373 if(sprinpos >= 64) { reg.OAMaddr=0; break; } 374 ++sprinpos; // next sprite 375 if(sproutpos<8) OAM2[sproutpos].y = sprtmp; 376 if(sproutpos<8) OAM2[sproutpos].sprindex = reg.OAMindex; 377 {int y1 = sprtmp, y2 = sprtmp + (reg.SPsize?16:8); 378 if(!( scanline >= y1 && scanline < y2 )) 379 reg.OAMaddr = sprinpos != 2 ? reg.OAMaddr+3 : 8;} 380 break; 381 case 1: 382 if(sproutpos<8) OAM2[sproutpos].index = sprtmp; 383 break; 384 case 2: 385 if(sproutpos<8) OAM2[sproutpos].attr = sprtmp; 386 break; 387 case 3: 388 if(sproutpos<8) OAM2[sproutpos].x = sprtmp; 389 if(sproutpos<8) ++sproutpos; else reg.SPoverflow = true; 390 if(sprinpos == 2) reg.OAMaddr = 8; 391 break; 392 } 393 } 394 void render_pixel() 395 { 396 bool edge = u8(x+8) < 16; // 0..7, 248..255 397 bool showbg = reg.ShowBG && (!edge || reg.ShowBG8); 398 bool showsp = reg.ShowSP && (!edge || reg.ShowSP8); 399 400 // Render the background 401 unsigned fx = scroll.xfine, xpos = 15 - (( (x&7) + fx + 8*!!(x&7) ) & 15); 402 403 unsigned pixel = 0, attr = 0; 404 if(showbg) // Pick a pixel from the shift registers 405 { 406 pixel = (bg_shift_pat >> (xpos*2)) & 3; 407 attr = (bg_shift_attr >> (xpos*2)) & (pixel ? 3 : 0); 408 } 409 else if( (vaddr.raw & 0x3F00) == 0x3F00 && !reg.ShowBGSP ) 410 pixel = vaddr.raw; 411 412 // Overlay the sprites 413 if(showsp) 414 for(unsigned sno=0; sno= 8) continue; // Also matches negative values 420 // Determine which pixel to display; skip transparent pixels 421 if(!(s.attr & 0x40)) xdiff = 7-xdiff; 422 u8 spritepixel = (s.pattern >> (xdiff*2)) & 3; 423 if(!spritepixel) continue; 424 // Register sprite-0 hit if applicable 425 if(x < 255 && pixel && s.sprindex == 0) reg.SP0hit = true; 426 // Render the pixel unless behind-background placement wanted 427 if(!(s.attr & 0x20) || !pixel) 428 { 429 attr = (s.attr & 3) + 4; 430 pixel = spritepixel; 431 } 432 // Only process the first non-transparent sprite pixel. 433 break; 434 } 435 pixel = palette[ (attr*4 + pixel) & 0x1F ] & (reg.Grayscale ? 0x30 : 0x3F); 436 IO::PutPixel(x, scanline, pixel | (reg.EmpRGB << 6), cycle_counter); 437 } 438 439 // PPU::tick() -- This function is called 3 times per each CPU cycle. 440 // Each call iterates through one pixel of the screen. 441 // The screen is divided into 262 scanlines, each having 341 columns, as such: 442 // 443 // x=0 x=256 x=340 444 // ___|____________________|__________| 445 // y=-1 | pre-render scanline| prepare | > 446 // ___|____________________| sprites _| > Graphics 447 // y=0 | visible area | for the | > processing 448 // | - this is rendered | next | > scanlines 449 // y=239 | on the screen. | scanline | > 450 // ___|____________________|______ 451 // y=240 | idle 452 // ___|_______________________________ 453 // y=241 | vertical blanking (idle) 454 // | 20 scanlines long 455 // y=260___|____________________|__________| 456 // 457 // On actual PPU, the scanline begins actually before x=0, with 458 // sync/colorburst/black/background color being rendered, and 459 // ends after x=256 with background/black being rendered first, 460 // but in this emulator we only care about the visible area. 461 // 462 // When background rendering is enabled, scanline -1 is 463 // 340 or 341 pixels long, alternating each frame. 464 // In all other situations the scanline is 341 pixels long. 465 // Thus, it takes 89341 or 89342 PPU::tick() calls to render 1 frame. 466 void tick() 467 { 468 // Set/clear vblank where needed 469 switch(VBlankState) 470 { 471 case -5: reg.status = 0; break; 472 case 2: reg.InVBlank = true; break; 473 case 0: CPU::nmi = reg.InVBlank && reg.NMIenabled; break; 474 } 475 if(VBlankState != 0) VBlankState += (VBlankState < 0 ? 1 : -1); 476 if(open_bus_decay_timer) if(!--open_bus_decay_timer) open_bus = 0; 477 478 // Graphics processing scanline? 479 if(scanline < 240) 480 { 481 /* Process graphics for this cycle */ 482 if(reg.ShowBGSP) rendering_tick(); 483 if(scanline >= 0 && x < 256) render_pixel(); 484 } 485 486 // Done with the cycle. Check for end of scanline. 487 if(++cycle_counter == 3) cycle_counter = 0; // For NTSC pixel shifting 488 if(++x >= scanline_end) 489 { 490 // Begin new scanline 491 IO::FlushScanline(scanline); 492 scanline_end = 341; 493 x = 0; 494 // Does something special happen on the new scanline? 495 switch(scanline += 1) 496 { 497 case 261: // Begin of rendering 498 scanline = -1; // pre-render line 499 even_odd_toggle = !even_odd_toggle; 500 // Clear vblank flag 501 VBlankState = -5; 502 break; 503 case 241: // Begin of vertical blanking 504 // I cheat here: I did not bother to learn how to use SDL events, 505 // so I simply read button presses from a movie file, which happens 506 // to be a TAS, rather than from the keyboard or from a joystick. 507 static FILE* fp = fopen(inputfn, "rb"); 508 if(fp) 509 { 510 static unsigned ctrlmask = 0; 511 if(!ftell(fp)) 512 { 513 fseek(fp, 0x05, SEEK_SET); 514 ctrlmask = fgetc(fp); 515 fseek(fp, 0x90, SEEK_SET); // Famtasia Movie format. 516 } 517 if(ctrlmask & 0x80) { IO::joy_next[0] = fgetc(fp); if(feof(fp)) IO::joy_next[0] = 0; } 518 if(ctrlmask & 0x40) { IO::joy_next[1] = fgetc(fp); if(feof(fp)) IO::joy_next[1] = 0; } 519 } 520 // Set vblank flag 521 VBlankState = 2; 522 } 523 } 524 } 525 } 526 527 namespace APU /* Audio Processing Unit */ 528 { 529 static const u8 LengthCounters[32] = { 10,254,20, 2,40, 4,80, 6,160, 8,60,10,14,12,26,14, 530 12, 16,24,18,48,20,96,22,192,24,72,26,16,28,32,30 }; 531 static const u16 NoisePeriods[16] = { 2,4,8,16,32,48,64,80,101,127,190,254,381,508,1017,2034 }; 532 static const u16 DMCperiods[16] = { 428,380,340,320,286,254,226,214,190,160,142,128,106,84,72,54 }; 533 534 bool FiveCycleDivider = false, IRQdisable = true, ChannelsEnabled[5] = { false }; 535 bool PeriodicIRQ = false, DMC_IRQ = false; 536 bool count(int& v, int reset) { return --v < 0 ? (v=reset),true : false; } 537 538 struct channel 539 { 540 int length_counter, linear_counter, address, envelope; 541 int sweep_delay, env_delay, wave_counter, hold, phase, level; 542 union // Per-channel register file 543 { 544 // 4000, 4004, 400C, 4012: // 4001, 4005, 4013: // 4002, 4006, 400A, 400E: 545 RegBit<0,8,u32> reg0; RegBit< 8,8,u32> reg1; RegBit<16,8,u32> reg2; 546 RegBit<6,2,u32> DutyCycle; RegBit< 8,3,u32> SweepShift; RegBit<16,4,u32> NoiseFreq; 547 RegBit<4,1,u32> EnvDecayDisable; RegBit<11,1,u32> SweepDecrease; RegBit<23,1,u32> NoiseType; 548 RegBit<0,4,u32> EnvDecayRate; RegBit<12,3,u32> SweepRate; RegBit<16,11,u32> WaveLength; 549 RegBit<5,1,u32> EnvDecayLoopEnable; RegBit<15,1,u32> SweepEnable; // 4003, 4007, 400B, 400F, 4010: 550 RegBit<0,4,u32> FixedVolume; RegBit< 8,8,u32> PCMlength; RegBit<24,8,u32> reg3; 551 RegBit<5,1,u32> LengthCounterDisable; RegBit<27,5,u32> LengthCounterInit; 552 RegBit<0,7,u32> LinearCounterInit; RegBit<30,1,u32> LoopEnabled; 553 RegBit<7,1,u32> LinearCounterDisable; RegBit<31,1,u32> IRQenable; 554 } reg; 555 556 // Function for updating the wave generators and taking the sample for each channel. 557 template 558 int tick() 559 { 560 channel& ch = *this; 561 if(!ChannelsEnabled[c]) return c==4 ? 64 : 8; 562 int wl = (ch.reg.WaveLength+1) * (c >= 2 ? 1 : 2); 563 if(c == 3) wl = NoisePeriods[ ch.reg.NoiseFreq ]; 564 int volume = ch.length_counter ? ch.reg.EnvDecayDisable ? ch.reg.FixedVolume : ch.envelope : 0; 565 // Sample may change at wavelen intervals. 566 auto& S = ch.level; 567 if(!count(ch.wave_counter, wl)) return S; 568 switch(c) 569 { 570 default:// Square wave. With four different 8-step binary waveforms (32 bits of data total). 571 if(wl < 8) return S = 8; 572 return S = (0xF33C0C04u & (1u << (++ch.phase % 8 + ch.reg.DutyCycle * 8))) ? volume : 0; 573 574 case 2: // Triangle wave 575 if(ch.length_counter && ch.linear_counter && wl >= 3) ++ch.phase; 576 return S = (ch.phase & 15) ^ ((ch.phase & 16) ? 15 : 0); 577 578 case 3: // Noise: Linear feedback shift register 579 if(!ch.hold) ch.hold = 1; 580 ch.hold = (ch.hold >> 1) 581 | (((ch.hold ^ (ch.hold >> (ch.reg.NoiseType ? 6 : 1))) & 1) << 14); 582 return S = (ch.hold & 1) ? 0 : volume; 583 584 case 4: // Delta modulation channel (DMC) 585 // hold = 8 bit value, phase = number of bits buffered 586 if(ch.phase == 0) // Nothing in sample buffer? 587 { 588 if(!ch.length_counter && ch.reg.LoopEnabled) // Loop? 589 { 590 ch.length_counter = ch.reg.PCMlength*16 + 1; 591 ch.address = (ch.reg.reg0 | 0x300) << 6; 592 } 593 if(ch.length_counter > 0) // Load next 8 bits if available 594 { 595 // Note: Re-entrant! But not recursive, because even 596 // the shortest wave length is greater than the read time. 597 // TODO: proper clock 598 if(ch.reg.WaveLength>20) 599 for(unsigned t=0; t<3; ++t) CPU::RB(u16(ch.address) | 0x8000); // timing 600 ch.hold = CPU::RB(u16(ch.address++) | 0x8000); // Fetch byte 601 ch.phase = 8; 602 --ch.length_counter; 603 } 604 else // Otherwise, disable channel or issue IRQ 605 ChannelsEnabled[4] = ch.reg.IRQenable && (CPU::intr = DMC_IRQ = true); 606 } 607 if(ch.phase != 0) // Update the signal if sample buffer nonempty 608 { 609 int v = ch.linear_counter; 610 if(ch.hold & (0x80 >> --ch.phase)) v += 2; else v -= 2; 611 if(v >= 0 && v <= 0x7F) ch.linear_counter = v; 612 } 613 return S = ch.linear_counter; 614 } 615 } 616 } channels[5] = { }; 617 618 struct { short lo, hi; } hz240counter = { 0,0 }; 619 620 void Write(u8 index, u8 value) 621 { 622 channel& ch = channels[(index/4) % 5]; 623 switch(index<0x10 ? index%4 : index) 624 { 625 case 0: if(ch.reg.LinearCounterDisable) ch.linear_counter=value&0x7F; ch.reg.reg0 = value; break; 626 case 1: ch.reg.reg1 = value; ch.sweep_delay = ch.reg.SweepRate; break; 627 case 2: ch.reg.reg2 = value; break; 628 case 3: 629 ch.reg.reg3 = value; 630 if(ChannelsEnabled[index/4]) 631 ch.length_counter = LengthCounters[ch.reg.LengthCounterInit]; 632 ch.linear_counter = ch.reg.LinearCounterInit; 633 ch.env_delay = ch.reg.EnvDecayRate; 634 ch.envelope = 15; 635 if(index < 8) ch.phase = 0; 636 break; 637 case 0x10: ch.reg.reg3 = value; ch.reg.WaveLength = DMCperiods[value&0x0F]; break; 638 case 0x12: ch.reg.reg0 = value; ch.address = (ch.reg.reg0 | 0x300) << 6; break; 639 case 0x13: ch.reg.reg1 = value; ch.length_counter = ch.reg.PCMlength*16 + 1; break; // sample length 640 case 0x11: ch.linear_counter = value & 0x7F; break; // dac value 641 case 0x15: 642 for(unsigned c=0; c<5; ++c) 643 ChannelsEnabled[c] = value & (1 << c); 644 for(unsigned c=0; c<5; ++c) 645 if(!ChannelsEnabled[c]) 646 channels[c].length_counter = 0; 647 else if(c == 4 && channels[c].length_counter == 0) 648 channels[c].length_counter = ch.reg.PCMlength*16 + 1; 649 break; 650 case 0x17: 651 IRQdisable = value & 0x40; 652 FiveCycleDivider = value & 0x80; 653 hz240counter = { 0,0 }; 654 if(IRQdisable) PeriodicIRQ = DMC_IRQ = false; 655 } 656 } 657 u8 Read() 658 { 659 u8 res = 0; 660 for(unsigned c=0; c<5; ++c) res |= (channels[c].length_counter ? 1 << c : 0); 661 if(PeriodicIRQ) res |= 0x40; PeriodicIRQ = false; 662 if(DMC_IRQ) res |= 0x80; DMC_IRQ = false; 663 CPU::intr = false; 664 return res; 665 } 666 667 void tick() // Invoked at CPU's rate. 668 { 669 // Divide CPU clock by 7457.5 to get a 240 Hz, which controls certain events. 670 if((hz240counter.lo += 2) >= 14915) 671 { 672 hz240counter.lo -= 14915; 673 if(++hz240counter.hi >= 4+FiveCycleDivider) hz240counter.hi = 0; 674 675 // 60 Hz interval: IRQ. IRQ is not invoked in five-cycle mode (48 Hz). 676 if(!IRQdisable && !FiveCycleDivider && hz240counter.hi==0) 677 CPU::intr = PeriodicIRQ = true; 678 679 // Some events are invoked at 96 Hz or 120 Hz rate. Others, 192 Hz or 240 Hz. 680 bool HalfTick = (hz240counter.hi&5)==1, FullTick = hz240counter.hi < 4; 681 for(unsigned c=0; c<4; ++c) 682 { 683 channel& ch = channels[c]; 684 int wl = ch.reg.WaveLength; 685 686 // Length tick (all channels except DMC, but different disable bit for triangle wave) 687 if(HalfTick && ch.length_counter 688 && !(c==2 ? ch.reg.LinearCounterDisable : ch.reg.LengthCounterDisable)) 689 ch.length_counter -= 1; 690 691 // Sweep tick (square waves only) 692 if(HalfTick && c < 2 && count(ch.sweep_delay, ch.reg.SweepRate)) 693 if(wl >= 8 && ch.reg.SweepEnable && ch.reg.SweepShift) 694 { 695 int s = wl >> ch.reg.SweepShift, d[4] = {s, s, ~s, -s}; 696 wl += d[ch.reg.SweepDecrease*2 + c]; 697 if(wl < 0x800) ch.reg.WaveLength = wl; 698 } 699 700 // Linear tick (triangle wave only) 701 if(FullTick && c == 2) 702 ch.linear_counter = ch.reg.LinearCounterDisable 703 ? ch.reg.LinearCounterInit 704 : (ch.linear_counter > 0 ? ch.linear_counter - 1 : 0); 705 706 // Envelope tick (square and noise channels) 707 if(FullTick && c != 2 && count(ch.env_delay, ch.reg.EnvDecayRate)) 708 if(ch.envelope > 0 || ch.reg.EnvDecayLoopEnable) 709 ch.envelope = (ch.envelope-1) & 15; 710 } 711 } 712 713 // Mix the audio: Get the momentary sample from each channel and mix them. 714 #define s(c) channels[c].tick() 715 auto v = [](float m,float n, float d) { return n!=0.f ? m/n : d; }; 716 short sample = 30000 * 717 (v(95.88f, (100.f + v(8128.f, s(0) + s(1), -100.f)), 0.f) 718 + v(159.79f, (100.f + v(1.0, s(2)/8227.f + s(3)/12241.f + s(4)/22638.f, -100.f)), 0.f) 719 - 0.5f 720 ); 721 #undef s 722 // I cheat here: I did not bother to learn how to use SDL mixer, let alone use it in <5 lines of code, 723 // so I simply use a combination of external programs for outputting the audio. 724 // Hooray for Unix principles! A/V sync will be ensured in post-process. 725 //return; // Disable sound because already device is in use 726 static FILE* fp = popen("resample mr1789800 r48000 | aplay -fdat 2>/dev/null", "w"); 727 fputc(sample, fp); 728 fputc(sample/256, fp); 729 } 730 } 731 732 namespace CPU 733 { 734 void tick() 735 { 736 // PPU clock: 3 times the CPU rate 737 for(unsigned n=0; n<3; ++n) PPU::tick(); 738 // APU clock: 1 times the CPU rate 739 for(unsigned n=0; n<1; ++n) APU::tick(); 740 } 741 742 template u8 MemAccess(u16 addr, u8 v) 743 { 744 // Memory writes are turned into reads while reset is being signalled 745 if(reset && write) return MemAccess<0>(addr); 746 747 tick(); 748 // Map the memory from CPU's viewpoint. 749 /**/ if(addr < 0x2000) { u8& r = RAM[addr & 0x7FF]; if(!write)return r; r=v; } 750 else if(addr < 0x4000) return PPU::Access(addr&7, v, write); 751 else if(addr < 0x4018) 752 switch(addr & 0x1F) 753 { 754 case 0x14: // OAM DMA: Copy 256 bytes from RAM into PPU's sprite memory 755 if(write) for(unsigned b=0; b<256; ++b) WB(0x2004, RB((v&7)*0x0100+b)); 756 return 0; 757 case 0x15: if(!write) return APU::Read(); APU::Write(0x15,v); break; 758 case 0x16: if(!write) return IO::JoyRead(0); IO::JoyStrobe(v); break; 759 case 0x17: if(!write) return IO::JoyRead(1); // write:passthru 760 default: if(!write) break; 761 APU::Write(addr&0x1F, v); 762 } 763 else return GamePak::Access(addr, v, write); 764 return 0; 765 } 766 767 // CPU registers: 768 u16 PC=0xC000; 769 u8 A=0,X=0,Y=0,S=0; 770 union /* Status flags: */ 771 { 772 u8 raw; 773 RegBit<0> C; // carry 774 RegBit<1> Z; // zero 775 RegBit<2> I; // interrupt enable/disable 776 RegBit<3> D; // decimal mode (unsupported on NES, but flag exists) 777 // 4,5 (0x10,0x20) don't exist 778 RegBit<6> V; // overflow 779 RegBit<7> N; // negative 780 } P; 781 782 u16 wrap(u16 oldaddr, u16 newaddr) { return (oldaddr & 0xFF00) + u8(newaddr); } 783 void Misfire(u16 old, u16 addr) { u16 q = wrap(old, addr); if(q != addr) RB(q); } 784 u8 Pop() { return RB(0x100 | u8(++S)); } 785 void Push(u8 v) { WB(0x100 | u8(S--), v); } 786 787 template // Execute a single CPU instruction, defined by opcode "op". 788 void Ins() // With template magic, the compiler will literally synthesize >256 different functions. 789 { 790 // Note: op 0x100 means "NMI", 0x101 means "Reset", 0x102 means "IRQ". They are implemented in terms of "BRK". 791 // User is responsible for ensuring that WB() will not store into memory while Reset is being processed. 792 unsigned addr=0, d=0, t=0xFF, c=0, sb=0, pbits = op<0x100 ? 0x30 : 0x20; 793 794 // Define the opcode decoding matrix, which decides which micro-operations constitute 795 // any particular opcode. (Note: The PLA of 6502 works on a slightly different principle.) 796 enum { o8 = op/8, o8m = 1 << (op%8) }; 797 // Fetch op'th item from a bitstring encoded in a data-specific variant of base64, 798 // where each character transmits 8 bits of information rather than 6. 799 // This peculiar encoding was chosen to reduce the source code size. 800 // Enum temporaries are used in order to ensure compile-time evaluation. 801 #define t(s,code) { enum { \ 802 i=o8m & (s[o8]>90 ? (130+" (),-089<>?BCFGHJLSVWZ[^hlmnxy|}"[s[o8]-94]) \ 803 : (s[o8]-" (("[s[o8]/39])) }; if(i) { code; } } 804 805 /* Decode address operand */ 806 t(" !", addr = 0xFFFA) // NMI vector location 807 t(" *", addr = 0xFFFC) // Reset vector location 808 t("! ,", addr = 0xFFFE) // Interrupt vector location 809 t("zy}z{y}zzy}zzy}zzy}zzy}zzy}zzy}z ", addr = RB(PC++)) 810 t("2 yy2 yy2 yy2 yy2 XX2 XX2 yy2 yy ", d = X) // register index 811 t(" 62 62 62 62 om om 62 62 ", d = Y) 812 t("2 y 2 y 2 y 2 y 2 y 2 y 2 y 2 y ", addr=u8(addr+d); d=0; tick()) // add zeropage-index 813 t(" y z!y z y z y z y z y z y z y z ", addr=u8(addr); addr+=256*RB(PC++)) // absolute address 814 t("3 6 2 6 2 6 286 2 6 2 6 2 6 2 6 /", addr=RB(c=addr); addr+=256*RB(wrap(c,c+1)))// indirect w/ page wrap 815 t(" *Z *Z *Z *Z 6z *Z *Z ", Misfire(addr, addr+d)) // abs. load: extra misread when cross-page 816 t(" 4k 4k 4k 4k 6z 4k 4k ", RB(wrap(addr, addr+d)))// abs. store: always issue a misread 817 /* Load source operand */ 818 t("aa__ff__ab__,4 ____ - ____ ", t &= A) // Many operations take A or X as operand. Some try in 819 t(" knnn 4 99 ", t &= X) // error to take both; the outcome is an AND operation. 820 t(" 9989 99 ", t &= Y) // sty,dey,iny,tya,cpy 821 t(" 4 ", t &= S) // tsx, las 822 t("!!!! !! !! !! ! !! !! !!/", t &= P.raw|pbits; c = t)// php, flag test/set/clear, interrupts 823 t("_^__dc___^__ ed__98 ", c = t; t = 0xFF) // save as second operand 824 t("vuwvzywvvuwvvuwv zy|zzywvzywv ", t &= RB(addr+d)) // memory operand 825 t(",2 ,2 ,2 ,2 -2 -2 -2 -2 ", t &= RB(PC++)) // immediate operand 826 /* Operations that mogrify memory operands directly */ 827 t(" 88 ", P.V = t & 0x40; P.N = t & 0x80) // bit 828 t(" nink nnnk ", sb = P.C) // rol,rla, ror,rra,arr 829 t("nnnknnnk 0 ", P.C = t & 0x80) // rol,rla, asl,slo,[arr,anc] 830 t(" nnnknink ", P.C = t & 0x01) // lsr,sre, ror,rra,asr 831 t("ninknink ", t = (t << 1) | (sb * 0x01)) 832 t(" nnnknnnk ", t = (t >> 1) | (sb * 0x80)) 833 t(" ! kink ", t = u8(t - 1)) // dec,dex,dey,dcp 834 t(" ! khnk ", t = u8(t + 1)) // inc,inx,iny,isb 835 /* Store modified value (memory) */ 836 t("kgnkkgnkkgnkkgnkzy|J kgnkkgnk ", WB(addr+d, t)) 837 t(" q ", WB(wrap(addr, addr+d), t &= ((addr+d) >> 8))) // [shx,shy,shs,sha?] 838 /* Some operations used up one clock cycle that we did not account for yet */ 839 t("rpstljstqjstrjst - - - -kjstkjst/", tick()) // nop,flag ops,inc,dec,shifts,stack,transregister,interrupts 840 /* Stack operations and unconditional jumps */ 841 t(" ! ! ! ", tick(); t = Pop()) // pla,plp,rti 842 t(" ! ! ", RB(PC++); PC = Pop(); PC |= (Pop() << 8)) // rti,rts 843 t(" ! ", RB(PC++)) // rts 844 t("! ! /", d=PC+(op?-1:1); Push(d>>8); Push(d)) // jsr, interrupts 845 t("! ! 8 8 /", PC = addr) // jmp, jsr, interrupts 846 t("!! ! /", Push(t)) // pha, php, interrupts 847 /* Bitmasks */ 848 t("! !! !! !! !! ! !! !! !!/", t = 1) 849 t(" ! ! !! !! ", t <<= 1) 850 t("! ! ! !! !! ! ! !/", t <<= 2) 851 t(" ! ! ! ! ! ", t <<= 4) 852 t(" ! ! ! !____ ", t = u8(~t)) // sbc, isb, clear flag 853 t("`^__ ! ! !/", t = c | t) // ora, slo, set flag 854 t(" !!dc`_ !! ! ! !! !! ! ", t = c & t) // and, bit, rla, clear/test flag 855 t(" _^__ ", t = c ^ t) // eor, sre 856 /* Conditional branches */ 857 t(" ! ! ! ! ", if(t) { tick(); Misfire(PC, addr = s8(addr) + PC); PC=addr; }) 858 t(" ! ! ! ! ", if(!t) { tick(); Misfire(PC, addr = s8(addr) + PC); PC=addr; }) 859 /* Addition and subtraction */ 860 t(" _^__ ____ ", c = t; t += A + P.C; P.V = (c^t) & (A^t) & 0x80; P.C = t & 0x100) 861 t(" ed__98 ", t = c - t; P.C = ~t & 0x100) // cmp,cpx,cpy, dcp, sbx 862 /* Store modified value (register) */ 863 t("aa__aa__aa__ab__ 4 !____ ____ ", A = t) 864 t(" nnnn 4 ! ", X = t) // ldx, dex, tax, inx, tsx,lax,las,sbx 865 t(" ! 9988 ! ", Y = t) // ldy, dey, tay, iny 866 t(" 4 0 ", S = t) // txs, las, shs 867 t("! ! ! !! ! ! ! ! !/", P.raw = t & ~0x30) // plp, rti, flag set/clear 868 /* Generic status flag updates */ 869 t("wwwvwwwvwwwvwxwv 5 !}}||{}wv{{wv ", P.N = t & 0x80) 870 t("wwwv||wvwwwvwxwv 5 !}}||{}wv{{wv ", P.Z = u8(t) == 0) 871 t(" 0 ", P.V = (((t >> 5)+1)&2)) // [arr] 872 /* All implemented opcodes are cycle-accurate and memory-access-accurate. 873 * [] means that this particular separate rule exists only to provide the indicated unofficial opcode(s). 874 */ 875 } 876 877 void Op() 878 { 879 /* Check the state of NMI flag */ 880 bool nmi_now = nmi; 881 882 unsigned op = RB(PC++); 883 884 if(reset) { op=0x101; } 885 else if(nmi_now && !nmi_edge_detected) { op=0x100; nmi_edge_detected = true; } 886 else if(intr && !P.I) { op=0x102; } 887 if(!nmi_now) nmi_edge_detected=false; 888 889 // Define function pointers for each opcode (00..FF) and each interrupt (100,101,102) 890 #define c(n) Ins<0x##n>,Ins<0x##n+1>, 891 #define o(n) c(n)c(n+2)c(n+4)c(n+6) 892 static void(*const i[0x108])() = 893 { 894 o(00)o(08)o(10)o(18)o(20)o(28)o(30)o(38) 895 o(40)o(48)o(50)o(58)o(60)o(68)o(70)o(78) 896 o(80)o(88)o(90)o(98)o(A0)o(A8)o(B0)o(B8) 897 o(C0)o(C8)o(D0)o(D8)o(E0)o(E8)o(F0)o(F8) o(100) 898 }; 899 #undef o 900 #undef c 901 i[op](); 902 903 reset = false; 904 } 905 } 906 907 int main(int/*argc*/, char** argv) 908 { 909 // Open the ROM file specified on commandline 910 FILE* fp = fopen(argv[1], "rb"); 911 inputfn = argv[2]; 912 913 // Read the ROM file header 914 assert(fgetc(fp)=='N' && fgetc(fp)=='E' && fgetc(fp)=='S' && fgetc(fp)=='\32'); 915 u8 rom16count = fgetc(fp); 916 u8 vrom8count = fgetc(fp); 917 u8 ctrlbyte = fgetc(fp); 918 u8 mappernum = fgetc(fp) | (ctrlbyte>>4); 919 fgetc(fp);fgetc(fp);fgetc(fp);fgetc(fp);fgetc(fp);fgetc(fp);fgetc(fp);fgetc(fp); 920 if(mappernum >= 0x40) mappernum &= 15; 921 GamePak::mappernum = mappernum; 922 923 // Read the ROM data 924 if(rom16count) GamePak::ROM.resize(rom16count * 0x4000); 925 if(vrom8count) GamePak::VRAM.resize(vrom8count * 0x2000); 926 fread(&GamePak::ROM[0], rom16count, 0x4000, fp); 927 fread(&GamePak::VRAM[0], vrom8count, 0x2000, fp); 928 929 fclose(fp); 930 printf("%u * 16kB ROM, %u * 8kB VROM, mapper %u, ctrlbyte %02X\n", rom16count, vrom8count, mappernum, ctrlbyte); 931 932 // Start emulation 933 GamePak::Init(); 934 IO::Init(); 935 PPU::reg.value = 0; 936 937 // Pre-initialize RAM the same way as FCEUX does, to improve TAS sync. 938 for(unsigned a=0; a<0x800; ++a) 939 CPU::RAM[a] = (a&4) ? 0xFF : 0x00; 940 941 // Run the CPU until the program is killed. 942 for(;;) CPU::Op(); 943 } 944 945 946 947 948