ppu.new.c 38 KB

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