eirexe

Untitled

Jun 27th, 2013
142
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 45.48 KB | None | 0 0
  1. #include <stdint.h>
  2. #include <signal.h>
  3. #include <assert.h>
  4. #include <cmath>
  5.  
  6. #include <SDL.h>
  7. #include <vector>
  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<unsigned bitno, unsigned nbits=1, typename T=u8>
  23. struct RegBit
  24. {
  25. T data;
  26. enum { mask = (1u << nbits) - 1u };
  27. template<typename T2>
  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(320, 240, 32, SDL_SWSURFACE)
  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<u8> 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<unsigned npages,unsigned char*(&b)[npages], std::vector<u8>& 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<VROM_Pages,Vbanks,VRAM,VROM_Granularity>;
  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<bool write> 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<sprrenpos; ++sno)
  415. {
  416. auto& s = OAM3[sno];
  417. // Check if this sprite is horizontally in range
  418. unsigned xdiff = x - s.x;
  419. if(xdiff >= 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<unsigned c>
  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<c==1 ? 0 : c>()
  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<bool write> 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<u16 op> // 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. }
Advertisement
Add Comment
Please, Sign In to add comment