oldppu.c 34 KB

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