Advertisement
xiahanlu

GBC PPU&LCD

Oct 2nd, 2018
184
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 38.82 KB | None | 0 0
  1. /* Game boy's GPU and LCD Screen
  2.  * LCD is Sharp LH5028 http://www.datasheetarchive.com/pdf/download.php?id=c615e5d8551c6b559c3db61b709b3234af856c&type=O&term=LH5028
  3.  */
  4.  
  5. #include "ppu.h"
  6. #include "gameboy.h"
  7. #include "internal.h"
  8.  
  9.  
  10.  
  11. int ppu_init (struct ppu **X5028) {
  12.   struct ppu *sys = ks_null;
  13.   assert (X5028 != ks_null);
  14.  
  15.   sys = (struct ppu *)calloc (sizeof (struct ppu), 1);
  16.   assert (sys != ks_null);
  17.   *X5028 = sys;
  18.  
  19.   return 0;
  20. }
  21.  
  22. int ppu_reset (struct ppu *X5028) {
  23.  
  24.   /* init register http://gbdev.gg8.se/files/docs/mirrors/pandocs.html#powerupsequence */
  25.   X5028->reg40_LCDC = 0x91;
  26.   X5028->reg42_SCY = 0x00;
  27.   X5028->reg43_SCX = 0x00;
  28.   X5028->reg45_LYC = 0x00;
  29.   X5028->reg47_BGP = 0xFC;
  30.   X5028->reg48_OBP0 = 0xFF;
  31.   X5028->reg49_OBP1 = 0xFF;
  32.   X5028->reg4A_WY = 0x00;
  33.   X5028->reg4B_WX = 0x00;
  34.   /* reset cache */
  35.   X5028->reg42_SCY_cac= X5028->reg42_SCY;
  36.   X5028->reg43_SCX_cac= X5028->reg43_SCX;
  37.   X5028->reg4A_WY_cac= X5028->reg4A_WY;
  38.   X5028->reg4B_WX_cac= X5028->reg4B_WX;
  39. }
  40.  
  41. void ppu_uninit (struct ppu **X5028);
  42. int ppu_getbuf_ (struct ppu *X5028, ks_uint16 **bufrv, ks_uint16 *pitch);
  43. void ppu_setupdate (struct ppu *X5028, void (*update) (struct ppu *X5028));
  44. void ppu_update (struct ppu *X5028);
  45. int ppu_reset_cycles (struct ppu *X5028);
  46. int ppu_attach (struct ppu *X5028, struct gameboy *gb);
  47. void ppu_write_io (struct ppu *X5028, ks_uint16 address, ks_uint8 value);
  48. ks_uint8 ppu_read_io (struct ppu *X5028, ks_uint16 address);
  49.  
  50.  
  51. static
  52. void sprite_render (struct ppu *X5028, ks_uint16 scanline) {}
  53. static
  54. void background_render (struct ppu *X5028, ks_uint16 scanline) {}
  55.  
  56.  
  57. static /* this method for gameboy color */
  58. void bgwin_render_cgb (struct ppu *X5028, ks_int16 scanline) {
  59.   struct {
  60.     union { ks_uint16 blk;
  61.       struct { ks_uint8 lo; ks_uint8 hi; }; };
  62.   } chrdat,  chrcac;
  63.   /* always scan 168 pixel in every line (21 tiles),
  64.     evenif omfx is ZERO .
  65.       fit buffer offset, so that every time we can scan a complete tile,
  66.           no matter how much omfx is.
  67.     */
  68.   ks_int32 omfx;
  69.   ks_int32 ofx;
  70.   ks_int32 obx;
  71.   ks_int32 omfy;
  72.   ks_int32 ofy;
  73.   ks_int32 vsc;
  74.   ks_uint8 tid;
  75.   ks_int8 tat;
  76.   ks_int32 tidaddr;
  77.   ks_uint16 pixcac;
  78.   ks_uint8 *tdat;
  79.   ks_int32 rxpos;
  80.   ks_uint32 c, q, c2, s;
  81.   ks_int32 c3;
  82.   ks_uint16 *vptrWinDrawStart;
  83.   ks_uint16 *vptrScrollStart;
  84.   /* check current scan region in BG or WINDOW (if WINDOW enable)*/
  85.   if ( X5028->win_stuff != ks_false && (X5028->reg40_LCDC & 0x20)) {
  86.     /* draw window  */
  87.     goto windraw;
  88.   } else {
  89.     /* draw background */
  90.     vsc = X5028->uscanR;
  91.     omfx = X5028->reg43_SCX_cac & 7;
  92.     ofx = X5028->reg43_SCX_cac >> 3;
  93.     omfy = X5028->reg42_SCY_cac & 7;
  94.     ofy = X5028->reg42_SCY_cac >> 3;
  95.     ofx = ofx + vsc;
  96.     ofy = ofy + scanline;
  97.     omfy = ofy & 7;
  98.     ofy = ofy >> 3;
  99.     ofx = ofx - (ofx & 32);
  100.     ofy = ofy - (ofy & 32);  
  101.     obx = vsc << 3;
  102.     vptrScrollStart = & X5028->buf[scanline *(X5028->bufp/sizeof (X5028->buf[0]))+(8-omfx)];
  103.     /* pick tileid and attr from ::Bit 3 - BG Tile Map Display Select (0=9800-9BFF, 1=9C00-9FFF) */
  104.     tidaddr = 0x9C00 - (((X5028->reg40_LCDC & 0x08) >> 3) << 10);
  105.     tidaddr = (tidaddr-GB_VRAM_ADDRESS_START)+(ofy<< 5)+ofx;
  106.     tid = X5028->ram[tidaddr]; // fetch tileid
  107.     tat = X5028->ram[tidaddr+GB_VRAM_LENGTH]; // fetch tileattr.
  108.     tdat = & X5028->ram[((tat & 0x08)>>3)<<13]; // bank select.
  109. #   if  1
  110.     if (X5028->reg40_LCDC & 0x10) // 0x8000 unsigned address
  111.       tdat = & tdat[tid<<4];
  112.     else //
  113.       tdat = & tdat[0x1000+(((ks_int8)tid)<<4)]; // TODO: done.
  114. #   else
  115.     cti16 = (X5028->reg40_LCDC & 0x10) << 8;
  116.     cti16^= 0x1000;
  117.     tdat = & tdat[cti16+((ks_int8)(cti16 >>5)) & (((ks_int8)tid) << 4)];
  118. #   endif
  119. #   if  1
  120.     if (tat & 0x40) // check vflip ?
  121.       tdat = & tdat[(7-omfy)*2];
  122.     else
  123.       tdat = & tdat[omfy*2];
  124. #   else
  125.     ctu8 = (tat & 0x40) >> 3; // 8
  126.     ctu8 = ctu8 - (ctu8 >> 3);// 0 or 7
  127.     tdat = & tdat[(ctu8^omfy)<<1];
  128. #   endif
  129.     chrdat.blk = *(ks_uint16 *)tdat;
  130.     /* check x flip  */
  131.     if (tat & 0x20) {
  132.       chrcac.blk = chrdat.blk & 0x8080;
  133.       pixcac = pixcac | (chrcac.lo << 7) | (chrcac.hi << 8);
  134.       chrcac.blk = chrdat.blk & 0x4040;
  135.       pixcac = pixcac | (chrcac.lo << 6) | (chrcac.hi << 7);
  136.       chrcac.blk = chrdat.blk & 0x2020;
  137.       pixcac = pixcac | (chrcac.lo << 5) | (chrcac.hi << 6);
  138.       chrcac.blk = chrdat.blk & 0x1010;
  139.       pixcac = pixcac | (chrcac.lo << 4) | (chrcac.hi << 5);
  140.       chrcac.blk = chrdat.blk & 0x0808;
  141.       pixcac = pixcac | (chrcac.lo << 3) | (chrcac.hi << 4);
  142.       chrcac.blk = chrdat.blk & 0x0404;
  143.       pixcac = pixcac | (chrcac.lo << 2) | (chrcac.hi << 3);
  144.       chrcac.blk = chrdat.blk & 0x0202;
  145.       pixcac = pixcac | (chrcac.lo << 1) | (chrcac.hi << 2);
  146.       chrcac.blk = chrdat.blk & 0x0101;
  147.       pixcac = pixcac | (chrcac.lo << 0) | (chrcac.hi << 1);        
  148.     } else {
  149.       chrcac.blk = chrdat.blk & 0x8080;
  150.       pixcac = pixcac | (chrcac.lo >> 7) | (chrcac.hi >> 6);
  151.       chrcac.blk = chrdat.blk & 0x4040;
  152.       pixcac = pixcac | (chrcac.lo >> 4) | (chrcac.hi >> 3);
  153.       chrcac.blk = chrdat.blk & 0x2020;
  154.       pixcac = pixcac | (chrcac.lo >> 1) | (chrcac.hi >> 0);
  155.       chrcac.blk = chrdat.blk & 0x1010;
  156.       pixcac = pixcac | (chrcac.lo << 2) | (chrcac.hi << 3);
  157.       chrcac.blk = chrdat.blk & 0x0808;
  158.       pixcac = pixcac | (chrcac.lo << 5) | (chrcac.hi << 6);
  159.       chrcac.blk = chrdat.blk & 0x0404;
  160.       pixcac = pixcac | (chrcac.lo << 8) | (chrcac.hi << 9);
  161.       chrcac.blk = chrdat.blk & 0x0202;
  162.       pixcac = pixcac | (chrcac.lo <<11) | (chrcac.hi <<12);
  163.       chrcac.blk = chrdat.blk & 0x0101;
  164.       pixcac = pixcac | (chrcac.lo <<14) | (chrcac.hi <<15);
  165.     }
  166.     rxpos = obx - omfx;
  167.     q = tat&7;
  168.     if (!(X5028->reg40_LCDC & 0x01)) {
  169.       vptrScrollStart = & vptrScrollStart[obx];
  170.       /* When Bit 0 is cleared, the background and window lose their priority,
  171.         the sprites will be always displayed on top of background and window,
  172.         independently of the priority flags in OAM and BG Map attributes.
  173.         */
  174.       for (c = 0; c != 8; c++) {
  175.         s = rxpos+c;
  176.         if (X5028->spiline[s] & PIXEL_SPRITE_NOTRANS) // spline ptr to +8
  177.           vptrScrollStart[c] = X5028->spbline[s];
  178.         else
  179.           vptrScrollStart[c] = X5028->bg_pal[q][pixcac & 3].rgb15;
  180.         pixcac >>= 2;
  181.       }
  182.     } else if (tat & 0x80) { // BG pri.
  183.       vptrScrollStart = & vptrScrollStart[obx];
  184.       for (c = 0; c != 8; c++) {
  185.         vptrScrollStart[c] = X5028->bg_pal[q][pixcac & 3].rgb15;
  186.         pixcac >>= 2;
  187.       }
  188.     } else  {
  189.       for (c = 0; c != 8; c++) {
  190.         s = rxpos+c;
  191.         c2 = pixcac & 3;
  192.         if (X5028->spiline[s] & PIXEL_SPRITE_NOTRANS)
  193.           if (!(X5028->spiline[s] & PIXEL_SPRITE_BACK))
  194.             vptrScrollStart[c] = X5028->spbline[s];
  195.           else if ( c2 == 0)
  196.             vptrScrollStart[c] = X5028->spbline[s];
  197.           else
  198.             vptrScrollStart[c] = X5028->bg_pal[q][c2].rgb15;
  199.         else
  200.           vptrScrollStart[c] = X5028->bg_pal[q][c2].rgb15;
  201.         pixcac >>= 2;
  202.       }
  203.     }
  204.     rxpos = obx - omfx; // -7 | 25
  205.     rxpos+= 8; // 1 | 33
  206.     rxpos+= 7; // 8 | 40
  207.     if ( X5028->win_stuff == ks_false && (X5028->reg40_LCDC & 0x20)
  208.         && (X5028->reg4B_WX_cac <= 166 && X5028->reg4B_WX_cac < rxpos) /* check X**/
  209.         && (X5028->reg4A_WY_cac <= scanline && (X5028->reg4A_WY_cac <= 143)))
  210.     {
  211.       X5028->win_stuff = ks_true;
  212.       X5028->xscanR = 0;
  213.       q = 15 - omfx; // 8 | 16-> 9
  214.       // 7->0
  215.       // 8->1
  216.       while (X5028->reg4B_WX_cac >= q) // 15 >= q / 16
  217.         {
  218.           X5028->xscanR ++; //  1 or 2
  219.           q += 8;
  220.         }
  221.       goto windraw;
  222.     }
  223.   }
  224.   return ;
  225. windraw:
  226.   ofx = X5028->uscanR - X5028->xscanR; // espl x
  227.   c = scanline - X5028->reg4A_WY_cac; // total - y
  228.   omfx = 0;
  229.   omfy = c & 7;
  230.   ofy = c >> 3;
  231.   c3 = ((ks_int8)X5028->reg4B_WX_cac)-7;
  232.   c3 = c3 + (ofx<<3);
  233.   vptrWinDrawStart = & X5028->buf[scanline *(X5028->bufp/sizeof (X5028->buf[0]))+(8-0)+(ofx<<3)+c3];
  234.   /* pick tileid and attr from ::Bit 6 - Tile Tile Map Display Select (0=9800-9BFF, 1=9C00-9FFF) */
  235.   tidaddr = 0x9C00 - (((X5028->reg40_LCDC & 0x40) >> 6) << 10);
  236.   tidaddr = (tidaddr-GB_VRAM_ADDRESS_START)+(ofy<< 5)+ofx;
  237.   tid = X5028->ram[tidaddr]; // fetch tileid
  238.   tat = X5028->ram[tidaddr+GB_VRAM_LENGTH]; // fetch tileattr.
  239.   tdat = & X5028->ram[((tat & 0x08)>>3)<<13]; // bank select.
  240. #   if  1
  241.   if (X5028->reg40_LCDC & 0x10) // 0x8000 unsigned address
  242.     tdat = & tdat[tid<<4];
  243.   else //
  244.     tdat = & tdat[0x1000+(((ks_int8)tid)<<4)]; // TODO: done.
  245. #   else
  246.   cti16 = (X5028->reg40_LCDC & 0x10) << 8;
  247.   cti16^= 0x1000;
  248.   tdat = & tdat[cti16+((ks_int8)(cti16 >>5)) & (((ks_int8)tid) << 4)];
  249. #   endif
  250. #   if  1
  251.   if (tat & 0x40) // check vflip ?
  252.     tdat = & tdat[(7-omfy)*2];
  253.   else
  254.     tdat = & tdat[omfy*2];
  255. #   else
  256.   ctu8 = (tat & 0x40) >> 3; // 8
  257.   ctu8 = ctu8 - (ctu8 >> 3);// 0 or 7
  258.   tdat = & tdat[(ctu8^omfy)<<1];
  259. #   endif
  260.   chrdat.blk = *(ks_uint16 *)tdat;
  261.   /* check x flip  */
  262.   if (tat & 0x20) {
  263.     chrcac.blk = chrdat.blk & 0x8080;
  264.     pixcac = pixcac | (chrcac.lo << 7) | (chrcac.hi << 8);
  265.     chrcac.blk = chrdat.blk & 0x4040;
  266.     pixcac = pixcac | (chrcac.lo << 6) | (chrcac.hi << 7);
  267.     chrcac.blk = chrdat.blk & 0x2020;
  268.     pixcac = pixcac | (chrcac.lo << 5) | (chrcac.hi << 6);
  269.     chrcac.blk = chrdat.blk & 0x1010;
  270.     pixcac = pixcac | (chrcac.lo << 4) | (chrcac.hi << 5);
  271.     chrcac.blk = chrdat.blk & 0x0808;
  272.     pixcac = pixcac | (chrcac.lo << 3) | (chrcac.hi << 4);
  273.     chrcac.blk = chrdat.blk & 0x0404;
  274.     pixcac = pixcac | (chrcac.lo << 2) | (chrcac.hi << 3);
  275.     chrcac.blk = chrdat.blk & 0x0202;
  276.     pixcac = pixcac | (chrcac.lo << 1) | (chrcac.hi << 2);
  277.     chrcac.blk = chrdat.blk & 0x0101;
  278.     pixcac = pixcac | (chrcac.lo << 0) | (chrcac.hi << 1);        
  279.   } else {
  280.     chrcac.blk = chrdat.blk & 0x8080;
  281.     pixcac = pixcac | (chrcac.lo >> 7) | (chrcac.hi >> 6);
  282.     chrcac.blk = chrdat.blk & 0x4040;
  283.     pixcac = pixcac | (chrcac.lo >> 4) | (chrcac.hi >> 3);
  284.     chrcac.blk = chrdat.blk & 0x2020;
  285.     pixcac = pixcac | (chrcac.lo >> 1) | (chrcac.hi >> 0);
  286.     chrcac.blk = chrdat.blk & 0x1010;
  287.     pixcac = pixcac | (chrcac.lo << 2) | (chrcac.hi << 3);
  288.     chrcac.blk = chrdat.blk & 0x0808;
  289.     pixcac = pixcac | (chrcac.lo << 5) | (chrcac.hi << 6);
  290.     chrcac.blk = chrdat.blk & 0x0404;
  291.     pixcac = pixcac | (chrcac.lo << 8) | (chrcac.hi << 9);
  292.     chrcac.blk = chrdat.blk & 0x0202;
  293.     pixcac = pixcac | (chrcac.lo <<11) | (chrcac.hi <<12);
  294.     chrcac.blk = chrdat.blk & 0x0101;
  295.     pixcac = pixcac | (chrcac.lo <<14) | (chrcac.hi <<15);
  296.   }
  297.   q = tat&7;
  298.   if (!(X5028->reg40_LCDC & 0x01)) {
  299.     for (c = 0; c != 8; c++) {
  300.       s = c3+c;
  301.       if (X5028->spiline[s] & PIXEL_SPRITE_NOTRANS) // spline ptr to +8
  302.         vptrWinDrawStart[c] = X5028->spbline[s];
  303.       else
  304.         vptrWinDrawStart[c] = X5028->bg_pal[q][pixcac & 3].rgb15;
  305.       pixcac >>= 2;
  306.     }
  307.   } else if (tat & 0x80) { // BG pri.
  308.     for (c = 0; c != 8; c++) {
  309.       vptrWinDrawStart[c] = X5028->bg_pal[q][pixcac & 3].rgb15;
  310.       pixcac >>= 2;
  311.     }
  312.   } else  {
  313.     for (c = 0; c != 8; c++) {
  314.       s = c3+c;
  315.       c2 = pixcac & 3;
  316.       if (X5028->spiline[s] & PIXEL_SPRITE_NOTRANS)
  317.         if (!(X5028->spiline[s] & PIXEL_SPRITE_BACK))
  318.           vptrWinDrawStart[c] = X5028->spbline[s];
  319.         else if ( c2 == 0)
  320.           vptrWinDrawStart[c] = X5028->spbline[s];
  321.         else
  322.           vptrWinDrawStart[c] = X5028->bg_pal[q][c2].rgb15;
  323.       else
  324.         vptrWinDrawStart[c] = X5028->bg_pal[q][c2].rgb15;
  325.       pixcac >>= 2;
  326.     }
  327.   }
  328. }
  329. static /* this method for gameboy */
  330. void bgwin_render_dmg (struct ppu *X5028, ks_int16 scanline) {
  331.   struct {
  332.     union { ks_uint16 blk;
  333.       struct { ks_uint8 lo; ks_uint8 hi; }; };
  334.   } chrdat,  chrcac;
  335.   /* always scan 168 pixel in every line (21 tiles),
  336.     evenif omfx is ZERO .
  337.       fit buffer offset, so that every time we can scan a complete tile,
  338.           no matter how much omfx is.
  339.     */
  340.   ks_int32 omfx;
  341.   ks_int32 ofx;
  342.   ks_int32 obx;
  343.   ks_int32 omfy;
  344.   ks_int32 ofy;
  345.   ks_int32 vsc;
  346.   ks_uint8 tid;
  347.   ks_int32 tidaddr;
  348.   ks_uint16 pixcac;
  349.   ks_uint8 *tdat;
  350.   ks_int32 rxpos;
  351.   ks_uint32 c, q, c2, s;
  352.   ks_int32 c3;
  353.   ks_uint16 *vptrWinDrawStart;
  354.   ks_uint16 *vptrScrollStart;
  355.   /* check current scan region in BG or WINDOW (if WINDOW enable)*/
  356.   if ( X5028->win_stuff != ks_false && (X5028->reg40_LCDC & 0x20)) {
  357.     /* draw window  */
  358.     goto windraw;
  359.   } else {
  360.     /* draw background */
  361.     vsc = X5028->uscanR;
  362.     omfx = X5028->reg43_SCX_cac & 7;
  363.     ofx = X5028->reg43_SCX_cac >> 3;
  364.     omfy = X5028->reg42_SCY_cac & 7;
  365.     ofy = X5028->reg42_SCY_cac >> 3;
  366.     ofx = ofx + vsc;
  367.     ofy = ofy + scanline;
  368.     omfy = ofy & 7;
  369.     ofy = ofy >> 3;
  370.     ofx = ofx - (ofx & 32);
  371.     ofy = ofy - (ofy & 32);  
  372.     obx = vsc << 3;
  373.     vptrScrollStart = & X5028->buf[scanline *(X5028->bufp/sizeof (X5028->buf[0]))+(8-omfx)];
  374.     /* pick tileid and attr from ::Bit 3 - BG Tile Map Display Select (0=9800-9BFF, 1=9C00-9FFF) */
  375.     tidaddr = 0x9C00 - (((X5028->reg40_LCDC & 0x08) >> 3) << 10);
  376.     tidaddr = (tidaddr-GB_VRAM_ADDRESS_START)+(ofy<< 5)+ofx;
  377.     tid = X5028->ram[tidaddr]; // fetch tileid
  378.     tdat = & X5028->ram[0];
  379. #   if  1
  380.     if (X5028->reg40_LCDC & 0x10) // 0x8000 unsigned address
  381.       tdat = & tdat[tid<<4];
  382.     else //
  383.       tdat = & tdat[0x1000+(((ks_int8)tid)<<4)]; // TODO: done.
  384. #   else
  385.     cti16 = (X5028->reg40_LCDC & 0x10) << 8;
  386.     cti16^= 0x1000;
  387.     tdat = & tdat[cti16+((ks_int8)(cti16 >>5)) & (((ks_int8)tid) << 4)];
  388. #   endif
  389.     tdat = & tdat[omfy*2];
  390.     chrdat.blk = *(ks_uint16 *)tdat;
  391.     chrcac.blk = chrdat.blk & 0x8080;
  392.     pixcac = pixcac | (chrcac.lo >> 7) | (chrcac.hi >> 6);
  393.     chrcac.blk = chrdat.blk & 0x4040;
  394.     pixcac = pixcac | (chrcac.lo >> 4) | (chrcac.hi >> 3);
  395.     chrcac.blk = chrdat.blk & 0x2020;
  396.     pixcac = pixcac | (chrcac.lo >> 1) | (chrcac.hi >> 0);
  397.     chrcac.blk = chrdat.blk & 0x1010;
  398.     pixcac = pixcac | (chrcac.lo << 2) | (chrcac.hi << 3);
  399.     chrcac.blk = chrdat.blk & 0x0808;
  400.     pixcac = pixcac | (chrcac.lo << 5) | (chrcac.hi << 6);
  401.     chrcac.blk = chrdat.blk & 0x0404;
  402.     pixcac = pixcac | (chrcac.lo << 8) | (chrcac.hi << 9);
  403.     chrcac.blk = chrdat.blk & 0x0202;
  404.     pixcac = pixcac | (chrcac.lo <<11) | (chrcac.hi <<12);
  405.     chrcac.blk = chrdat.blk & 0x0101;
  406.     pixcac = pixcac | (chrcac.lo <<14) | (chrcac.hi <<15);
  407.     rxpos = obx - omfx;
  408.    
  409.     if (!(X5028->reg40_LCDC & 0x01)) {
  410.       vptrScrollStart = & vptrScrollStart[obx];
  411.       /* When Bit 0 is cleared, the background and window lose their priority,
  412.         the sprites will be always displayed on top of background and window,
  413.         independently of the priority flags in OAM and BG Map attributes.
  414.         */
  415.       for (c = 0; c != 8; c++) {
  416.         s = rxpos+c;
  417.         if (X5028->spiline[s] & PIXEL_SPRITE_NOTRANS) // spline ptr to +8
  418.           vptrScrollStart[c] = X5028->spbline[s];
  419.         else
  420.           vptrScrollStart[c] = X5028->bg_pal_dmg[0];
  421.         pixcac >>= 2;
  422.       }
  423.     } else  {
  424.       for (c = 0; c != 8; c++) {
  425.         s = rxpos+c;
  426.         c2 = pixcac & 3;
  427.         if (X5028->spiline[s] & PIXEL_SPRITE_NOTRANS)
  428.           if (!(X5028->spiline[s] & PIXEL_SPRITE_BACK))
  429.             vptrScrollStart[c] = X5028->spbline[s];
  430.           else if ( c2 == 0)
  431.             vptrScrollStart[c] = X5028->spbline[s];
  432.           else
  433.             vptrScrollStart[c] = X5028->bg_pal_dmg[pixcac & 3];
  434.         else
  435.           vptrScrollStart[c] = X5028->bg_pal_dmg[pixcac & 3];
  436.         pixcac >>= 2;
  437.       }
  438.     }
  439.     rxpos = obx - omfx; // -7 | 25
  440.     rxpos+= 8; // 1 | 33
  441.     rxpos+= 7; // 8 | 40
  442.     if ( X5028->win_stuff == ks_false && (X5028->reg40_LCDC & 0x20)
  443.         && (X5028->reg4B_WX_cac <= 166 && X5028->reg4B_WX_cac < rxpos) /* check X**/
  444.         && (X5028->reg4A_WY_cac <= scanline && (X5028->reg4A_WY_cac <= 143)))
  445.     {
  446.       X5028->win_stuff = ks_true;
  447.       X5028->xscanR = 0;
  448.       q = 15 - omfx; // 8 | 16-> 9
  449.       // 7->0
  450.       // 8->1
  451.       while (X5028->reg4B_WX_cac >= q) // 15 >= q / 16
  452.         {
  453.           X5028->xscanR ++; //  1 or 2
  454.           q += 8;
  455.         }
  456.       goto windraw;
  457.     }
  458.   }
  459.   return ;
  460. windraw:
  461.   ofx = X5028->uscanR - X5028->xscanR; // espl x
  462.   c = scanline - X5028->reg4A_WY_cac; // total - y
  463.   omfx = 0;
  464.   omfy = c & 7;
  465.   ofy = c >> 3;
  466.   c3 = ((ks_int8)X5028->reg4B_WX_cac)-7;
  467.   c3 = c3 + (ofx<<3);
  468.   vptrWinDrawStart = & X5028->buf[scanline *(X5028->bufp/sizeof (X5028->buf[0]))+(8-0)+(ofx<<3)+c3];
  469.   /* pick tileid and attr from ::Bit 6 - Tile Tile Map Display Select (0=9800-9BFF, 1=9C00-9FFF) */
  470.   tidaddr = 0x9C00 - (((X5028->reg40_LCDC & 0x40) >> 6) << 10);
  471.   tidaddr = (tidaddr-GB_VRAM_ADDRESS_START)+(ofy<< 5)+ofx;
  472.   tid = X5028->ram[tidaddr]; // fetch tileid
  473.   tdat = & X5028->ram[0]; // bank select.
  474. #   if  1
  475.   if (X5028->reg40_LCDC & 0x10) // 0x8000 unsigned address
  476.     tdat = & tdat[tid<<4];
  477.   else //
  478.     tdat = & tdat[0x1000+(((ks_int8)tid)<<4)]; // TODO: done.
  479. #   else
  480.   cti16 = (X5028->reg40_LCDC & 0x10) << 8;
  481.   cti16^= 0x1000;
  482.   tdat = & tdat[cti16+((ks_int8)(cti16 >>5)) & (((ks_int8)tid) << 4)];
  483. #   endif
  484.   tdat = & tdat[omfy*2];
  485.   chrdat.blk = *(ks_uint16 *)tdat;
  486.   chrcac.blk = chrdat.blk & 0x8080;
  487.   pixcac = pixcac | (chrcac.lo >> 7) | (chrcac.hi >> 6);
  488.   chrcac.blk = chrdat.blk & 0x4040;
  489.   pixcac = pixcac | (chrcac.lo >> 4) | (chrcac.hi >> 3);
  490.   chrcac.blk = chrdat.blk & 0x2020;
  491.   pixcac = pixcac | (chrcac.lo >> 1) | (chrcac.hi >> 0);
  492.   chrcac.blk = chrdat.blk & 0x1010;
  493.   pixcac = pixcac | (chrcac.lo << 2) | (chrcac.hi << 3);
  494.   chrcac.blk = chrdat.blk & 0x0808;
  495.   pixcac = pixcac | (chrcac.lo << 5) | (chrcac.hi << 6);
  496.   chrcac.blk = chrdat.blk & 0x0404;
  497.   pixcac = pixcac | (chrcac.lo << 8) | (chrcac.hi << 9);
  498.   chrcac.blk = chrdat.blk & 0x0202;
  499.   pixcac = pixcac | (chrcac.lo <<11) | (chrcac.hi <<12);
  500.   chrcac.blk = chrdat.blk & 0x0101;
  501.   pixcac = pixcac | (chrcac.lo <<14) | (chrcac.hi <<15);
  502.  
  503.   if (!(X5028->reg40_LCDC & 0x01)) {
  504.     for (c = 0; c != 8; c++) {
  505.       s = c3+c;
  506.       if (X5028->spiline[s] & PIXEL_SPRITE_NOTRANS) // spline ptr to +8
  507.         vptrWinDrawStart[c] = X5028->spbline[s];
  508.       else
  509.         vptrWinDrawStart[c] = X5028->bg_pal_dmg[0];
  510.     }
  511.   } else  {
  512.     for (c = 0; c != 8; c++) {
  513.       s = c3+c;
  514.       c2 = pixcac & 3;
  515.       if (X5028->spiline[s] & PIXEL_SPRITE_NOTRANS)
  516.         if (!(X5028->spiline[s] & PIXEL_SPRITE_BACK))
  517.           vptrWinDrawStart[c] = X5028->spbline[s];
  518.         else if ( c2 == 0)
  519.           vptrWinDrawStart[c] = X5028->spbline[s];
  520.         else
  521.           vptrWinDrawStart[c] = X5028->bg_pal_dmg[pixcac & 3];
  522.       else
  523.         vptrWinDrawStart[c] = X5028->bg_pal_dmg[pixcac & 3];
  524.       pixcac >>= 2;
  525.     }
  526.   }
  527. }
  528. static /* this method for gameboy color */
  529. void sprite_render_cgb (struct ppu *X5028, ks_int16 scanline) {
  530.  
  531.   ks_int16 size_y; /* ?8*16:8*8 */
  532.   /* ks_bool touch;*/
  533.  
  534.   size_y = (X5028->reg40_LCDC & 0x04)? 16 : 8;
  535.   /* touch = ks_false; */
  536.  
  537.   /* check sprite in visual scanline */
  538.   for (; X5028->vscan40 < 40; X5028->vscan40++) {
  539.     ks_int16 x;
  540.     ks_int16 y;
  541.     ks_int16 id;
  542.     struct oam *ptr = & X5028->sp[X5028->vscan40];
  543.     y = ptr->y;
  544.     x = ptr->x;
  545.  
  546.     if (ptr->y == 0 || ptr->y >= 160)
  547.       continue ;
  548.     y -= 16;
  549.     if (scanline >= y && (scanline < (y + size_y))
  550.       && (x != 0 && x < 168)) {
  551.  
  552.         struct nca {
  553.           union {
  554.             ks_uint16 blk;
  555.             struct {
  556.               ks_uint8 lo;
  557.               ks_uint8 hi;
  558.             };
  559.           };
  560.         } chrdat,  chrcac;
  561.  
  562.         ks_uint16 pixcac ;
  563.         ks_uint8 *chrb;
  564.         /* sprite inc */
  565.         X5028->vscanR++;
  566.         /* pick tile data by tile id and atrr's D3*/
  567.         chrb = & X5028->ram[ptr->attr & 0x08 ? 0x2000 : 0x0000];
  568.         if (size_y != 16)
  569.           chrb = & chrb[ptr->id *16]; // a tile data include 16 bytes
  570.         else
  571.           chrb = & chrb[(ptr->id & 0xFE) *16]; // always pointer tile16's high part in init state .
  572.         /* check Y mapper */
  573.         if (ptr->attr & 0x40) {
  574.           if (size_y == 16) {
  575.             /* sprite16 flip */
  576.             /* get rev offset */
  577.             int calct = scanline - y;
  578.             calct = 7 -calct; /* flip Y in one tile */
  579.             calct *= 2;
  580.             /* get oppo base tile byte8 (^source pos[high or low])*/
  581.             if (calct <= 7) /* high, switch to low */ {
  582.               calct += 16;
  583.             } else { /* low switch to high, nodone, already in high (see line 114).*/    
  584.             }
  585.             chrdat.blk = *(ks_int16 *)& chrb[calct];
  586.           } else {
  587.             /* sprite8 flip */
  588.             int calct = scanline - y;
  589.             calct = 7 -calct; /* flip Y */
  590.             calct *= 2;
  591.             chrdat.blk = *(ks_int16 *)& chrb[calct];
  592.           }
  593.         } else {
  594.           int calct = scanline - y;
  595.           calct *= 2;
  596.           chrdat.blk = *(ks_int16 *)& chrb[calct];
  597.         }
  598.         /* mix gbc's pixel (d1d0) */
  599.         /* see GBCPUman.pdf:: 2.8.1. Tiles */
  600.         pixcac = 0; // reset all
  601.         /* check x flip  */
  602.         if (ptr->attr & 0x20) {
  603.           chrcac.blk = chrdat.blk & 0x8080;
  604.           pixcac = pixcac | (chrcac.lo << 7) | (chrcac.hi << 8);
  605.           chrcac.blk = chrdat.blk & 0x4040;
  606.           pixcac = pixcac | (chrcac.lo << 6) | (chrcac.hi << 7);
  607.           chrcac.blk = chrdat.blk & 0x2020;
  608.           pixcac = pixcac | (chrcac.lo << 5) | (chrcac.hi << 6);
  609.           chrcac.blk = chrdat.blk & 0x1010;
  610.           pixcac = pixcac | (chrcac.lo << 4) | (chrcac.hi << 5);
  611.           chrcac.blk = chrdat.blk & 0x0808;
  612.           pixcac = pixcac | (chrcac.lo << 3) | (chrcac.hi << 4);
  613.           chrcac.blk = chrdat.blk & 0x0404;
  614.           pixcac = pixcac | (chrcac.lo << 2) | (chrcac.hi << 3);
  615.           chrcac.blk = chrdat.blk & 0x0202;
  616.           pixcac = pixcac | (chrcac.lo << 1) | (chrcac.hi << 2);
  617.           chrcac.blk = chrdat.blk & 0x0101;
  618.           pixcac = pixcac | (chrcac.lo << 0) | (chrcac.hi << 1);        
  619.         } else {
  620.           chrcac.blk = chrdat.blk & 0x8080;
  621.           pixcac = pixcac | (chrcac.lo >> 7) | (chrcac.hi >> 6);
  622.           chrcac.blk = chrdat.blk & 0x4040;
  623.           pixcac = pixcac | (chrcac.lo >> 4) | (chrcac.hi >> 3);
  624.           chrcac.blk = chrdat.blk & 0x2020;
  625.           pixcac = pixcac | (chrcac.lo >> 1) | (chrcac.hi >> 0);
  626.           chrcac.blk = chrdat.blk & 0x1010;
  627.           pixcac = pixcac | (chrcac.lo << 2) | (chrcac.hi << 3);
  628.           chrcac.blk = chrdat.blk & 0x0808;
  629.           pixcac = pixcac | (chrcac.lo << 5) | (chrcac.hi << 6);
  630.           chrcac.blk = chrdat.blk & 0x0404;
  631.           pixcac = pixcac | (chrcac.lo << 8) | (chrcac.hi << 9);
  632.           chrcac.blk = chrdat.blk & 0x0202;
  633.           pixcac = pixcac | (chrcac.lo <<11) | (chrcac.hi <<12);
  634.           chrcac.blk = chrdat.blk & 0x0101;
  635.           pixcac = pixcac | (chrcac.lo <<14) | (chrcac.hi <<15);
  636.         }
  637.         x -= 8;
  638.         for (id = 0; id != 8; id++) {
  639.           ks_uint8 idxpal; /* palette group index, max is8, see OAM struct */
  640.           idxpal = pixcac & 3;
  641.           if (x >= 0 && x <= 159) {
  642.             /* check trans or */
  643.             if (X5028->spi_cac[x+8] & PIXEL_SPRITE_NOTRANS) {
  644.               /* notrans */
  645.               if (X5028->spi_cac[x+8] & PIXEL_SPRITE_BACK) {
  646.                 if (!(ptr->attr & 0x80) && idxpal != 0) {
  647. #               if  1 /* maybe error, it's not a big problem. */
  648.                   /* cur pick oam is foreground sprite */
  649.                   ks_uint16 idxpg = ptr->attr & 7;
  650.                   X5028->spb_cac[x+8] = X5028->sp_pal[idxpg][idxpal].rgb15;
  651.                   X5028->spi_cac[x+8] = PIXEL_SPRITE_NOTRANS;            
  652. #               endif
  653.                 }
  654.               } else {
  655.                 /* nodone in foreground sprite */
  656.               }
  657.             } else {
  658.               /* trans, write directly */
  659.               ks_uint16 idxpg = ptr->attr & 7;
  660.               X5028->spb_cac[x+8] = X5028->sp_pal[idxpg][idxpal].rgb15;
  661.               X5028->spi_cac[x+8] = 0;
  662.               if (ptr->attr & 0x80) {
  663.                 /* background sprite */
  664.                 X5028->spi_cac[x+8] |= PIXEL_SPRITE_BACK;
  665.               }
  666.               if (idxpal != 0) {
  667.                 /* idxpal is trans color */
  668.                 X5028->spi_cac[x+8] |= PIXEL_SPRITE_NOTRANS;
  669.               }
  670.             }
  671.           }
  672.           x ++;
  673.           pixcac >>= 2;
  674.         }
  675.         /* scan one sprite tile compete */
  676.         return ;
  677.     }
  678.   }
  679. }
  680. static /* this method for gameboy */
  681. void sprite_render_dmg (struct ppu *X5028, ks_int16 scanline) {
  682.  
  683.   ks_int16 size_y; /* ?8*16:8*8 */
  684.   /* ks_bool touch;*/
  685.  
  686.   size_y = (X5028->reg40_LCDC & 0x04)? 16 : 8;
  687.   /* touch = ks_false; */
  688.  
  689.   /* check sprite in visual scanline */
  690.   for (; X5028->vscan40 < 40; X5028->vscan40++) {
  691.     ks_int16 x;
  692.     ks_int16 y;
  693.     ks_int16 id;
  694.     struct oam *ptr = & X5028->sp[X5028->vscan40];
  695.     y = ptr->y;
  696.     x = ptr->x;
  697.  
  698.     if (ptr->y == 0 || ptr->y >= 160)
  699.       continue ;
  700.     y -= 16;
  701.     if (scanline >= y && (scanline < (y + size_y))
  702.       && (x != 0 && x < 168)) {
  703.  
  704.         struct nca {
  705.           union {
  706.             ks_uint16 blk;
  707.             struct {
  708.               ks_uint8 lo;
  709.               ks_uint8 hi;
  710.             };
  711.           };
  712.         } chrdat,  chrcac;
  713.  
  714.         ks_uint16 pixcac ;
  715.         ks_uint8 *chrb;
  716.         /* sprite inc */
  717.         X5028->vscanR++;
  718.         /* pick tile data by tile id and atrr's D3*/
  719.         chrb = & X5028->ram[ptr->attr & 0x08 ? 0x2000 : 0x0000];
  720.         if (size_y != 16)
  721.           chrb = & chrb[ptr->id *16]; // a tile data include 16 bytes
  722.         else
  723.           chrb = & chrb[(ptr->id & 0xFE) *16]; // always pointer tile16's high part in init state .
  724.         /* check Y mapper */
  725.         if (ptr->attr & 0x40) {
  726.           if (size_y == 16) {
  727.             /* sprite16 flip */
  728.             /* get rev offset */
  729.             int calct = scanline - y;
  730.             calct = 7 -calct; /* flip Y in one tile */
  731.             calct *= 2;
  732.             /* get oppo base tile byte8 (^source pos[high or low])*/
  733.             if (calct <= 7) /* high, switch to low */ {
  734.               calct += 16;
  735.             } else { /* low switch to high, nodone, already in high (see line 114).*/    
  736.             }
  737.             chrdat.blk = *(ks_int16 *)& chrb[calct];
  738.           } else {
  739.             /* sprite8 flip */
  740.             int calct = scanline - y;
  741.             calct = 7 -calct; /* flip Y */
  742.             calct *= 2;
  743.             chrdat.blk = *(ks_int16 *)& chrb[calct];
  744.           }
  745.         } else {
  746.           int calct = scanline - y;
  747.           calct *= 2;
  748.           chrdat.blk = *(ks_int16 *)& chrb[calct];
  749.         }
  750.         /* mix gbc's pixel (d1d0) */
  751.         /* see GBCPUman.pdf:: 2.8.1. Tiles */
  752.         pixcac = 0; // reset all
  753.         /* check x flip  */
  754.         if (ptr->attr & 0x20) {
  755.           chrcac.blk = chrdat.blk & 0x8080;
  756.           pixcac = pixcac | (chrcac.lo << 7) | (chrcac.hi << 8);
  757.           chrcac.blk = chrdat.blk & 0x4040;
  758.           pixcac = pixcac | (chrcac.lo << 6) | (chrcac.hi << 7);
  759.           chrcac.blk = chrdat.blk & 0x2020;
  760.           pixcac = pixcac | (chrcac.lo << 5) | (chrcac.hi << 6);
  761.           chrcac.blk = chrdat.blk & 0x1010;
  762.           pixcac = pixcac | (chrcac.lo << 4) | (chrcac.hi << 5);
  763.           chrcac.blk = chrdat.blk & 0x0808;
  764.           pixcac = pixcac | (chrcac.lo << 3) | (chrcac.hi << 4);
  765.           chrcac.blk = chrdat.blk & 0x0404;
  766.           pixcac = pixcac | (chrcac.lo << 2) | (chrcac.hi << 3);
  767.           chrcac.blk = chrdat.blk & 0x0202;
  768.           pixcac = pixcac | (chrcac.lo << 1) | (chrcac.hi << 2);
  769.           chrcac.blk = chrdat.blk & 0x0101;
  770.           pixcac = pixcac | (chrcac.lo << 0) | (chrcac.hi << 1);        
  771.         } else {
  772.           chrcac.blk = chrdat.blk & 0x8080;
  773.           pixcac = pixcac | (chrcac.lo >> 7) | (chrcac.hi >> 6);
  774.           chrcac.blk = chrdat.blk & 0x4040;
  775.           pixcac = pixcac | (chrcac.lo >> 4) | (chrcac.hi >> 3);
  776.           chrcac.blk = chrdat.blk & 0x2020;
  777.           pixcac = pixcac | (chrcac.lo >> 1) | (chrcac.hi >> 0);
  778.           chrcac.blk = chrdat.blk & 0x1010;
  779.           pixcac = pixcac | (chrcac.lo << 2) | (chrcac.hi << 3);
  780.           chrcac.blk = chrdat.blk & 0x0808;
  781.           pixcac = pixcac | (chrcac.lo << 5) | (chrcac.hi << 6);
  782.           chrcac.blk = chrdat.blk & 0x0404;
  783.           pixcac = pixcac | (chrcac.lo << 8) | (chrcac.hi << 9);
  784.           chrcac.blk = chrdat.blk & 0x0202;
  785.           pixcac = pixcac | (chrcac.lo <<11) | (chrcac.hi <<12);
  786.           chrcac.blk = chrdat.blk & 0x0101;
  787.           pixcac = pixcac | (chrcac.lo <<14) | (chrcac.hi <<15);
  788.         }
  789.         x -= 8;
  790.         for (id = 0; id != 8; id++) {
  791.           ks_uint8 idxpal; /* palette group index, max is8, see OAM struct */
  792.           idxpal = pixcac & 3;
  793.           if (x >= 0 && x <= 159) {
  794.             /* check trans or */
  795.             if (X5028->spi_cac[x+8] & PIXEL_SPRITE_NOTRANS) {
  796.               /* notrans */
  797.               if (X5028->spi_cac[x+8] & PIXEL_SPRITE_BACK) {
  798.                 if (!(ptr->attr & 0x80) && idxpal != 0) {
  799. #               if  1 /* maybe error, it's not a big problem. */
  800.                   /* cur pick oam is foreground sprite */
  801.                   ks_uint16 idxpg = (ptr->attr & 0x10) >> 4;
  802.                   X5028->spb_cac[x+8] = X5028->obp_pal_dmg[idxpg][idxpal];
  803.                   X5028->spi_cac[x+8] = PIXEL_SPRITE_NOTRANS;            
  804. #               endif
  805.                 }
  806.               } else {
  807.                 /* nodone in foreground sprite */
  808.               }
  809.             } else {
  810.               /* trans, write directly */
  811.               ks_uint16 idxpg = (ptr->attr & 0x10) >> 4;
  812.               X5028->spb_cac[x+8] = X5028->obp_pal_dmg[idxpg][idxpal];
  813.               X5028->spi_cac[x+8] = 0;
  814.               if (ptr->attr & 0x80) {
  815.                 /* background sprite */
  816.                 X5028->spi_cac[x+8] |= PIXEL_SPRITE_BACK;
  817.               }
  818.               if (idxpal != 0) {
  819.                 /* idxpal is trans color */
  820.                 X5028->spi_cac[x+8] |= PIXEL_SPRITE_NOTRANS;
  821.               }
  822.             }
  823.           }
  824.           x ++;
  825.           pixcac >>= 2;
  826.         }
  827.         /* scan one sprite tile compete */
  828.         return ; // TODO: gb sprite priority.
  829.     }
  830.   }
  831. }
  832. /* XXX:so bad */
  833. int ppu_run (struct ppu *X5028) {
  834.  
  835.   ks_int32 scanline;
  836.   ks_int16 interv;
  837.   ks_int16 _nums;
  838.   ks_double clkline;
  839.  
  840.   if (X5028->gb->cpu_clks_ppu > X5028->gb->mach_tools->frame_cycles) {
  841.     X5028->gb->cpu_clks_ppu -= X5028->gb->mach_tools->frame_cycles; // sub a frame block
  842.     /* at this time and in the scanning of the next frame of the device.
  843.               reset ppu device context  */
  844.    
  845.     /* vblank Interrupt, check touch */
  846.     if (X5028->vbl_flop == ks_false)
  847.       if (X5028->reg41_LCDS & 0x10)
  848.         X5028->gb->reg0F_IF |= IRQ_1;
  849.       else {}
  850.     else {}
  851.    
  852.     /* reset context */
  853.     X5028->vbl_flop = ks_false;
  854.     X5028->oam_flop = ks_false;
  855.     X5028->hbl_flop = ks_false;
  856.     X5028->interrupt45_flop = ks_false;
  857.     X5028->interrupt45_strike = ks_false;
  858.     X5028->vscan = -1;
  859.     X5028->vscanR = 0;
  860.     X5028->vscan40 = 0;
  861.     X5028->uscan = -1;
  862.     X5028->uscanR = 0;
  863.     X5028->uscan168 = 0;
  864.     X5028->win_stuff = ks_false;
  865.   }
  866.   scanline = (ks_int32) (X5028->gb->cpu_clks_ppu/ X5028->gb->mach_tools->line_cycles);
  867.   clkline = fmod (X5028->gb->cpu_clks_ppu, X5028->gb->mach_tools->line_cycles);
  868.   /* clear mask */
  869.   X5028->reg40_LCDC &= ~LCDCS_MODE_FLAG_ALL_MASK;
  870.  
  871.   /*
  872.     PPU time series
  873.  
  874.     Mode 0: The LCD controller is in the H-Blank period and
  875.          the CPU can access both the display RAM (8000h-9FFFh)
  876.          and OAM (FE00h-FE9Fh)
  877.  
  878.     Mode 1: The LCD controller is in the V-Blank period (or the
  879.          display is disabled) and the CPU can access both the
  880.          display RAM (8000h-9FFFh) and OAM (FE00h-FE9Fh)
  881.  
  882.     Mode 2: The LCD controller is reading from OAM memory.
  883.          The CPU <cannot> access OAM memory (FE00h-FE9Fh)
  884.          during this period.
  885.  
  886.     Mode 3: The LCD controller is reading from both OAM and VRAM,
  887.          The CPU <cannot> access OAM and VRAM during this period.
  888.          CGB Mode: Cannot access Palette Data (FF69,FF6B) either.
  889.     The following are typical when the display is enabled:
  890.  
  891.     Mode 2  2_____2_____2_____2_____2_____2___________________2____
  892.     Mode 3  _33____33____33____33____33____33__________________3___
  893.     Mode 0  ___000___000___000___000___000___000________________000
  894.     Mode 1  ____________________________________11111111111111_____
  895.  
  896.     The Mode Flag goes through the values 0, 2, and 3 at a cycle of about 109uS.
  897.     0 is present about 48.6uS, 2 about 19uS,
  898.     and 3 about 41uS. This is interrupted every 16.6ms by the VBlank (1).
  899.     The mode flag stays set at 1 for about 1.08 ms.
  900.  
  901.     Mode 0 is present between 201-207 clks, 2 about 77-83 clks, and 3 about 169-175 clks.
  902.     A complete cycle through these states takes 456 clks.
  903.     VBlank lasts 4560 clks. A complete screen refresh occurs every 70224 clks.)
  904.  */
  905.  
  906.   /* check scanline and LCDY interrupt */
  907.   if (X5028->line_cac != scanline
  908.        || (X5028->interrupt45_strike != ks_false)) {
  909.     /* setting onrush effective */
  910.     if (X5028->line_cac != scanline) {
  911.       X5028->interrupt45_flop = ks_false; /* reset gate */
  912.       X5028->interrupt45_strike = ks_false; /* close strike function*/
  913.     } /*  scanline next, (low to high) for each scanline,
  914.                    multiple LCDY interruptions can not be triggered at the same time
  915.            during each vertical synchronization  */
  916.     if (X5028->reg45_LYC == scanline) /*  check enable ?*/
  917.          /* Bit 6 - LYC=LY Coincidence Interrupt (1=Enable) (Read/Write) */
  918.       if (X5028->reg41_LCDS & 0x40 && !X5028->interrupt45_flop) {      
  919.         X5028->interrupt45_strike = ks_false; /* close strike function*/
  920.         X5028->interrupt45_flop = ks_true;
  921.         X5028->gb->reg0F_IF |= IRQ_2;
  922.       } else {}
  923.     else {}
  924.   }
  925.   /* check FF41::Bit 2 Coincidence Flag  (0:LYC<>LY, 1:LYC=LY) (Read Only)*/
  926.   if (scanline == X5028->reg45_LYC)
  927.     X5028->reg41_LCDS |= 0x04;
  928.   else X5028->reg41_LCDS &= ~0x04;
  929.  
  930.   /* check mode */
  931.   if (clkline < X5028->gb->mach_tools->vbl_clk_st) {
  932.     if (clkline > X5028->hbl_clks_st) {
  933.       /*  LCD MODE0 -  hblank period */
  934.       X5028->reg41_LCDS |= LCDCS_MODE_FLAG_HBLANK;
  935.       /*  check edge */
  936.       if (X5028->lcdm_cac != LCDCS_MODE_FLAG_HBLANK) {
  937.         /* oamvram to current, (low to high) */
  938.         while (X5028->uscanR < 21) {
  939.           X5028->bgwin_render (X5028, scanline);
  940.           X5028->uscanR ++;
  941.         }
  942.         /* reset next mode-2 | mode- 3*/
  943.         X5028->oam_flop = ks_false;
  944.         X5028->vscan = -1;
  945.         X5028->vscan40 = 0;
  946.         X5028->uscan = -1;
  947.         X5028->vscanR = 0;
  948.         X5028->uscanR = 0;
  949.         /* check HDMA. **/
  950.         if (scanline >= 0 && scanline <= 143 && X5028->gb->dma_gen)  {
  951.           /* copy 16 bytes  */
  952.           if (gameboy_hdma_copy (X5028->gb) == 0)
  953.             X5028->gb->dma_gen = ks_false;
  954.           /* add hdma cycles, ~ 8us */
  955.           X5028->hdma_clk += (X5028->gb->mach_tools->clk_ns * 8.0);
  956.         }
  957.       }
  958.       /* check hblank interrupt  */
  959.       if ((X5028->reg41_LCDS & 0x08) && X5028->hbl_flop == ks_false) {
  960.         X5028->hbl_flop = ks_true;
  961.         X5028->gb->reg0F_IF |= IRQ_2;
  962.       }
  963.     } else if (clkline > X5028->gb->mach_tools->oambg_clk_st) {
  964.       /* LCD MODE3  - oamvram */
  965.       clkline -= X5028->gb->mach_tools->oambg_clk_st; // sub, get start clcks epls.
  966.       X5028->reg41_LCDS |= LCDCS_MODE_FLAG_SERACH_OAMVRAM;
  967.       /* check edge */
  968.       if (X5028->lcdm_cac != LCDCS_MODE_FLAG_SERACH_OAMVRAM) {
  969.         /*  check stride sprite render  */
  970.         /* get render pos */
  971.         interv = 9;
  972.  
  973.         /* check render oam *.*/
  974.         if ( X5028->vscan != interv
  975.              &&   X5028->vscanR < 10
  976.                && X5028->vscan40   < 40) {
  977.           _nums = interv - X5028->vscan;
  978.           X5028->vscan += _nums;
  979.           /* render sprite */
  980.           do
  981.           {
  982.                    X5028->sprite_render (X5028, scanline); }
  983.              while (--_nums);
  984.         }
  985.         /*  check sprite interrupt  */
  986.         if ((X5028->reg41_LCDS & 0x20) && !X5028->oam_flop) {      
  987.           X5028->oam_flop = ks_true;
  988.           X5028->gb->reg0F_IF |= IRQ_2;
  989.         }
  990.         X5028->oam_flop = ks_false;
  991.  
  992.         /* adjust BGOAM clk */
  993.  
  994.         X5028->hbl_clks_st = (X5028->gb->mach_tools->oambg_b_cycles +
  995.               X5028->vscanR * X5028->gb->mach_tools->oam_clk_add_hbl_per);
  996.         X5028->oambg_clks_divider21 =
  997.             X5028->hbl_clks_st / 21.0;
  998.         X5028->hbl_clks_st += X5028->gb->mach_tools->oam_cycles;
  999.       }
  1000.       /* get render pos */
  1001.       interv = KS_INT16_CAST (clkline/ X5028->oambg_clks_divider21);
  1002.  
  1003.       /* check render bg *.*/
  1004.       if (interv != X5028->uscan) {
  1005.         _nums = interv - X5028->uscan;
  1006.         X5028->uscan += _nums;
  1007.         do {
  1008.           X5028->bgwin_render (X5028, scanline);
  1009.           X5028->uscanR ++;
  1010.         }  while (--_nums);
  1011.       }
  1012.     } else   {
  1013.       /* LCD MODE2 - oam */
  1014.       X5028->reg41_LCDS |= LCDCS_MODE_FLAG_SERACH_OAM;
  1015.       /* check edge */
  1016.       if (X5028->lcdm_cac == LCDCS_MODE_FLAG_HBLANK) {
  1017.         /* hblank to current, (low to high), check stride interrupt */
  1018.         if (X5028->hbl_flop == ks_false)      
  1019.           if (X5028->reg41_LCDS & 0x08)
  1020.             X5028->gb->reg0F_IF |= IRQ_2;
  1021.           else {}
  1022.         else {}
  1023.         X5028->hbl_flop = ks_false;
  1024.       }
  1025.       /* get render pos */
  1026.       interv = KS_INT16_CAST (clkline/ X5028->gb->mach_tools->oam_clk_pick_per);
  1027.  
  1028.       /* check render oam *.*/
  1029.       if ( X5028->vscan != interv
  1030.            &&   X5028->vscanR < 10
  1031.              && X5028->vscan40   < 40) {
  1032.         _nums = interv - X5028->vscan;
  1033.         X5028->vscan += _nums;
  1034.         /* render sprite */
  1035.         do
  1036.         {
  1037.                  X5028->sprite_render (X5028, scanline); }
  1038.            while (--_nums);
  1039.       }
  1040.       /*  check sprite interrupt  */
  1041.       if ((X5028->reg41_LCDS & 0x20) && !X5028->oam_flop) {      
  1042.         X5028->oam_flop = ks_true;
  1043.         X5028->gb->reg0F_IF |= IRQ_2;
  1044.       }
  1045.     }
  1046.   } else {
  1047.     /* LCD MODE1 - vblank */
  1048.     X5028->reg41_LCDS |= LCDCS_MODE_FLAG_VLANK;
  1049.     /* check edge */
  1050.     if (X5028->lcdm_cac != LCDCS_MODE_FLAG_VLANK) {
  1051.       /* post device render */
  1052.       X5028->device_blit (X5028, X5028->obj);
  1053.       /* check hblank lack */
  1054.     }
  1055.     /*  check vblank interrupt  */
  1056.     if ((X5028->reg41_LCDS & 0x10) && !X5028->vbl_flop) {      
  1057.       X5028->vbl_flop = ks_true;
  1058.       X5028->gb->reg0F_IF |= IRQ_1;
  1059.     }
  1060.   }
  1061.   X5028->line_cac = scanline;
  1062.   X5028->lcdm_cac = X5028->reg41_LCDS & LCDCS_MODE_FLAG_ALL_MASK;
  1063.   return 0;
  1064. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement