main.c 33 KB

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