main.c 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204
  1. /*
  2. * Main application source file - The TI-NESulator Project
  3. * main.c
  4. *
  5. * Created by Manoel TRAPIER.
  6. * Copyright (c) 2003-2008 986Corp. All rights reserved.
  7. *
  8. * $LastChangedDate$
  9. * $Author$
  10. * $HeadURL$
  11. * $Revision$
  12. *
  13. */
  14. /* System includes */
  15. #if !defined(__TIGCC__) && !defined(__GCC4TI__) && !defined(__GTC__)
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <string.h>
  19. #include <signal.h>
  20. #include <sys/mman.h>
  21. #include <sys/time.h>
  22. #include <time.h>
  23. #include <ctype.h>
  24. /* Allegro includes */
  25. #ifdef __APPLE__
  26. #define USE_CONSOLE
  27. #include <Allegro/allegro.h>
  28. #else
  29. #define USE_CONSOLE
  30. #include <allegro.h>
  31. #endif
  32. #else
  33. #define TIGCC_COMPAT
  34. #include <tigcclib.h>
  35. #endif
  36. /* TI-NES modules includes */
  37. #include <os_dependent.h>
  38. #include <corecpu.h>
  39. #include <ppu/ppu.h>
  40. #include <NESCarts.h>
  41. #include <paddle.h>
  42. #include <mappers/manager.h>
  43. #include <memory/manager.h>
  44. #include <plugins/manager.h>
  45. #ifdef USE_SOUND
  46. #include <Sound.h>
  47. #endif
  48. #include <palette.h>
  49. /* PAL support is broken, so force NTSC mode */
  50. #if ISPAL || ISNTSC
  51. #undef ISPAL
  52. #undef ISNTSC
  53. #endif
  54. #define ISNTSC 1
  55. #if ISPAL && !ISNTSC
  56. int VBLANK_TIME = 70;
  57. int HBLANK_TIME = 140;
  58. double APU_BASEFREQ = 1.7734474;
  59. #elif !ISPAL && ISNTSC
  60. int VBLANK_TIME = 20;
  61. int HBLANK_TIME = 113;
  62. double APU_BASEFREQ = 1.7897725;
  63. #elif !ISPAL && !ISNTSC
  64. # error You MUST define one of ISPAL Xor ISNTSC
  65. #else
  66. # error Cannot use ISPAL with ISNTSC together !
  67. #endif
  68. /* TI-NESulator Version */
  69. #define V_MAJOR 0
  70. #define V_MINOR 40
  71. /* SVN specific values */
  72. #define VS_ID "$Id$"
  73. #define VS_REVISION "$Revision$"
  74. #define VS_LASTCHANGEDDATE "$LastChangedDate$"
  75. #define VS_HEADURL "$HeadURL$"
  76. #define VS_AUTHOR "$Author$"
  77. /*
  78. #define MAXLASTOP 42
  79. word latestop[MAXLASTOP];
  80. */
  81. /* NES specific variables */
  82. quick6502_cpu *MainCPU;
  83. NesCart *Cart;
  84. byte *FDSRom;
  85. byte *FDSRam;
  86. /* Allegro main screen */
  87. BITMAP *Buffer;
  88. /* Command line options */
  89. byte START_DEBUG = 0;
  90. byte START_WITH_FDS = 0;
  91. char *CART_FILENAME = NULL;
  92. char *PALETTE_FILENAME = NULL;
  93. Paddle P1, P2;
  94. unsigned short ScanLine;
  95. volatile int frame = 0;
  96. volatile int ccount;
  97. char MapperWantIRQ = 0;
  98. char WantClosing = 0;
  99. struct timeval timeStart;
  100. struct timeval timeEnd;
  101. volatile unsigned long FPS, IPS;
  102. PALETTE pal;
  103. short IRQScanHit = -1;
  104. /* palette */
  105. unsigned long ColorPalette[ 8 * 63 ];
  106. #define SET_RGB(r,g,b) ((((r<<8)|g)<<8)|b)|0xFF000000
  107. /* Memory functions */
  108. byte MemoryRead (unsigned short Addr);
  109. byte MemoryOpCodeRead (unsigned short Addr);
  110. byte MemoryStackRead (unsigned short Addr);
  111. byte MemoryPageZeroRead (unsigned short Addr);
  112. void MemoryWrite (unsigned short Addr, byte Value);
  113. void MemoryStackWrite (unsigned short Addr, byte Value);
  114. void MemoryPageZeroWrite (unsigned short Addr, byte Value);
  115. void Loop6502(quick6502_cpu *R);
  116. void CloseHook(void)
  117. {
  118. WantClosing = 1;
  119. }
  120. void ips_fps_counter(void)
  121. {
  122. FPS = frame;
  123. IPS = ccount;
  124. frame = 0;
  125. ccount = 0;
  126. }
  127. END_OF_FUNCTION(ips_fps_counter);
  128. void SaveSaveRam(char *name)
  129. {
  130. FILE *fp;
  131. int i;
  132. char fname[512];
  133. strcpy(fname, name);
  134. strcat(fname, ".svt");
  135. if ((fp = fopen(fname, "wb")))
  136. {
  137. console_printf(Console_Default, "Saving savestate '%s'\n", fname);
  138. for( i = 0x60; i < 0x80; i++)
  139. {
  140. fwrite(get_page_ptr(i), 1, 0x100, fp);
  141. }
  142. fclose(fp);
  143. }
  144. }
  145. void LoadSaveRam(char *name)
  146. {
  147. FILE *fp;
  148. int i;
  149. char fname[512];
  150. strcpy(fname, name);
  151. strcat(fname, ".svt");
  152. if ((fp = fopen(fname, "rb")))
  153. {
  154. console_printf(Console_Default, "Loading savestate '%s'\n", fname);
  155. for( i = 0x60; i < 0x80; i++)
  156. {
  157. fread(get_page_ptr(i), 1, 0x0100, fp);
  158. }
  159. fclose(fp);
  160. }
  161. }
  162. void LoadPalette(char *filename, PALETTE pal)
  163. {
  164. FILE *fp;
  165. unsigned char r, v, b, i;
  166. console_printf(Console_Default, "%s: try to load pallette file '%s'", __func__, filename);
  167. if ((fp = fopen(filename, "rb")) != NULL)
  168. {
  169. for (i = 0; i < 64; i++)
  170. {
  171. fread(&r, 1, 1, fp);
  172. fread(&v, 1, 1, fp);
  173. fread(&b, 1, 1, fp);
  174. /* r = (r * 64) / 255;
  175. v = (v * 64) / 255;
  176. b = (b * 64) / 255;*/
  177. #ifdef USE_24BITS
  178. ColorPalette[i + (0 * 63)] = SET_RGB(r,v,b);
  179. /* Red emphase */
  180. ColorPalette[i + (1 * 63)] = SET_RGB(r + 10, v - 05, b - 05);
  181. /* Green emphase */
  182. ColorPalette[i + (2 * 63)] = SET_RGB(r - 05, v + 10, b - 05);
  183. /* Red + green emphase */
  184. ColorPalette[i + (3 * 63)] = SET_RGB(r + 05, v + 05, b - 10);
  185. /* Blue emphase */
  186. ColorPalette[i + (4 * 63)] = SET_RGB(r - 05, v - 05, b + 10);
  187. /* Red + blue emphase */
  188. ColorPalette[i + (5 * 63)] = SET_RGB(r + 05, v - 10, b + 05);
  189. /* Blue + green emphase */
  190. ColorPalette[i + (6 * 63)] = SET_RGB(r - 10, v + 05, b + 05);
  191. /* Red + Green + Blue emphase */
  192. ColorPalette[i + (7 * 63)] = SET_RGB(r + 00, v + 00, b + 00);*/
  193. #else /* Else Use 8Bits */
  194. pal[i].r = r;
  195. pal[i].g = v;
  196. pal[i].b = b;
  197. pal[i + 64].r = r;
  198. pal[i + 64].g = v;
  199. pal[i + 64].b = b;
  200. pal[i + 128].r = r;
  201. pal[i + 128].g = v;
  202. pal[i + 128].b = b;
  203. pal[i + 192].r = r;
  204. pal[i + 192].g = v;
  205. pal[i + 192].b = b;
  206. #endif
  207. }
  208. fclose(fp);
  209. console_printf(Console_Default, " [ OK ]\n");
  210. }
  211. else
  212. {
  213. console_printf(Console_Error, "Error loading palette '%s'!\n", filename);
  214. exit(-1);
  215. }
  216. }
  217. void *signalhandler(int sig)
  218. {
  219. #if 0
  220. static int state=0;
  221. byte F;
  222. int J, I;
  223. static char FA[8] = "NVRBDIZC";
  224. char S[128];
  225. char name[512];
  226. static FILE *fp = NULL;
  227. sprintf(name, "crashdump-%d.txt", (int)time(NULL));
  228. if (state != 0)
  229. {
  230. console_printf(Console_Error, "\n\n\nCrashed within signal!\nEmergency exit\n");
  231. exit(42);
  232. }
  233. state = 1;
  234. if (fp == NULL)
  235. fp = fopen(name, "wt");
  236. state = 2;
  237. if (fp) console_printf(Console_Error,
  238. "\n\n\n\n\n"
  239. "#sick# TI-NESulator %d.%d #sick#\n"
  240. "see %s for more information",
  241. V_MAJOR,
  242. V_MINOR,
  243. name);
  244. if (!fp) fp = stderr;
  245. fprintf(fp,"\n\n\n\n\n"
  246. "#sick# TI-NESulator %d.%d #sick# signal: ",
  247. V_MAJOR,
  248. V_MINOR);
  249. switch(sig)
  250. {
  251. default:
  252. case SIGABRT: fprintf(fp,"Abnormal termination"); break;
  253. case SIGILL: fprintf(fp,"Illegal instruction"); break;
  254. case SIGINT: fprintf(fp,"CTRL+C signal"); break;
  255. case SIGSEGV: fprintf(fp,"Segmentation fault"); break;
  256. case SIGTERM: fprintf(fp,"Termination request"); break;
  257. }
  258. fprintf(fp,"\nAn error occured during the excution.\n Crash report information :\n");
  259. #ifdef DEBUG
  260. DAsm(S, R->PC.W);
  261. #endif
  262. fprintf(fp, "CPU: A:%02X P:%02X X:%02X Y:%02X S:%04X PC:%04X Flags:[",
  263. R->A, R->P, R->X, R->Y, R->S + 0x0100, R->PC.W);
  264. for (J = 0, F = R->P; J < 8; J++, F <<= 1)
  265. fprintf(fp, "%c", F & 0x80 ? FA[J] : '.');
  266. fprintf(fp, "]\nCPU: ");
  267. fprintf(fp, "AT PC: [%02X - %s] AT SP: [%02X %02X %02X]\nLast execution :\n",
  268. Rd6502(R->PC.W), S,
  269. Rd6502(0x0100 + (byte) (R->S + 1)),
  270. Rd6502(0x0100 + (byte) (R->S + 2)),
  271. Rd6502(0x0100 + (byte) (R->S + 3)));
  272. showlastop(fp);
  273. // fprintf(fp, "PPU: CR1: 0x%02X (NT:%d AI:%d SP:%d BP:%d SS:%d NMI:%d)\n",ppu.ControlRegister1.b, ppu.ControlRegister1.s.NameTblAddr, ppu.ControlRegister1.s.AddrIncrmt, ppu.ControlRegister1.s.SptPattern, ppu.ControlRegister1.s.BgPattern, ppu.ControlRegister1.s.SpriteSize, ppu.ControlRegister1.s.VBlank_NMI);
  274. // fprintf(fp, "PPU: CR2: 0x%02X (FBC/CI:%d SV:%d BV:%d SC:%d BC:%d DT:%d)\n",ppu.ControlRegister2.b,ppu.ControlRegister2.s.Colour,ppu.ControlRegister2.s.SpriteVisibility,ppu.ControlRegister2.s.BgVisibility,ppu.ControlRegister2.s.SpriteClipping,ppu.ControlRegister2.s.BgClipping,ppu.ControlRegister2.s.DisplayType);
  275. // fprintf(fp, "PPU: SR: 0x%02X (VB:%d S0:%d SSC:%d VWF:%d)\n", ppu.StatusRegister.b,ppu.StatusRegister.s.VBlankOccur,ppu.StatusRegister.s.Sprite0Occur,ppu.StatusRegister.s.SprtCount,ppu.StatusRegister.s.VRAMProtect);
  276. // fprintf(fp, "PPU: M:%d ST:%d VRAMPtr:0x%04X T:0x%04X\n",ppu.MirrorDir,ppu.ScreenType,ppu.VRAMAddrReg2.W,ppu.TmpVRamPtr);
  277. //MapperDump(fp);
  278. for(I = 0; I < 0xFFFF; I += 0x10)
  279. fprintf(fp, "%04X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X | %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n",
  280. I,
  281. Rd6502(I+0x00), Rd6502(I+0x01), Rd6502(I+0x02), Rd6502(I+0x03),
  282. Rd6502(I+0x04), Rd6502(I+0x05), Rd6502(I+0x06), Rd6502(I+0x07),
  283. Rd6502(I+0x08), Rd6502(I+0x09), Rd6502(I+0x0A), Rd6502(I+0x0B),
  284. Rd6502(I+0x0C), Rd6502(I+0x0D), Rd6502(I+0x0E), Rd6502(I+0x0F),
  285. // --- //
  286. isprint(Rd6502(I+0x00))?Rd6502(I+0x00):'_',
  287. isprint(Rd6502(I+0x01))?Rd6502(I+0x01):'_',
  288. isprint(Rd6502(I+0x02))?Rd6502(I+0x02):'_',
  289. isprint(Rd6502(I+0x03))?Rd6502(I+0x03):'_',
  290. isprint(Rd6502(I+0x04))?Rd6502(I+0x04):'_',
  291. isprint(Rd6502(I+0x05))?Rd6502(I+0x05):'_',
  292. isprint(Rd6502(I+0x06))?Rd6502(I+0x06):'_',
  293. isprint(Rd6502(I+0x07))?Rd6502(I+0x07):'_',
  294. isprint(Rd6502(I+0x08))?Rd6502(I+0x08):'_',
  295. isprint(Rd6502(I+0x09))?Rd6502(I+0x09):'_',
  296. isprint(Rd6502(I+0x0A))?Rd6502(I+0x0A):'_',
  297. isprint(Rd6502(I+0x0B))?Rd6502(I+0x0B):'_',
  298. isprint(Rd6502(I+0x0C))?Rd6502(I+0x0C):'_',
  299. isprint(Rd6502(I+0x0D))?Rd6502(I+0x0D):'_',
  300. isprint(Rd6502(I+0x0E))?Rd6502(I+0x0E):'_',
  301. isprint(Rd6502(I+0x0F))?Rd6502(I+0x0F):'_');
  302. DumpMemoryState(fp);
  303. console_printf(Console_Error, "\nPlease join this informations when submiting crash report\n");
  304. if (fp != stderr) fclose(fp);
  305. #endif
  306. exit(-42);
  307. }
  308. byte Page40[256];
  309. void WrHook4000Multiplexer(byte addr, byte value)
  310. {
  311. static byte SQ1V = 0;
  312. static byte SQ2V = 0;
  313. static byte NOIV = 0;
  314. static unsigned short SQ1P = 0;
  315. static unsigned short SQ2P = 0;
  316. static unsigned short TRIP = 0;
  317. static unsigned short NOIP = 0;
  318. static byte Sq1_reg0 = 0;
  319. static byte Sq1_reg1 = 0;
  320. static byte Sq1_reg2 = 0;
  321. static byte Sq1_reg3 = 0;
  322. static byte Sq2_reg0 = 0;
  323. static byte Sq2_reg1 = 0;
  324. static byte Sq2_reg2 = 0;
  325. static byte Sq2_reg3 = 0;
  326. double SQ = 0.0;
  327. switch(addr)
  328. {
  329. #ifdef USE_SOUND
  330. case 0x00: /* DDLE NNNN */
  331. Sq1_reg0 = value;
  332. if (Sq1_reg0 & 0x10)
  333. {
  334. SQ1V = (0x04+(value&0x0F))& 0x0F;
  335. }
  336. else
  337. {
  338. SQ1V = value&0x0F;
  339. }
  340. break;
  341. case 0x01: /* EPPP NSSS */
  342. Sq1_reg1 = value;
  343. break;
  344. case 0x02:
  345. /*console_printf(Console_Default, "Sq1 reg0: 0x%02X - duty:0x%X loop:0x%X env:0x%X vol:0x%X\n",
  346. Sq1_reg0,
  347. (Sq1_reg0&0xC0)>>6,
  348. (Sq1_reg0&0x20)>>5,
  349. (Sq1_reg0&0x10)>>4,
  350. Sq1_reg0&0x0F);
  351. console_printf(Console_Default, "Sq1 reg1: 0x%02X - sweep:0x%X period:0x%X neg:0x%X shift:0x%X\n",
  352. Sq1_reg1,
  353. (Sq1_reg1&0x80)>>8,
  354. (Sq1_reg1&0x70)>>4,
  355. (Sq1_reg1&0x08)>>3,
  356. Sq1_reg1&0x07);
  357. console_printf(Console_Default, "Sq1 reg2: 0x%02X\n", value);
  358. console_printf(Console_Default, "Sq1 reg3: 0x%02X\n", Sq1_reg3);*/
  359. SQ1P = value | ((Sq1_reg3&0x7) << 8);
  360. SQ = APU_BASEFREQ * 1000 * 1000 / (SQ1P+1 /*+
  361. (Sq1_reg1&0x80)?0:( (Sq1_reg1&0x08)?(SQ1P>>(Sq1_reg1&0x07)):(SQ1P<<(Sq1_reg1&0x07)) )*/);
  362. //SetSound(0,SND_MELODIC);
  363. //console_printf(Console_Default, "SQ1V = %d - SQ = %f - SQ1P = %d\n", SQ1V, SQ, SQ1P);
  364. #ifdef SOUND_LOG
  365. { FILE *fp = fopen("sound.log", "at"); fprintf(fp, "%d %d %d\n", 0, SQ1P, SQ1V); fclose(fp); }
  366. #endif
  367. Sound(0, (int) SQ/22, (0xFF/0x0F) * SQ1V);
  368. //console_printf(Console_Default, "40%02X: 0x%02X (SQ1P:%d SQ:%f (%d))\n", addr, value, SQ1P, SQ, (int) SQ);
  369. Sq1_reg2 = value;
  370. break;
  371. case 0x03:
  372. Sq1_reg3 = value;
  373. SQ1P = Sq1_reg2 | ((value&0x7) << 8);
  374. SQ = APU_BASEFREQ * 1000 * 1000 / (SQ1P+1 /*+
  375. (Sq1_reg1&0x80)?0:( (Sq1_reg1&0x08)?(SQ1P>>(Sq1_reg1&0x07)):(SQ1P<<(Sq1_reg1&0x07)) )*/);
  376. #ifdef SOUND_LOG
  377. { FILE *fp = fopen("sound.log", "at"); fprintf(fp, "%d %d %d\n", 0, SQ1P, SQ1V); fclose(fp); }
  378. #endif
  379. Sound(0, (int) SQ/22, (0xFF/0x0F) * SQ1V);
  380. break;
  381. case 0x04:
  382. Sq2_reg0 = value;
  383. if (Sq2_reg0 & 0x10)
  384. {
  385. SQ2V = (0x04+(value&0x0F))& 0x0F;
  386. }
  387. else
  388. {
  389. SQ2V = value&0x0F;
  390. }
  391. break;
  392. case 0x05:
  393. Sq2_reg1 = value;
  394. break;
  395. case 0x06:
  396. Sq2_reg2 = value;
  397. SQ2P = Sq2_reg2 | ((Sq2_reg3&0x7) << 8);
  398. SQ = APU_BASEFREQ * 1000 * 1000 / (SQ2P+1 /*+
  399. (Sq2_reg1&0x80)?0:( (Sq2_reg1&0x08)?(SQ2P>>(Sq2_reg1&0x07)):(SQ2P<<(Sq2_reg1&0x07)) )*/);
  400. /* console_printf(Console_Default, "Sq2 reg0: 0x%02X - duty:0x%X loop:0x%X env:0x%X vol:0x%X\n",
  401. Sq2_reg0,
  402. (Sq2_reg0&0xC0)>>6,
  403. (Sq2_reg0&0x20)>>5,
  404. (Sq2_reg0&0x10)>>4,
  405. Sq2_reg0&0x0F);
  406. console_printf(Console_Default, "Sq2 reg1: 0x%02X - sweep:0x%X period:0x%X neg:0x%X shift:0x%X\n",
  407. Sq2_reg1,
  408. (Sq2_reg1&0x80)>>8,
  409. (Sq2_reg1&0x70)>>4,
  410. (Sq2_reg1&0x08)>>3,
  411. Sq2_reg1&0x07);
  412. console_printf(Console_Default, "Sq2 reg2: 0x%02X\n", value);
  413. console_printf(Console_Default, "Sq2 reg3: 0x%02X\n", Sq2_reg3);
  414. console_printf(Console_Default, "SQ2V = %d - SQ = %f - SQ2P = %d\n", SQ2V, SQ, SQ2P);*/
  415. #ifdef SOUND_LOG
  416. { FILE *fp = fopen("sound.log", "at"); fprintf(fp, "%d %d %d\n", 1, SQ2P, SQ2V); fclose(fp); }
  417. #endif
  418. Sound(1, (int) SQ/22, (0xFF/0x0F) * SQ2V);
  419. break;
  420. case 0x07:
  421. Sq2_reg3 = value;
  422. SQ2P = Sq2_reg2 | ((Sq2_reg3&0x7) << 8);
  423. SQ = APU_BASEFREQ * 1000 * 1000 / (SQ2P+1 /*+
  424. (Sq2_reg1&0x80)?0:( (Sq2_reg1&0x08)?(SQ2P>>(Sq2_reg1&0x07)):(SQ2P<<(Sq2_reg1&0x07)) )*/);
  425. #ifdef SOUND_LOG
  426. { FILE *fp = fopen("sound.log", "at"); fprintf(fp, "%d %d %d\n", 1, SQ2P, SQ2V); fclose(fp); }
  427. #endif
  428. Sound(1, (int) SQ/22, (0xFF/0x0F) * SQ2V);
  429. break;
  430. case 0x0A:
  431. TRIP = (TRIP & 0xFF00) | value;
  432. SQ = APU_BASEFREQ * 1000 * 1000 / TRIP;
  433. #ifdef SOUND_LOG
  434. { FILE *fp = fopen("sound.log", "at"); fprintf(fp, "%d %d %d\n", 2, TRIP, 127); fclose(fp); }
  435. #endif
  436. Sound(2, (int) SQ/22, 127);
  437. break;
  438. case 0x0B:
  439. TRIP = (TRIP & 0x00FF) | ((value&0x7) << 8);;
  440. SQ = APU_BASEFREQ * 1000 * 1000 / TRIP;
  441. #ifdef SOUND_LOG
  442. { FILE *fp = fopen("sound.log", "at"); fprintf(fp, "%d %d %d\n", 2, TRIP, 127); fclose(fp); }
  443. #endif
  444. Sound(2, (int) SQ/22, 127);
  445. break;
  446. case 0x0C:
  447. NOIV = value & 0x0F;
  448. #ifdef SOUND_LOG
  449. { FILE *fp = fopen("sound.log", "at"); fprintf(fp, "%d %d %d\n", 3, NOIP, NOIV); fclose(fp); }
  450. #endif
  451. //SetSound(3, SND_NOISE);
  452. Sound(3, (int) SQ/22, (0xFF/0x0F) * NOIV);
  453. break;
  454. case 0x0E:
  455. NOIP = value & 0x0F;
  456. SQ = APU_BASEFREQ * 1000 * 1000 / NOIP;
  457. #ifdef SOUND_LOG
  458. { FILE *fp = fopen("sound.log", "at"); fprintf(fp, "%d %d %d\n", 3, NOIP, NOIV); fclose(fp); }
  459. #endif
  460. //SetSound(3, SND_NOISE);
  461. Sound(3, (int) SQ/22, NOIV);
  462. break;
  463. case 0x0F:
  464. break;
  465. case 0x15:
  466. /* DMC, Noise, Triangle, Sq 2, Sq 1 */
  467. //SetChannels(0, (value&0x01)?0x01:0);
  468. /* console_printf(Console_Default, "40%02X: 0x%02X [%c%c%c%c%c]\n", addr, value,
  469. (value&0x10)?'d':'.',
  470. (value&0x08)?'n':'.',
  471. (value&0x04)?'t':'.',
  472. (value&0x02)?'2':'.',
  473. (value&0x01)?'1':'.');*/
  474. break;
  475. #endif
  476. case 0x14:
  477. ppu_fillSprRamDMA(value);
  478. break;
  479. case 0x16:
  480. WritePaddle(&P1, value);
  481. //WritePaddle(&P2, value);
  482. break;
  483. case 0x17:
  484. if (value == 0x00)
  485. {
  486. quick6502_int(MainCPU, Q6502_IRQ_SIGNAL);
  487. }
  488. break;
  489. // default:
  490. //Page40[addr] = value;
  491. // console_printf(Console_Default, "40%02X: 0x%02X\n", addr, value);
  492. // console_printf(Console_Default, "pAPU: 0x%X @ 0x40%X\n", value, addr);
  493. }
  494. }
  495. byte RdHook4000Multiplexer(byte addr)
  496. {
  497. byte ret;
  498. switch(addr)
  499. {
  500. case 0x16:
  501. ret = ReadPaddle(&P1);
  502. break;
  503. case 0x17:
  504. ret = 0x40;
  505. break;
  506. case 0x15:
  507. ret = 0x1F;
  508. break;
  509. default:
  510. ret = 0x42;
  511. }
  512. return ret;
  513. }
  514. void printUsage(int argc, char *argv[])
  515. {
  516. console_printf(Console_Default, "Usage : %s game.nes [-p number][-f][-b filename.pal][ filename.nes\n"
  517. " -p: to add plugin 'number'\n"
  518. " -f: to start in FDS mode\n"
  519. " -d: to start directily into the debugguer\n"
  520. " -b: to use palette file 'filename.pal'\n",
  521. argv[0]);
  522. exit(0);
  523. }
  524. int main(int argc, char *argv[])
  525. {
  526. int i;
  527. unsigned char j, k;
  528. unsigned char *MemoryPage;
  529. quick6502_cpuconfig CpuConfig;
  530. /* Here we will fill the memory */
  531. /*
  532. --------------------------------------- $10000
  533. Upper Bank of Cartridge ROM
  534. --------------------------------------- $C000
  535. Lower Bank of Cartridge ROM
  536. --------------------------------------- $8000
  537. Cartridge RAM (may be battery-backed)
  538. --------------------------------------- $6000
  539. Expansion Modules
  540. --------------------------------------- $5000
  541. Input/Output
  542. --------------------------------------- $2000
  543. 2kB Internal RAM, mirrored 4 times
  544. --------------------------------------- $0000
  545. */
  546. console_init(Console_Default);
  547. /* Print the banner */
  548. console_printf(Console_Default, "--------------------------------------------------------------------------------\n"
  549. "Welcome to TI-NESulator v%d.%d - by Godzil\n"
  550. "Copyright 2003-2008 TRAPIER Manoel (godzil@godzil.net)\n"
  551. "%s\n%s\n%s\n"
  552. "--------------------------------------------------------------------------------\n\n",
  553. V_MAJOR,
  554. V_MINOR,
  555. VS_REVISION,
  556. VS_LASTCHANGEDDATE,
  557. VS_AUTHOR);
  558. console_printf(Console_Default, "Install signal handlers...\t[");
  559. // signal(SIGABRT,signalhandler);
  560. console_printf(Console_Default, "A");
  561. // signal(SIGILL,signalhandler);
  562. console_printf(Console_Default, "I");
  563. /*signal(SIGINT,signalhandler);*/
  564. console_printf(Console_Default, ".");
  565. // signal(SIGSEGV,signalhandler);
  566. console_printf(Console_Default, "S");
  567. // signal(SIGTERM,signalhandler);
  568. console_printf(Console_Default, "T]\n");
  569. /* */
  570. console_printf(Console_Default, "Initialize memory...\t\t");
  571. InitMemory();
  572. console_printf(Console_Default, "[ OK ]\n");
  573. console_printf(Console_Default, "Parsing parameters (%d)...\n", argc);
  574. /* Now we use a real argument parser ! */
  575. for(i = 1 ; (i < argc) && (argv[i][0]=='-'); i++)
  576. {
  577. switch(argv[i][1])
  578. {
  579. default: /* Option not recognized */
  580. case 'h': /* ask for help */
  581. printUsage(argc, argv);
  582. break;
  583. case 'p':
  584. if (atoi(argv[i+1]) != 0)
  585. {
  586. console_printf(Console_Default, "-Load plugin #%d...\n", atoi(argv[i+1]));
  587. if ( plugin_load(atoi(argv[i+1])) == -1)
  588. {
  589. plugin_list();
  590. exit(0);
  591. }
  592. i++;
  593. }
  594. else
  595. {
  596. plugin_list();
  597. exit(0);
  598. }
  599. break;
  600. case 'f':
  601. console_printf(Console_Default, "-Start with fds!\n");
  602. START_WITH_FDS = 1;
  603. break;
  604. case 'd':
  605. console_printf(Console_Default, "-Start with debug!\n");
  606. START_DEBUG = 1;
  607. break;
  608. case 'b':
  609. console_printf(Console_Default, "-Palette file is %s\n", argv[i+1]);
  610. PALETTE_FILENAME = argv[i+1];
  611. i++;
  612. break;
  613. }
  614. }
  615. CART_FILENAME = argv[argc-1];
  616. if (CART_FILENAME == NULL)
  617. printUsage(argc, argv);
  618. console_printf(Console_Default, "Allocating 6502 memory\t\t");
  619. /* Allocating first 0x7FF memory */
  620. MemoryPage = (unsigned char *)malloc (0x800);
  621. set_page_ptr_2k(0,MemoryPage);
  622. for (i = 0; i < 0x08; i++)
  623. {
  624. set_page_readable(i, true);
  625. set_page_writeable(i, true);
  626. }
  627. /* Set ghost starting from 0x800 */
  628. set_page_ghost(0x08,true,0x00);
  629. set_page_ghost(0x09,true,0x01);
  630. set_page_ghost(0x0A,true,0x02);
  631. set_page_ghost(0x0B,true,0x03);
  632. set_page_ghost(0x0C,true,0x04);
  633. set_page_ghost(0x0D,true,0x05);
  634. set_page_ghost(0x0E,true,0x06);
  635. set_page_ghost(0x0F,true,0x07);
  636. /* Set ghost starting from 0x1000 */
  637. set_page_ghost(0x10,true,0x00);
  638. set_page_ghost(0x11,true,0x01);
  639. set_page_ghost(0x12,true,0x02);
  640. set_page_ghost(0x13,true,0x03);
  641. set_page_ghost(0x14,true,0x04);
  642. set_page_ghost(0x15,true,0x05);
  643. set_page_ghost(0x16,true,0x06);
  644. set_page_ghost(0x17,true,0x07);
  645. /* Set ghost starting from 0x1800 */
  646. set_page_ghost(0x18,true,0x00);
  647. set_page_ghost(0x19,true,0x01);
  648. set_page_ghost(0x1A,true,0x02);
  649. set_page_ghost(0x1B,true,0x03);
  650. set_page_ghost(0x1C,true,0x04);
  651. set_page_ghost(0x1D,true,0x05);
  652. set_page_ghost(0x1E,true,0x06);
  653. set_page_ghost(0x1F,true,0x07);
  654. /* Set 0x4000 registers */
  655. /* "hack" : only page $40 is used by multiple devices, we need to multiplexe
  656. it*/
  657. set_page_wr_hook(0x40, WrHook4000Multiplexer);
  658. set_page_rd_hook(0x40, RdHook4000Multiplexer);
  659. set_page_readable(0x40, true);
  660. set_page_writeable(0x40, true);
  661. /* Exp ROM : Nothing to do actually */
  662. /* ROM ptr will be set by mapper */
  663. /* But we will set the readable bit */
  664. for (i = 0x80; i < 0x100; i++)
  665. {
  666. set_page_readable(i, true);
  667. set_page_writeable(i, false);
  668. }
  669. console_printf(Console_Default, "[ OK ]\n");
  670. #define Value(s) (((s%0xFF) + (rand()%0xFF-128) )%0xFF)
  671. console_printf(Console_Default, "Testing memory validity...\n");
  672. map_sram();
  673. console_printf(Console_Verbose, "Testing Page Zero\n");
  674. for( i = 0 ; i < 0x100 ; i++)
  675. {
  676. j = rand() % 0xFF;
  677. MemoryPage[i] = j;
  678. if ((k = MemoryPageZeroRead(i)) != j)
  679. console_printf(Console_Error, "Error MemoryPageZeroRead @ 0x%04X [j:%02X, should:%02X, is:%02X]\n", i, j, MemoryPage[i], k);
  680. j = rand() % 0xFF;
  681. MemoryPageZeroWrite(i, j);
  682. if ((k = MemoryPage[i]) != j)
  683. console_printf(Console_Error, "Error MemoryPageZeroWrite @ 0x%04X [j:%02X, should:%02X, is:%02X]\n", i, j, MemoryPage[i], k);
  684. MemoryPage[i] = 0;
  685. }
  686. console_printf(Console_Verbose, "Testing memory... (<0x2000)\n");
  687. for( i = 0 ; i < 0x2000 ; i++ )
  688. {
  689. j = Value(i);
  690. MemoryWrite(i, j);
  691. if ((k=MemoryRead(i)) != j)
  692. console_printf(Console_Error, "Error read/write @ 0x%X [w:%d,r:%d]\n", i, j, k);
  693. if ((k=MemoryOpCodeRead(i)) != j)
  694. console_printf(Console_Error, "Error opcode @ 0x%X [w:%d,r:%d]\n", i, j, k);
  695. }
  696. /* SRAM (0x6000 : 0x2000 bytes ) */
  697. MemoryPage = (unsigned char *)malloc (0x2000);
  698. set_page_ptr_8k(0x60, MemoryPage);
  699. for(i = 0x6000; i < 0x8000; i ++)
  700. {
  701. if (MemoryPage[i-0x6000] != (k = MemoryRead(i)))
  702. console_printf(Console_Error, "Error MemoryRead @ 0x%X [should:%d,is:%d]\n", i, MemoryPage[i-0x6000], k);
  703. if (MemoryPage[i-0x6000] != (k = MemoryOpCodeRead(i)))
  704. console_printf(Console_Error, "Error MemoryOpCodeRead @ 0x%X [should:%d,is:%d]\n", i, MemoryPage[i-0x6000], k);
  705. }
  706. console_printf(Console_Verbose, "Testing memory... (0x6000-0x8000)\n");
  707. for(i=0x6000;i<0x8000;i++)
  708. {
  709. j = Value(i);
  710. MemoryWrite(i, j);
  711. if ((k=MemoryRead(i)) != j)
  712. console_printf(Console_Error, "Error read/write @ 0x%X [w:%d,r:%d]\n", i, j, k);
  713. if ((k=MemoryOpCodeRead(i)) != j)
  714. console_printf(Console_Error, "Error opcode @ 0x%X [w:%d,r:%d]\n", i, j, k);
  715. }
  716. console_printf(Console_Default, "Reseting main RAM...\t\t");
  717. /* Force the stack to be full of zero */
  718. for( i = 0x100 ; i < 0x200 ; i++ )
  719. {
  720. MemoryWrite(i, 0x00);
  721. }
  722. console_printf(Console_Default, "[ OK ]\n");
  723. Cart = malloc( sizeof (NesCart));
  724. if (Cart == NULL)
  725. {
  726. console_printf(Console_Error, "Memory allocation error...\n");
  727. exit(-1);
  728. }
  729. if (START_WITH_FDS)
  730. {
  731. int fd;
  732. console_printf(Console_Default, "Loading FDS ROM...\t\t");
  733. //fd = open("../data/disksys.rom", O_RDONLY);
  734. fd = open("TI-NESulator.app/Contents/Resources/disksys.rom", O_RDONLY);
  735. FDSRom = mmap(NULL, 8*1024, PROT_READ, MAP_PRIVATE, fd, 0);
  736. console_printf(Console_Default, "%p [ OK ]\n", FDSRom);
  737. close(fd);
  738. set_page_ptr_8k(0xE0, FDSRom);
  739. console_printf(Console_Default, "Allocating FDS RAM...\n");
  740. FDSRam = (byte*) malloc( (8+16) * 1024);
  741. if (FDSRam == NULL)
  742. {
  743. console_printf(Console_Error, "Allocation error\n");
  744. exit(-1);
  745. }
  746. for (i = 0x80; i < 0xE0; i++)
  747. {
  748. set_page_ptr(i, FDSRam + (i*0x100));
  749. set_page_readable(i, true);
  750. set_page_writeable(i, true);
  751. }
  752. Cart->MapperID = 100;
  753. }
  754. else
  755. {
  756. console_printf(Console_Default, "Please Wait while loading %s cartridge...\n", CART_FILENAME);
  757. if (LoadCart(CART_FILENAME, Cart) != 0)
  758. {
  759. console_printf(Console_Error, "Loading error...\n");
  760. exit(-1);
  761. }
  762. if (Cart->Flags & iNES_BATTERY)
  763. {
  764. LoadSaveRam(CART_FILENAME);
  765. }
  766. }
  767. unmap_sram();
  768. InitPaddle(&P1);
  769. console_printf(Console_Default, "Initializing Allegro...\t\t");
  770. allegro_init();
  771. install_timer();
  772. install_keyboard();
  773. console_printf(Console_Default, "[ OK ]\n");
  774. console_printf(Console_Default, "Set graphic mode...\t\t");
  775. set_color_depth(8);
  776. set_gfx_mode(GFX_AUTODETECT_WINDOWED, 512 + 256, 480, 512 + 256, 480);
  777. Buffer = create_bitmap(512 + 256, 480);
  778. clear_to_color(Buffer, 0x0D);
  779. //set_close_button_callback(CloseHook);
  780. //set_window_title("TI-NESulator");
  781. console_printf(Console_Default, "[ OK ]\n");
  782. console_printf(Console_Default, "Init PPU...\n");
  783. if (ppu_init() != 0)
  784. {
  785. console_printf(Console_Error, "PPU Initialisation error..\n");
  786. exit(-1);
  787. }
  788. DumpMemoryState();
  789. if (Cart->Flags & iNES_4SCREEN)
  790. {
  791. ppu_setScreenMode(PPU_SCMODE_FOURSC);
  792. }
  793. else
  794. {
  795. ppu_setScreenMode(PPU_SCMODE_NORMAL);
  796. ppu_setMirroring((Cart->Flags & iNES_MIRROR)?PPU_MIRROR_VERTICAL:PPU_MIRROR_HORIZTAL);
  797. }
  798. console_printf(Console_Default, "Init mapper...\t\t\t");
  799. if (mapper_init(Cart) == -1)
  800. return -1;
  801. console_printf(Console_Default, "[ OK ]\n");
  802. if (PALETTE_FILENAME == NULL)
  803. {
  804. set_palette(basicPalette);
  805. }
  806. else
  807. {
  808. LoadPalette(PALETTE_FILENAME, pal);
  809. set_palette(pal);
  810. }
  811. #ifdef USE_SOUND
  812. InitSound(44400,!0);
  813. SetSound(0, SND_RECTANGLE);
  814. SetSound(1, SND_RECTANGLE);
  815. SetSound(2, SND_TRIANGLE);
  816. SetSound(3, SND_NOISE);
  817. #endif
  818. // Actually no real debugguer...
  819. //console_printf(Console_Default, "Press ESC to pause emulation and jump to debugguer\n");
  820. install_int(ips_fps_counter, 1000);
  821. ScanLine = 0;
  822. /* Initialize the CPU */
  823. CpuConfig.memory_read = MemoryRead;
  824. CpuConfig.memory_write = MemoryWrite;
  825. CpuConfig.memory_page0_read = MemoryPageZeroRead;
  826. CpuConfig.memory_page0_write = MemoryPageZeroWrite;
  827. CpuConfig.memory_stack_read = MemoryStackRead;
  828. CpuConfig.memory_stack_write = MemoryStackWrite;
  829. CpuConfig.memory_opcode_read = MemoryOpCodeRead;
  830. MainCPU = quick6502_init(&CpuConfig);
  831. quick6502_reset(MainCPU);
  832. /* No debugger actually
  833. MainCPU.Trace = 0;
  834. if (START_DEBUG)
  835. MainCPU.Trace = 1;
  836. */
  837. gettimeofday(&timeStart, NULL);
  838. while(!WantClosing)
  839. {
  840. ccount += quick6502_run(MainCPU, HBLANK_TIME);
  841. Loop6502(MainCPU);
  842. }
  843. if (Cart->Flags & iNES_BATTERY)
  844. {
  845. SaveSaveRam(CART_FILENAME);
  846. }
  847. return 0;
  848. }
  849. //END_OF_MAIN()
  850. /* Access directly to Memory pages *HACKISH* */
  851. extern byte *memory_pages[0xFF];
  852. /* Memory functions */
  853. /* Read memory, general function */
  854. byte MemoryRead (unsigned short Addr)
  855. {
  856. return ReadMemory((Addr&0xFF00)>>8,Addr&0x00FF);
  857. }
  858. /* Read memory for opcode (need fast access) */
  859. byte MemoryOpCodeRead (unsigned short Addr)
  860. {
  861. byte *ptr;
  862. return ((ptr = memory_pages[(Addr&0xFF00)>>8])>(byte*)1)?ptr[Addr&0x00FF]:0xEA;
  863. }
  864. byte MemoryStackRead (unsigned short Addr)
  865. {
  866. byte *ptr = memory_pages[1];
  867. return ptr[Addr&0x00FF];
  868. }
  869. byte MemoryPageZeroRead (unsigned short Addr)
  870. {
  871. byte *ptr = memory_pages[0];
  872. return ptr[Addr&0x00FF];
  873. }
  874. /* Write to memory, general function */
  875. void MemoryWrite (unsigned short Addr, byte Value)
  876. {
  877. WriteMemory((Addr&0xFF00)>>8,Addr&0x00FF, Value);
  878. }
  879. void MemoryStackWrite (unsigned short Addr, byte Value)
  880. {
  881. byte *ptr = memory_pages[1];
  882. ptr[Addr&0x00FF] = Value;
  883. }
  884. void MemoryPageZeroWrite (unsigned short Addr, byte Value)
  885. {
  886. byte *ptr = memory_pages[0];
  887. ptr[Addr&0x00FF] = Value;
  888. }
  889. void Loop6502(quick6502_cpu *R)
  890. {
  891. byte ret;
  892. short skey;
  893. long WaitTime;
  894. static long delta=0;
  895. ret = 0;
  896. if ( mapper_irqloop (ScanLine) )
  897. {
  898. ret = Q6502_IRQ_SIGNAL;
  899. IRQScanHit = ScanLine;
  900. }
  901. if ( MapperWantIRQ == 1)
  902. {
  903. MapperWantIRQ = 0;
  904. ret = Q6502_IRQ_SIGNAL;
  905. }
  906. if ( ppu_hblank(ScanLine) != 0 )
  907. {
  908. ret = Q6502_NMI_SIGNAL;
  909. }
  910. if (ScanLine == 239)
  911. frame++;
  912. if (ScanLine == (239 + VBLANK_TIME))
  913. { /* End of VBlank Time */
  914. /* Sync at 60FPS */
  915. /* Get current time in microseconds */
  916. gettimeofday(&timeEnd, NULL);
  917. WaitTime = (timeEnd.tv_sec) - (timeStart.tv_sec);
  918. WaitTime *= 1000000;
  919. WaitTime += (timeEnd.tv_usec - timeStart.tv_usec);
  920. #if !ISPAL && ISNTSC
  921. /* Calculate the waiting time, 16666 is the time of one frame in microseconds at a 60Hz rate) */
  922. WaitTime = 16666 - WaitTime + delta;
  923. #elif ISPAL && !ISNTSC
  924. WaitTime = 20000 - WaitTime + delta;
  925. #endif
  926. /* If we press Page Up, we want to accelerate "time" */
  927. if (!key[KEY_PGUP])
  928. if ((WaitTime >= 0) && (WaitTime < 100000))
  929. usleep(WaitTime);
  930. /* Now get the time after sleep */
  931. gettimeofday(&timeStart, NULL);
  932. /* Now calculate How many microseconds we really spend in sleep and
  933. calculate a delta for next iteration */
  934. delta = (timeStart.tv_sec) - (timeEnd.tv_sec);
  935. delta *= 1000000;
  936. delta += (timeStart.tv_usec - timeEnd.tv_usec);
  937. delta = WaitTime - delta;
  938. /* To avoid strange time warp when stoping emulation or using acceleration a lot */
  939. if ((delta > 10000) || (delta < -10000))
  940. delta = 0;
  941. }
  942. /* There is Two dummy scanline */
  943. if (ScanLine >= (239 + VBLANK_TIME + 4))
  944. ScanLine = 0;
  945. else
  946. ScanLine++;
  947. //console_printf(Console_Default, "SL:%d HBT:%d VbT:%d\n", ScanLine, HBLANK_TIME, VBLANK_TIME);
  948. if (keypressed())
  949. {
  950. skey = (readkey() & 0xFF);
  951. // TODO: NO DEBUGER
  952. /* if (skey == 27)
  953. R->Trace = 1;*/
  954. if (skey == '9')
  955. {
  956. VBLANK_TIME += 2;
  957. console_printf(Console_Default, "VBLT: %d\n", VBLANK_TIME);
  958. }
  959. if (skey == '6')
  960. {
  961. VBLANK_TIME -= 2;
  962. console_printf(Console_Default, "VBLT: %d\n", VBLANK_TIME);
  963. }
  964. if (skey == '7')
  965. {
  966. HBLANK_TIME += 1;
  967. console_printf(Console_Default, "HBLT: %d\n", HBLANK_TIME);
  968. }
  969. if (skey == '4')
  970. {
  971. HBLANK_TIME -= 1;
  972. console_printf(Console_Default, "HBLT: %d\n", HBLANK_TIME);
  973. }
  974. if ((skey == 'r') || (skey == 'R'))
  975. {
  976. /* Force the PPU to stop NMIs */
  977. MemoryWrite(0x2000, 0x00);
  978. quick6502_reset(R);
  979. }
  980. plugin_keypress(skey);
  981. }
  982. if (ret != 0)
  983. quick6502_int(R, ret);
  984. }