ppu.24.c 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312
  1. /*
  2. * PPU emulation - The peTI-NESulator Project
  3. * ppu.c
  4. *
  5. * Define and emulate the PPU (Picture Processing Unit) of the real NES
  6. *
  7. * Created by Manoel TRAPIER.
  8. * Copyright (c) 2003-2008 986Corp. All rights reserved.
  9. *
  10. * $LastChangedDate$
  11. * $Author$
  12. * $HeadURL$
  13. * $Revision$
  14. *
  15. */
  16. #include <allegro.h>
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include "ppu.h"
  20. #include "memory.h"
  21. #include "M6502.h"
  22. #define __TINES_PLUGINS__
  23. #include "plugins.h"
  24. #define GetTileColor(tile,x1,y1) ( ( ppu.Memory[tile+y1] & (1<<(7-x1)) ) == 0 ? 0 : 1 ) | \
  25. ( ( ppu.Memory[tile+y1+8] & (1<<(7-x1)) ) == 0 ? 0 : 1<<1 )
  26. #define GetColor(col) (col)
  27. extern PPU ppu;
  28. extern BITMAP *Buffer;
  29. extern unsigned short ScanLine;
  30. unsigned long BgColor;
  31. volatile extern int frame;
  32. volatile extern unsigned long IPS, FPS;
  33. extern unsigned long ColorPalette[ 8 * 63 ];
  34. extern short IRQScanHit;
  35. byte NOBLIT = 0;
  36. int InitPPU(PPU * ppu)
  37. {
  38. int i;
  39. if ((ppu->Memory = (unsigned char *) malloc(0x4000)) == NULL)
  40. return -1;
  41. NOBLIT = 0;
  42. /* Initializing register.. */
  43. ppu->In_VBlank = 0;
  44. ppu->BaseOneScreen = 0x2000;
  45. ppu->ControlRegister1.b = 0;
  46. ppu->ControlRegister2.b = 0;
  47. ppu->StatusRegister.b = 0;
  48. ppu->SPR_RAMAddr = 0;
  49. ppu->VRAMAddrReg1.W = 0;
  50. ppu->VRAMAddrReg2.W = 0;
  51. ppu->VRAMAddrMode = 0;
  52. ppu->Bg_Pattern_Table = 0x0000;
  53. ppu->Name_Table_Addresse = 0x2000;
  54. ppu->Sprt_Pattern_Table = 0x0000;
  55. ppu->PPU_Inc = 1;
  56. ppu->MirrorDir = 0;
  57. ppu->ScreenType = 1;
  58. ppu->ForceBgVisibility = 0;
  59. ppu->ForceSpriteVisibility = 0;
  60. ppu->DisplayNameTables = ~0;
  61. ppu->DisplayAttributeTable = ~0;
  62. ppu->DisplayPalette = ~0;
  63. ppu->DisplayVRAM = ~0;
  64. /* Set PPU registers */
  65. set_page_rd_hook(0x20, ReadPPUReg);
  66. set_page_wr_hook(0x20, WritePPUReg);
  67. set_page_readable(0x20, true);
  68. set_page_writeable(0x20, true);
  69. /* Set PPU Ghost Registers */
  70. for(i = 0x21; i < 0x40; i++)
  71. set_page_ghost(i, true, 0x20);
  72. plugin_install_keypressHandler('i', DebugSprites);
  73. plugin_install_keypressHandler('I', DebugSprites);
  74. plugin_install_keypressHandler('u', DebugColor);
  75. plugin_install_keypressHandler('U', DebugColor);
  76. return 0;
  77. }
  78. PPUSprite PPUGetSprite(unsigned short i)
  79. {
  80. PPUSprite ret;
  81. ret.y = ppu.SPRRAM[i * 4];
  82. ret.tileid = ppu.SPRRAM[i * 4 + 1];
  83. /*ret.flags.s.BgPrio = (ppu.SPRRAM[i * 4 + 2] & (1 << 5)) == 0 ? 0 : 1;
  84. ret.flags.s.HFlip = (ppu.SPRRAM[i * 4 + 2] & (1 << 6)) == 0 ? 0 : 1;
  85. ret.flags.s.UpperColor = ppu.SPRRAM[i * 4 + 2] & 0x03;
  86. ret.flags.s.VFlip = (ppu.SPRRAM[i * 4 + 2] & (1 << 7)) == 0 ? 0 : 1;*/
  87. ret.flags.b = ppu.SPRRAM[i * 4 + 2];
  88. ret.x = ppu.SPRRAM[i * 4 + 3];
  89. return ret;
  90. }
  91. void PPUSetSprite(unsigned short i, PPUSprite *sprt)
  92. {
  93. ppu.SPRRAM[i * 4] = sprt->y;
  94. ppu.SPRRAM[i * 4 + 1] = sprt->tileid;
  95. /*ret.flags.s.BgPrio = (ppu.SPRRAM[i * 4 + 2] & (1 << 5)) == 0 ? 0 : 1;
  96. ret.flags.s.HFlip = (ppu.SPRRAM[i * 4 + 2] & (1 << 6)) == 0 ? 0 : 1;
  97. ret.flags.s.UpperColor = ppu.SPRRAM[i * 4 + 2] & 0x03;
  98. ret.flags.s.VFlip = (ppu.SPRRAM[i * 4 + 2] & (1 << 7)) == 0 ? 0 : 1;*/
  99. ppu.SPRRAM[i * 4 + 2] = sprt->flags.b;
  100. ppu.SPRRAM[i * 4 + 3] = sprt->x;
  101. }
  102. //(Addr & 0x1FF) /* Addr In NT */
  103. // (Addr & 0xC00) >> 2 /* NT number */
  104. #define GetNT(a) ( (a&0xC00) >> 10 )
  105. #define RelAddr(a) (a & 0x3FF)
  106. #define PalAddr(a) (a & 0x1F)
  107. unsigned char PPU_Rd(unsigned short Addr)
  108. {
  109. if (Addr > (unsigned short) 0x3FFF)
  110. {
  111. Addr &= 0x3FFF;
  112. }
  113. if ((Addr < 0x3F00) && (Addr >= 0x2000))
  114. {
  115. if (Addr > 0x3000)
  116. {
  117. Addr -= 0x1000;
  118. }
  119. if (ppu.ScreenType == 0)
  120. { /* 1 Screen Mode */
  121. return ppu.Memory[RelAddr(Addr) + ppu.BaseOneScreen];
  122. }
  123. else
  124. if (ppu.ScreenType)
  125. { /* Miroring mode */
  126. if (ppu.MirrorDir)
  127. { /* Horizontal */
  128. if (GetNT(Addr) & 0x2)
  129. { /* NT2-3 */
  130. return ppu.Memory[0x2000 + RelAddr(Addr)];
  131. }
  132. else
  133. {
  134. return ppu.Memory[0x2400 + RelAddr(Addr)];
  135. }
  136. }
  137. else
  138. { /* Vertical */
  139. if (GetNT(Addr) & 0x1)
  140. { /* NT0-2 */
  141. return ppu.Memory[0x2400 + RelAddr(Addr)];
  142. }
  143. else
  144. {
  145. return ppu.Memory[0x2000 + RelAddr(Addr)];
  146. }
  147. }
  148. }
  149. else
  150. { /* Four Screen mode */
  151. }
  152. }
  153. else
  154. if (Addr >= 0x3F00)
  155. {
  156. return ppu.Memory[0x3F00 | PalAddr(Addr)];
  157. }
  158. return ppu.Memory[Addr];
  159. }
  160. void PPU_Wr(unsigned short Addr, unsigned char Value)
  161. {
  162. if (Addr > (unsigned short) 0x3FFF)
  163. {
  164. Addr &= 0x3FFF;
  165. }
  166. if ((Addr < 0x3F00) && (Addr >= 0x2000))
  167. {
  168. if (Addr > 0x3000)
  169. {
  170. Addr -= 0x1000;
  171. }
  172. if (ppu.ScreenType == 0)
  173. { /* 1 Screen Mode */
  174. ppu.Memory[RelAddr(Addr) + 0x2000] = Value;
  175. }
  176. else
  177. if (ppu.ScreenType == 1)
  178. { /* Miroring mode */
  179. if (ppu.MirrorDir == 0)
  180. { /* Vertical */
  181. if (GetNT(Addr) & 0x1)
  182. { /* NT0-2 */
  183. ppu.Memory[0x2400 + RelAddr(Addr)] = Value;
  184. }
  185. else
  186. {
  187. ppu.Memory[0x2000 + RelAddr(Addr)] = Value;
  188. }
  189. }
  190. else
  191. { /* Horizontal */
  192. if (GetNT(Addr) & 0x2)
  193. { /* NT2-3 */
  194. ppu.Memory[0x2000 + RelAddr(Addr)] = Value;
  195. }
  196. else
  197. {
  198. ppu.Memory[0x2400 + RelAddr(Addr)] = Value;
  199. }
  200. }
  201. }
  202. else
  203. { /* Four Screen mode */
  204. }
  205. }
  206. else
  207. if (Addr >= 0x3F00)
  208. {
  209. //console_printf(Console_Default, "%s palette: color %x new value : %d (0x%x)\n", (PalAddr(Addr) < 0x10) ? "Bgnd" : "Sprt", PalAddr(Addr), Value & 0x3F, Addr);
  210. ppu.Memory[ /* 0x3F00 | PalAddr(Addr) */ Addr] = Value & 0x3F;
  211. if (PalAddr(Addr) == 0x10)
  212. ppu.Memory[0x3F00] = Value & 0x3F;
  213. }
  214. else
  215. {
  216. ppu.Memory[Addr] = Value;
  217. }
  218. }
  219. unsigned short NbOfSprite[255];
  220. void NewPPUDispSprite()
  221. {
  222. int x, y, x1, y1, px, py, i;
  223. unsigned long Color;
  224. PPUSprite sprite;
  225. unsigned short bg;
  226. short SprtAddr;
  227. for (i = 63; i >= 0; i--)
  228. {
  229. sprite = PPUGetSprite(i);
  230. bg = sprite.flags.b & PPUSPRITE_FLAGS_BGPRIO;
  231. y = sprite.y;
  232. if (y < 248)
  233. {
  234. SprtAddr = ((sprite.tileid) << 4) + ppu.Sprt_Pattern_Table;
  235. x = sprite.x;
  236. for (y1 = 0; y1 < 8; y1++)
  237. {
  238. py = y + ((sprite.flags.b & PPUSPRITE_FLAGS_VFLIP) == 0 ? y1 : ((8 - 1) - y1));
  239. if ((py > 0) && (py < 249) && ((++NbOfSprite[py]) > 7))
  240. {
  241. ppu.StatusRegister.b |= PPU_FLAG_SR_8SPRT ;
  242. //console_printf(Console_Default, "%d Hohoho!\n", py);
  243. // line(Buffer, 0, py+1, 256, py+1, 10);
  244. //continue; // Do not display more than 8 sprites on this line :p
  245. }
  246. for (x1 = 0; x1 < 8; x1++)
  247. {
  248. px = x + ((sprite.flags.b & PPUSPRITE_FLAGS_HFLIP) != 0 ? (7 - x1) : x1);
  249. Color = GetTileColor(SprtAddr, x1, y1);
  250. if (Color)
  251. {
  252. Color = (Color) | ((sprite.flags.b & PPUSPRITE_FLAGS_UPPERCOLOR) << 2);
  253. Color = ppu.Memory[0x3F10 + Color];
  254. if ((i == 0) && (_getpixel8(Buffer,px,py) != BgColor) && (ppu.HitSpriteAt == 255))
  255. {
  256. //Ligne utilis� pour le d�buguage
  257. //line(Buffer, 0, py+1, 256, py+1, GetColor(10));
  258. ppu.HitSpriteAt = py+1;
  259. }
  260. if ((bg == 0) || ((bg != 0) && (_getpixel8(Buffer,px,py) == BgColor)))
  261. _putpixel8(Buffer, px, py, GetColor(Color));
  262. }
  263. }
  264. }
  265. }
  266. }
  267. }
  268. void NewPPUDispSprite_8x16()
  269. {
  270. int x, y, x1, y1, px, py, i, loop, tile;
  271. unsigned long Color;
  272. PPUSprite sprite;
  273. unsigned short bg;
  274. short SprtAddr;
  275. unsigned short SprtTable;
  276. for (i = 63; i >= 0; i--)
  277. {
  278. sprite = PPUGetSprite(i);
  279. bg = sprite.flags.b & PPUSPRITE_FLAGS_BGPRIO;
  280. tile = sprite.tileid;
  281. y = sprite.y + 1;
  282. if (y < 248)
  283. {
  284. if ( (SprtTable = (tile & 0x1) * 0x1000) == 0x1000)
  285. tile -=1;
  286. if ((sprite.flags.b & PPUSPRITE_FLAGS_VFLIP) != 0)
  287. {
  288. y +=8;
  289. }
  290. for (loop = 0; loop < 2; loop++)
  291. {
  292. SprtAddr = ((tile) << 4) + SprtTable;
  293. x = sprite.x;
  294. for (y1 = 0; y1 < 8; y1++)
  295. {
  296. py = y + ((sprite.flags.b & PPUSPRITE_FLAGS_VFLIP) == 0 ? y1 : ((8 - 1) - y1));
  297. if ((py > 0) && (py < 249) && ((++NbOfSprite[py]) > 7))
  298. {
  299. ppu.StatusRegister.b |= PPU_FLAG_SR_8SPRT ;
  300. // puts("Ho!");
  301. //continue; // No more sprites on this line :p
  302. }
  303. for (x1 = 0; x1 < 8; x1++)
  304. {
  305. px = x + (((sprite.flags.b & PPUSPRITE_FLAGS_HFLIP) != 0) ? (7 - x1) : x1);
  306. Color = GetTileColor(SprtAddr, x1, y1);
  307. if (Color)
  308. {
  309. Color = (Color) | ((sprite.flags.b & PPUSPRITE_FLAGS_UPPERCOLOR) << 2);
  310. Color = ppu.Memory[0x3F10 + Color];
  311. if ((i == 0) && (_getpixel8(Buffer, px, py) != BgColor) && (ppu.HitSpriteAt == 255))
  312. {
  313. //Ligne utilise pour le debuguage
  314. //line(Buffer, 0, py, 256, py, 10);
  315. ppu.HitSpriteAt = py+1;
  316. }
  317. if ((bg == 0) || ((bg != 0) && (_getpixel8(Buffer, px, py) == BgColor)))
  318. _putpixel8(Buffer, px, py, GetColor(Color));
  319. }
  320. }
  321. }
  322. tile += 1;
  323. if ( (sprite.flags.b & PPUSPRITE_FLAGS_VFLIP) != 0)
  324. y -= 8;
  325. else
  326. y += 8;
  327. }
  328. }
  329. }
  330. }
  331. void DebugColor()
  332. {
  333. static unsigned short x = 128;
  334. static unsigned short y = 128;
  335. unsigned char OldDisplayPalette = ppu.DisplayPalette;
  336. byte keyb;
  337. unsigned int i;
  338. unsigned long Color;
  339. NOBLIT = 1;
  340. ppu.DisplayPalette = ~0;
  341. while(!key[KEY_ESC])
  342. {
  343. frame++;
  344. PPUVBlank();
  345. Color = /*Buffer->line[y][x]*/ _getpixel8(Buffer, x, y);
  346. textprintf(Buffer, font, 5, 340, GetColor(3), "Pos [%d:%d] Color: %d Bg: %d", x, y, Color, BgColor);
  347. line(Buffer, x-10, y, x+10, y, GetColor(1));
  348. line(Buffer, x, y-10, x, y+10, GetColor(1));
  349. /*
  350. rect(Buffer, 0, 255, 4 * 20 + 2, 255 + 4 * 20 + 2, 0);
  351. rect(Buffer, 90, 255, 90 + 4 * 20 + 2, 255 + 4 * 20 + 2, 0);
  352. for (i = 0; i < 16; i++)
  353. {
  354. rectfill(Buffer, 1 + (i % 4) * 20, 256 + (i / 4) * 20, 1 + (i % 4) * 20 + 20, 256 + (i / 4) * 20 + 20, ppu.Memory[0x3F00 + i]);
  355. rectfill(Buffer, 91 + (i % 4) * 20, 256 + (i / 4) * 20, 91 + (i % 4) * 20 + 20, 256 + (i / 4) * 20 + 20, ppu.Memory[0x3F10 + i]);
  356. }*/
  357. for( i = 0; i < 16; i++)
  358. {
  359. if (GetColor(ppu.Memory[0x3F00 + i]) == Color)
  360. {
  361. line(Buffer, 1+(i%4)*20, 256 + (i / 4) * 20, 1 + (i % 4) * 20 + 20, 256 + (i / 4) * 20 + 20, 0xFFFFFFFF);
  362. line(Buffer, 1+(i%4)*20, 256 + (i / 4) * 20 + 20, 1 + (i % 4) * 20 + 20, 256 + (i / 4) * 20, 0xFFFFFFFF);
  363. }
  364. if (GetColor(ppu.Memory[0x3F10 + i]) == Color)
  365. {
  366. line(Buffer, 91+(i%4)*20, 256 + (i / 4) * 20, 91 + (i % 4) * 20 + 20, 256 + (i / 4) * 20 + 20, 0xFFFFFFFF);
  367. line(Buffer, 91+(i%4)*20, 256 + (i / 4) * 20 + 20, 91 + (i % 4) * 20 + 20, 256 + (i / 4) * 20, 0xFFFFFFFF);
  368. }
  369. }
  370. blit(Buffer, screen, 0, 0, 0, 0, 512 + 256, 480);
  371. if (keypressed())
  372. {
  373. keyb = (readkey() & 0xFF);
  374. if (keyb == '4')
  375. {
  376. x--;
  377. }
  378. if (keyb == '8')
  379. {
  380. y--;
  381. }
  382. if (keyb == '6')
  383. {
  384. x++;
  385. }
  386. if (keyb == '2')
  387. {
  388. y++;
  389. }
  390. }
  391. }
  392. ppu.DisplayPalette = OldDisplayPalette;
  393. NOBLIT = 0;
  394. }
  395. void DebugSprites()
  396. {
  397. byte keyb;
  398. static int SelSprite = 0;
  399. PPUSprite sprite;
  400. NOBLIT = 1;
  401. ppu.ControlRegister2.b |= PPU_CR2_SPRTVISIBILITY;
  402. while(!key[KEY_ESC])
  403. {
  404. frame++;
  405. PPUVBlank();
  406. sprite = PPUGetSprite(SelSprite);
  407. if (ppu.ControlRegister1.b & PPU_CR1_SPRTSIZE)
  408. {
  409. rect(Buffer, sprite.x-1, sprite.y-1, sprite.x+9, sprite.y+17, 1);
  410. }
  411. else
  412. {
  413. rect(Buffer, sprite.x-1, sprite.y-1, sprite.x+9, sprite.y+9, 1);
  414. }
  415. textprintf(Buffer, font, 5, 340, GetColor(3), "Sprite %d [%d:%d]", SelSprite, sprite.x, sprite.y);
  416. textprintf(Buffer, font, 5, 349, GetColor(3), "B0: 0x%X B1: 0x%X B2: 0x%X B3: 0x%X",sprite.y,sprite.tileid,sprite.flags.b,sprite.x);
  417. textprintf(Buffer, font, 5, 358, GetColor(3), "Tile Index: %d", sprite.tileid);
  418. textprintf(Buffer, font, 5, 367, GetColor(3), "Vertical Flip: %d", sprite.flags.s.VFlip);
  419. textprintf(Buffer, font, 5, 376, GetColor(3), "Horizontal Flip: %d", sprite.flags.s.HFlip);
  420. textprintf(Buffer, font, 5, 385, GetColor(3), "Background Priority: %d", sprite.flags.s.BgPrio);
  421. textprintf(Buffer, font, 5, 394, GetColor(3), "Upper Color: %d", sprite.flags.s.UpperColor);
  422. blit(Buffer, screen, 0, 0, 0, 0, 512 + 256, 480);
  423. if (keypressed())
  424. {
  425. keyb = (readkey() & 0xFF);
  426. if (keyb == '+')
  427. SelSprite = (SelSprite<63)?SelSprite+1:0;
  428. if (keyb == '-')
  429. SelSprite = (SelSprite>0)?SelSprite-1:63;
  430. if (keyb == 'h')
  431. {
  432. sprite.flags.s.HFlip = ~sprite.flags.s.HFlip;
  433. PPUSetSprite(SelSprite, &sprite);
  434. }
  435. if (keyb == 'b')
  436. {
  437. sprite.flags.s.BgPrio = ~sprite.flags.s.BgPrio;
  438. PPUSetSprite(SelSprite, &sprite);
  439. }
  440. if (keyb == 'v')
  441. {
  442. sprite.flags.s.VFlip = ~sprite.flags.s.VFlip;
  443. PPUSetSprite(SelSprite, &sprite);
  444. }
  445. if (keyb == '4')
  446. {
  447. sprite.x--;
  448. PPUSetSprite(SelSprite, &sprite);
  449. }
  450. if (keyb == '8')
  451. {
  452. sprite.y--;
  453. PPUSetSprite(SelSprite, &sprite);
  454. }
  455. if (keyb == '6')
  456. {
  457. sprite.x++;
  458. PPUSetSprite(SelSprite, &sprite);
  459. }
  460. if (keyb == '2')
  461. {
  462. sprite.y++;
  463. PPUSetSprite(SelSprite, &sprite);
  464. }
  465. }
  466. }
  467. NOBLIT = 0;
  468. }
  469. #define GetTilePos(addr,x,y) (addr+x+(y*32))
  470. void ppu_displayNameTables()
  471. {
  472. int x, y, x1, y1, i;
  473. unsigned long Reg2;
  474. unsigned short ab_x, ab_y;
  475. unsigned short Color;
  476. unsigned short AttrByte;
  477. unsigned short TileID;
  478. if (ppu.DisplayAttributeTable)
  479. {
  480. /* NT 2000 */
  481. for (x = 0; x < 0x40; x++)
  482. {
  483. AttrByte = /*ppu.Memory[0x23C0 + x];*/PPU_Rd(0x23C0 + x);
  484. x1 = x % 8;
  485. y1 = x / 8;
  486. Color = AttrByte & 0x3; // Pattern 1;
  487. if (ppu.DisplayNameTables == 0)
  488. Color = ppu.Memory[0x3F00 + (Color * 4) + 1];
  489. rectfill(Buffer,256+(x1*32),240+(y1*32),256+15+(x1*32),240+15+(y1*32),Color);
  490. Color = (AttrByte>>2) & 0x3; // Pattern 2;
  491. if (ppu.DisplayNameTables == 0)
  492. Color = ppu.Memory[0x3F00 + (Color * 4) + 1];
  493. rectfill(Buffer,16+256+(x1*32),240+(y1*32),16+256+15+(x1*32),240+15+(y1*32),Color);
  494. Color = (AttrByte>>4) & 0x3; // Pattern 3;
  495. if (ppu.DisplayNameTables == 0)
  496. Color = ppu.Memory[0x3F00 + (Color * 4) + 1];
  497. rectfill(Buffer,256+(x1*32),16+240+(y1*32),256+15+(x1*32),16+240+15+(y1*32),Color);
  498. Color = (AttrByte>>6) & 0x3; // Pattern 4;
  499. if (ppu.DisplayNameTables == 0)
  500. Color = ppu.Memory[0x3F00 + (Color * 4) + 1];
  501. rectfill(Buffer,16+256+(x1*32),16+240+(y1*32),16+256+15+(x1*32),16+240+15+(y1*32),Color);
  502. }
  503. /* NT 2800 */
  504. for (x = 0; x < 0x40; x++)
  505. {
  506. AttrByte = PPU_Rd(0x2BC0 + x);
  507. x1 = x % 8;
  508. y1 = x / 8;
  509. Color = AttrByte & 0x3; // Pattern 1;
  510. if (ppu.DisplayNameTables == 0)
  511. Color = ppu.Memory[0x3F00 + (Color * 4) + 1];
  512. rectfill(Buffer,256+(x1*32),(y1*32),256+15+(x1*32),15+(y1*32),Color);
  513. Color = (AttrByte>>2) & 0x3; // Pattern 2;
  514. if (ppu.DisplayNameTables == 0)
  515. Color = ppu.Memory[0x3F00 + (Color * 4) + 1];
  516. rectfill(Buffer,16+256+(x1*32),(y1*32),16+256+15+(x1*32),15+(y1*32),Color);
  517. Color = (AttrByte>>4) & 0x3; // Pattern 3;
  518. if (ppu.DisplayNameTables == 0)
  519. Color = ppu.Memory[0x3F00 + (Color * 4) + 1];
  520. rectfill(Buffer,256+(x1*32),16+(y1*32),256+15+(x1*32),16+15+(y1*32),Color);
  521. Color = (AttrByte>>6) & 0x3; // Pattern 4;
  522. if (ppu.DisplayNameTables == 0)
  523. Color = ppu.Memory[0x3F00 + (Color * 4) + 1];
  524. rectfill(Buffer,16+256+(x1*32),16+(y1*32),16+256+15+(x1*32),16+15+(y1*32),Color);
  525. }
  526. /* NT 2400 */
  527. for (x = 0; x < 0x40; x++)
  528. {
  529. AttrByte = PPU_Rd(0x27C0 + x);
  530. x1 = x % 8;
  531. y1 = x / 8;
  532. Color = AttrByte & 0x3; // Pattern 1;
  533. if (ppu.DisplayNameTables == 0)
  534. Color = ppu.Memory[0x3F00 + (Color * 4) + 1];
  535. rectfill(Buffer,256+256+(x1*32),240+(y1*32),256+256+15+(x1*32),240+15+(y1*32),Color);
  536. Color = (AttrByte>>2) & 0x3; // Pattern 2;
  537. if (ppu.DisplayNameTables == 0)
  538. Color = ppu.Memory[0x3F00 + (Color * 4) + 1];
  539. rectfill(Buffer,16+256+256+(x1*32),240+(y1*32),16+256+256+15+(x1*32),240+15+(y1*32),Color);
  540. Color = (AttrByte>>4) & 0x3; // Pattern 3;
  541. if (ppu.DisplayNameTables == 0)
  542. Color = ppu.Memory[0x3F00 + (Color * 4) + 1];
  543. rectfill(Buffer,256+256+(x1*32),240+16+(y1*32),256+256+15+(x1*32),240+16+15+(y1*32),Color);
  544. Color = (AttrByte>>6) & 0x3; // Pattern 4;
  545. if (ppu.DisplayNameTables == 0)
  546. Color = ppu.Memory[0x3F00 + (Color * 4) + 1];
  547. rectfill(Buffer,16+256+256+(x1*32),240+16+(y1*32),16+256+256+15+(x1*32),240+16+15+(y1*32),Color);
  548. }
  549. /* NT 2C00 */
  550. for (x = 0; x < 0x40; x++)
  551. {
  552. AttrByte = PPU_Rd(0x2FC0 + x);//PPU_Rd(0x27C0 + x);
  553. x1 = x % 8;
  554. y1 = x / 8;
  555. Color = AttrByte & 0x3; // Pattern 1;
  556. if (ppu.DisplayNameTables == 0)
  557. Color = ppu.Memory[0x3F00 + (Color * 4) + 1];
  558. rectfill(Buffer,256+256+(x1*32),(y1*32),256+256+15+(x1*32),15+(y1*32),Color);
  559. Color = (AttrByte>>2) & 0x3; // Pattern 2;
  560. if (ppu.DisplayNameTables == 0)
  561. Color = ppu.Memory[0x3F00 + (Color * 4) + 1];
  562. rectfill(Buffer,16+256+256+(x1*32),(y1*32),16+256+256+15+(x1*32),15+(y1*32),Color);
  563. Color = (AttrByte>>4) & 0x3; // Pattern 3;
  564. if (ppu.DisplayNameTables == 0)
  565. Color = ppu.Memory[0x3F00 + (Color * 4) + 1];
  566. rectfill(Buffer,256+256+(x1*32),16+(y1*32),256+256+15+(x1*32),16+15+(y1*32),Color);
  567. Color = (AttrByte>>6) & 0x3; // Pattern 4;
  568. if (ppu.DisplayNameTables == 0)
  569. Color = ppu.Memory[0x3F00 + (Color * 4) + 1];
  570. rectfill(Buffer,16+256+256+(x1*32),16+(y1*32),16+256+256+15+(x1*32),16+15+(y1*32),Color);
  571. }
  572. if (ppu.DisplayNameTables == 0)
  573. {
  574. for (x = 0; x < 33; x++)
  575. {
  576. line(Buffer, 256 + x * 16, 0, 256 + x * 16, 240 + 240, 8);
  577. line(Buffer, 256, 0 + x * 16, 256 + 256 + 256, 0 + x * 16, 8);
  578. }
  579. for (x = 0; x < 17; x++)
  580. {
  581. line(Buffer, 256 + x * 32, 0, 256 + x * 32, 240 + 240, 6);
  582. line(Buffer, 256, 0 + x * 32, 256 + 256 + 256, 0 + x * 32, 6);
  583. }
  584. }
  585. }
  586. if (ppu.DisplayNameTables)
  587. {
  588. /* NT 2000 */
  589. for (x = 0; x < 32; x++)
  590. for (y = 0; y < 30; y++)
  591. {
  592. TileID = (PPU_Rd/*ppu.Memory[*/(0x2000 + x + (y * 32))/*]*/ << 4) + ppu.Bg_Pattern_Table;
  593. for (x1 = 0; x1 < 8; x1++)
  594. for (y1 = 0; y1 < 8; y1++)
  595. {
  596. Color = GetTileColor(TileID, x1, y1);
  597. if (ppu.DisplayAttributeTable != 0)
  598. Color |= (Buffer->line[(8 * y) + 240 + y1][(8 * x) + 256 + x1] & 0x3) << 2;
  599. if ((Color != 0) || (ppu.DisplayAttributeTable != 0))
  600. {
  601. Color = ppu.Memory[0x3F00 + Color];
  602. Buffer->line[(8 * y) + 240 + y1][(8 * x) + 256 + x1] = Color;
  603. }
  604. }
  605. }
  606. /* NT 2800 */
  607. for (x = 0; x < 32; x++)
  608. for (y = 0; y < 30; y++)
  609. {
  610. TileID = (PPU_Rd(0x2800 + x + (y * 32)) << 4) + ppu.Bg_Pattern_Table;
  611. for (x1 = 0; x1 < 8; x1++)
  612. for (y1 = 0; y1 < 8; y1++)
  613. {
  614. Color = GetTileColor(TileID, x1, y1);
  615. if (Color != 0)
  616. {
  617. Color = ppu.Memory[0x3F00 + Color + 4];
  618. Buffer->line[(8 * y) + y1][(8 * x) + 256 + x1] = Color;
  619. }
  620. }
  621. }
  622. /* NT 2400 */
  623. for (x = 0; x < 32; x++)
  624. for (y = 0; y < 30; y++)
  625. {
  626. TileID = (PPU_Rd(0x2400 + x + (y * 32)) << 4) + ppu.Bg_Pattern_Table;
  627. for (x1 = 0; x1 < 8; x1++)
  628. for (y1 = 0; y1 < 8; y1++)
  629. {
  630. Color = GetTileColor(TileID, x1, y1);
  631. if (ppu.DisplayAttributeTable != 0)
  632. Color |= (Buffer->line[(8 * y) + 240 + y1][(8 * x) + 256 + x1] & 0x3) << 2;
  633. if ((Color != 0) || (ppu.DisplayAttributeTable != 0))
  634. {
  635. Color = ppu.Memory[0x3F00 + Color];
  636. Buffer->line[(8 * y) + 240+ y1][(8 * x) + 256 + 256 + x1] = Color;
  637. }
  638. }
  639. }
  640. /* NT 2C00 */
  641. for (x = 0; x < 32; x++)
  642. for (y = 0; y < 30; y++)
  643. {
  644. TileID = (PPU_Rd(0x2C00 + x + (y * 32)) << 4) + ppu.Bg_Pattern_Table;
  645. for (x1 = 0; x1 < 8; x1++)
  646. for (y1 = 0; y1 < 8; y1++)
  647. {
  648. Color = GetTileColor(TileID, x1, y1);
  649. if (Color != 0)
  650. {
  651. Color = ppu.Memory[0x3F00 + Color + 12];
  652. Buffer->line[(8 * y) + y1][(8 * x) + 256 + 256 + x1] = Color;
  653. }
  654. }
  655. }
  656. }
  657. }
  658. int
  659. PPUVBlank()
  660. {
  661. int x, y, x1, y1, i;
  662. unsigned long Reg2;
  663. unsigned short ab_x, ab_y;
  664. unsigned long Color;
  665. unsigned short AttrByte;
  666. unsigned short TileID;
  667. static short LAST_FPS = 0;
  668. unsigned char XScroll, YScroll;
  669. ppu.StatusRegister.b |= PPU_FLAG_SR_VBLANK;
  670. BgColor = ppu.Memory[0x3F00];//0xC0;
  671. //goto NoDraw;
  672. acquire_bitmap(Buffer);
  673. clear_to_color(Buffer, GetColor(BgColor));
  674. if (ppu.ControlRegister2.s.Colour != 0)
  675. console_printf(Console_Default, "ppu.ColorEmphasis : %d\n", ppu.ControlRegister2.s.Colour);
  676. for (i = 0; i < 249; i++)
  677. NbOfSprite[i] = 0;
  678. ppu.StatusRegister.b &= ~(PPU_FLAG_SR_8SPRT);
  679. ppu.HitSpriteAt = 255;
  680. /*
  681. * A faires les choses qui faut faire durant un lanc� de vblank,
  682. * comme dessiner par ex..
  683. */
  684. if (((ppu.ControlRegister2.b & PPU_CR2_BGVISIBILITY) != 0) || ppu.ForceBgVisibility)
  685. {
  686. /* Display BG with scrolling informations */
  687. /* J'ai la solution :D */
  688. /*
  689. frame start (line 0) (if background or sprites are enabled):
  690. v=t
  691. */
  692. ppu.VRAMAddrReg2.W = ppu.TimedTmpPtr[0] | 0x2000;
  693. //console_printf(Console_Default, "Starting addresses : 0x%X\n",ppu.VRAMAddrReg2.W);
  694. XScroll = ppu.TimedHScroll[0];
  695. YScroll = ppu.TmpVScroll;
  696. for (y = 0; y < 240; y++)
  697. {
  698. /*
  699. scanline start (if background and sprites are enabled):
  700. 8421 8421 8421 8421 8421 8421 8421 8421
  701. v:0000 0100 0001 1111=t:0000 0100 0001 1111
  702. 1111 1198 7654 3210
  703. 5432 10
  704. */
  705. //if (y == 142)
  706. // console_printf(Console_Default, "______________142 Ptr:0x%04X ____ 0x%04X\n", ppu.TimedTmpPtr[y], ppu.VRAMAddrReg2.W);
  707. ppu.VRAMAddrReg2.W = (ppu.VRAMAddrReg2.W & 0xFBE0)
  708. | ((ppu.TimedTmpPtr[y]) & 0x041F)
  709. | 0x2000;
  710. //if (y == 142)
  711. // console_printf(Console_Default, "______________142 Ptr:0x%04X ____ 0x%04X\n", ppu.TimedTmpPtr[y], ppu.VRAMAddrReg2.W);
  712. TileID = (PPU_Rd(ppu.VRAMAddrReg2.W) << 4)
  713. | ppu.Bg_Pattern_Table;
  714. XScroll = ppu.TimedHScroll[y];
  715. for (x = 0; x < 256; x++)
  716. {
  717. /* Calculer la couleur du point */
  718. /* Bits 1 et 0 */
  719. Color = GetTileColor(TileID, XScroll, YScroll);
  720. /* Bits 3 et 2 */
  721. /*
  722. XScroll : 0,1,2,3,4
  723. X = (ppu.VRAMAddrReg2.W & 0x1F)
  724. Y : 5,6,7,8,9
  725. Y = (ppu.VRAMAddrReg2.W & 0x3E0) >> 5
  726. */
  727. /*ab_y = ((ppu.VRAMAddrReg2.W & 0x3E0) >> 5);
  728. ab_x = (ppu.VRAMAddrReg2.W & 0x1F);
  729. AttrByte = (((ab_y) >> 2) << 3) +
  730. ((ab_x) >> 2);
  731. AttrByte = (PPU_Rd((ppu.VRAMAddrReg2.W & 0x2C00) + 0x3C0 + AttrByte) >>
  732. ((((ab_y & 2) * 2) + (((ppu.VRAMAddrReg2.W & 0x2C00)) & 2)))) & 0x03;*/
  733. /*
  734. 00DC BA98 7654 3210
  735. 0000 BA54 3c-2 10b-
  736. 0000 0000 0001 1100 : 0x001C >> 2
  737. 0000 0011 1000 0000 : 0x0380 >> 4
  738. 10 --11 11-- ----
  739. 0xC000
  740. & 0x0C3F | 0x23C0
  741. b
  742. val >> ( (Reg2 & 0x2) | ( (Reg2 & 0x0x40)>>4)
  743. */
  744. Reg2 = ppu.VRAMAddrReg2.W;
  745. AttrByte = ((Reg2 & 0x0380) >> 4) | ((Reg2 & 0x001C) >> 2) | (Reg2 & 0x0C00);
  746. AttrByte &= 0x0C3F;
  747. AttrByte |= 0x23C0;
  748. AttrByte = PPU_Rd(AttrByte);
  749. AttrByte = AttrByte >> ( 0x0 | (Reg2 & 0x02) | ( (Reg2 & 0x40) >> 4) );
  750. AttrByte &= 0x3;
  751. if (Color)
  752. {
  753. Color |= (AttrByte << 2);
  754. Color = ppu.Memory[0x3F00 + Color];
  755. _putpixel8(Buffer, x,y, GetColor(Color));
  756. }
  757. XScroll++;
  758. XScroll &= 7;
  759. if (XScroll == 0)
  760. { /* On incr�mente le compteur de tile */
  761. if ((ppu.VRAMAddrReg2.W & 0x1F) == 0x1F)
  762. { /* On met a 0 et change
  763. * l'etat du bit 10 */
  764. ppu.VRAMAddrReg2.W &= ~0x1F;
  765. /* A voir si ya pas bcp mieux */
  766. if ((ppu.VRAMAddrReg2.W & 0x400))
  767. ppu.VRAMAddrReg2.W &= ~0x400;
  768. else
  769. ppu.VRAMAddrReg2.W |= 0x400;
  770. }
  771. else
  772. { /* on incremente juste */
  773. ppu.VRAMAddrReg2.W = (ppu.VRAMAddrReg2.W & ~0x1F) | ((ppu.VRAMAddrReg2.W + 1) & 0x1F);
  774. }
  775. TileID = (PPU_Rd(ppu.VRAMAddrReg2.W) << 4)
  776. | ppu.Bg_Pattern_Table;
  777. }
  778. }
  779. /*
  780. you can think of bits 5,6,7,8,9 as the "y scroll"(*8). this functions
  781. slightly different from the X. it wraps to 0 and bit 11 is switched when
  782. it's incremented from _29_ instead of 31. there are some odd side effects
  783. from this.. if you manually set the value above 29 (from either 2005 or
  784. 2006), the wrapping from 29 obviously won't happen, and attrib data will be
  785. used as name table data. the "y scroll" still wraps to 0 from 31, but
  786. without switching bit 11. this explains why writing 240+ to 'Y' in 2005
  787. appeared as a negative scroll value.
  788. */
  789. YScroll++;
  790. YScroll &= 7;
  791. if (YScroll == 0)
  792. { /* On incr�mente le compteur de tile */
  793. if ((ppu.VRAMAddrReg2.W & 0x3E0) == 0x3A0)
  794. { /* On met a 0 et change l'etat du bit
  795. * 10 */
  796. ppu.VRAMAddrReg2.W &= ~0x3F0;
  797. /* A voir si ya pas bcp mieux */
  798. if ((ppu.VRAMAddrReg2.W & 0x800))
  799. ppu.VRAMAddrReg2.W &= ~0x800;
  800. else
  801. ppu.VRAMAddrReg2.W |= 0x800;
  802. }
  803. else
  804. { /* on incremente juste */
  805. ppu.VRAMAddrReg2.W = (ppu.VRAMAddrReg2.W & ~0x3F0) | ((((ppu.VRAMAddrReg2.W & 0x3F0) >> 5) + 1) << 5);
  806. }
  807. }
  808. }
  809. //while (!key[KEY_ENTER]);
  810. }
  811. /*
  812. * if (ppu.ControlRegister2.s.SpriteVisibility == 1)
  813. * PPUDispSprite(0);
  814. */
  815. if (((ppu.ControlRegister2.b & PPU_CR2_SPRTVISIBILITY) != 0) || ppu.ForceSpriteVisibility)
  816. {
  817. if (ppu.ControlRegister1.b & PPU_CR1_SPRTSIZE)
  818. {
  819. NewPPUDispSprite_8x16();
  820. }
  821. else
  822. {
  823. NewPPUDispSprite();
  824. }
  825. }
  826. if (ppu.DisplayPalette)
  827. {
  828. textout(Buffer, font, "Bg Palette", 0, 247, 5);
  829. textout(Buffer, font, "Sprt Palette", 90, 247, 5);
  830. rect(Buffer, 0, 255, 4 * 20 + 2, 255 + 4 * 20 + 2, GetColor(0));
  831. rect(Buffer, 90, 255, 90 + 4 * 20 + 2, 255 + 4 * 20 + 2, GetColor(0));
  832. for (i = 0; i < 16; i++)
  833. {
  834. rectfill(Buffer, 1 + (i % 4) * 20, 256 + (i / 4) * 20, 1 + (i % 4) * 20 + 20, 256 + (i / 4) * 20 + 20, GetColor(ppu.Memory[0x3F00 + i]));
  835. rectfill(Buffer, 91 + (i % 4) * 20, 256 + (i / 4) * 20, 91 + (i % 4) * 20 + 20, 256 + (i / 4) * 20 + 20, GetColor(ppu.Memory[0x3F10 + i]));
  836. }
  837. }
  838. if (ppu.DisplayVRAM)
  839. {
  840. /* y:346 */
  841. x1 = 0;
  842. y1 = 0;
  843. for (i = 0; i < 256; i++)
  844. {
  845. TileID = 0x0000 + (i << 4);
  846. for (x = 0; x < 8; x++)
  847. for (y = 0; y < 8; y++)
  848. {
  849. Color = GetTileColor(TileID, x, y);
  850. _putpixel8(Buffer, 10 + x1 + x, 347 + y1 + y, GetColor(ppu.Memory[0x3F00 + Color]));
  851. }
  852. x1 += 8;
  853. if (x1 >= 128)
  854. {
  855. x1 = 0;
  856. y1 += 8;
  857. }
  858. }
  859. x1 = 0;
  860. y1 = 0;
  861. for (i = 0; i < 256; i++)
  862. {
  863. TileID = 0x1000 + (i << 4);
  864. for (x = 0; x < 8; x++)
  865. for (y = 0; y < 8; y++)
  866. {
  867. Color = GetTileColor(TileID, x, y);
  868. _putpixel8(Buffer, 10 + 128 + x1 + x, 347 + y1 + y, GetColor(ppu.Memory[0x3F10 + Color]) );
  869. }
  870. x1 += 8;
  871. if (x1 >= 128)
  872. {
  873. x1 = 0;
  874. y1 += 8;
  875. }
  876. }
  877. }
  878. for (i = 0; i < 240; i++)
  879. {
  880. _putpixel8(Buffer, 257 + 0, i, 0xFFFFFFFF);
  881. _putpixel8(Buffer, 257 + 1, i, ppu.TimedTmpPtr[y]*4 | 0xFF000000);
  882. _putpixel8(Buffer, 257 + 2, i, ppu.TimedTmpPtr[y]*4 | 0xFF000000);
  883. _putpixel8(Buffer, 257 + 3, i, ppu.TimedTmpPtr[y]*4 | 0xFF000000);
  884. _putpixel8(Buffer, 257 + 4, i, ppu.TmpVScroll*4 | 0xFF000000);
  885. _putpixel8(Buffer, 257 + 5, i, ppu.TmpVScroll*4 | 0xFF000000);
  886. _putpixel8(Buffer, 257 + 6, i, ppu.TmpVScroll*4 | 0xFF000000);
  887. _putpixel8(Buffer, 257 + 7, i, ppu.TimedHScroll[i]*4 | 0xFF000000);
  888. _putpixel8(Buffer, 257 + 8, i, ppu.TimedHScroll[i]*4 | 0xFF000000);
  889. _putpixel8(Buffer, 257 + 9, i, ppu.TimedHScroll[i]*4 | 0xFF000000);
  890. _putpixel8(Buffer, 257 + 10, i, 0xFFFFFFFF);
  891. }
  892. if (IRQScanHit != -1)
  893. {
  894. line(Buffer, 257+12, IRQScanHit, 257+22, IRQScanHit, 0xFF00FF);
  895. line(Buffer, 257+12, IRQScanHit, 257+18, IRQScanHit-3, 0xFF00FF);
  896. line(Buffer, 257+12, IRQScanHit, 257+18, IRQScanHit+3, 0xFF00FF);
  897. }
  898. NoDraw:
  899. textprintf(Buffer, font, 5, 340, GetColor(4), "FPS : %d IPS : %d", FPS, IPS);
  900. textprintf(Buffer, font, 5, 3, GetColor(4), "FPS : %d (CPU@~%2.2fMhz : %d%%)", FPS, (float) (((float) IPS) / 1000000.0), (int) ((((float) IPS) / 1770000.0) * 100.0));
  901. release_bitmap(Buffer);
  902. if (NOBLIT == 0)
  903. {
  904. blit(Buffer, screen, 0, 0, 0, 0, 512 + 256, 480);
  905. //stretch_blit(Buffer, screen, 0, 0, 256, 240, 0, 0, 512, 480);
  906. }
  907. if ((ppu.ControlRegister1.b & PPU_CR1_EXECNMI) != 0)
  908. return 1;
  909. return 0;
  910. }
  911. byte ReadPPUReg(byte RegID)
  912. {
  913. /* RegID is the nb of the reg 0-7 */
  914. unsigned char ret;
  915. RegID &= 0x07;
  916. switch (RegID)
  917. {
  918. default:
  919. ret = (unsigned char) 0x00; /* Can return every thing you
  920. * want here :D */
  921. break;
  922. case 1: /* Control Register 2 */
  923. ret = ppu.ControlRegister2.b;
  924. break;
  925. case 2:
  926. ret = ppu.StatusRegister.b;
  927. ppu.StatusRegister.b &= ~(PPU_FLAG_SR_VBLANK);
  928. ppu.StatusRegister.b &= ~(PPU_FLAG_SR_SPRT0);
  929. ppu.VRAMAddrMode = 0;
  930. break;
  931. case 5:
  932. ret = ppu.VRAMAddrReg2.B.l;
  933. break;
  934. case 6:
  935. ret = ppu.VRAMAddrReg2.B.h;
  936. break;
  937. case 7: /* PPU in NES is really strange.. Bufferised
  938. * send is weird.. */
  939. if (ppu.VRAMAddrReg2.W < 0x3EFF)
  940. {
  941. ret = ppu.VRAMBuffer;
  942. ppu.VRAMBuffer = PPU_Rd(ppu.VRAMAddrReg2.W);
  943. ppu.VRAMAddrReg2.W += ppu.PPU_Inc;
  944. ppu.VRAMAddrReg2.W &= 0x3FFF;
  945. }
  946. else
  947. {
  948. ret = PPU_Rd(ppu.VRAMAddrReg2.W);
  949. ppu.VRAMAddrReg2.W += ppu.PPU_Inc;
  950. }
  951. break;
  952. }
  953. return ret;
  954. }
  955. void WritePPUReg(byte RegID, byte val)
  956. {
  957. /* RegID is the nb of the reg 0-7 */
  958. RegID &= 0x07;
  959. switch (RegID)
  960. {
  961. default:/* For not writeable reg */
  962. console_printf(Console_Default, "WritePPU error\n");
  963. break;
  964. case 0: /* Control Register 1 */
  965. ppu.ControlRegister1.b = val;
  966. ppu.Bg_Pattern_Table = (ppu.ControlRegister1.s.BgPattern == 1) ? 0x1000 : 0x0000;
  967. ppu.Sprt_Pattern_Table = (ppu.ControlRegister1.s.SptPattern == 1) ? 0x1000 : 0x0000;
  968. ppu.PPU_Inc = (ppu.ControlRegister1.s.AddrIncrmt == 1) ? 32 : 1;
  969. ppu.Name_Table_Addresse = 0x2000;
  970. switch (ppu.ControlRegister1.s.NameTblAddr)
  971. {
  972. case 3:
  973. ppu.Name_Table_Addresse += 0x400;
  974. case 2:
  975. ppu.Name_Table_Addresse += 0x400;
  976. case 1:
  977. ppu.Name_Table_Addresse += 0x400;
  978. case 0:
  979. break;
  980. }
  981. ppu.TimedNT[ScanLine] = ppu.ControlRegister1.s.NameTblAddr;
  982. /*
  983. 2000 write:
  984. 1111 0011 1111 1111 ( F3FF )
  985. t:0000 1100 0000 0000 = d:0000 0011
  986. */
  987. ppu.TmpVRamPtr = ( (ppu.TmpVRamPtr & 0xF3FF)
  988. | ( ((ppu.ControlRegister1.s.NameTblAddr) & 0x03) << 10 )
  989. );
  990. break;
  991. case 1: /* Control Register 2 */
  992. //console_printf(Console_Default, "PPU: new CR2 ; 0x%x\n", val);
  993. ppu.ControlRegister2.b = val;
  994. break;
  995. case 3: /* SPR-RAM Addresse Register */
  996. ppu.SPR_RAMAddr = val;
  997. break;
  998. case 4: /* SPR-RAM Input Register */
  999. ppu.SPRRAM[ppu.SPR_RAMAddr] = val;
  1000. break;
  1001. case 5: /* VRAM Address register 1 */
  1002. if (ppu.VRAMAddrMode == 0)
  1003. {
  1004. /*
  1005. 2005 first write:
  1006. t:0000 0000 0001 1111=d:1111 1000
  1007. x=d:00000111
  1008. */
  1009. //console_printf(Console_Default, "2005[1st][%d]: 0x%02X [0x%04X]\n", ScanLine, val, ppu.TmpVRamPtr);
  1010. ppu.VRAMAddrMode = 1;
  1011. ppu.TmpVRamPtr = ((ppu.TmpVRamPtr & 0xFFE0) | ((val & 0xF8) >> 3));
  1012. ppu.HScroll = val & 0x7;
  1013. //console_printf(Console_Default, "2005[1st][%d]: 0x%02X [0x%04X]\n", ScanLine, val, ppu.TmpVRamPtr);
  1014. //console_printf(Console_Default, "%d -> 2005 w1: 0x%04X (val: 0x%02X)\n", ScanLine, ppu.TmpVRamPtr, val);
  1015. }
  1016. else
  1017. {
  1018. /*
  1019. 2005 second write:
  1020. 1111 1100 0000 0000
  1021. 5432 1098 7654 3210
  1022. 8421 8421 8421 8421
  1023. -------------------
  1024. t:0000 0011 1110 0000=d:1111 1000
  1025. t:0111 0000 0000 0000=d:0000 0111
  1026. */
  1027. //console_printf(Console_Default, "2005[2nd][%d]: 0x%02X [0x%04X]\n", ScanLine, val, ppu.TmpVRamPtr);
  1028. ppu.VRAMAddrMode = 0;
  1029. ppu.TmpVRamPtr = ((ppu.TmpVRamPtr & 0xFC1F) | ((val & 0xF8) << 2));
  1030. ppu.TmpVRamPtr = ((ppu.TmpVRamPtr & 0x8FFF) | ((val & 0x07) << 12));
  1031. ppu.TmpVScroll = (val & 0x7);
  1032. //if (ppu.TmpVScroll != 0)
  1033. //console_printf(Console_Default, "2002: TmpVScroll == %d \n", ppu.TmpVScroll);
  1034. //console_printf(Console_Default, "2005[2nd][%d]: 0x%02X [0x%04X]\n", ScanLine, val, ppu.TmpVRamPtr);
  1035. //console_printf(Console_Default, "%d -> 2005 w2: 0x%04X (val: 0x%02X)\n", ScanLine, ppu.TmpVRamPtr, val);
  1036. }
  1037. break;
  1038. case 6: /* VRAM Address register 2 */
  1039. if (ppu.VRAMAddrMode == 0)
  1040. {
  1041. //console_printf(Console_Default, "2006[1st][%d]: 0x%02X [0x%04X]\n", ScanLine, val, ppu.TmpVRamPtr);
  1042. ppu.VRAMAddrMode = 1;
  1043. /*
  1044. 2006 first write:
  1045. t:0011 1111 0000 0000 = d:0011 1111
  1046. t:1100 0000 0000 0000=0
  1047. */
  1048. ppu.TmpVRamPtr = ((ppu.TmpVRamPtr & 0xC0FF) | ((val&0x3F) << 8)) & 0x3FFF;
  1049. //console_printf(Console_Default, "2006[1st][%d]: 0x%02X [0x%04X]\n", ScanLine, val, ppu.TmpVRamPtr);
  1050. //console_printf(Console_Default, "%d -> 2006 w1: 0x%04X (val: 0x%02X)\n", ScanLine, ppu.TmpVRamPtr, val);
  1051. }
  1052. else
  1053. {
  1054. //console_printf(Console_Default, "2006[2nd][%d]: 0x%02X [0x%04X]\n", ScanLine, val, ppu.TmpVRamPtr);
  1055. ppu.VRAMAddrMode = 0;
  1056. /*
  1057. 2006 second write:
  1058. t:0000000011111111=d:11111111
  1059. v=t
  1060. */
  1061. ppu.TmpVRamPtr = ((ppu.TmpVRamPtr & 0xFF00) | (val & 0x00FF));
  1062. ppu.VRAMAddrReg2.W = ppu.TmpVRamPtr;
  1063. //console_printf(Console_Default, "2006[2nd][%d]: 0x%02X [0x%04X]\n", ScanLine, val, ppu.TmpVRamPtr);
  1064. //console_printf(Console_Default, "%d -> 2006 w2: 0x%04X (val: 0x%02X)\n", ScanLine, ppu.TmpVRamPtr, val);
  1065. }
  1066. break;
  1067. case 7: /* VRAM I/O */
  1068. PPU_Wr(ppu.VRAMAddrReg2.W, val);
  1069. ppu.VRAMAddrReg2.W += ppu.PPU_Inc;
  1070. break;
  1071. }
  1072. }
  1073. void FillSprRamDMA(byte value)
  1074. {
  1075. int i;
  1076. for (i = 0x00; i < 0x100; i++)
  1077. {
  1078. ppu.SPRRAM[i] = ReadMemory( value, i);
  1079. }
  1080. }