ppu.old.c 39 KB

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