Coverage Report - uk.co.javagear.Vdp
 
Classes in this File Line Coverage Branch Coverage Complexity
Vdp
0% 
0% 
3.964
 
 1  
 /*
 2  
  * Vdp.java
 3  
  *
 4  
  * This file is part of JavaGear.
 5  
  *
 6  
  * JavaGear is free software; you can redistribute it and/or modify
 7  
  * it under the terms of the GNU General Public License as published by
 8  
  * the Free Software Foundation; either version 2 of the License, or
 9  
  * (at your option) any later version.
 10  
  *
 11  
  * JavaGear is distributed in the hope that it will be useful,
 12  
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 13  
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 14  
  * GNU General Public License for more details.
 15  
  *
 16  
  * You should have received a copy of the GNU General Public License
 17  
  * along with JavaGear; if not, write to the Free Software
 18  
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 19  
  */
 20  
 
 21  
 package uk.co.javagear;
 22  
 
 23  
 import java.util.Arrays;
 24  
 import org.apache.log4j.Logger;
 25  
 
 26  
 /**
 27  
  * SMS and GG VDP Emulation.
 28  
  *
 29  
  * @author Copyright (C) 2002-2003 Chris White
 30  
  * @version 18th January 2003
 31  
  * @see "JavaGear Final Project Report"
 32  
  */
 33  
 public final class Vdp {
 34  
     
 35  
     /**
 36  
      * Connection to Z80 interrupt line.
 37  
      */
 38  
     private InterruptLine irq;
 39  
     
 40  
     /**
 41  
      * Pointer to general parameters.
 42  
      */
 43  
     private Setup setup;
 44  
     
 45  
     /**
 46  
      * Video RAM.
 47  
      */
 48  
     private byte[] vRam;
 49  
     
 50  
     /**
 51  
      * Colour RAM.
 52  
      */
 53  
     private int[] cRam;
 54  
     
 55  
     /**
 56  
      * VDP Registers.
 57  
      */
 58  
     private int[] vdpreg;
 59  
     
 60  
     /**
 61  
      * Status Register.
 62  
      */
 63  
     private int status;
 64  
     
 65  
     /**
 66  
      * First or second byte of command word.
 67  
      */
 68  
     private boolean firstByte;
 69  
     
 70  
     /**
 71  
      * Command word first byte latch.
 72  
      */
 73  
     private int commandByte;
 74  
     
 75  
     /**
 76  
      * Location in VRAM.
 77  
      */
 78  
     private int location;
 79  
     
 80  
     /**
 81  
      * Store type of operation taking place.
 82  
      */
 83  
     private int operation;
 84  
     
 85  
     /**
 86  
      * Buffer VRAM reads.
 87  
      */
 88  
     private int readBuffer;
 89  
     
 90  
     /**
 91  
      * Current line number.
 92  
      */
 93  
     private int line;
 94  
     
 95  
     /**
 96  
      * Vertical line interrupt counter.
 97  
      */
 98  
     private int counter;
 99  
     
 100  
     /**
 101  
      * Line interrupt pending.
 102  
      */
 103  
     private boolean lineint;
 104  
     
 105  
     /**
 106  
      * Frame interrupt pending.
 107  
      */
 108  
     private boolean frameint;
 109  
     
 110  
     /**
 111  
      * Background priorites.
 112  
      */
 113  
     private boolean[] bgPriority;
 114  
     
 115  
     /**
 116  
      * Sprite collisions.
 117  
      */
 118  
     private boolean[] spritecol;
 119  
     
 120  
     /**
 121  
      * Pointer to current display.
 122  
      */
 123  
     private int[] display;
 124  
     
 125  
     /**
 126  
      * Pointer to previous frame.
 127  
      */
 128  
     private int[] oldDisplay;
 129  
     
 130  
     /**
 131  
      * Frame 1.
 132  
      */
 133  
     private int[] display1;
 134  
     
 135  
     /**
 136  
      * Frame 2.
 137  
      */
 138  
     private int[] display2; 
 139  
     
 140  
     /**
 141  
      * Generate background layer.
 142  
      */
 143  0
     private boolean displayBackgroundLayer = true;
 144  
     
 145  
     /**
 146  
      * Generate sprite layer.
 147  
      */
 148  0
     private boolean displaySpriteLayer = true;
 149  
     
 150  
     /**
 151  
      * NTSC/PAL.
 152  
      */
 153  
     private boolean ntsc;
 154  
     
 155  
     
 156  
     /**
 157  
      * Vdp Constructor.
 158  
      *
 159  
      * @param set pointer to general parameters
 160  
      * @param i pointer to Z80 interrupt line
 161  
      */
 162  0
     public Vdp(Setup set, InterruptLine i) {
 163  0
         this.irq = i;
 164  0
         this.setup = set;
 165  
         
 166  0
         display1 = new int[setup.SMS_WIDTH * (setup.SMS_HEIGHT + 1)];
 167  0
         display2 = new int[setup.SMS_WIDTH * (setup.SMS_HEIGHT + 1)];
 168  
         
 169  
         // 16K of Video RAM
 170  0
         vRam = new byte[0x4000];
 171  
         
 172  
         // 64 Bytes of Colour RAM (32 on SMS)
 173  0
         cRam = new int[0x40];
 174  
         
 175  
         // 15 Registers, (0-10) used by SMS, but some programs write > 10
 176  0
         vdpreg = new int[16];
 177  
         
 178  0
         bgPriority = new boolean[setup.SMS_WIDTH + 7];
 179  0
         spritecol   = new boolean[setup.SMS_WIDTH];
 180  
         
 181  0
         reset();
 182  0
     }
 183  
     
 184  
     /**
 185  
      * Reset VDP.
 186  
      */
 187  
     public void reset() {
 188  0
         display   = display1;
 189  0
         oldDisplay = display2;
 190  0
         firstByte = true;
 191  0
         lineint = false;
 192  0
         frameint = false;
 193  0
         location = 0;
 194  0
         counter = 0;
 195  0
         status = 0;
 196  0
         operation = 0;
 197  0
         vdpreg[0] = 0;
 198  0
         vdpreg[1] = 0;
 199  0
         vdpreg[2] = 0x0E; // B1-B3 high on startup
 200  0
         vdpreg[3] = 0;
 201  0
         vdpreg[4] = 0;
 202  0
         vdpreg[5] = 0x7E; // B1-B6 high on startup
 203  0
         vdpreg[6] = 0;
 204  0
         vdpreg[7] = 0;
 205  0
         vdpreg[8] = 0;
 206  0
         vdpreg[9] = 0;
 207  0
         vdpreg[10] = 0;
 208  
         
 209  
         // Clear Memory
 210  0
         Arrays.fill(display1, 0);
 211  0
         Arrays.fill(display2, 0);
 212  0
         Arrays.fill(vRam, (byte) 0);
 213  0
         Arrays.fill(cRam, 0);
 214  0
         Arrays.fill(bgPriority, false);
 215  0
         Arrays.fill(spritecol, false);
 216  
         
 217  0
         irq.setLine(false);
 218  0
     }
 219  
     
 220  
     
 221  
     /**
 222  
      * Set NTSC / PAL VDP Mode.
 223  
      *
 224  
      * @param b <code>true</code> if NTSC, <code>false</code> if PAL.
 225  
      */
 226  
     public void setNTSC(boolean b) {
 227  0
         ntsc = b;
 228  0
     }
 229  
     
 230  
     /**
 231  
      * Returns the value of property <code>display</code>. The pointer to the current display.
 232  
      *
 233  
      * @return the value of property <code>display</code>.
 234  
      */
 235  
     public int[] getDisplay() {
 236  0
         return display;
 237  
     }
 238  
     
 239  
     /**
 240  
      * Sets the value of property <code>display</code>. The pointer to the current display.
 241  
      *
 242  
      * @param display the new value of property <code>display</code>.
 243  
      */
 244  
     public void setDisplay(int[] display) {
 245  0
         this.display = display;
 246  0
     }
 247  
     
 248  
     /**
 249  
      * Toggle background layer generation on/off.
 250  
      */
 251  
     public void setBackgroundLayer() {
 252  0
         displayBackgroundLayer = !displayBackgroundLayer;
 253  0
     }
 254  
     
 255  
     /**
 256  
      * Toggle Sprite Layer Generation On/Off.
 257  
      */
 258  
     public void setSpriteLayer() {
 259  0
         displaySpriteLayer = !displaySpriteLayer;
 260  0
     }
 261  
     
 262  
     
 263  
     /**
 264  
      * Get a VDP register.
 265  
      *
 266  
      * @param index index of register.
 267  
      *
 268  
      * @return register data.
 269  
      */
 270  
     public int getReg(int index) {
 271  0
         return vdpreg[index];
 272  
     }
 273  
     
 274  
     
 275  
     /**
 276  
      * Get line number under generation.
 277  
      *
 278  
      * @return line number.
 279  
      */
 280  
     
 281  
     public int getLineNo() {
 282  0
         return line;
 283  
     }
 284  
     
 285  
     
 286  
     /**
 287  
      * Get line interrupt counter.
 288  
      *
 289  
      * @return line interrupt counter.
 290  
      */
 291  
     
 292  
     public int getCounter() {
 293  0
         return counter;
 294  
     }
 295  
     
 296  
     
 297  
     /**
 298  
      * Get line interrupt pending flag.
 299  
      *
 300  
      * @return <code>true</code> if pending.
 301  
      */
 302  
     public boolean getLineIntPending() {
 303  0
         return lineint;
 304  
     }
 305  
     
 306  
     
 307  
     /**
 308  
      * Get frame interrupt pending flag.
 309  
      *
 310  
      * @return <code>true</code> if pending.
 311  
      */
 312  
     public boolean getFrameIntPending() {
 313  0
         return frameint;
 314  
     }
 315  
     
 316  
     
 317  
     /**
 318  
      * Get interruptLine status.
 319  
      *
 320  
      * @return <code>true</code> if pending.
 321  
      */
 322  
     public boolean getIrqStatus() {
 323  0
         return irq.getLine();
 324  
     }
 325  
     
 326  
     
 327  
     /**
 328  
      * Get sprite overflow status.
 329  
      *
 330  
      * @return <code>true</code> if overflow has occurred.
 331  
      */
 332  
     public boolean getSpriteOverflow() {
 333  0
         return (status & 0x40) == 0x40;
 334  
     }
 335  
     
 336  
     /**
 337  
      * Read vertical port.
 338  
      *
 339  
      * @return VCounter value
 340  
      */
 341  
     public int getVCount() {
 342  0
         if (ntsc) {
 343  0
             if (line > 0xDA) { // Values from 00 to DA, then jump to D5-FF
 344  0
                 return line - 6;
 345  
             }
 346  0
         } else if (!ntsc) {
 347  0
             if (line > 0xF2) {
 348  0
                 return line - 0x39;
 349  
             }
 350  
         }
 351  0
         return line;
 352  
     }
 353  
     
 354  
     
 355  
     /**
 356  
      * Write to VDP control port (<code>0xBF</code>).
 357  
      *
 358  
      * @param value value to write.
 359  
      */
 360  
     
 361  
     public void controlWrite(int value) {
 362  
         // Store First Byte of Command Word
 363  0
         if (firstByte) {
 364  0
             firstByte = false;
 365  0
             commandByte = value;
 366  
         } else {
 367  0
             firstByte = true;
 368  
             
 369  
             // Set VDP Register
 370  0
             if ((value >> 4) == 0x08) {
 371  0
                 vdpreg[(value & 0x0F)] = commandByte; // Set reg to previous byte
 372  
                 
 373  
                 // Interrupt Control IE1/IE0,
 374  
                 // Verified using test program by Charles MacDonald
 375  0
                 if (lineint) {
 376  0
                     if (((value & 0x0F) == 0) && ((commandByte & 0x10) == 0x0)) {
 377  0
                         irq.setLine(false);
 378  0
                     } else if (((value & 0x0F) == 0) && ((commandByte & 0x10) == 0x10)) {
 379  0
                         irq.setLine(true);
 380  
                     }
 381  
                 }
 382  
                 
 383  0
                 if (frameint) {
 384  0
                     if (((value & 0x0F) == 1) && ((commandByte & 0x20) == 0x0)) {
 385  0
                         irq.setLine(false);
 386  0
                     } else if (((value & 0x0F) == 1) && ((commandByte & 0x20) == 0x20)) {
 387  0
                         irq.setLine(true);
 388  
                     }
 389  
                 }
 390  
             } else {
 391  
                 // Operation from B6 + B7
 392  0
                 operation = (value >> 6);
 393  
                 // Set location in VRAM
 394  0
                 location = commandByte + ((value & 0x3F) << 8);
 395  
                 
 396  0
                 if (operation == 0) {
 397  0
                     readBuffer = unsigned(vRam[location]);
 398  0
                     if (++location > 0x3FFF) {
 399  0
                         location = 0;
 400  
                     }
 401  
                 }
 402  
             }
 403  
         }
 404  0
     }
 405  
     
 406  
     
 407  
     /**
 408  
      * Read VDP control port (<code>0xBF</code>).
 409  
      *
 410  
      * @return copy of status register.
 411  
      */
 412  
     public int controlRead() {
 413  
         // Reset flag
 414  0
         firstByte = true;
 415  
         
 416  
         // Create copy, as we'll need to clear bits of status reg
 417  0
         int statuscopy = status;
 418  
         
 419  
         // Clear b7, b6, b5 when status register read
 420  0
         status &= ~0x80 & ~0x40 & ~0x20;
 421  
         
 422  
         // Clear pending interrupts
 423  0
         lineint = false;
 424  0
         frameint = false;
 425  
         
 426  
         // Clear IRQ Line
 427  0
         irq.setLine(false);
 428  
         
 429  0
         return statuscopy;
 430  
     }
 431  
     
 432  
     
 433  
     /**
 434  
      * Write to VDP data port (<code>0xBE</code>).
 435  
      *
 436  
      * @param value value to write
 437  
      */
 438  
     public void dataWrite(int value) {
 439  
         // Reset flag
 440  0
         firstByte = true;
 441  
         
 442  0
         switch(operation) {
 443  
             // VRAM Write
 444  
             case 0x00:
 445  
             case 0x01:
 446  
             case 0x02:
 447  0
                 vRam[location] = (byte) value;
 448  0
                 break;
 449  
                 /* CRAM Write
 450  
                  * Instead of writing real colour to CRAM, write converted Java palette colours for
 451  
                  * speed. Slightly inaccurate, as CRAM doesn't contain real values, but it is never
 452  
                  * read by software. */
 453  
             case 0x03:
 454  0
                 switch (setup.getSystem()) {
 455  
                     case SMS:
 456  0
                         cRam[location & 0x1F] = SMS_JAVA[value & 0x3F]; // SMS
 457  0
                         break;
 458  
                     case GG:
 459  0
                         if ((location & 1) == 0) { // first byte
 460  0
                             cRam[(location & 0x3F) >> 1] = GG_JAVA1[value]; // GG
 461  
                         } else {
 462  0
                             cRam[((location & 0x3F) - 1) >> 1] |= GG_JAVA2[value & 0x0F];
 463  
                         }
 464  0
                         break;
 465  
                     default:
 466  0
                         Logger.getLogger(this.getClass()).fatal("Invalid system: " 
 467  
                                 + setup.getSystem());
 468  
                 }
 469  0
                 break;
 470  
             default:
 471  
                 break;
 472  
         }
 473  
         
 474  0
         if (++location > 0x3FFF) {
 475  0
             location = 0;
 476  
         }
 477  0
     }
 478  
     
 479  
     
 480  
     /**
 481  
      * Read VDP data port (<code>0xBE</code>).
 482  
      *
 483  
      * @return buffered read from VRAM
 484  
      */
 485  
     public int dataRead() {
 486  0
         int value = 0; // Stores value to be returned
 487  0
         firstByte = true; // Reset flag
 488  
         
 489  0
         switch(operation) {
 490  
             // VRAM Read
 491  
             case 0x00:
 492  
             case 0x01:
 493  
             case 0x02:
 494  0
                 value = readBuffer;
 495  0
                 readBuffer = unsigned(vRam[location]);
 496  0
                 break;
 497  
                 // CRAM Read
 498  
                 // Shouldn't occur but GameGear 'NBA Action' tries this.
 499  
             case 0x03:
 500  0
                 break;
 501  
             default:
 502  
                 break;
 503  
         }
 504  
         
 505  0
         if (++location > 0x3FFF) {
 506  0
             location = 0;
 507  
         }
 508  
         
 509  0
         return value;
 510  
     }
 511  
     
 512  
     
 513  
     /**
 514  
      * Generate VDP interrupts.
 515  
      * Assert the IRQ line as necessary for a particular scanline.
 516  
      *
 517  
      * @param lineno line to check for interrupts.
 518  
      */
 519  
     public void interrupts(int lineno) {
 520  0
         line = lineno;
 521  
         
 522  0
         if (lineno <= 192) {
 523  
             // Frame Interrupt Pending
 524  0
             if (lineno == 192) {
 525  0
                 status |= 0x80;
 526  0
                 frameint = true;
 527  
             }
 528  
             
 529  
             // Counter Expired = Line Interrupt Pending
 530  0
             if (counter == 0) {
 531  
                 // Reload Counter
 532  0
                 counter = vdpreg[10];
 533  0
                 lineint = true;
 534  
             } else { // Otherwise Decrement Counter
 535  0
                 counter--;
 536  
             }
 537  
             
 538  
             // Line Interrupts Enabled and Pending. Assert IRQ Line.
 539  0
             if (lineint && ((vdpreg[0] & 0x10) == 0x10)) {
 540  0
                 irq.setLine(true);
 541  
             }
 542  
         } else { // lineno >= 193
 543  
             // Reload counter on every line outside active display + 1
 544  0
             counter = vdpreg[10];
 545  
             
 546  
             // Frame Interrupts Enabled and Pending. Assert IRQ Line.
 547  0
             if (frameint && ((vdpreg[1] & 0x20) == 0x20) && (lineno < 224)) {
 548  0
                 irq.setLine(true);
 549  
             }
 550  
         }
 551  0
     }
 552  
     
 553  
     
 554  
     /**
 555  
      * Render line of SMS/GG display.
 556  
      *
 557  
      * @param lineno line number to render.
 558  
      */
 559  
     public void drawLine(int lineno) {
 560  0
         if (lineno > 191) {
 561  0
             return;
 562  
         }
 563  
         
 564  
         // Clear Collision Array at start of line
 565  0
         for (int i = spritecol.length; i-- != 0;) {
 566  0
             spritecol[i] = false;
 567  
         }
 568  
         
 569  0
         if (lineno == 0) {
 570  
             // Swap buffers
 571  0
             if (display == display1) {
 572  0
                 display = display2;
 573  0
                 oldDisplay = display1;
 574  
             } else {
 575  0
                 display = display1;
 576  0
                 oldDisplay = display2;
 577  
             }
 578  
         }
 579  
         
 580  
         // Blank Display
 581  0
         if ((vdpreg[1] & 0x40) != 0) {
 582  
             // Draw Background Layer
 583  0
             if (displayBackgroundLayer) {
 584  0
                 drawBg(lineno);
 585  
             } else {
 586  0
                 drawBGColour(lineno);
 587  
             }
 588  
             
 589  
             // Draw Sprite Layer
 590  0
             if (displaySpriteLayer) {
 591  0
                 drawSprite(lineno);
 592  
             }
 593  
         } else { // Blank Display
 594  0
             drawBGColour(lineno);
 595  
         }
 596  
         
 597  
         // Blank Leftmost Column (SMS Only)
 598  0
         if (Setup.System.SMS == setup.getSystem() 
 599  
                 && (vdpreg[0] & 0x20) == 0x20) {
 600  0
             blankColumn(lineno);
 601  
         }
 602  0
     }
 603  
     
 604  
     
 605  
     /**
 606  
      * Render line of sprite layer.
 607  
      *
 608  
      * @param lineno line number to render.
 609  
      */
 610  
     private void drawSprite(int lineno) {
 611  
         // Sprite Attribute Table Address
 612  0
         int sat = (vdpreg[5] & ~0x01 & ~0x80) << 7;
 613  
         
 614  
         // Number of Sprites drawn on this line (max 8)
 615  0
         int count = 0;
 616  
         
 617  
         // Height of Sprites
 618  0
         int height = 8;
 619  
         
 620  
         // Zoom Sprites
 621  0
         boolean zoomed = false;
 622  
         
 623  
         // Enable 8x16 Sprites
 624  0
         if ((vdpreg[1] & 0x02) == 0x02) {
 625  0
             height = 16;
 626  
         }
 627  
         
 628  
         // Enable Zoomed Sprites
 629  0
         if ((vdpreg[1] & 0x01) == 0x01) {
 630  0
             height <<= 1;
 631  0
             zoomed = true;
 632  
         }
 633  
         
 634  
         // Search Sprite Attribute Table (64 Bytes)
 635  0
         for (int spriteno = 0; spriteno < 0x40; spriteno++) {
 636  
             // Sprite Overflow (more than 8 sprites on line)
 637  0
             if (count >= 8) {
 638  0
                 status |= 0x40;
 639  0
                 return;
 640  
             }
 641  
             // Sprite Y Position
 642  0
             int y = vRam[sat + spriteno] & 0xFF;
 643  
             // Address of Sprite in Sprite Attribute Table
 644  0
             int address = sat + (spriteno << 1);
 645  
             // Sprite X Position
 646  0
             int x = vRam[address + 0x80] & 0xFF;
 647  
             // Sprite Pattern Index
 648  0
             int i = vRam[address + 0x81] & 0xFF;
 649  
             
 650  
             // VDP stops drawing if y == 208
 651  0
             if (y == 208) {
 652  0
                 return;
 653  
             }
 654  
             
 655  
             // y is actually at +1 of value
 656  0
             y++;
 657  
             
 658  
             // Use Pattern Index from 100 - 1FFh
 659  0
             if ((vdpreg[6] & 0x04) == 0x04) {
 660  0
                 i |= 0x100;
 661  
             }
 662  
             
 663  
             // When using 8x16 sprites LSB has no effect
 664  0
             if ((vdpreg[1] & 0x02) == 0x02) {
 665  0
                 i &= ~0x01;
 666  
             }
 667  
             
 668  
             // Shift pixels left by 8
 669  0
             if ((vdpreg[0] & 0x08) == 0x08) {
 670  0
                 x -= 8;
 671  
             }
 672  
             
 673  
             // If off screen, draw from negative 16 onwards
 674  0
             if (y > 240) {
 675  0
                 y -= 256;
 676  
             }
 677  
             
 678  
             // If Sprite Falls on this line
 679  0
             if ((lineno >= y) && ((lineno - y) < height)) {
 680  0
                 int rowPrecal = lineno << 8;
 681  
                 
 682  
                 // Plot Normal Sprites (Width = 8)
 683  0
                 if (!zoomed) {
 684  
                     // Address of 8 Pixels in VRAM
 685  0
                     int adr = (i << 5) + ((lineno - y) << 2);
 686  
                     
 687  
                     // Cycle through 8 Pixels
 688  0
                     for (int bit = 0x80; bit != 0; bit >>= 1) {
 689  
                         // Make sure we're in the valid viewing area
 690  0
                         if ((x >= 0) && (y >= 0) && (x <= 255)) {
 691  
                             // Plot Single Pixel
 692  0
                             plotSpritePixel(x, lineno, x + rowPrecal, adr, bit);
 693  
                         }
 694  
                         // Increement X Position
 695  0
                         x++;
 696  
                     }
 697  0
                 } else { // Plot Zoomed Sprites (Width = 16)
 698  0
                     int adr = (i << 5) + (((lineno - y) >> 1) << 2);
 699  
                     
 700  0
                     int pixel = 0;
 701  
                     
 702  0
                     for (int bit = 0x80; bit != 0; bit >>= 1) {
 703  0
                         if ((x + pixel + 1 >= 0) && (y >= 0) && (x <= 255)) {
 704  
                             // Plot Two Pixels
 705  0
                             plotSpritePixel(x + pixel, lineno, x + pixel + rowPrecal, adr, bit);
 706  0
                             plotSpritePixel(x + pixel + 1, lineno, x + pixel + 1 + rowPrecal
 707  
                                     , adr, bit);
 708  
                         }
 709  0
                         x++;
 710  0
                         pixel++;
 711  
                     }
 712  
                 }
 713  
                 // Increment number of sprites drawn
 714  0
                 count++;
 715  
             }
 716  
         } // end for loop
 717  0
     }
 718  
     
 719  
     
 720  
     /**
 721  
      * Plot single sprite pixel.
 722  
      *
 723  
      * @param x <i>x</i> coordinate of pixel (for location array).
 724  
      * @param y <i>y</i> coordinate of pixel.
 725  
      * @param location coordinates to plot pixel at <code>x+(y*256)</code>.
 726  
      * @param address VRAM address of pixel plane.
 727  
      * @param bit bit of plane to plot.
 728  
      */
 729  
     private void plotSpritePixel(int x, int y, int location, int address, int bit) {
 730  
         // Colour of pixel
 731  0
         int colour = 0;
 732  
         
 733  
         // Set Colour of Pixel (0-15)
 734  0
         if ((vRam[address + 0] & bit) != 0) {
 735  0
             colour |= 0x01;
 736  
         }
 737  0
         if ((vRam[address + 1] & bit) != 0) {
 738  0
             colour |= 0x02;
 739  
         }
 740  0
         if ((vRam[address + 2] & bit) != 0) {
 741  0
             colour |= 0x04;
 742  
         }
 743  0
         if ((vRam[address + 3] & bit) != 0) {
 744  0
             colour |= 0x08;
 745  
         }
 746  
         
 747  
         // Plot Pixel, check background priority for location
 748  0
         if (!(bgPriority[x]) && (colour != 0)) {
 749  
             // Check for existing sprite collision
 750  0
             if (!spritecol[x]) {
 751  0
                 spritecol[x] = true;
 752  0
                 display[location] = cRam[colour + 16];
 753  
             } else {
 754  0
                 status |= 0x20; // set bit 5 of status flag
 755  
             }
 756  
         }
 757  0
     }
 758  
     
 759  
     
 760  
     /**
 761  
      * Render line of background layer.
 762  
      *
 763  
      * @param lineno line number to render.
 764  
      */
 765  
     private void drawBg(int lineno) {
 766  
         // Backup the _real_ line number to be plotted
 767  0
         int y = lineno;
 768  
         
 769  
         // Vertical Scroll Fine Tune
 770  0
         if (vdpreg[9] != 0) {
 771  0
             lineno += vdpreg[9] & 0x07;
 772  
         }
 773  
         
 774  
         // Address of Background Table in VRAM
 775  0
         int bgt = (vdpreg[2] & 0x0f & ~0x01) << 10;
 776  
         
 777  
         // Tile Pattern Number
 778  0
         int pattern = 0;
 779  
         
 780  
         // Palette To Use
 781  0
         int pal = 0;
 782  
         
 783  
         // Horizontal Scroll Value
 784  0
         int hscroll = 0;
 785  
         
 786  
         // Start Column (for Horizontal Scroll)
 787  0
         int startColumn = 0;
 788  
         
 789  
         // Start Row (For Vertical Scroll)
 790  0
         int startRow = lineno;
 791  
         
 792  
         // Tile Row Count
 793  0
         int tilex = 0;
 794  
         
 795  
         // Row of Tile to Plot
 796  0
         int tiley = (lineno & 7);
 797  
         
 798  
         // Adjust Horizontal Scroll
 799  
         
 800  
         // Top Two Rows Not Affected by Horizontal Scrolling (SMS Only)
 801  0
         if (((vdpreg[0] & 0x40) == 0x40) && (y < 16) 
 802  
                 && Setup.System.SMS == setup.getSystem()) {
 803  0
             hscroll = 0;
 804  0
         } else if (vdpreg[8] != 0) {
 805  
             // Horizontal Scroll Fine Tune Value
 806  0
             hscroll = vdpreg[8] & 0x07;
 807  
             // Horizontal Scroll Starting Column
 808  0
             startColumn = 32 - (vdpreg[8] >> 3);
 809  
         }
 810  
         
 811  
         // Omit First 5 Columns on Game Gear
 812  0
         if (setup.getSystem() == Setup.System.GG) {
 813  0
             startColumn = (startColumn + 5) & 0x1F;
 814  
         }
 815  
         
 816  
         // Adjust Vertical Scroll
 817  0
         if (vdpreg[9] != 0) {
 818  
             // Vertical Scroll Starting Row
 819  0
             startRow += vdpreg[9] & 0xF8;
 820  0
             if (startRow > 223) {
 821  0
                 startRow -= 224;
 822  
             }
 823  
         }
 824  
         
 825  
         // Cycle through background table
 826  0
         for (int x = setup.getHStart(); x < setup.getHEnd(); x += 8) {
 827  
             // wraps at 32
 828  0
             if (startColumn == 32) {
 829  0
                 startColumn = 0;
 830  
             }
 831  
             
 832  
             // Rightmost 8 columns Not Affected by Vertical Scrolling
 833  0
             if (((vdpreg[0] & 0x80) == 0x80) && (x > 184)) {
 834  0
                 startRow = y;
 835  0
                 tiley = (y & 7);
 836  
             }
 837  
             
 838  
             // Get the two bytes from VRAM containing the tile's properties
 839  0
             int tileProps = bgt + (startColumn << 1) + ((startRow - tiley) << 3);
 840  0
             int firstbyte =  vRam[tileProps] & 0xFF;
 841  0
             int secondbyte = vRam[tileProps + 1] & 0xFF;
 842  
             
 843  
             // Priority of tile
 844  0
             int priority = secondbyte & 0x10;
 845  
             
 846  
             // Select Palette
 847  0
             pal = ((secondbyte & 0x08) == 0x08) ? 16 : 0;
 848  
             
 849  
             // Pattern Number
 850  0
             pattern = (firstbyte + ((secondbyte & 0x01) << 8)) << 5;
 851  
             
 852  
             // Address in VRAM of tile
 853  
             int address;
 854  
             
 855  0
             address = ((secondbyte & 0x04) == 0) ? (tiley << 2) + pattern
 856  
                     : ((7 - tiley) << 2) + pattern;
 857  
             
 858  
             // Rowcount
 859  0
             tilex = 0;
 860  
             
 861  
             // X Position on Screen
 862  
             int xpos;
 863  
             
 864  
             // Precalculate Y Position
 865  0
             int rowPrecal = y << 8;
 866  
             
 867  0
             int address0 = vRam[address + 0];
 868  0
             int address1 = vRam[address + 1];
 869  0
             int address2 = vRam[address + 2];
 870  0
             int address3 = vRam[address + 3];
 871  
             
 872  
             // Plots row of 8 pixels
 873  0
             for (int bit = 0x80; bit != 0; bit >>= 1) {
 874  0
                 xpos = ((secondbyte & 0x02) == 0) ? (tilex + hscroll + x)
 875  
                         // Horizontal Tile Flip
 876  
                         : (7 - tilex + hscroll + x);
 877  
                 
 878  0
                 int colour = 0;
 879  
                 
 880  
                 // Set Colour of Pixel (0-15)
 881  0
                 if ((address0 & bit) != 0) {
 882  0
                     colour |= 0x01;
 883  
                 }
 884  0
                 if ((address1 & bit) != 0) {
 885  0
                     colour |= 0x02;
 886  
                 }
 887  0
                 if ((address2 & bit) != 0) {
 888  0
                     colour |= 0x04;
 889  
                 }
 890  0
                 if ((address3 & bit) != 0) {
 891  0
                     colour |= 0x08;
 892  
                 }
 893  
                 
 894  
                 // Set Priority Array (Sprites over background tile)
 895  0
                 bgPriority[xpos] = (priority == 0x10) && (colour != 0);
 896  
                 
 897  0
                 display[xpos + rowPrecal] = cRam[colour + pal];
 898  
                 
 899  0
                 tilex++;
 900  
             }
 901  0
             startColumn++;
 902  
         } // end loop
 903  0
     }
 904  
     
 905  
     
 906  
     /**
 907  
      * Draw a line of the current background colour.
 908  
      *
 909  
      * @param lineno line number to render.
 910  
      */
 911  
     private void drawBGColour(int lineno) {
 912  0
         int colour = cRam[16 + (vdpreg[7] & 0x0F)];
 913  0
         int rowPrecal = lineno << 8;
 914  0
         Arrays.fill(display, rowPrecal, rowPrecal + setup.SMS_WIDTH, colour);
 915  0
     }
 916  
     
 917  
     
 918  
     /**
 919  
      * Blank leftmost column of a particular line.
 920  
      *
 921  
      * @param lineno line number to render.
 922  
      * @deprecated now, faster <code>fillRect</code> method used.
 923  
      */
 924  
     private void blankColumn(int lineno) {
 925  0
         int colour = cRam[16 + (vdpreg[7] & 0x0F)];
 926  0
         int rowPrecal = lineno << 8;
 927  0
         Arrays.fill(display, rowPrecal, rowPrecal + 8, colour);
 928  0
     }
 929  
     
 930  
     /**
 931  
      * Unsign an integer.
 932  
      *
 933  
      * @param b value to unsign.
 934  
      * @return unsigned value.
 935  
      */
 936  
     private int unsigned(byte b) {
 937  0
         return b & 0xFF;
 938  
     }
 939  
     
 940  
     /**
 941  
      * Compare this frame with the previous frame, and flag what lines have been changed.
 942  
      *
 943  
      * @param pixelUpdate array to flag changes in.
 944  
      */
 945  
     public void flagChanges(boolean[] pixelUpdate) {
 946  0
         for (int y = setup.getVEnd(); y-- != 0; ) {
 947  0
             int rowPrecal = y << 8;
 948  0
             boolean updateRow = false;
 949  0
             for (int x = setup.getHEnd(); x-- != 0; ) {
 950  0
                 if (display[x + rowPrecal] != oldDisplay[x + rowPrecal]) {
 951  0
                     updateRow = true;
 952  0
                     break;
 953  
                 }
 954  
             }
 955  0
             pixelUpdate[y] = updateRow;
 956  0
         }
 957  0
     }
 958  
     
 959  
     /**
 960  
      * SMS Colours converted into Java RGB for speed purposes.
 961  
      */
 962  0
     private static final int[] SMS_JAVA = {
 963  
         -16777216, -11206656, -5636096, -65536, -16755456, -11184896, -5614336, -43776,
 964  
         -16733696, -11163136, -5592576, -22016, -16711936, -11141376, -5570816,   -256,
 965  
         -16777131, -11206571, -5636011, -65451, -16755371, -11184811, -5614251, -43691,
 966  
         -16733611, -11163051, -5592491, -21931, -16711851, -11141291, -5570731,   -171,
 967  
         -16777046, -11206486, -5635926, -65366, -16755286, -11184726, -5614166, -43606,
 968  
         -16733526, -11162966, -5592406, -21846, -16711766, -11141206, -5570646,    -86,
 969  
         -16776961, -11206401, -5635841, -65281, -16755201, -11184641, -5614081, -43521,
 970  
         -16733441, -11162881, -5592321, -21761, -16711681, -11141121, -5570561,     -1};
 971  
     
 972  
     /**
 973  
      * GG Colours.
 974  
      */
 975  0
     private static final int[] GG_JAVA1 = {
 976  
         -16777216, -15728640, -14680064, -13631488, -12582912, -11534336, -10485760,
 977  
          -9437184,  -8388608,  -7340032,  -6291456,  -5242880,  -4194304,  -3145728,
 978  
          -2097152,  -1048576, -16773120, -15724544, -14675968, -13627392, -12578816,
 979  
         -11530240, -10481664,  -9433088,  -8384512,  -7335936,  -6287360,  -5238784,
 980  
          -4190208,  -3141632,  -2093056,  -1044480, -16769024, -15720448, -14671872,
 981  
         -13623296, -12574720, -11526144, -10477568,  -9428992,  -8380416,  -7331840,
 982  
          -6283264,  -5234688,  -4186112,  -3137536,  -2088960,  -1040384, -16764928,
 983  
         -15716352, -14667776, -13619200, -12570624, -11522048, -10473472,  -9424896,
 984  
          -8376320,  -7327744,  -6279168,  -5230592,  -4182016,  -3133440,  -2084864,
 985  
          -1036288, -16760832, -15712256, -14663680, -13615104, -12566528, -11517952,
 986  
         -10469376,  -9420800,  -8372224,  -7323648,  -6275072,  -5226496,  -4177920,
 987  
          -3129344,  -2080768,  -1032192, -16756736, -15708160, -14659584, -13611008,
 988  
         -12562432, -11513856, -10465280,  -9416704,  -8368128,  -7319552,  -6270976,
 989  
          -5222400,  -4173824,  -3125248,  -2076672,  -1028096, -16752640, -15704064,
 990  
         -14655488, -13606912, -12558336, -11509760, -10461184,  -9412608,  -8364032,
 991  
          -7315456,  -6266880,  -5218304,  -4169728,  -3121152,  -2072576,  -1024000,
 992  
         -16748544, -15699968, -14651392, -13602816, -12554240, -11505664, -10457088,
 993  
          -9408512,  -8359936,  -7311360,  -6262784,  -5214208,  -4165632,  -3117056,
 994  
          -2068480,  -1019904, -16744448, -15695872, -14647296, -13598720, -12550144,
 995  
         -11501568, -10452992,  -9404416,  -8355840,  -7307264,  -6258688,  -5210112,
 996  
          -4161536,  -3112960,  -2064384,  -1015808, -16740352, -15691776, -14643200,
 997  
         -13594624, -12546048, -11497472, -10448896,  -9400320,  -8351744,  -7303168,
 998  
          -6254592,  -5206016,  -4157440,  -3108864,  -2060288,  -1011712, -16736256,
 999  
         -15687680, -14639104, -13590528, -12541952, -11493376, -10444800,  -9396224,
 1000  
          -8347648,  -7299072,  -6250496,  -5201920,  -4153344,  -3104768,  -2056192,
 1001  
          -1007616, -16732160, -15683584, -14635008, -13586432, -12537856, -11489280,
 1002  
         -10440704,  -9392128,  -8343552,  -7294976,  -6246400,  -5197824,  -4149248,
 1003  
          -3100672,  -2052096,  -1003520, -16728064, -15679488, -14630912, -13582336,
 1004  
         -12533760, -11485184, -10436608,  -9388032,  -8339456,  -7290880,  -6242304,
 1005  
          -5193728,  -4145152,  -3096576,  -2048000,   -999424, -16723968, -15675392,
 1006  
         -14626816, -13578240, -12529664, -11481088, -10432512,  -9383936,  -8335360,
 1007  
          -7286784,  -6238208,  -5189632,  -4141056,  -3092480,  -2043904,   -995328,
 1008  
         -16719872, -15671296, -14622720, -13574144, -12525568, -11476992, -10428416,
 1009  
          -9379840,  -8331264,  -7282688,  -6234112,  -5185536,  -4136960,  -3088384,
 1010  
          -2039808,   -991232, -16715776, -15667200, -14618624, -13570048, -12521472,
 1011  
         -11472896, -10424320,  -9375744,  -8327168,  -7278592,  -6230016,  -5181440,
 1012  
          -4132864,  -3084288,  -2035712, -987136};
 1013  
     
 1014  0
     private static final int[] GG_JAVA2 = {
 1015  
         0, 16, 32, 48, 64, 80, 96, 112, 128, 144, 160, 176, 192, 208, 224, 240};
 1016  
     
 1017  
 }