ppu.new2.c 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329
  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&0xFF)
  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) && (_getpixel(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) && (_getpixel(Buffer,px,py) == BgColor)))
  261. _putpixel(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) && (_getpixel(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) && (_getpixel(Buffer, px, py) == BgColor)))
  318. _putpixel(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]*/ _getpixel(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. ppu_displayNameTables();
  675. if (ppu.ControlRegister2.s.Colour != 0)
  676. console_printf(Console_Default, "ppu.ColorEmphasis : %d\n", ppu.ControlRegister2.s.Colour);
  677. for (i = 0; i < 249; i++)
  678. NbOfSprite[i] = 0;
  679. ppu.StatusRegister.b &= ~(PPU_FLAG_SR_8SPRT);
  680. ppu.HitSpriteAt = 255;
  681. /*
  682. * A faires les choses qui faut faire durant un lanc� de vblank,
  683. * comme dessiner par ex..
  684. */
  685. if (((ppu.ControlRegister2.b & PPU_CR2_BGVISIBILITY) != 0) || ppu.ForceBgVisibility)
  686. {
  687. /* Display BG with scrolling informations */
  688. /* J'ai la solution :D */
  689. /*
  690. frame start (line 0) (if background or sprites are enabled):
  691. v=t
  692. */
  693. ppu.VRAMAddrReg2.W = ppu.TimedTmpPtr[0]|0x2000;
  694. //console_printf(Console_Default, "Starting addresses : 0x%X\n",ppu.VRAMAddrReg2.W);
  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 == IRQScanHit)||(y == IRQScanHit + 1))
  706. console_printf(Console_Default, "%s: IRQ Hit : bf Reg2: 0x%04X\n", __func__, ppu.VRAMAddrReg2.W);
  707. #define PPU_SSCAN_MASK 0x041F
  708. ppu.VRAMAddrReg2.W = (ppu.VRAMAddrReg2.W & (~PPU_SSCAN_MASK))
  709. | (ppu.TimedTmpPtr[y] & PPU_SSCAN_MASK )
  710. | 0x2000;
  711. TileID = (PPU_Rd(ppu.VRAMAddrReg2.W) << 4)
  712. | ppu.Bg_Pattern_Table;
  713. XScroll = ppu.TimedHScroll[y];
  714. if (y == IRQScanHit)
  715. console_printf(Console_Default, "%s: IRQ Hit : Reg2: 0x%04X TmpPtr:0x%04X \n", __func__, ppu.VRAMAddrReg2.W, ppu.TimedTmpPtr[y]);
  716. if (y == IRQScanHit + 1)
  717. console_printf(Console_Default, "%s: IRQ Hit + 1: Reg2: 0x%04X TmpPtr:0x%04X \n", __func__, ppu.VRAMAddrReg2.W, ppu.TimedTmpPtr[y]);
  718. for (x = 0; x < 256; x++)
  719. {
  720. /* Calculer la couleur du point */
  721. /* Bits 1 et 0 */
  722. Color = GetTileColor(TileID, XScroll, YScroll);
  723. /* Bits 3 et 2 */
  724. /*
  725. XScroll : 0,1,2,3,4
  726. X = (ppu.VRAMAddrReg2.W & 0x1F)
  727. Y : 5,6,7,8,9
  728. Y = (ppu.VRAMAddrReg2.W & 0x3E0) >> 5
  729. */
  730. /*ab_y = ((ppu.VRAMAddrReg2.W & 0x3E0) >> 5);
  731. ab_x = (ppu.VRAMAddrReg2.W & 0x1F);
  732. AttrByte = (((ab_y) >> 2) << 3) +
  733. ((ab_x) >> 2);
  734. AttrByte = (PPU_Rd((ppu.VRAMAddrReg2.W & 0x2C00) + 0x3C0 + AttrByte) >>
  735. ((((ab_y & 2) * 2) + (((ppu.VRAMAddrReg2.W & 0x2C00)) & 2)))) & 0x03;*/
  736. /*
  737. 00DC BA98 7654 3210
  738. 0000 BA54 3c-2 10b-
  739. 0000 0000 0001 1100 : 0x001C >> 2
  740. 0000 0011 1000 0000 : 0x0380 >> 4
  741. 10 --11 11-- ----
  742. 0xC000
  743. & 0x0C3F | 0x23C0
  744. b
  745. val >> ( (Reg2 & 0x2) | ( (Reg2 & 0x0x40)>>4)
  746. */
  747. Reg2 = ppu.VRAMAddrReg2.W;
  748. AttrByte = ((Reg2 & 0x0380) >> 4) | ((Reg2 & 0x001C) >> 2) | (Reg2 & 0x0C00);
  749. AttrByte &= 0x0C3F;
  750. AttrByte |= 0x23C0;
  751. AttrByte = PPU_Rd(AttrByte);
  752. AttrByte = AttrByte >> ( 0x0 | (Reg2 & 0x02) | ( (Reg2 & 0x40) >> 4) );
  753. AttrByte &= 0x3;
  754. if (Color)
  755. {
  756. Color |= (AttrByte << 2);
  757. Color = ppu.Memory[0x3F00 + Color];
  758. _putpixel(Buffer, x,y, GetColor(Color));
  759. }
  760. XScroll++;
  761. XScroll &= 7;
  762. if (XScroll == 0)
  763. { /* On incr�mente le compteur de tile */
  764. if ((ppu.VRAMAddrReg2.W & 0x1F) == 0x1F)
  765. { /* On met a 0 et change
  766. * l'etat du bit 10 */
  767. ppu.VRAMAddrReg2.W &= ~0x1F;
  768. /* A voir si ya pas bcp mieux */
  769. /* if ((ppu.VRAMAddrReg2.W & 0x400))
  770. ppu.VRAMAddrReg2.W &= ~0x400;
  771. else
  772. ppu.VRAMAddrReg2.W |= 0x400;*/
  773. ppu.VRAMAddrReg2.W ^= 0x400;
  774. }
  775. else
  776. { /* on incremente juste */
  777. ppu.VRAMAddrReg2.W = (ppu.VRAMAddrReg2.W & ~0x1F) | ((ppu.VRAMAddrReg2.W + 1) & 0x1F);
  778. }
  779. TileID = (PPU_Rd(ppu.VRAMAddrReg2.W) << 4)
  780. | ppu.Bg_Pattern_Table;
  781. }
  782. }
  783. /*
  784. you can think of bits 5,6,7,8,9 as the "y scroll"(*8). this functions
  785. slightly different from the X. it wraps to 0 and bit 11 is switched when
  786. it's incremented from _29_ instead of 31. there are some odd side effects
  787. from this.. if you manually set the value above 29 (from either 2005 or
  788. 2006), the wrapping from 29 obviously won't happen, and attrib data will be
  789. used as name table data. the "y scroll" still wraps to 0 from 31, but
  790. without switching bit 11. this explains why writing 240+ to 'Y' in 2005
  791. appeared as a negative scroll value.
  792. 8421 8421 8421 8421
  793. v:0000 0011 1110 0000
  794. 1111 1198 7654 3210
  795. 5432 10
  796. */
  797. YScroll++;
  798. YScroll &= 7;
  799. if (YScroll == 0)
  800. { /* On incr�mente le compteur de tile */
  801. if ((ppu.VRAMAddrReg2.W & 0x3E0) == (29<<5))
  802. { /* On met a 0 et change l'etat du bit 11 */
  803. ppu.VRAMAddrReg2.W &= ~0x3E0;
  804. /* A voir si ya pas bcp mieux */
  805. /* if ((ppu.VRAMAddrReg2.W & 0x800))
  806. ppu.VRAMAddrReg2.W &= ~0x800;
  807. else
  808. ppu.VRAMAddrReg2.W |= 0x800;*/
  809. ppu.VRAMAddrReg2.W ^= 0x800;
  810. }
  811. else
  812. { /* on incremente juste */
  813. ppu.VRAMAddrReg2.W = (ppu.VRAMAddrReg2.W & (~0x3F0))
  814. | ((((ppu.VRAMAddrReg2.W & 0x3F0) >> 5) + 1) << 5);
  815. }
  816. }
  817. }
  818. //while (!key[KEY_ENTER]);
  819. }
  820. /*
  821. * if (ppu.ControlRegister2.s.SpriteVisibility == 1)
  822. * PPUDispSprite(0);
  823. */
  824. if (((ppu.ControlRegister2.b & PPU_CR2_SPRTVISIBILITY) != 0) || ppu.ForceSpriteVisibility)
  825. {
  826. if (ppu.ControlRegister1.b & PPU_CR1_SPRTSIZE)
  827. {
  828. NewPPUDispSprite_8x16();
  829. }
  830. else
  831. {
  832. NewPPUDispSprite();
  833. }
  834. }
  835. if (ppu.DisplayPalette)
  836. {
  837. textout(Buffer, font, "Bg Palette", 0, 247, 5);
  838. textout(Buffer, font, "Sprt Palette", 90, 247, 5);
  839. rect(Buffer, 0, 255, 4 * 20 + 2, 255 + 4 * 20 + 2, GetColor(0));
  840. rect(Buffer, 90, 255, 90 + 4 * 20 + 2, 255 + 4 * 20 + 2, GetColor(0));
  841. for (i = 0; i < 16; i++)
  842. {
  843. 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]));
  844. 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]));
  845. }
  846. }
  847. if (ppu.DisplayVRAM)
  848. {
  849. /* y:346 */
  850. x1 = 0;
  851. y1 = 0;
  852. for (i = 0; i < 256; i++)
  853. {
  854. TileID = 0x0000 + (i << 4);
  855. for (x = 0; x < 8; x++)
  856. for (y = 0; y < 8; y++)
  857. {
  858. Color = GetTileColor(TileID, x, y);
  859. _putpixel(Buffer, 10 + x1 + x, 347 + y1 + y, GetColor(ppu.Memory[0x3F00 + Color]));
  860. }
  861. x1 += 8;
  862. if (x1 >= 128)
  863. {
  864. x1 = 0;
  865. y1 += 8;
  866. }
  867. }
  868. x1 = 0;
  869. y1 = 0;
  870. for (i = 0; i < 256; i++)
  871. {
  872. TileID = 0x1000 + (i << 4);
  873. for (x = 0; x < 8; x++)
  874. for (y = 0; y < 8; y++)
  875. {
  876. Color = GetTileColor(TileID, x, y);
  877. _putpixel(Buffer, 10 + 128 + x1 + x, 347 + y1 + y, GetColor(ppu.Memory[0x3F10 + Color]) );
  878. }
  879. x1 += 8;
  880. if (x1 >= 128)
  881. {
  882. x1 = 0;
  883. y1 += 8;
  884. }
  885. }
  886. }
  887. for (i = 0; i < 240; i++)
  888. {
  889. _putpixel(Buffer, 257 + 0, i, 48);
  890. _putpixel(Buffer, 257 + 1, i, ((ppu.TimedTmpPtr[y]*4))&0xFF);
  891. _putpixel(Buffer, 257 + 2, i, ((ppu.TimedTmpPtr[y]*4)>>8)&0xFF);
  892. _putpixel(Buffer, 257 + 3, i, ((ppu.TimedTmpPtr[y]*4)>>16)&0xFF);
  893. _putpixel(Buffer, 257 + 4, i, ((ppu.TmpVScroll*4))&0xFF);
  894. _putpixel(Buffer, 257 + 5, i, ((ppu.TmpVScroll*4)>>8)&0xFF);
  895. _putpixel(Buffer, 257 + 6, i, ((ppu.TmpVScroll*4)>>16)&0xFF);
  896. _putpixel(Buffer, 257 + 7, i, ((ppu.TimedHScroll[i]*4)) & 0xFF);
  897. _putpixel(Buffer, 257 + 8, i, ((ppu.TimedHScroll[i]*4)>>8) & 0xFF);
  898. _putpixel(Buffer, 257 + 9, i, ((ppu.TimedHScroll[i]*4)>>16)& 0xFF);
  899. _putpixel(Buffer, 257 + 10, i, 48);
  900. }
  901. if (IRQScanHit != -1)
  902. {
  903. line(Buffer, 257+12, IRQScanHit, 257+22, IRQScanHit, 10);
  904. line(Buffer, 257+12, IRQScanHit, 257+18, IRQScanHit-3, 10);
  905. line(Buffer, 257+12, IRQScanHit, 257+18, IRQScanHit+3, 10);
  906. }
  907. NoDraw:
  908. textprintf(Buffer, font, 5, 340, GetColor(4), "FPS : %d IPS : %d", FPS, IPS);
  909. 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));
  910. release_bitmap(Buffer);
  911. if (NOBLIT == 0)
  912. {
  913. blit(Buffer, screen, 0, 0, 0, 0, 512 + 256, 480);
  914. //stretch_blit(Buffer, screen, 0, 0, 256, 240, 0, 0, 512, 480);
  915. }
  916. if ((ppu.ControlRegister1.b & PPU_CR1_EXECNMI) != 0)
  917. return 1;
  918. return 0;
  919. }
  920. byte ReadPPUReg(byte RegID)
  921. {
  922. /* RegID is the nb of the reg 0-7 */
  923. unsigned char ret;
  924. RegID &= 0x07;
  925. switch (RegID)
  926. {
  927. default:
  928. ret = (unsigned char) 0x00; /* Can return every thing you
  929. * want here :D */
  930. break;
  931. case 1: /* Control Register 2 */
  932. ret = ppu.ControlRegister2.b;
  933. break;
  934. case 2:
  935. ret = ppu.StatusRegister.b;
  936. ppu.StatusRegister.b &= ~(PPU_FLAG_SR_VBLANK);
  937. ppu.StatusRegister.b &= ~(PPU_FLAG_SR_SPRT0);
  938. ppu.VRAMAddrMode = 0;
  939. break;
  940. case 5:
  941. ret = ppu.VRAMAddrReg2.B.l;
  942. break;
  943. case 6:
  944. ret = ppu.VRAMAddrReg2.B.h;
  945. break;
  946. case 7: /* PPU in NES is really strange.. Bufferised
  947. * send is weird.. */
  948. if (ppu.VRAMAddrReg2.W < 0x3EFF)
  949. {
  950. ret = ppu.VRAMBuffer;
  951. ppu.VRAMBuffer = PPU_Rd(ppu.VRAMAddrReg2.W);
  952. ppu.VRAMAddrReg2.W += ppu.PPU_Inc;
  953. ppu.VRAMAddrReg2.W &= 0x3FFF;
  954. }
  955. else
  956. {
  957. ret = PPU_Rd(ppu.VRAMAddrReg2.W);
  958. ppu.VRAMAddrReg2.W += ppu.PPU_Inc;
  959. }
  960. break;
  961. }
  962. return ret;
  963. }
  964. void WritePPUReg(byte RegID, byte val)
  965. {
  966. /* RegID is the nb of the reg 0-7 */
  967. RegID &= 0x07;
  968. switch (RegID)
  969. {
  970. default:/* For not writeable reg */
  971. console_printf(Console_Default, "WritePPU error\n");
  972. break;
  973. case 0: /* Control Register 1 */
  974. ppu.ControlRegister1.b = val;
  975. ppu.Bg_Pattern_Table = (ppu.ControlRegister1.s.BgPattern == 1) ? 0x1000 : 0x0000;
  976. ppu.Sprt_Pattern_Table = (ppu.ControlRegister1.s.SptPattern == 1) ? 0x1000 : 0x0000;
  977. ppu.PPU_Inc = (ppu.ControlRegister1.s.AddrIncrmt == 1) ? 32 : 1;
  978. ppu.Name_Table_Addresse = 0x2000;
  979. switch (ppu.ControlRegister1.s.NameTblAddr)
  980. {
  981. case 3:
  982. ppu.Name_Table_Addresse += 0x400;
  983. case 2:
  984. ppu.Name_Table_Addresse += 0x400;
  985. case 1:
  986. ppu.Name_Table_Addresse += 0x400;
  987. case 0:
  988. break;
  989. }
  990. ppu.TimedNT[ScanLine] = ppu.ControlRegister1.s.NameTblAddr;
  991. /*
  992. 2000 write:
  993. 1111 0011 1111 1111 ( F3FF )
  994. t:0000 1100 0000 0000 = d:0000 0011
  995. */
  996. ppu.TmpVRamPtr = ( (ppu.TmpVRamPtr & 0xF3FF)
  997. | ( (ppu.ControlRegister1.s.NameTblAddr & 0x03) << 10 )
  998. );
  999. break;
  1000. case 1: /* Control Register 2 */
  1001. //console_printf(Console_Default, "PPU: new CR2 ; 0x%x\n", val);
  1002. ppu.ControlRegister2.b = val;
  1003. break;
  1004. case 3: /* SPR-RAM Addresse Register */
  1005. ppu.SPR_RAMAddr = val;
  1006. break;
  1007. case 4: /* SPR-RAM Input Register */
  1008. ppu.SPRRAM[ppu.SPR_RAMAddr] = val;
  1009. break;
  1010. case 5: /* VRAM Address register 1 */
  1011. if (ppu.VRAMAddrMode == 0)
  1012. {
  1013. /*
  1014. 2005 first write:
  1015. t:0000 0000 0001 1111=d:1111 1000
  1016. x=d:00000111
  1017. */
  1018. //console_printf(Console_Default, "2005[1st][%d]: 0x%02X [0x%04X]\n", ScanLine, val, ppu.TmpVRamPtr);
  1019. ppu.VRAMAddrMode = 1;
  1020. ppu.TmpVRamPtr = ((ppu.TmpVRamPtr & 0xFFE0) | ((val & 0xF8) >> 3));
  1021. ppu.HScroll = val & 0x7;
  1022. //console_printf(Console_Default, "2005[1st][%d]: 0x%02X [0x%04X]\n", ScanLine, val, ppu.TmpVRamPtr);
  1023. //console_printf(Console_Default, "%d -> 2005 w1: 0x%04X (val: 0x%02X)\n", ScanLine, ppu.TmpVRamPtr, val);
  1024. }
  1025. else
  1026. {
  1027. /*
  1028. 2005 second write:
  1029. 1111 1100 0000 0000
  1030. 5432 1098 7654 3210
  1031. 8421 8421 8421 8421
  1032. -------------------
  1033. t:0000 0011 1110 0000=d:1111 1000
  1034. t:0111 0000 0000 0000=d:0000 0111
  1035. */
  1036. //console_printf(Console_Default, "2005[2nd][%d]: 0x%02X [0x%04X]\n", ScanLine, val, ppu.TmpVRamPtr);
  1037. ppu.VRAMAddrMode = 0;
  1038. ppu.TmpVRamPtr = ((ppu.TmpVRamPtr & ~(0x03E0)) | ((val & 0xF8) << 2));
  1039. ppu.TmpVRamPtr = ((ppu.TmpVRamPtr & 0x8FFF ) | ((val & 0x07) << 12));
  1040. ppu.TmpVScroll = (val & 0x7);
  1041. //if (ppu.TmpVScroll != 0)
  1042. //console_printf(Console_Default, "2002: TmpVScroll == %d \n", ppu.TmpVScroll);
  1043. //console_printf(Console_Default, "2005[2nd][%d]: 0x%02X [0x%04X]\n", ScanLine, val, ppu.TmpVRamPtr);
  1044. //console_printf(Console_Default, "%d -> 2005 w2: 0x%04X (val: 0x%02X)\n", ScanLine, ppu.TmpVRamPtr, val);
  1045. }
  1046. break;
  1047. case 6: /* VRAM Address register 2 */
  1048. if (ppu.VRAMAddrMode == 0)
  1049. {
  1050. //console_printf(Console_Default, "2006[1st][%d]: 0x%02X [0x%04X]\n", ScanLine, val, ppu.TmpVRamPtr);
  1051. ppu.VRAMAddrMode = 1;
  1052. /*
  1053. 2006 first write:
  1054. t:0011 1111 0000 0000 = d:0011 1111
  1055. t:1100 0000 0000 0000=0
  1056. */
  1057. ppu.TmpVRamPtr = ((ppu.TmpVRamPtr & 0x00FF) | ((val&0x3F) << 8));
  1058. //console_printf(Console_Default, "2006[1st][%d]: 0x%02X [0x%04X]\n", ScanLine, val, ppu.TmpVRamPtr);
  1059. //console_printf(Console_Default, "%d -> 2006 w1: 0x%04X (val: 0x%02X)\n", ScanLine, ppu.TmpVRamPtr, val);
  1060. }
  1061. else
  1062. {
  1063. //console_printf(Console_Default, "2006[2nd][%d]: 0x%02X [0x%04X]\n", ScanLine, val, ppu.TmpVRamPtr);
  1064. ppu.VRAMAddrMode = 0;
  1065. /*
  1066. 2006 second write:
  1067. t:0000000011111111=d:11111111
  1068. v=t
  1069. */
  1070. ppu.TmpVRamPtr = ((ppu.TmpVRamPtr & 0xFF00) | (val & 0x00FF));
  1071. ppu.VRAMAddrReg2.W = ppu.TmpVRamPtr;
  1072. //console_printf(Console_Default, "2006[2nd][%d]: 0x%02X [0x%04X]\n", ScanLine, val, ppu.TmpVRamPtr);
  1073. //console_printf(Console_Default, "%d -> 2006 w2: 0x%04X (val: 0x%02X)\n", ScanLine, ppu.TmpVRamPtr, val);
  1074. }
  1075. break;
  1076. case 7: /* VRAM I/O */
  1077. PPU_Wr(ppu.VRAMAddrReg2.W, val);
  1078. ppu.VRAMAddrReg2.W += ppu.PPU_Inc;
  1079. break;
  1080. }
  1081. }
  1082. void FillSprRamDMA(byte value)
  1083. {
  1084. int i;
  1085. for (i = 0x00; i < 0x100; i++)
  1086. {
  1087. ppu.SPRRAM[i] = ReadMemory( value, i);
  1088. }
  1089. }