PokittoLib is the library needed for programming the Pokitto DIY game console (www.pokitto.com)

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers HWLCD.cpp Source File

HWLCD.cpp

Go to the documentation of this file.
00001 /**************************************************************************/
00002 /*!
00003     @file     HWLCD.cpp
00004     @author   Jonne Valola
00005 
00006     @section LICENSE
00007 
00008     Software License Agreement (BSD License)
00009 
00010     Copyright (c) 2016, Jonne Valola
00011     All rights reserved.
00012 
00013     Redistribution and use in source and binary forms, with or without
00014     modification, are permitted provided that the following conditions are met:
00015     1. Redistributions of source code must retain the above copyright
00016     notice, this list of conditions and the following disclaimer.
00017     2. Redistributions in binary form must reproduce the above copyright
00018     notice, this list of conditions and the following disclaimer in the
00019     documentation and/or other materials provided with the distribution.
00020     3. Neither the name of the copyright holders nor the
00021     names of its contributors may be used to endorse or promote products
00022     derived from this software without specific prior written permission.
00023 
00024     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
00025     EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00026     WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00027     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
00028     DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00029     (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00030     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00031     ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00032     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00033     SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00034 */
00035 /**************************************************************************/
00036 
00037 #include "HWLCD.h " //HWLCD.h" #include "HWLCD.h"
00038 #include "Pokitto_settings.h "
00039 
00040 #define avrmax(a,b) ((a)>(b)?(a):(b))
00041 #define avrmin(a,b) ((a)<(b)?(a):(b))
00042 
00043 #ifdef DISABLEAVRMIN
00044 #include <algorithm>
00045 using std::min;
00046 using std::max;
00047 #endif // DISABLEAVRMIN
00048 
00049 #define AB_JUMP 1024 // jump one 1-bit Arduboy screen forward to get next color bit
00050 #define GB_JUMP 504 // jump one 1-bit Gamebuino screen forward to get next color bit
00051 
00052 using namespace Pokitto;
00053 
00054 uint16_t prevdata=0; // if data does not change, do not adjust LCD bus lines
00055 
00056 #if POK_BOARDREV == 2
00057     pwmout_t backlightpwm;
00058 #endif
00059 
00060 volatile uint32_t *LCD = reinterpret_cast< volatile uint32_t * >(0xA0002188);
00061 
00062 /**************************************************************************/
00063 /*!
00064     @brief  set up the 16-bit bus
00065 */
00066 /**************************************************************************/
00067 
00068 static inline void setup_data_16(uint16_t data)
00069 {
00070     //uint32_t p2=0;
00071 
00072     //if (data != prevdata) {
00073     //
00074     //prevdata=data;
00075 
00076     /** D0...D16 = P2_3 ... P2_18 **/
00077     //p2 = data << 3;
00078 
00079     //__disable_irq();    // Disable Interrupts
00080     SET_MASK_P2;
00081     LPC_GPIO_PORT->MPIN[2] = (data<<3); // write bits to port
00082     CLR_MASK_P2;
00083     //__enable_irq();     // Enable Interrupts
00084     //}
00085 }
00086 
00087 
00088 /**************************************************************************/
00089 /*!
00090     @brief  Write a command to the lcd, 16-bit bus
00091 */
00092 /**************************************************************************/
00093 inline void write_command_16(uint16_t data)
00094 {
00095    CLR_CS; // select lcd
00096    CLR_CD; // clear CD = command
00097    SET_RD; // RD high, do not read
00098    setup_data_16(data); // function that inputs the data into the relevant bus lines
00099    CLR_WR_SLOW;  // WR low
00100    SET_WR;  // WR low, then high = write strobe
00101    SET_CS; // de-select lcd
00102 }
00103 
00104 /**************************************************************************/
00105 /*!
00106     @brief  Write data to the lcd, 16-bit bus
00107 */
00108 /**************************************************************************/
00109 inline void write_data_16(uint16_t data)
00110 {
00111    CLR_CS;
00112    SET_CD;
00113    SET_RD;
00114    setup_data_16(data);
00115    CLR_WR;
00116    SET_WR;
00117    SET_CS;
00118 }
00119 
00120 /**************************************************************************/
00121 /*!
00122     @brief  Pump data to the lcd, 16-bit bus, public function
00123 */
00124 /**************************************************************************/
00125 void Pokitto::pumpDRAMdata(uint16_t* data,uint16_t counter)
00126 {
00127    while (counter--) {
00128    CLR_CS;
00129    SET_CD;
00130    SET_RD;
00131    setup_data_16(*data++);
00132    CLR_WR;
00133    SET_WR;
00134    SET_CS;
00135    }
00136 }
00137 
00138 
00139 /**************************************************************************/
00140 /*!
00141     @brief  Point to a (x,y) location in the LCD DRAM
00142 */
00143 /**************************************************************************/
00144 static inline void setDRAMptr(uint8_t xptr, uint8_t yoffset)
00145 {
00146     write_command(0x20);  // Vertical DRAM Address
00147     write_data(yoffset);
00148     write_command(0x21);  // Horizontal DRAM Address
00149     write_data(xptr);  //
00150     write_command(0x22); // write data to DRAM
00151     CLR_CS_SET_CD_RD_WR;
00152 }
00153 
00154 /**************************************************************************/
00155 /*!
00156     @brief  Point to a (x,y) location in the LCD DRAM, public function
00157 */
00158 /**************************************************************************/
00159 void Pokitto::setDRAMpoint(uint8_t xptr, uint8_t yoffset)
00160 {
00161     write_command(0x20);  // Vertical DRAM Address
00162     write_data(yoffset);
00163     write_command(0x21);  // Horizontal DRAM Address
00164     write_data(xptr);  //
00165     write_command(0x22); // write data to DRAM
00166     CLR_CS_SET_CD_RD_WR;
00167 }
00168 
00169 void Pokitto::initBacklight() {
00170     #if POK_BOARDREV == 2
00171     pwmout_init(&backlightpwm,POK_BACKLIGHT_PIN);
00172     pwmout_period_us(&backlightpwm,5);
00173     pwmout_write(&backlightpwm,POK_BACKLIGHT_INITIALVALUE);
00174     #endif
00175 }
00176 
00177 void Pokitto::setBacklight(float value) {
00178     if (value>0.999f) value = 0.999f;
00179     pwmout_write(&backlightpwm,value);
00180 }
00181 
00182 void Pokitto::lcdInit() {
00183    initBacklight();
00184 
00185    SET_RESET;
00186    wait_ms(10);
00187    CLR_RESET;
00188    wait_ms(10);
00189    SET_RESET;
00190    wait_ms(10);
00191   //************* Start Initial Sequence **********//
00192     write_command(0x01); // driver output control, this also affects direction
00193     write_data(0x11C); // originally: 0x11C 100011100 SS,NL4,NL3,NL2
00194                         // NL4...0 is the number of scan lines to drive the screen !!!
00195                         // so 11100 is 1c = 220 lines, correct
00196                         // test 1: 0x1C 11100 SS=0,NL4,NL3,NL2 -> no effect
00197                         // test 2: 0x31C 1100011100 GS=1,SS=1,NL4,NL3,NL2 -> no effect
00198                         // test 3: 0x51C 10100011100 SM=1,GS=0,SS=1,NL4,NL3,NL2 -> no effect
00199                         // test 4: 0x71C SM=1,GS=1,SS=1,NL4,NL3,NL2
00200                         // test 5: 0x
00201                         // seems to have no effect... is this perhaps only for RGB mode ?
00202 
00203     write_command(0x02); // LCD driving control
00204     write_data(0x0100); // INV = 1
00205 
00206     write_command(0x03); // Entry mode... lets try if this affects the direction
00207     write_data(0x1030); // originally 0x1030 1000000110000 BGR,ID1,ID0
00208                         // test 1: 0x1038 1000000111000 BGR,ID1,ID0,AM=1 ->drawing DRAM horizontally
00209                         // test 4: am=1, id0=0, id1=0, 1000000001000,0x1008 -> same as above, but flipped on long
00210                         // test 2: am=0, id0=0, 1000000100000, 0x1020 -> flipped on long axis
00211                         // test 3: am=0, id1=0, 1000000010000, 0x1010 -> picture flowed over back to screen
00212 
00213 
00214     write_command(0x08); // Display control 2
00215     write_data(0x0808); // 100000001000 FP2,BP2
00216 
00217     write_command(0x0C); // RGB display interface
00218     write_data(0x0000); // all off
00219 
00220     write_command(0x0F); // Frame marker position
00221     write_data(0x0001); // OSC_EN
00222 
00223     write_command(0x20);  // Horizontal DRAM Address
00224     write_data(0x0000);  // 0
00225 
00226     write_command(0x21);  // Vertical DRAM Address
00227     write_data(0x0000); // 0
00228 
00229  //*************Power On sequence ****************//
00230     write_command(0x10);
00231     write_data(0x0000);
00232 
00233     write_command(0x11);
00234     write_data(0x1000);
00235     wait_ms(10);
00236 //------------------------ Set GRAM area --------------------------------//
00237     write_command(0x30); // Gate scan position
00238     write_data(0x0000); // if GS=0, 00h=G1, else 00h=G220
00239 
00240     write_command(0x31); // Vertical scroll control
00241     write_data(0x00DB); // scroll start line 11011011 = 219
00242 
00243     write_command(0x32); // Vertical scroll control
00244     write_data(0x0000); // scroll end line 0
00245 
00246     write_command(0x33); // Vertical scroll control
00247     write_data(0x0000); // 0=vertical scroll disabled
00248 
00249     write_command(0x34); // Partial screen driving control
00250     write_data(0x00DB); // db = full screen (end)
00251 
00252     write_command(0x35); // partial screen
00253     write_data(0x0000); // 0 = start
00254 
00255     write_command(0x36); // Horizontal and vertical RAM position
00256     write_data(0x00AF); //end address 175
00257 
00258     write_command(0x37);
00259     write_data(0x0000); // start address 0
00260 
00261     write_command(0x38);
00262     write_data(0x00DB); //end address 219
00263 
00264     write_command(0x39); // start address 0
00265     write_data(0x0000);
00266     wait_ms(10);
00267     write_command(0xff); // start gamma register control
00268     write_data(0x0003);
00269 
00270 // ----------- Adjust the Gamma  Curve ----------//
00271     write_command(0x50);
00272     write_data(0x0203);
00273 
00274     write_command(0x051);
00275     write_data(0x0A09);
00276 
00277     write_command(0x52);
00278     write_data(0x0005);
00279 
00280     write_command(0x53);
00281     write_data(0x1021);
00282 
00283     write_command(0x54);
00284     write_data(0x0602);
00285 
00286     write_command(0x55);
00287     write_data(0x0003);
00288 
00289     write_command(0x56);
00290     write_data(0x0703);
00291 
00292     write_command(0x57);
00293     write_data(0x0507);
00294 
00295     write_command(0x58);
00296     write_data(0x1021);
00297 
00298     write_command(0x59);
00299     write_data(0x0703);
00300 
00301     write_command(0xB0);
00302     write_data(0x2501);
00303 
00304     write_command(0xFF);
00305     write_data(0x0000);
00306 
00307     write_command(0x07);
00308     write_data(0x1017);
00309     wait_ms(200);
00310     write_command(0x22);
00311 
00312     lcdClear();
00313 }
00314 
00315 void Pokitto::lcdSleep(void){
00316    write_command(0xFF);
00317    write_data(0x0000);
00318 
00319    write_command(0x07);
00320    write_data(0x0000);
00321    wait_ms(50);
00322    write_command(0x10);// Enter Standby mode
00323    write_data(0x0003);
00324    wait_ms(200);
00325 
00326 }
00327 
00328 void Pokitto::lcdWakeUp (void){
00329 
00330    wait_ms(200);
00331    write_command(0xFF);
00332    write_data(0x0000);
00333 
00334    write_command(0x10);// Exit Sleep/ Standby mode
00335    write_data(0x0000);
00336    wait_ms(50);
00337    write_command(0x07);
00338    write_data(0x0117);
00339    wait_ms(200);
00340   }
00341 
00342 void Pokitto::lcdFillSurface(uint16_t c) {
00343     uint32_t i;
00344     write_command(0x20);  // Horizontal DRAM Address
00345     write_data(0x0000);  // 0
00346     write_command(0x21);  // Vertical DRAM Address
00347     write_data(0);
00348     write_command(0x22); // write data to DRAM
00349     setup_data_16(c);
00350     CLR_CS_SET_CD_RD_WR;
00351     for(i=0;i<220*176;i++)
00352     {
00353     CLR_WR;
00354     SET_WR;
00355     }
00356 }
00357 
00358 void Pokitto::lcdClear() {
00359     uint32_t i;
00360     write_command(0x20);  // Horizontal DRAM Address
00361     write_data(0x0000);  // 0
00362     write_command(0x21);  // Vertical DRAM Address
00363     write_data(0);
00364     write_command(0x22); // write data to DRAM
00365     setup_data_16(0x0000);
00366     CLR_CS_SET_CD_RD_WR;
00367     for(i=0;i<220*176;i++)
00368     {
00369         CLR_WR;
00370         SET_WR;
00371     }
00372 }
00373 
00374 void Pokitto::lcdPixel(int16_t x, int16_t y, uint16_t color) {
00375     if ((x < 0) || (x >= POK_LCD_W) || (y < 0) || (y >= POK_LCD_H))
00376     return;
00377     write_command(0x20);  // Horizontal DRAM Address
00378     write_data(y);  // 0
00379     write_command(0x21);  // Vertical DRAM Address
00380     write_data(x);
00381     write_command(0x22); // write data to DRAM
00382     CLR_CS_SET_CD_RD_WR;
00383     setup_data_16(color);
00384     CLR_WR;SET_WR;
00385 }
00386 
00387 void Pokitto::setWindow(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2) {
00388     write_command(0x37); write_data(x1);
00389     write_command(0x36); write_data(x2);
00390     write_command(0x39); write_data(y1);
00391     write_command(0x38); write_data(y2);
00392     write_command(0x20); write_data(x1);
00393     write_command(0x21); write_data(y1);
00394 }
00395 
00396 void Pokitto::lcdTile(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t* gfx){
00397     int width=x1-x0;
00398     int height=y1-y0;
00399     if (x0 > POK_LCD_W) return;
00400     if (y0 > POK_LCD_H) return;
00401     if (x0 < 0) x0=0;
00402     if (y0 < 0) y0=0;
00403 
00404     setWindow(y0, x0, y1-1, x1-1);
00405     write_command(0x22);
00406 
00407     for (int x=0; x<=width*height-1;x++) {
00408         write_data(gfx[x]);
00409     }
00410     setWindow(0, 0, 175, 219);
00411 }
00412 
00413 void Pokitto::lcdRectangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color) {
00414     int16_t temp;
00415     if (x0>x1) {temp=x0;x0=x1;x1=temp;}
00416     if (y0>y1) {temp=y0;y0=y1;y1=temp;}
00417     if (x0 > POK_LCD_W) return;
00418     if (y0 > POK_LCD_H) return;
00419     if (x1 > POK_LCD_W) x1=POK_LCD_W;
00420     if (y1 > POK_LCD_H) y1=POK_LCD_H;
00421     if (x0 < 0) x0=0;
00422     if (y0 < 0) y0=0;
00423     
00424     int16_t x,y;
00425     
00426     for (y=y0; y<y1;y++) {
00427     
00428         write_command(0x20); // Horizontal DRAM Address (=y on pokitto screen)
00429         
00430         write_data(y);
00431         
00432         write_command(0x21); // Vertical DRAM Address (=x on pokitto screen)
00433         
00434         write_data(x0);
00435         
00436         write_command(0x22); // write data to DRAM
00437         
00438         CLR_CS_SET_CD_RD_WR; // go to vram write mode
00439         
00440         for (x=x0; x<x1;x++) {
00441         
00442             setup_data_16(color); // setup the data (flat color = no change between pixels)
00443             
00444             CLR_WR;SET_WR; //CLR_WR;SET_WR;//toggle writeline, pokitto screen writes a column up to down
00445         
00446         }
00447     
00448     }
00449 
00450 }
00451 
00452 
00453 /***
00454  * Update the screen buffer of 220x176 pixels, 4 colors to LCD.
00455  *
00456  * The update rect is used for drawing only part of the screen buffer to LCD. Because of speed optimizations, the
00457  * x, y, and width of the update rect must be dividable by 4 pixels, and the height must be dividable by 8 pixels.
00458  * Note: The update rect is currently used for 220x176, 4 colors, screen mode only.
00459  * @param scrbuf The screen buffer.
00460  * @param updRectX The update rect.
00461  * @param updRectY The update rect.
00462  * @param updRectW The update rect.
00463  * @param updRectH The update rect.
00464  * @param paletteptr The screen palette.
00465 */
00466 void Pokitto::lcdRefreshMode1(uint8_t * scrbuf, uint8_t updRectX, uint8_t updRectY, uint8_t updRectW, uint8_t updRectH, uint16_t* paletteptr) {
00467 
00468     uint16_t x,y;
00469     uint16_t scanline[4][176]; // read 4 half-nibbles = 4 pixels at a time
00470     uint8_t *d;
00471 
00472     // If not the full screen is updated, check the validity of the update rect.
00473     if ( updRectX != 0 || updRectY != 0 ||updRectW != LCDWIDTH ||updRectH != LCDHEIGHT ) {
00474         uint8_t org_screenx = updRectX;
00475         updRectX &= 0xfc; // Make the value dividable by 4.
00476         updRectW += org_screenx - updRectX;
00477         updRectW = (updRectW + 3) & 0xfc; // Make the value dividable by 4, round up.
00478 
00479         uint8_t org_screeny = updRectY;
00480         updRectY &= 0xfc; // Make the value dividable by 4.
00481         updRectH += org_screeny - updRectY;
00482         updRectH = (updRectH + 7) & 0xf8; // Make the value dividable by 8 (because of loop unroll optimization), round up.
00483     }
00484 
00485 
00486     #ifdef PROJ_SHOW_FPS_COUNTER
00487     xptr = 8;
00488     setDRAMptr(8, 0);
00489     #else
00490     setDRAMptr(0, 0);
00491     #endif
00492 
00493     for (x=updRectX; x<updRectX+updRectW; x+=4) {
00494         d = scrbuf+(x>>2);// point to beginning of line in data
00495 
00496         /** find colours in one scanline **/
00497         d += (updRectY * 220/4);
00498         for (y=updRectY; y<updRectY+updRectH; y++) {
00499             uint8_t tdata = *d;
00500             uint8_t t4 = tdata & 0x03; tdata >>= 2;// lowest half-nibble
00501             uint8_t t3 = tdata & 0x03; tdata >>= 2;// second lowest half-nibble
00502             uint8_t t2 = tdata & 0x03; tdata >>= 2;// second highest half-nibble
00503             uint8_t t = tdata & 0x03;// highest half-nibble
00504 
00505             /** put nibble values in the scanlines **/
00506             scanline[0][y] = paletteptr[t];
00507             scanline[1][y] = paletteptr[t2];
00508             scanline[2][y] = paletteptr[t3];
00509             scanline[3][y] = paletteptr[t4];
00510 
00511             d += 220/4; // jump to read byte directly below in screenbuffer
00512         }
00513 
00514         #ifdef PROJ_SHOW_FPS_COUNTER
00515         if (x>=8 ) {
00516         #else
00517         {
00518 
00519         #endif
00520 
00521             // Draw 8 vertical pixels at a time for performance reasons
00522             setDRAMptr(x, updRectY);
00523             for (uint8_t s=updRectY; s<updRectY+updRectH;) {
00524                 setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
00525                 setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
00526                 setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
00527                 setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
00528                 setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
00529                 setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
00530                 setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
00531                 setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
00532             }
00533             setDRAMptr(x+1, updRectY);
00534             for (uint8_t s=updRectY; s<updRectY+updRectH;) {
00535                 setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
00536                 setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
00537                 setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
00538                 setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
00539                 setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
00540                 setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
00541                 setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
00542                 setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
00543             }
00544             setDRAMptr(x+2, updRectY);
00545             for (uint8_t s=updRectY; s<updRectY+updRectH;) {
00546                 setup_data_16(scanline[2][s++]);CLR_WR;SET_WR;
00547                 setup_data_16(scanline[2][s++]);CLR_WR;SET_WR;
00548                 setup_data_16(scanline[2][s++]);CLR_WR;SET_WR;
00549                 setup_data_16(scanline[2][s++]);CLR_WR;SET_WR;
00550                 setup_data_16(scanline[2][s++]);CLR_WR;SET_WR;
00551                 setup_data_16(scanline[2][s++]);CLR_WR;SET_WR;
00552                 setup_data_16(scanline[2][s++]);CLR_WR;SET_WR;
00553                 setup_data_16(scanline[2][s++]);CLR_WR;SET_WR;
00554             }
00555             setDRAMptr(x+3, updRectY);
00556             for (uint8_t s=updRectY; s<updRectY+updRectH;) {
00557                 setup_data_16(scanline[3][s++]);CLR_WR;SET_WR;
00558                 setup_data_16(scanline[3][s++]);CLR_WR;SET_WR;
00559                 setup_data_16(scanline[3][s++]);CLR_WR;SET_WR;
00560                 setup_data_16(scanline[3][s++]);CLR_WR;SET_WR;
00561                 setup_data_16(scanline[3][s++]);CLR_WR;SET_WR;
00562                 setup_data_16(scanline[3][s++]);CLR_WR;SET_WR;
00563                 setup_data_16(scanline[3][s++]);CLR_WR;SET_WR;
00564                 setup_data_16(scanline[3][s++]);CLR_WR;SET_WR;
00565             }
00566         }
00567     }
00568 
00569     #ifdef POK_SIM
00570     simulator.refreshDisplay();
00571     #endif
00572 }
00573 
00574 // Copy sprite pixels to the scanline
00575 #define SPRITE_2BPP_INNER_LOOP(n)\
00576 \
00577     /* If the sprite is enabled and contained in this vertical scanline, copy 4 pixels. */\
00578     if (sprScanlineAddr[(n)] &&\
00579         y >= sprites[(n)].y && y < sprites[(n)].y + sprites[(n)].h ) {\
00580 \
00581         int16_t sprx = sprites[(n)].x;\
00582         uint16_t s_data16b = 0;  /* sprite data, 2 bytes */\
00583 \
00584         /* Get pixel block, 4 or 8 pixels horizontally. Use the predefined bitshift mode. */\
00585         /* Note:it is cheapest to compare to 0 first. */\
00586         if (sprScanlineBitshiftMode[(n)] == BITSHIFT_MODE_MIDDLE_BYTE) {\
00587             s_data16b = *(sprScanlineAddr[(n)]);\
00588             uint16_t leftByte = *(sprScanlineAddr[(n)]-1);\
00589             s_data16b = (leftByte << 8) | s_data16b;\
00590         }\
00591         else if (sprScanlineBitshiftMode[(n)] == BITSHIFT_MODE_FIRST_BYTE) {\
00592             s_data16b = *(sprScanlineAddr[(n)]);\
00593         }\
00594         else { /* BITSHIFT_MODE_LAST_BYTE */\
00595             uint16_t leftByte = *(sprScanlineAddr[(n)]-1);\
00596             s_data16b = (leftByte << 8) | s_data16b;\
00597         }\
00598 \
00599         /* Shift sprite pixels according to sprite x. After shifting we have only 4 pixels. */\
00600         uint8_t shiftRight = (sprx&0x3) << 1;\
00601         s_data16b = (s_data16b >> shiftRight);\
00602 \
00603         /* Get individual pixels */\
00604         uint8_t s_t4 = s_data16b & 0x03; s_data16b >>= 2; /* lowest half-nibble */\
00605         uint8_t s_t3 = s_data16b & 0x03; s_data16b >>= 2; /* second lowest half-nibble */\
00606         uint8_t s_t2 = s_data16b & 0x03; s_data16b >>= 2; /* second highest half-nibble */\
00607         uint8_t s_t1 = s_data16b & 0x03;                  /* highest half-nibble */\
00608 \
00609         /* Store pixels as 16-bit colors from the palette */\
00610         if (s_t4 != transparentColor) p4 = sprites[(n)].palette[s_t4];\
00611         if (s_t3 != transparentColor) p3 = sprites[(n)].palette[s_t3];\
00612         if (s_t2 != transparentColor) p2 = sprites[(n)].palette[s_t2];\
00613         if (s_t1 != transparentColor) p = sprites[(n)].palette[s_t1];\
00614 \
00615         /* Advance scanline address */\
00616         sprScanlineAddr[(n)] += (sprites[(n)].w >> 2);\
00617     }
00618 
00619 // Loop unrolling macros
00620 #define UNROLLED_LOOP_1() SPRITE_2BPP_INNER_LOOP(0)
00621 #define UNROLLED_LOOP_2() UNROLLED_LOOP_1() SPRITE_2BPP_INNER_LOOP(1)
00622 #define UNROLLED_LOOP_3() UNROLLED_LOOP_2() SPRITE_2BPP_INNER_LOOP(2)
00623 #define UNROLLED_LOOP_4() UNROLLED_LOOP_3() SPRITE_2BPP_INNER_LOOP(3)
00624 #define UNROLLED_LOOP_5() UNROLLED_LOOP_4() SPRITE_2BPP_INNER_LOOP(4)
00625 #define UNROLLED_LOOP_6() UNROLLED_LOOP_5() SPRITE_2BPP_INNER_LOOP(5)
00626 #define UNROLLED_LOOP_7() UNROLLED_LOOP_6() SPRITE_2BPP_INNER_LOOP(6)
00627 #define UNROLLED_LOOP_8() UNROLLED_LOOP_7() SPRITE_2BPP_INNER_LOOP(7)
00628 #define UNROLLED_LOOP_9() UNROLLED_LOOP_8() SPRITE_2BPP_INNER_LOOP(8)
00629 #define UNROLLED_LOOP_10() UNROLLED_LOOP_9() SPRITE_2BPP_INNER_LOOP(9)
00630 #define UNROLLED_LOOP_11() UNROLLED_LOOP_10() SPRITE_2BPP_INNER_LOOP(10)
00631 #define UNROLLED_LOOP_12() UNROLLED_LOOP_11() SPRITE_2BPP_INNER_LOOP(11)
00632 #define UNROLLED_LOOP_13() UNROLLED_LOOP_12() SPRITE_2BPP_INNER_LOOP(12)
00633 #define UNROLLED_LOOP_14() UNROLLED_LOOP_13() SPRITE_2BPP_INNER_LOOP(13)
00634 #define UNROLLED_LOOP_15() UNROLLED_LOOP_14() SPRITE_2BPP_INNER_LOOP(14)
00635 #define UNROLLED_LOOP_16() UNROLLED_LOOP_15() SPRITE_2BPP_INNER_LOOP(15)
00636 #define UNROLLED_LOOP_N_(n) UNROLLED_LOOP_##n()
00637 #define UNROLLED_LOOP_N(n) UNROLLED_LOOP_N_(n)
00638 
00639 /***
00640  * Update the screen buffer of 220x176 pixels, 4 colors and free size 4 color sprites to LCD.
00641  *
00642  * The update rect is used for drawing only part of the screen buffer to LCD. Because of speed optimizations, the
00643  * x, y, and width of the update rect must be dividable by 4 pixels, and the height must be dividable by 8 pixels.
00644  * Note: The update rect is currently used for 220x176, 4 colors, screen mode only.
00645  * If drawSpritesOnly=true, only sprites are fully updated to LCD. However, the dirty rect of the screen buffer is
00646  * drawn behind the sprite current and previous location.
00647  * Note: Sprite is enabled if sprite.bitmapData is not NULL. Also all enabled sprites must be at the beginning of
00648  * the sprites array. No gaps are allowed in the array.
00649  * @param scrbuf The screen buffer.
00650  * @param updRectX The update rect.
00651  * @param updRectY The update rect.
00652  * @param updRectW The update rect.
00653  * @param updRectH The update rect.
00654  * @param paletteptr The screen palette.
00655  * @param sprites The sprite array.
00656  * @param drawSpritesOnly True, if only sprites are drawn. False, if both sprites and the screen buffer are drawn.
00657 */
00658 void Pokitto::lcdRefreshMode1Spr(
00659     uint8_t * scrbuf, uint8_t updRectX, uint8_t updRectY, uint8_t updRectW, uint8_t updRectH, uint16_t* paletteptr,
00660     SpriteInfo* sprites, bool drawSpritesOnly) {
00661 
00662     // In direct mode draw only sprites and their dirty rects. Return now if there are no sprites
00663     if (drawSpritesOnly && (sprites == NULL || sprites[0].bitmapData == NULL))
00664         return;
00665 
00666     uint16_t x,y;
00667     uint16_t scanline[4][176]; // read 4 half-nibbles (= 4 pixels) at a time
00668     const uint8_t transparentColor = 0;  // fixed palette index 0 for transparency
00669 
00670     // If not the full screen is updated, check the validity of the update rect.
00671     if ( updRectX != 0 || updRectY != 0 ||updRectW != LCDWIDTH ||updRectH != LCDHEIGHT ) {
00672         uint8_t org_screenx = updRectX;
00673         updRectX &= 0xfc; // Make the value dividable by 4.
00674         updRectW += org_screenx - updRectX;
00675         updRectW = (updRectW + 3) & 0xfc; // Make the value dividable by 4, round up.
00676 
00677         uint8_t org_screeny = updRectY;
00678         updRectY &= 0xfc; // Make the value dividable by 4.
00679         updRectH += org_screeny - updRectY;
00680         updRectH = (updRectH + 7) & 0xf8; // Make the value dividable by 8 (because of loop unroll optimization), round up.
00681     }
00682 
00683     // Calculate the current  amount of sprites
00684     // Note: Sprites must be taken into use from index 0 upwards, because the first sprite with bitmapData==NULL is considered as the last sprite
00685     uint8_t spriteCount = 0;
00686     if (sprites != NULL)
00687         for (;sprites[spriteCount].bitmapData != NULL && spriteCount < SPRITE_COUNT; spriteCount++);
00688 
00689     // If drawing the screen buffer, set the start pos to LCD commands only here.
00690     #ifdef PROJ_SHOW_FPS_COUNTER
00691     if (!drawSpritesOnly) setDRAMptr(8, 0);
00692     #else
00693     if (!drawSpritesOnly) setDRAMptr(0, 0);
00694     #endif
00695 
00696     //*** GO THROUGH EACH VERTICAL GROUP OF 4 SCANLINES.***
00697 
00698     for (x=0; x<LCDWIDTH; x+=4) {
00699 
00700         uint8_t *screenBufScanlineAddr = scrbuf + (x>>2);// point to beginning of line in data
00701 
00702         /*Prepare scanline start address for sprites that are visible in this vertical scanline. Sprite width cannot exceed the screen width*/
00703         uint8_t *sprScanlineAddr[SPRITE_COUNT];  // Sprite start address for the scanline
00704         uint8_t sprScanlineBitshiftMode[SPRITE_COUNT];  // Sprite bitshift mode for the scanline
00705         const uint8_t BITSHIFT_MODE_MIDDLE_BYTE = 0;
00706         const uint8_t BITSHIFT_MODE_FIRST_BYTE = 1;
00707         const uint8_t BITSHIFT_MODE_LAST_BYTE = 2;
00708         uint8_t scanlineMinY = 255; // Init to uninitialized value. Do not draw by default.
00709         uint8_t scanlineMaxY = 0; // Init to uninitialized value. Do not draw by default.
00710 
00711         //*** CALCULATE DIRTY RECTS AND RESOLVE WHICH SPRITES BELONG TO THIS SCANLINE GROUP ***
00712 
00713         if (sprites != NULL) {
00714 
00715             // Check all the sprites for this scanline. That is used for handling the given update rect
00716             // Note that the last round is when (sprindex == spriteCount). That is used to add the screen buffer
00717             // update rect to the dirty rect.
00718             for (int sprindex = 0; sprindex <= spriteCount; sprindex++) {
00719 
00720                 int16_t sprx, spry, sprOldX, sprOldY;
00721                 uint8_t sprw, sprh;
00722                 bool isCurrentSpriteOutOfScreen = false;
00723                 bool isOldSpriteOutOfScreen = false;
00724 
00725                 if (sprindex < spriteCount) {
00726 
00727                     sprx = sprites[sprindex].x;
00728                     spry = sprites[sprindex].y;
00729                     sprw = sprites[sprindex].w;
00730                     sprh = sprites[sprindex].h;
00731                     sprOldX = sprites[sprindex].oldx;
00732                     sprOldY = sprites[sprindex].oldy;
00733                }
00734 
00735                 // Handle the screen buffer update rect after all sprites
00736                 else if(!drawSpritesOnly){
00737 
00738                     sprx = updRectX;
00739                     spry = updRectY;
00740                     sprw = updRectW;
00741                     sprh = updRectH;
00742                     sprOldX = updRectX;
00743                     sprOldY = updRectY;
00744                     isCurrentSpriteOutOfScreen = false;
00745                     isOldSpriteOutOfScreen = false;
00746                 }
00747 
00748                 // Check for out-of-screen
00749                 if (sprx >= LCDWIDTH || spry >= LCDHEIGHT)
00750                     isCurrentSpriteOutOfScreen = true;
00751                 if (sprOldX >= LCDWIDTH || sprOldY >= LCDHEIGHT)
00752                     isOldSpriteOutOfScreen = true;
00753 
00754                 // Skip if current and old sprites are out-of-screen
00755                 if (isCurrentSpriteOutOfScreen && isOldSpriteOutOfScreen)
00756                     continue;
00757 
00758                 // Detect the dirty rect x-span by combining the previous and current sprite position.
00759                 int16_t sprDirtyXMin = avrmin(sprx, sprOldX);
00760                 int16_t sprDirtyXMax = avrmax(sprx, sprOldX);
00761                 if (isCurrentSpriteOutOfScreen)
00762                     sprDirtyXMax = sprOldX;
00763                 if (isOldSpriteOutOfScreen)
00764                     sprDirtyXMax = sprx;
00765 
00766                 // Is current x inside the sprite combined dirty rect ?
00767                 int16_t sprDirtyXMaxEnd = sprDirtyXMax + sprw - 1 + 4; // Add 4 pixels to dirty rect width (needed?)
00768                 if (sprDirtyXMin <= x+3 && x <= sprDirtyXMaxEnd) {
00769 
00770                     // *** COMBINE DIRTY RECTS FOR THIS SCANLINE GROUP ***
00771 
00772                     // Dirty rect
00773                     int sprDirtyYMin = avrmin(spry, sprOldY);
00774                     sprDirtyYMin = avrmax((int)sprDirtyYMin, 0);
00775                     int sprDirtyYMax = avrmax(spry, sprOldY);
00776                     if (isCurrentSpriteOutOfScreen)
00777                         sprDirtyYMax = sprOldY;
00778                     if (isOldSpriteOutOfScreen)
00779                         sprDirtyYMax = spry;
00780                     int sprDirtyYMaxEnd = sprDirtyYMax + sprh - 1;
00781                     sprDirtyYMaxEnd = avrmin(sprDirtyYMaxEnd, LCDHEIGHT - 1);  // Should use LCDHEIGHT instead of screenH? Same with other screen* ?
00782 
00783                     // Get the scanline min and max y values for drawing
00784                     if (sprDirtyYMin < scanlineMinY)
00785                         scanlineMinY = sprDirtyYMin;
00786                     if (sprDirtyYMaxEnd > scanlineMaxY)
00787                         scanlineMaxY = sprDirtyYMaxEnd;
00788 
00789                    // *** PREPARE SPRITE FOR DRAWING ***
00790 
00791                    // Check if the sprite should be active for this vertical scanline group.
00792                     if (sprindex < spriteCount &&  // not for update rect
00793                         !isCurrentSpriteOutOfScreen && //out-of-screen
00794                         sprx <= x+3 && x < sprx + sprw) { // note: cover group of 4 pixels of the scanline (x+3)
00795 
00796                         // Find the byte number in the sprite data
00797                         int16_t byteNum = ((x+3) - sprx)>>2;
00798 
00799                         // Get the start addres of the spite data in this scanline.
00800                         sprScanlineAddr[sprindex] = const_cast<uint8_t*>(sprites[sprindex].bitmapData + byteNum);
00801 
00802                         // If the sprite goes over the top, it must be clipped from the top.
00803                         if(spry < 0)
00804                             sprScanlineAddr[sprindex] += (-spry) * (sprw >> 2);
00805 
00806                         // Select the bitshift mode for the blit algorithm
00807                         if (byteNum == 0)
00808                             sprScanlineBitshiftMode[sprindex] = BITSHIFT_MODE_FIRST_BYTE;
00809                         else if (byteNum >= (sprw >> 2))
00810                             sprScanlineBitshiftMode[sprindex] = BITSHIFT_MODE_LAST_BYTE;
00811                         else
00812                             sprScanlineBitshiftMode[sprindex] = BITSHIFT_MODE_MIDDLE_BYTE;
00813                     }
00814                     else
00815                         sprScanlineAddr[sprindex] = NULL;  // Deactive sprite for this scanline
00816                 }
00817                 else
00818                     sprScanlineAddr[sprindex] = NULL;  // Deactive sprite for this scanline
00819             }
00820         }
00821 
00822         // *** ADJUST THE SCANLINE GROUP HEIGHT ***
00823 
00824         // The height must dividable by 8. That is needed because later we copy 8 pixels at a time to the LCD.
00825         if (scanlineMaxY - scanlineMinY + 1 > 0) {
00826             uint8_t scanlineH = scanlineMaxY - scanlineMinY + 1;
00827             uint8_t addW = 8 - (scanlineH & 0x7);
00828 
00829             // if height is not dividable by 8, make it be.
00830             if (addW != 0) {
00831                 if (scanlineMinY > addW )
00832                     scanlineMinY -= addW;
00833                 else if( scanlineMaxY + addW < updRectY+updRectH)
00834                     scanlineMaxY += addW;
00835                 else {
00836                     // Draw full height scanline
00837                     scanlineMinY = updRectY;
00838                     scanlineMaxY = updRectY+updRectH-1;
00839                 }
00840             }
00841         }
00842 
00843         // *** COMBINE THE SCANLINE GROUP OF THE SCREEN BUFFER AND ALL SPRITES ***
00844 
00845         // Find colours in this group of 4 scanlines
00846         screenBufScanlineAddr += (scanlineMinY * 220/4);
00847         for (y=scanlineMinY; y<=scanlineMaxY; y++)
00848         {
00849             // get the screen buffer data first
00850             uint8_t tdata = *screenBufScanlineAddr;
00851             uint8_t t4 = tdata & 0x03; tdata >>= 2;// lowest half-nibble
00852             uint8_t t3 = tdata & 0x03; tdata >>= 2;// second lowest half-nibble
00853             uint8_t t2 = tdata & 0x03; tdata >>= 2;// second highest half-nibble
00854             uint8_t t = tdata & 0x03;// highest half-nibble
00855 
00856             // Convert to 16-bit colors in palette
00857             uint16_t p = paletteptr[t];
00858             uint16_t p2 = paletteptr[t2];
00859             uint16_t p3 = paletteptr[t3];
00860             uint16_t p4 = paletteptr[t4];
00861 
00862             #if 0
00863             // Dirty rect visual test
00864             p = COLOR_BLUE >> (Core::frameCount % 5);
00865             p2 = COLOR_BLUE >> (Core::frameCount % 5);
00866             p3 = COLOR_BLUE >> (Core::frameCount % 5);
00867             p4 = COLOR_BLUE >> (Core::frameCount % 5);
00868             #endif
00869 
00870             // Add active sprite pixels
00871             if (sprites != NULL) {
00872 
00873                 // Use loop unrolling for speed optimization
00874                 UNROLLED_LOOP_N(SPRITE_COUNT)
00875             }
00876 
00877             // put the result nibble values in the scanline
00878             scanline[0][y] = p;
00879             scanline[1][y] = p2;
00880             scanline[2][y] = p3;
00881             scanline[3][y] = p4;
00882 
00883             screenBufScanlineAddr += 220>>2; // jump to read byte directly below in screenbuffer
00884         }
00885 
00886         // *** DRAW THE SCANLINE GROUP TO LCD
00887 
00888 #ifdef PROJ_SHOW_FPS_COUNTER
00889         if (x>=8 && scanlineMaxY - scanlineMinY +1 > 0) {
00890 #else
00891         if (scanlineMaxY - scanlineMinY +1 > 0) {
00892 #endif
00893             // Draw 8 vertical pixels at a time for performance reasons
00894 
00895             setDRAMptr(x, scanlineMinY);
00896             for (uint8_t s=scanlineMinY;s<=scanlineMaxY;) {
00897                 setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
00898                 setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
00899                 setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
00900                 setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
00901                 setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
00902                 setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
00903                 setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
00904                 setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
00905             }
00906 
00907             setDRAMptr(x+1, scanlineMinY);
00908             for (uint8_t s=scanlineMinY;s<=scanlineMaxY;) {
00909                 setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
00910                 setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
00911                 setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
00912                 setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
00913                 setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
00914                 setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
00915                 setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
00916                 setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
00917             }
00918 
00919             setDRAMptr(x+2, scanlineMinY);
00920             for (uint8_t s=scanlineMinY;s<=scanlineMaxY;) {
00921                 setup_data_16(scanline[2][s++]);CLR_WR;SET_WR;
00922                 setup_data_16(scanline[2][s++]);CLR_WR;SET_WR;
00923                 setup_data_16(scanline[2][s++]);CLR_WR;SET_WR;
00924                 setup_data_16(scanline[2][s++]);CLR_WR;SET_WR;
00925                 setup_data_16(scanline[2][s++]);CLR_WR;SET_WR;
00926                 setup_data_16(scanline[2][s++]);CLR_WR;SET_WR;
00927                 setup_data_16(scanline[2][s++]);CLR_WR;SET_WR;
00928                 setup_data_16(scanline[2][s++]);CLR_WR;SET_WR;
00929             }
00930 
00931             setDRAMptr(x+3, scanlineMinY);
00932             for (uint8_t s=scanlineMinY;s<=scanlineMaxY;) {
00933                 setup_data_16(scanline[3][s++]);CLR_WR;SET_WR;
00934                 setup_data_16(scanline[3][s++]);CLR_WR;SET_WR;
00935                 setup_data_16(scanline[3][s++]);CLR_WR;SET_WR;
00936                 setup_data_16(scanline[3][s++]);CLR_WR;SET_WR;
00937                 setup_data_16(scanline[3][s++]);CLR_WR;SET_WR;
00938                 setup_data_16(scanline[3][s++]);CLR_WR;SET_WR;
00939                 setup_data_16(scanline[3][s++]);CLR_WR;SET_WR;
00940                 setup_data_16(scanline[3][s++]);CLR_WR;SET_WR;
00941             }
00942         }
00943     }
00944 
00945     // Update old x and y for the sprites
00946     if (sprites != NULL) {
00947         for (int sprindex = 0; sprindex < spriteCount; sprindex++) {
00948             sprites[sprindex].oldx = sprites[sprindex].x;
00949             sprites[sprindex].oldy = sprites[sprindex].y;
00950         }
00951     }
00952 
00953     #ifdef POK_SIM
00954     simulator.refreshDisplay();
00955     #endif
00956 }
00957 
00958   
00959 #define MODE2_INNER_LOOP_B              \
00960   " ldm %[scanline]!, {%[c]}"   "\n"        \
00961            "    str %[c], [%[LCD], 0]"    "\n"  \
00962            "    str %[t], [%[LCD], 124]"  "\n"  \
00963            "    movs %[c], 252"   "\n"      \
00964            "    str %[t], [%[LCD], %[c]]" "\n"  \
00965            "    str %[t], [%[LCD], 124]"  "\n"  \
00966            "    subs %[x], 1"             "\n"  \
00967            "    str %[t], [%[LCD], %[c]]" "\n"  \
00968     
00969 
00970 void Pokitto::lcdRefreshMode2(uint8_t * scrbuf, uint16_t* paletteptr ) {
00971   uint32_t x,y;
00972   uint32_t scanline[110];
00973 
00974   write_command(0x03); write_data(0x1038);
00975   write_command(0x20);  // Horizontal DRAM Address
00976   write_data(0);  // 0
00977   write_command(0x21);  // Vertical DRAM Address
00978   write_data(1);
00979   write_command(0x22); // write data to DRAM
00980   CLR_CS_SET_CD_RD_WR;
00981   SET_MASK_P2;
00982 
00983 #ifndef __ARMCC_VERSION
00984    asm volatile(
00985      ".syntax unified"         "\n"
00986      
00987      "mov r10, %[scanline]"    "\n"
00988      "mov r11, %[t]"           "\n"
00989      
00990      "mode2OuterLoop:"        "\n"
00991      
00992      "movs %[x], 110"          "\n"
00993      "mode2InnerLoopA:"
00994 
00995 
00996      "  ldrb %[byte], [%[scrbuf],0]"   "\n"             
00997      "  lsrs %[c], %[byte], 4"    "\n"
00998 
00999      "  movs %[t], 15" "\n"
01000      "  ands %[byte], %[t]"    "\n"     
01001      
01002      "  lsls %[c], 1"             "\n"          
01003      "  ldrh %[t], [%[paletteptr], %[c]]"      "\n" 
01004      "  lsls %[t], %[t], 3"       "\n"          
01005      "  str %[t], [%[LCD], 0]"    "\n"          
01006      "  mov %[c], r11" "\n"             
01007      "  str %[c], [%[LCD], 124]"  "\n"          
01008      "  stm %[scanline]!, {%[t]}" "\n"          
01009      "  movs %[t], 252"   "\n"              
01010      "  str %[c], [%[LCD], %[t]]" "\n"          
01011      "  str %[c], [%[LCD], 124]"  "\n"          
01012      "  lsls %[byte], %[byte], 1"             "\n"          
01013      "  str %[c], [%[LCD], %[t]]" "\n"
01014 
01015      "  ldrh %[t], [%[paletteptr], %[byte]]"      "\n"  
01016      "  lsls %[t], %[t], 3"       "\n"          
01017      "  str %[t], [%[LCD], 0]"    "\n"          
01018      "  mov %[c], r11" "\n"             
01019      "  str %[c], [%[LCD], 124]"  "\n"          
01020      "  stm %[scanline]!, {%[t]}" "\n"          
01021      "  movs %[t], 252"   "\n"              
01022      "  str %[c], [%[LCD], %[t]]" "\n"          
01023      "  str %[c], [%[LCD], 124]"  "\n"          
01024      "  adds %[scrbuf], %[scrbuf], 1" "\n"      
01025      "  str %[c], [%[LCD], %[t]]" "\n"
01026      
01027      "  subs %[x], 2"          "\n" 
01028      "  bne mode2InnerLoopA"  "\n"
01029 
01030      "mov %[scanline], r10"    "\n"
01031      "movs %[x], 110"          "\n"
01032      "mov %[t], r11"           "\n"
01033      "mode2InnerLoopB:"
01034      MODE2_INNER_LOOP_B  
01035      MODE2_INNER_LOOP_B  
01036      MODE2_INNER_LOOP_B  
01037      MODE2_INNER_LOOP_B  
01038      MODE2_INNER_LOOP_B  
01039      MODE2_INNER_LOOP_B  
01040      MODE2_INNER_LOOP_B  
01041      MODE2_INNER_LOOP_B  
01042      MODE2_INNER_LOOP_B  
01043      MODE2_INNER_LOOP_B  
01044      "  bne mode2InnerLoopB"     "\n"
01045      
01046      "mov %[scanline], r10"    "\n"
01047      "movs %[t], 1"              "\n"
01048      "movs %[c], 88"             "\n"
01049      "add %[y], %[t]"            "\n" // y++... derpy, but it's the outer loop
01050      "cmp %[y], %[c]"            "\n"
01051      "bne mode2OuterLoop"       "\n" // if y != 88, loop
01052      
01053      : // outputs
01054        [c]"+l" (c),
01055        [t]"+l" (t),
01056        [x]"+l" (x),
01057        [y]"+h" (y),  // +:Read-Write l:lower (0-7) register
01058        [scrbuf]"+l" (scrbuf)
01059        
01060      : // inputs
01061        [LCD]"l" (0xA0002188),
01062        [scanline]"l" (scanline),
01063        [paletteptr]"l" (paletteptr),
01064        [byte]"l" (byte)
01065      : // clobbers
01066        "cc", "r10", "r11"
01067        );
01068 
01069  
01070 #else
01071 uint8_t* d = scrbuf;// point to beginning of line in data
01072 
01073   #ifdef PROJ_SHOW_FPS_COUNTER
01074   setDRAMptr(0, 8);
01075   wait_us(200); // Add wait to compensate skipping of 8 lines. Makes FPS counter to show the correct value.
01076   for(y=4;y<88;y++)
01077   #else
01078   for(y=0;y<88;y++)
01079   #endif
01080   {
01081 
01082 
01083     uint8_t s=0;
01084     for(x=0;x<110;x+=2)
01085     {
01086       uint8_t t = *d++;
01087       uint32_t color;
01088       color = uint32_t(paletteptr[t>>4])<<3;
01089       scanline[s]=*LCD=color;TGL_WR_OP(s++);TGL_WR;
01090       color = uint32_t(paletteptr[t&0xF])<<3;
01091       scanline[s]=*LCD=color;TGL_WR_OP(s++);TGL_WR;
01092     }
01093 
01094     s=0;
01095     for (s=0;s<110;) {
01096       *LCD = (scanline[s]);TGL_WR_OP(s++);TGL_WR;
01097       *LCD = (scanline[s]);TGL_WR_OP(s++);TGL_WR;
01098       *LCD = (scanline[s]);TGL_WR_OP(s++);TGL_WR;
01099       *LCD = (scanline[s]);TGL_WR_OP(s++);TGL_WR;
01100       *LCD = (scanline[s]);TGL_WR_OP(s++);TGL_WR;
01101       *LCD = (scanline[s]);TGL_WR_OP(s++);TGL_WR;
01102       *LCD = (scanline[s]);TGL_WR_OP(s++);TGL_WR;
01103       *LCD = (scanline[s]);TGL_WR_OP(s++);TGL_WR;
01104       *LCD = (scanline[s]);TGL_WR_OP(s++);TGL_WR;
01105       *LCD = (scanline[s]);TGL_WR_OP(s++);TGL_WR;
01106     }
01107 
01108   }
01109 #endif
01110 
01111  CLR_MASK_P2;
01112 }
01113 
01114 void Pokitto::lcdRefreshMode3(uint8_t * scrbuf, uint16_t* paletteptr) {
01115 uint16_t x,y;
01116 uint16_t scanline[2][176]; // read two nibbles = pixels at a time
01117 uint8_t *d;
01118 
01119 write_command(0x20);  // Horizontal DRAM Address
01120 write_data(0);  // 0
01121 write_command(0x21);  // Vertical DRAM Address
01122 write_data(0);
01123 write_command(0x22); // write data to DRAM
01124 CLR_CS_SET_CD_RD_WR;
01125 
01126 for(x=0;x<220;x+=2)
01127   {
01128     d = scrbuf+(x>>1);// point to beginning of line in data
01129     /** find colours in one scanline **/
01130     uint8_t s=0;
01131     for(y=0;y<176;y++)
01132     {
01133     uint8_t t = *d >> 4; // higher nibble
01134     uint8_t t2 = *d & 0xF; // lower nibble
01135     /** higher nibble = left pixel in pixel pair **/
01136     scanline[0][s] = paletteptr[t];
01137     scanline[1][s++] = paletteptr[t2];
01138     /** testing only **/
01139     //scanline[0][s] = 0xFFFF*(s&1);
01140     //scanline[1][s] = 0xFFFF*(!(s&1));
01141     //s++;
01142     /** until here **/
01143     d+=220/2; // jump to read byte directly below in screenbuffer
01144     }
01145     s=0;
01146     /** draw scanlines **/
01147     /** leftmost scanline**/
01148 
01149     #ifdef PROJ_SHOW_FPS_COUNTER
01150     if (x<8) continue;
01151     setDRAMptr(x, 0);
01152     #endif
01153 
01154     for (s=0;s<176;) {
01155         setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
01156         setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
01157         setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
01158         setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
01159         setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
01160         setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
01161         setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
01162         setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
01163     }
01164 
01165     /** rightmost scanline**/
01166     //setDRAMptr(xptr++,yoffset);
01167     for (s=0;s<176;) {
01168         setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
01169         setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
01170         setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
01171         setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
01172         setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
01173         setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
01174         setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
01175         setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
01176     }
01177   }
01178 }
01179 
01180 void Pokitto::lcdRefreshGB(uint8_t * scrbuf, uint16_t* paletteptr) {
01181 uint16_t x,y;
01182 uint16_t scanline[48];
01183 uint8_t * d;
01184 
01185 #if POK_STRETCH
01186 //uint16_t xptr = 8;
01187 #else
01188 //xptr = 26;
01189 #endif
01190 
01191 write_command(0x20);  // Horizontal DRAM Address
01192 write_data(0);  // 0
01193 write_command(0x21);  // Vertical DRAM Address
01194 write_data(0);
01195 write_command(0x22); // write data to DRAM
01196 CLR_CS_SET_CD_RD_WR;
01197 
01198 /** draw border **/
01199     for (int s=0;s<5*176;) {
01200             setup_data_16(COLOR_BLACK);CLR_WR;SET_WR;s++;
01201     }
01202 
01203 for(x=0;x<84;x++)
01204   {
01205 
01206         d = scrbuf + x;// point to beginning of line in data
01207 
01208         /** find colours in one scanline **/
01209         uint8_t s=0;
01210         for(y=0;y<6;y++)
01211             {
01212             uint8_t t = *d;
01213             #if POK_COLORDEPTH > 1
01214             uint8_t t2 = *(d+504);
01215             #endif
01216             #if POK_COLORDEPTH > 2
01217             uint8_t t3 = *(d+504+504);
01218             #endif
01219             #if POK_COLORDEPTH > 3
01220             uint8_t t4 = *(d+504+504+504);
01221             #endif
01222             uint8_t paletteindex = 0;
01223 
01224             /** bit 1 **/
01225             #if POK_COLORDEPTH == 1
01226             paletteindex = (t & 0x1);
01227             #elif POK_COLORDEPTH == 2
01228             paletteindex = ((t & 0x1)) | ((t2 & 0x01)<<1);
01229             #elif POK_COLORDEPTH == 3
01230             paletteindex = (t & 0x1) | ((t2 & 0x1)<<1) | ((t3 & 0x1)<<2);
01231             #elif POK_COLORDEPTH == 4
01232             paletteindex = (t & 0x1) | ((t2 & 0x1)<<1) | ((t3 & 0x1)<<2) | ((t4 & 0x1)<<3);
01233             #endif
01234             scanline[s++] = paletteptr[paletteindex];
01235 
01236             /** bit 2 **/
01237             #if POK_COLORDEPTH == 1
01238             paletteindex = (t & 0x2)>>1;
01239             #elif POK_COLORDEPTH == 2
01240             paletteindex = ((t & 0x2)>>1) | ((t2 & 0x02));
01241             #elif POK_COLORDEPTH == 3
01242             paletteindex = ((t & 0x2)>>1) | ((t2 & 0x2)) | ((t3 & 0x2)<<1);
01243             #elif POK_COLORDEPTH == 4
01244             paletteindex = ((t & 0x2)>>1) | ((t2 & 0x2)) | ((t3 & 0x2)<<1) | ((t4 & 0x2)<<2);
01245             #endif
01246             scanline[s++] = paletteptr[paletteindex];
01247 
01248             /** bit 3 **/
01249             #if POK_COLORDEPTH == 1
01250             paletteindex = (t & 0x4)>>2;
01251             #elif POK_COLORDEPTH == 2
01252             paletteindex = ((t & 4)>>2) | ((t2 & 0x04)>>1);
01253             #elif POK_COLORDEPTH == 3
01254             paletteindex = ((t & 0x4)>>2) | ((t2 & 0x4)>>1) | (t3 & 0x4);
01255             #elif POK_COLORDEPTH == 4
01256             paletteindex = ((t & 0x4)>>2) | ((t2 & 0x4)>>1) | (t3 & 0x4) | ((t4 & 0x4)<<1);
01257             #endif
01258             scanline[s++] = paletteptr[paletteindex];
01259 
01260             /** bit 4 **/
01261             #if POK_COLORDEPTH == 1
01262             paletteindex = (t & 0x8)>>3;
01263             #elif POK_COLORDEPTH == 2
01264             paletteindex = ((t & 0x8)>>3) | ((t2 & 0x08)>>2);
01265             #elif POK_COLORDEPTH == 3
01266             paletteindex = ((t & 0x8)>>3) | ((t2 & 0x8)>>2) | ((t3 & 0x8)>>1);
01267             #elif POK_COLORDEPTH == 4
01268             paletteindex = ((t & 0x8)>>3) | ((t2 & 0x8)>>2) | ((t3 & 0x8)>>1) | (t4 & 0x8);
01269             #endif
01270             scanline[s++] = paletteptr[paletteindex];
01271 
01272             /** bit 5 **/
01273             #if POK_COLORDEPTH == 1
01274             paletteindex = (t & 0x10)>>4;
01275             #elif POK_COLORDEPTH == 2
01276             paletteindex = ((t & 0x10)>>4) | ((t2 & 0x10)>>3);
01277             #elif POK_COLORDEPTH == 3
01278             paletteindex = ((t & 0x10)>>4) | ((t2 & 0x10)>>3) | ((t3 & 0x10)>>2);
01279             #elif POK_COLORDEPTH == 4
01280             paletteindex = ((t & 0x10)>>4) | ((t2 & 0x10)>>3) | ((t3 & 0x10)>>2) | ((t4 & 0x10)>>1);
01281             #endif
01282             scanline[s++] = paletteptr[paletteindex];
01283 
01284             /** bit 6 **/
01285             #if POK_COLORDEPTH == 1
01286             paletteindex = (t & 0x20)>>5;
01287             #elif POK_COLORDEPTH == 2
01288             paletteindex = ((t & 0x20)>>5) | ((t2 & 0x20)>>4);
01289             #elif POK_COLORDEPTH == 3
01290             paletteindex = ((t & 0x20)>>5) | ((t2 & 0x20)>>4) | ((t3 & 0x20)>>3);
01291             #elif POK_COLORDEPTH == 4
01292             paletteindex = ((t & 0x20)>>5) | ((t2 & 0x20)>>4) | ((t3 & 0x20)>>3) | ((t4 & 0x20)>>2);
01293             #endif
01294             scanline[s++] = paletteptr[paletteindex];
01295 
01296             /** bit 7 **/
01297             #if POK_COLORDEPTH == 1
01298             paletteindex = (t & 0x40)>>6;
01299             #elif POK_COLORDEPTH == 2
01300             paletteindex = ((t & 0x40)>>6) | ((t2 & 0x40)>>5);
01301             #elif POK_COLORDEPTH == 3
01302             paletteindex = ((t & 0x40)>>6) | ((t2 & 0x40)>>5) | ((t3 & 0x40)>>4) ;
01303             #elif POK_COLORDEPTH == 4
01304             paletteindex = ((t & 0x40)>>6) | ((t2 & 0x40)>>5) | ((t3 & 0x40)>>4) | ((t4 & 0x40)>>3);
01305             #endif
01306             scanline[s++] = paletteptr[paletteindex];
01307 
01308             /** bit 8 **/
01309             #if POK_COLORDEPTH == 1
01310             paletteindex = (t & 0x80)>>7;
01311             #elif POK_COLORDEPTH == 2
01312             paletteindex = ((t & 0x80)>>7) | ((t2 & 0x80)>>6);
01313             #elif POK_COLORDEPTH == 3
01314             paletteindex = ((t & 0x80)>>7) | ((t2 & 0x80)>>6) | ((t3 & 0x80)>>5);
01315             #elif POK_COLORDEPTH == 4
01316             paletteindex = ((t & 0x80)>>7) | ((t2 & 0x80)>>6) | ((t3 & 0x80)>>5) | ((t4 & 0x80)>>4);
01317             #endif
01318             scanline[s++] = paletteptr[paletteindex];
01319 
01320             d+=84; // jump to byte directly below
01321             }
01322 
01323 
01324         /*write_command(0x20);  // Horizontal DRAM Address
01325         write_data(0x10);  // 0
01326         write_command(0x21);  // Vertical DRAM Address
01327         write_data(xptr++);
01328         write_command(0x22); // write data to DRAM
01329         CLR_CS_SET_CD_RD_WR;*/
01330         /** draw border **/
01331         setup_data_16(COLOR_BLACK);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;        CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
01332 
01333         s=0;
01334 
01335         /** draw scanlines **/
01336         for (s=0;s<48;) {
01337             setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
01338             setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
01339             setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
01340             setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
01341             setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
01342             setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
01343             setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
01344             setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
01345         }
01346         /** draw border **/
01347         setup_data_16(COLOR_BLACK);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;        CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
01348 
01349 
01350         /*write_command(0x20);  // Horizontal DRAM Address
01351         write_data(0x10);  // 0
01352         write_command(0x21);  // Vertical DRAM Address
01353         write_data(xptr++);
01354         write_command(0x22); // write data to DRAM
01355         CLR_CS_SET_CD_RD_WR;*/
01356         /** draw border **/
01357         setup_data_16(COLOR_BLACK);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;        CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
01358 
01359         for (s=0;s<48;) {
01360             setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
01361             setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
01362             setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
01363             setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
01364             setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
01365             setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
01366             setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
01367             setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
01368         }
01369 
01370         /** draw border **/
01371         setup_data_16(COLOR_BLACK);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;        CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
01372 
01373 
01374         #if POK_STRETCH
01375         //if (x>16 && x<68)
01376         if (x&2)// && x&2)
01377         {
01378             /*write_command(0x20);  // Horizontal DRAM Address
01379             write_data(0x10);  // 0
01380             write_command(0x21);  // Vertical DRAM Address
01381             write_data(xptr++);
01382             write_command(0x22); // write data to DRAM
01383             CLR_CS_SET_CD_RD_WR;*/
01384             /** draw border **/
01385         setup_data_16(COLOR_BLACK);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;        CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
01386 
01387 
01388             for (s=0;s<48;) {
01389             setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
01390             setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
01391             setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
01392             setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
01393             setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
01394             setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
01395             setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
01396             setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
01397             }
01398 
01399             /** draw border **/
01400         setup_data_16(COLOR_BLACK);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;        CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
01401 
01402         }
01403         #endif
01404     }
01405     /** draw border **/
01406     for (int s=0;s<5*176;) {
01407             setup_data_16(COLOR_BLACK);CLR_WR;SET_WR;s++;
01408     }
01409 }
01410 
01411 
01412 void Pokitto::lcdRefreshAB(uint8_t * scrbuf, uint16_t* paletteptr) {
01413 uint16_t x,y;
01414 uint16_t scanline[64];
01415 uint8_t *d;
01416 //lcdClear();
01417 #if POK_STRETCH
01418 uint16_t xptr = 14;
01419 uint8_t yoffset = 24;
01420 #else
01421 uint16_t xptr = 0;
01422 uint8_t yoffset = 0;
01423 #endif
01424 
01425 for(x=0;x<128;x++)
01426   {
01427     write_command(0x20);  // Horizontal DRAM Address
01428     write_data(yoffset);  // 0
01429     write_command(0x21);  // Vertical DRAM Address
01430     write_data(xptr++);
01431     write_command(0x22); // write data to DRAM
01432     CLR_CS_SET_CD_RD_WR;
01433     //setDRAMptr(xptr++,yoffset);
01434 
01435         d = scrbuf + x;// point to beginning of line in data
01436 
01437         /** find colours in one scanline **/
01438         uint8_t s=0;
01439         for(y=0;y<8;y++)
01440             {
01441             uint8_t t = *d;
01442             #if POK_COLORDEPTH > 1
01443             uint8_t t2 = *(d+AB_JUMP);
01444             #endif // POK_COLORDEPTH
01445             #if POK_COLORDEPTH > 2
01446             uint8_t t3 = *(d+AB_JUMP+AB_JUMP);
01447             #endif // POK_COLORDEPTH
01448             #if POK_COLORDEPTH > 3
01449             uint8_t t4 = *(d+AB_JUMP+AB_JUMP+AB_JUMP);
01450             #endif // POK_COLORDEPTH
01451             uint8_t paletteindex = 0;
01452 
01453             /** bit 1 **/
01454             #if POK_COLORDEPTH == 1
01455             paletteindex = (t & 0x1);
01456             #elif POK_COLORDEPTH == 2
01457             paletteindex = ((t & 0x1)) | ((t2 & 0x01)<<1);
01458             #elif POK_COLORDEPTH == 3
01459             paletteindex = (t & 0x1) | ((t2 & 0x1)<<1) | ((t3 & 0x1)<<2);
01460             #elif POK_COLORDEPTH == 4
01461             paletteindex = (t & 0x1) | ((t2 & 0x1)<<1) | ((t3 & 0x1)<<2) | ((t4 & 0x1)<<3);
01462             #endif
01463             scanline[s++] = paletteptr[paletteindex];
01464 
01465             /** bit 2 **/
01466             #if POK_COLORDEPTH == 1
01467             paletteindex = (t & 0x2)>>1;
01468             #elif POK_COLORDEPTH == 2
01469             paletteindex = ((t & 0x2)>>1) | ((t2 & 0x02));
01470             #elif POK_COLORDEPTH == 3
01471             paletteindex = ((t & 0x2)>>1) | ((t2 & 0x2)) | ((t3 & 0x2)<<1);
01472             #elif POK_COLORDEPTH == 4
01473             paletteindex = ((t & 0x2)>>1) | ((t2 & 0x2)) | ((t3 & 0x2)<<1) | ((t4 & 0x2)<<2);
01474             #endif
01475             scanline[s++] = paletteptr[paletteindex];
01476 
01477             /** bit 3 **/
01478             #if POK_COLORDEPTH == 1
01479             paletteindex = (t & 0x4)>>2;
01480             #elif POK_COLORDEPTH == 2
01481             paletteindex = ((t & 4)>>2) | ((t2 & 0x04)>>1);
01482             #elif POK_COLORDEPTH == 3
01483             paletteindex = ((t & 0x4)>>2) | ((t2 & 0x4)>>1) | (t3 & 0x4);
01484             #elif POK_COLORDEPTH == 4
01485             paletteindex = ((t & 0x4)>>2) | ((t2 & 0x4)>>1) | (t3 & 0x4) | ((t4 & 0x4)<<1);
01486             #endif
01487             scanline[s++] = paletteptr[paletteindex];
01488 
01489             /** bit 4 **/
01490             #if POK_COLORDEPTH == 1
01491             paletteindex = (t & 0x8)>>3;
01492             #elif POK_COLORDEPTH == 2
01493             paletteindex = ((t & 0x8)>>3) | ((t2 & 0x08)>>2);
01494             #elif POK_COLORDEPTH == 3
01495             paletteindex = ((t & 0x8)>>3) | ((t2 & 0x8)>>2) | ((t3 & 0x8)>>1);
01496             #elif POK_COLORDEPTH == 4
01497             paletteindex = ((t & 0x8)>>3) | ((t2 & 0x8)>>2) | ((t3 & 0x8)>>1) | (t4 & 0x8);
01498             #endif
01499             scanline[s++] = paletteptr[paletteindex];
01500 
01501             /** bit 5 **/
01502             #if POK_COLORDEPTH == 1
01503             paletteindex = (t & 0x10)>>4;
01504             #elif POK_COLORDEPTH == 2
01505             paletteindex = ((t & 0x10)>>4) | ((t2 & 0x10)>>3);
01506             #elif POK_COLORDEPTH == 3
01507             paletteindex = ((t & 0x10)>>4) | ((t2 & 0x10)>>3) | ((t3 & 0x10)>>2);
01508             #elif POK_COLORDEPTH == 4
01509             paletteindex = ((t & 0x10)>>4) | ((t2 & 0x10)>>3) | ((t3 & 0x10)>>2) | ((t4 & 0x10)>>1);
01510             #endif
01511             scanline[s++] = paletteptr[paletteindex];
01512 
01513             /** bit 6 **/
01514             #if POK_COLORDEPTH == 1
01515             paletteindex = (t & 0x20)>>5;
01516             #elif POK_COLORDEPTH == 2
01517             paletteindex = ((t & 0x20)>>5) | ((t2 & 0x20)>>4);
01518             #elif POK_COLORDEPTH == 3
01519             paletteindex = ((t & 0x20)>>5) | ((t2 & 0x20)>>4) | ((t3 & 0x20)>>3);
01520             #elif POK_COLORDEPTH == 4
01521             paletteindex = ((t & 0x20)>>5) | ((t2 & 0x20)>>4) | ((t3 & 0x20)>>3) | ((t4 & 0x20)>>2);
01522             #endif
01523             scanline[s++] = paletteptr[paletteindex];
01524 
01525             /** bit 7 **/
01526             #if POK_COLORDEPTH == 1
01527             paletteindex = (t & 0x40)>>6;
01528             #elif POK_COLORDEPTH == 2
01529             paletteindex = ((t & 0x40)>>6) | ((t2 & 0x40)>>5);
01530             #elif POK_COLORDEPTH == 3
01531             paletteindex = ((t & 0x40)>>6) | ((t2 & 0x40)>>5) | ((t3 & 0x40)>>4) ;
01532             #elif POK_COLORDEPTH == 4
01533             paletteindex = ((t & 0x40)>>6) | ((t2 & 0x40)>>5) | ((t3 & 0x40)>>4) | ((t4 & 0x40)>>3);
01534             #endif
01535             scanline[s++] = paletteptr[paletteindex];
01536 
01537             /** bit 8 **/
01538             #if POK_COLORDEPTH == 1
01539             paletteindex = (t & 0x80)>>7;
01540             #elif POK_COLORDEPTH == 2
01541             paletteindex = ((t & 0x80)>>7) | ((t2 & 0x80)>>6);
01542             #elif POK_COLORDEPTH == 3
01543             paletteindex = ((t & 0x80)>>7) | ((t2 & 0x80)>>6) | ((t3 & 0x80)>>5);
01544             #elif POK_COLORDEPTH == 4
01545             paletteindex = ((t & 0x80)>>7) | ((t2 & 0x80)>>6) | ((t3 & 0x80)>>5) | ((t4 & 0x80)>>4);
01546             #endif
01547             scanline[s++] = paletteptr[paletteindex];
01548 
01549             d+=128; // jump to byte directly below
01550             }
01551 
01552         s=0;
01553 
01554         /** draw scanlines **/
01555         for (s=0;s<64;) {
01556             setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
01557             setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
01558             setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
01559             setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
01560             setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
01561             setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
01562             setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
01563             setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
01564         }
01565 
01566         #if POK_STRETCH
01567         if (x&1) {
01568         write_command(0x20);  // Horizontal DRAM Address
01569         write_data(yoffset);  // 0
01570         write_command(0x21);  // Vertical DRAM Address
01571         write_data(xptr++);
01572         write_command(0x22); // write data to DRAM
01573         CLR_CS_SET_CD_RD_WR;
01574         //setDRAMptr(xptr++,yoffset);
01575 
01576         for (s=0;s<64;) {
01577             setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
01578             setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
01579             setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
01580             setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
01581             setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
01582             setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
01583             setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
01584             setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
01585         }
01586         }
01587         #endif
01588     }
01589 }
01590 
01591 void Pokitto::lcdRefreshModeGBC(uint8_t * scrbuf, uint16_t* paletteptr) {
01592 uint16_t x,y,xptr;
01593 uint16_t scanline[4][144]; // read 4 half-nibbles = 4 pixels at a time
01594 uint8_t *d, yoffset=0;
01595 
01596 xptr = 0;
01597 setDRAMptr(xptr,yoffset);
01598 
01599 
01600 for(x=0;x<160;x+=4)
01601   {
01602     d = scrbuf+(x>>2);// point to beginning of line in data
01603     /** find colours in one scanline **/
01604     uint8_t s=0;
01605     for(y=0;y<144;y++)
01606     {
01607     uint8_t tdata = *d;
01608     uint8_t t4 = tdata & 0x03; tdata >>= 2;// lowest half-nibble
01609     uint8_t t3 = tdata & 0x03; tdata >>= 2;// second lowest half-nibble
01610     uint8_t t2 = tdata & 0x03; tdata >>= 2;// second highest half-nibble
01611     uint8_t t = tdata & 0x03;// highest half-nibble
01612 
01613     /** put nibble values in the scanlines **/
01614 
01615     scanline[0][s] = paletteptr[t];
01616     scanline[1][s] = paletteptr[t2];
01617     scanline[2][s] = paletteptr[t3];
01618     scanline[3][s++] = paletteptr[t4];
01619 
01620      d+=160/4; // jump to read byte directly below in screenbuffer
01621     }
01622 
01623     s=0;
01624     /** draw scanlines **/
01625     for (s=0;s<144;) {
01626         setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
01627         setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
01628         setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
01629         setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
01630         setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
01631         setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
01632     }
01633     setDRAMptr(++xptr,yoffset);
01634     for (s=0;s<144;) {
01635         setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
01636         setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
01637         setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
01638         setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
01639         setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
01640         setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
01641     }
01642     setDRAMptr(++xptr,yoffset);
01643     for (s=0;s<144;) {
01644         setup_data_16(scanline[2][s++]);CLR_WR;SET_WR;
01645         setup_data_16(scanline[2][s++]);CLR_WR;SET_WR;
01646         setup_data_16(scanline[2][s++]);CLR_WR;SET_WR;
01647         setup_data_16(scanline[2][s++]);CLR_WR;SET_WR;
01648         setup_data_16(scanline[2][s++]);CLR_WR;SET_WR;
01649         setup_data_16(scanline[2][s++]);CLR_WR;SET_WR;
01650     }
01651     setDRAMptr(++xptr,yoffset);
01652     for (s=0;s<144;) {
01653         setup_data_16(scanline[3][s++]);CLR_WR;SET_WR;
01654         setup_data_16(scanline[3][s++]);CLR_WR;SET_WR;
01655         setup_data_16(scanline[3][s++]);CLR_WR;SET_WR;
01656         setup_data_16(scanline[3][s++]);CLR_WR;SET_WR;
01657         setup_data_16(scanline[3][s++]);CLR_WR;SET_WR;
01658         setup_data_16(scanline[3][s++]);CLR_WR;SET_WR;
01659     }
01660     setDRAMptr(++xptr,yoffset);
01661   }
01662 }
01663 
01664 
01665 void Pokitto::lcdRefreshT1(uint8_t* tilebuf, uint8_t* tilecolorbuf, uint8_t* tileset, uint16_t* paletteptr) {
01666 #ifdef POK_TILEMODE
01667 uint16_t x,y,data,xptr;
01668 uint16_t scanline[176];
01669 uint8_t yoffset=0, tilebyte, tileindex, tilex=0, tiley=0,xcount;
01670 
01671 
01672 if (!tileset) return;
01673 
01674 #if LCDWIDTH < POK_LCD_W
01675 xptr = (POK_LCD_W-LCDWIDTH)/2;
01676 #else
01677 xptr = 0;
01678 #endif
01679 #if LCDHEIGHT < POK_LCD_H
01680 yoffset = (POK_LCD_H-LCDHEIGHT)/2;
01681 #else
01682 yoffset = 0;
01683 #endif
01684 
01685 for(x=0, xcount=0 ;x<LCDWIDTH;x++,xcount++)  // loop through vertical columns
01686   {
01687     setDRAMptr(xptr++,yoffset); //point to VRAM
01688 
01689         /** find colours in one scanline **/
01690         uint8_t s=0, tiley=0;
01691         //tileindex = tilebuf[tilex*POK_TILES_Y];
01692         if (xcount==POK_TILE_W) {
01693             tilex++;
01694             xcount=0;
01695         }
01696 
01697         for(y=0;y<LCDHEIGHT;)
01698         {
01699             uint8_t tileval = tilebuf[tilex+tiley*POK_TILES_X]; //get tile number
01700             uint16_t index = tileval*POK_TILE_W+xcount;
01701             uint8_t tilebyte = tileset[index]; //get bitmap data
01702             for (uint8_t ycount=0, bitcount=0; ycount<POK_TILE_H; ycount++, y++, bitcount++) {
01703                 if (bitcount==8) {
01704                     bitcount=0;
01705                     index += 176; //jump to byte below in the tileset bitmap
01706                     tilebyte = tileset[index]; //get bitmap data
01707                 }
01708                 //tilebyte = tile[(tileindex>>4)+*POK_TILE_W]; //tilemaps are 16x16
01709                 //uint8_t paletteindex = ((tilebyte>>(bitcount&0x7)) & 0x1);
01710                 if (!tileval) scanline[s++] = COLOR_MAGENTA*((tilebyte>>bitcount)&0x1);//paletteptr[paletteindex];
01711                 else scanline[s++] = paletteptr[((tilebyte>>bitcount)&0x1)*tileval];//paletteptr[paletteindex];
01712             }
01713             tiley++; //move to next tile
01714         }
01715         s=0;
01716 
01717         /** draw scanlines **/
01718         for (s=0;s<LCDHEIGHT;) {
01719             setup_data_16(scanline[s++]);CLR_WR;SET_WR;
01720         }
01721     }
01722     #endif
01723 }
01724 
01725 #define MODE13_INNER_LOOP_A                     \
01726   " ldrb %[t], [%[scrbuf],0]"   "\n"                \
01727            "    add %[t], %[t], %[offset]"  "\n"        \
01728            "    uxtb %[c], %[t] " "\n"              \
01729            "    lsls %[c], 1"             "\n"          \
01730            "    ldrh %[t], [%[paletteptr], %[c]]"      "\n" \
01731            "    lsls %[t], %[t], 3"       "\n"          \
01732            "    str %[t], [%[LCD], 0]"    "\n"          \
01733            "    mov %[c], r11" "\n"             \
01734            "    str %[c], [%[LCD], 124]"  "\n"          \
01735            "    stm %[scanline]!, {%[t]}" "\n"          \
01736            "    movs %[t], 252"   "\n"              \
01737            "    str %[c], [%[LCD], %[t]]" "\n"          \
01738            "    str %[c], [%[LCD], 124]"  "\n"          \
01739            "    adds %[scrbuf], %[scrbuf], 1" "\n"      \
01740            "    str %[c], [%[LCD], %[t]]" "\n"
01741   
01742 #define MODE13_INNER_LOOP_B             \
01743   " ldm %[scanline]!, {%[c]}"   "\n"        \
01744            "    str %[c], [%[LCD], 0]"    "\n"  \
01745            "    str %[t], [%[LCD], 124]"  "\n"  \
01746            "    movs %[c], 252"   "\n"      \
01747            "    str %[t], [%[LCD], %[c]]" "\n"  \
01748            "    str %[t], [%[LCD], 124]"  "\n"  \
01749            "    subs %[x], 1"             "\n"  \
01750            "    str %[t], [%[LCD], %[c]]" "\n"  \
01751 
01752  
01753  void Pokitto::lcdRefreshMode13(uint8_t * scrbuf, uint16_t* paletteptr, uint8_t offset){
01754    uint32_t scanline[110]; // read two nibbles = pixels at a time
01755    
01756    write_command_16(0x03); write_data_16(0x1038);
01757    write_command(0x20); write_data(0);
01758    write_command(0x21); write_data(1);
01759    write_command(0x22);
01760    CLR_CS_SET_CD_RD_WR;
01761    SET_MASK_P2;
01762    
01763    uint32_t x, y=0;
01764    
01765 #ifndef __ARMCC_VERSION
01766    asm volatile(
01767      ".syntax unified"         "\n"
01768      
01769      "mov r10, %[scanline]"    "\n"
01770      
01771      "movs %[t], 1"            "\n"
01772      "lsls %[t], %[t], 12"     "\n"
01773      "mov r11, %[t]"           "\n"
01774      
01775      "mode13OuterLoop:"        "\n"
01776      
01777      "movs %[x], 110"          "\n"
01778      "mode13InnerLoopA:"
01779      MODE13_INNER_LOOP_A
01780      MODE13_INNER_LOOP_A
01781      "  subs %[x], 2"          "\n" 
01782      "  bne mode13InnerLoopA"  "\n"
01783 
01784      "mov %[scanline], r10"    "\n"
01785      "movs %[x], 110"          "\n"
01786      "mov %[t], r11"           "\n"
01787      "mode13InnerLoopB:"
01788      MODE13_INNER_LOOP_B     
01789      MODE13_INNER_LOOP_B     
01790      MODE13_INNER_LOOP_B     
01791      MODE13_INNER_LOOP_B     
01792      MODE13_INNER_LOOP_B     
01793      MODE13_INNER_LOOP_B     
01794      MODE13_INNER_LOOP_B     
01795      MODE13_INNER_LOOP_B     
01796      MODE13_INNER_LOOP_B     
01797      MODE13_INNER_LOOP_B     
01798      "  bne mode13InnerLoopB"     "\n"
01799      
01800      "mov %[scanline], r10"    "\n"
01801      "movs %[t], 1"              "\n"
01802      "movs %[c], 88"             "\n"
01803      "add %[y], %[t]"            "\n" // y++... derpy, but it's the outer loop
01804      "cmp %[y], %[c]"            "\n"
01805      "bne mode13OuterLoop"       "\n" // if y != 88, loop
01806      
01807      : // outputs
01808        [c]"+l" (c),
01809        [t]"+l" (t),
01810        [x]"+l" (x),
01811        [y]"+h" (y),  // +:Read-Write l:lower (0-7) register
01812        [scrbuf]"+l" (scrbuf)
01813        
01814      : // inputs
01815        [LCD]"l" (0xA0002188),
01816        [scanline]"l" (scanline),
01817        [paletteptr]"l" (paletteptr),
01818        [offset]"l" (offset)
01819      : // clobbers
01820        "cc", "r10", "r11"
01821        );
01822 
01823 #else
01824    uint8_t* d = scrbuf;// point to beginning of line in data
01825    for(y=0;y<88;y++){
01826      
01827      uint32_t* s = scanline;
01828      
01829      for(x=0;x<110;x+=10){
01830        *LCD = *s = paletteptr[(*d + offset)&255]<<3; TGL_WR_OP(s++);TGL_WR_OP(d++); 
01831        *LCD = *s = paletteptr[(*d + offset)&255]<<3; TGL_WR_OP(s++);TGL_WR_OP(d++); 
01832        *LCD = *s = paletteptr[(*d + offset)&255]<<3; TGL_WR_OP(s++);TGL_WR_OP(d++); 
01833        *LCD = *s = paletteptr[(*d + offset)&255]<<3; TGL_WR_OP(s++);TGL_WR_OP(d++); 
01834        *LCD = *s = paletteptr[(*d + offset)&255]<<3; TGL_WR_OP(s++);TGL_WR_OP(d++); 
01835        *LCD = *s = paletteptr[(*d + offset)&255]<<3; TGL_WR_OP(s++);TGL_WR_OP(d++); 
01836        *LCD = *s = paletteptr[(*d + offset)&255]<<3; TGL_WR_OP(s++);TGL_WR_OP(d++); 
01837        *LCD = *s = paletteptr[(*d + offset)&255]<<3; TGL_WR_OP(s++);TGL_WR_OP(d++); 
01838        *LCD = *s = paletteptr[(*d + offset)&255]<<3; TGL_WR_OP(s++);TGL_WR_OP(d++); 
01839        *LCD = *s = paletteptr[(*d + offset)&255]<<3; TGL_WR_OP(s++);TGL_WR_OP(d++); 
01840      }
01841      
01842      s = scanline;
01843      uint32_t c = *s;
01844      for(x=0;x<110;x+=10){
01845        *LCD = c; TGL_WR_OP(s++);TGL_WR_OP(c=*s);
01846        *LCD = c; TGL_WR_OP(s++);TGL_WR_OP(c=*s);
01847        *LCD = c; TGL_WR_OP(s++);TGL_WR_OP(c=*s);
01848        *LCD = c; TGL_WR_OP(s++);TGL_WR_OP(c=*s);
01849        *LCD = c; TGL_WR_OP(s++);TGL_WR_OP(c=*s);
01850        *LCD = c; TGL_WR_OP(s++);TGL_WR_OP(c=*s);
01851        *LCD = c; TGL_WR_OP(s++);TGL_WR_OP(c=*s);
01852        *LCD = c; TGL_WR_OP(s++);TGL_WR_OP(c=*s);
01853        *LCD = c; TGL_WR_OP(s++);TGL_WR_OP(c=*s);
01854        *LCD = c; TGL_WR_OP(s++);TGL_WR_OP(c=*s);
01855      }
01856    
01857    }
01858 #endif
01859  }
01860 
01861 void Pokitto::lcdRefreshMode14(uint8_t * scrbuf, uint16_t* paletteptr) {
01862 uint16_t x,y;
01863 uint16_t scanline[176]; uint16_t* scptr;
01864 uint8_t *d;
01865 
01866 write_command(0x20); write_data(0);
01867 write_command(0x21); write_data(0);
01868 write_command(0x22);
01869 CLR_CS_SET_CD_RD_WR;
01870 
01871 for(x=0;x<220;x++)
01872   {
01873         d = scrbuf+x;
01874         scptr = &scanline[0];
01875 
01876         /** find colours in one scanline **/
01877         /*for(y=0;y<22;y++)
01878             {
01879 
01880             uint16_t t = *d;
01881             uint16_t t2 = *(d+POK_BITFRAME);
01882             uint16_t t3 = *(d+POK_BITFRAME+POK_BITFRAME);
01883 
01884             *scptr++ = (t & 0x1)*R_MASK | (t2 & 0x1)*G_MASK | (t3 & 0x1)*B_MASK; t >>= 1;t2 >>= 1;t3 >>= 1;
01885             *scptr++ = (t & 0x1)*R_MASK | (t2 & 0x1)*G_MASK | (t3 & 0x1)*B_MASK; t >>= 1;t2 >>= 1;t3 >>= 1;
01886             *scptr++ = (t & 0x1)*R_MASK | (t2 & 0x1)*G_MASK | (t3 & 0x1)*B_MASK; t >>= 1;t2 >>= 1;t3 >>= 1;
01887             *scptr++ = (t & 0x1)*R_MASK | (t2 & 0x1)*G_MASK | (t3 & 0x1)*B_MASK; t >>= 1;t2 >>= 1;t3 >>= 1;
01888 
01889             *scptr++ = (t & 0x1)*R_MASK | (t2 & 0x1)*G_MASK | (t3 & 0x1)*B_MASK; t >>= 1;t2 >>= 1;t3 >>= 1;
01890             *scptr++ = (t & 0x1)*R_MASK | (t2 & 0x1)*G_MASK | (t3 & 0x1)*B_MASK; t >>= 1;t2 >>= 1;t3 >>= 1;
01891             *scptr++ = (t & 0x1)*R_MASK | (t2 & 0x1)*G_MASK | (t3 & 0x1)*B_MASK; t >>= 1;t2 >>= 1;t3 >>= 1;
01892             *scptr++ = (t & 0x1)*R_MASK | (t2 & 0x1)*G_MASK | (t3 & 0x1)*B_MASK; t >>= 1;t2 >>= 1;t3 >>= 1;
01893 
01894 
01895             d+=220; // jump to word directly below
01896             }
01897         */
01898         /** alternative way: go through one color at a time **/
01899             scptr = &scanline[0]; // set to beginning of scanline
01900             for(y=0;y<22;y++, d +=220)
01901             {
01902             uint16_t t = *d & 0xFF;
01903 
01904             *scptr++ = R_MASK * (t&0x1); t >>= 1;
01905             *scptr++ = R_MASK * (t&0x1); t >>= 1;
01906             *scptr++ = R_MASK * (t&0x1); t >>= 1;
01907             *scptr++ = R_MASK * (t&0x1); t >>= 1;
01908             *scptr++ = R_MASK * (t&0x1); t >>= 1;
01909             *scptr++ = R_MASK * (t&0x1); t >>= 1;
01910             *scptr++ = R_MASK * (t&0x1); t >>= 1;
01911             *scptr++ = R_MASK * (t&0x1);
01912             }
01913             scptr = &scanline[0]; // set to beginning of scanline
01914             d = scrbuf+x+POK_BITFRAME;
01915             for(y=0;y<22;y++, d +=220)
01916             {
01917             uint16_t t = *d & 0xFF;
01918 
01919             *scptr++ |= G_MASK * (t&0x1); t >>= 1;
01920             *scptr++ |= G_MASK * (t&0x1); t >>= 1;
01921             *scptr++ |= G_MASK * (t&0x1); t >>= 1;
01922             *scptr++ |= G_MASK * (t&0x1); t >>= 1;
01923             *scptr++ |= G_MASK * (t&0x1); t >>= 1;
01924             *scptr++ |= G_MASK * (t&0x1); t >>= 1;
01925             *scptr++ |= G_MASK * (t&0x1); t >>= 1;
01926             *scptr++ |= G_MASK * (t&0x1);
01927             }
01928             scptr = &scanline[0]; // set to beginning of scanline
01929             d = scrbuf+x+POK_BITFRAME*2;
01930             for(y=0;y<22;y++, d +=220)
01931             {
01932             uint16_t t = *d & 0xFF;
01933 
01934             *scptr++ |= B_MASK * (t&0x1); t >>= 1;
01935             *scptr++ |= B_MASK * (t&0x1); t >>= 1;
01936             *scptr++ |= B_MASK * (t&0x1); t >>= 1;
01937             *scptr++ |= B_MASK * (t&0x1); t >>= 1;
01938             *scptr++ |= B_MASK * (t&0x1); t >>= 1;
01939             *scptr++ |= B_MASK * (t&0x1); t >>= 1;
01940             *scptr++ |= B_MASK * (t&0x1); t >>= 1;
01941             *scptr++ |= B_MASK * (t&0x1);
01942             }
01943 
01944 
01945         #ifdef PROJ_SHOW_FPS_COUNTER
01946         if (x<8) continue;
01947         setDRAMptr(x, 0);
01948         #endif
01949 
01950         /** draw scanlines **/
01951         for (int s=0;s<176;) {
01952             setup_data_16(scanline[s++]);CLR_WR;SET_WR;
01953             setup_data_16(scanline[s++]);CLR_WR;SET_WR;
01954             setup_data_16(scanline[s++]);CLR_WR;SET_WR;
01955             setup_data_16(scanline[s++]);CLR_WR;SET_WR;
01956             setup_data_16(scanline[s++]);CLR_WR;SET_WR;
01957             setup_data_16(scanline[s++]);CLR_WR;SET_WR;
01958             setup_data_16(scanline[s++]);CLR_WR;SET_WR;
01959             setup_data_16(scanline[s++]);CLR_WR;SET_WR;
01960 
01961         }
01962 
01963     }
01964 }
01965 
01966 //#define ADEKTOSMODE15
01967 
01968 #ifdef ADEKTOSMODE15
01969 void Pokitto::lcdRefreshMode15(uint16_t* pal, uint8_t* scrbuf){
01970     write_command(0x03); write_data(0x1038); //realy only need to call this once
01971     write_command(0x20); write_data(0);
01972     write_command(0x21); write_data(0);
01973 
01974     write_command(0x22);
01975 
01976     #ifdef PROJ_SHOW_FPS_COUNTER
01977     for (int x=0,xt=0; x<0x4BA0;x++,xt++) {
01978     if (xt==110) xt=0;
01979     if (xt<8) {
01980         write_data(0);
01981         write_data(0);
01982     } else {
01983         write_data(pal[(((scrbuf[x]) & 0xf0) >> 4)]);
01984         write_data(pal[( (scrbuf[x]) & 0x0f)]);
01985     }
01986 
01987     }
01988     #else
01989     for (int x=0; x<0x4BA0;x++) {
01990         write_data(pal[(((scrbuf[x]) & 0xf0) >> 4)]);
01991         write_data(pal[( (scrbuf[x]) & 0x0f)]);
01992     }
01993     #endif //PROJ_SHOW_FPS_COUNTER
01994 }
01995 
01996 #else
01997 
01998 void Pokitto::lcdRefreshMode15(uint16_t* paletteptr, uint8_t* scrbuf){
01999 uint16_t x,y;
02000 uint16_t scanline[2][176]; // read two nibbles = pixels at a time
02001 uint8_t *d;
02002 
02003 //setDRAMptr(xptr,yoffset);
02004 
02005 write_command(0x20); write_data(0);
02006 write_command(0x21); write_data(0);
02007 write_command(0x22);
02008 CLR_CS_SET_CD_RD_WR;
02009 
02010 for(x=0;x<220;x+=2)
02011   {
02012     d = scrbuf+(x>>1);// point to beginning of line in data
02013     // find colours in one scanline
02014     uint8_t s=0;
02015     for(y=0;y<176;y++)
02016     {
02017     uint8_t t = *d >> 4; // higher nibble
02018     uint8_t t2 = *d & 0xF; // lower nibble
02019     // higher nibble = left pixel in pixel pair
02020     scanline[0][s] = paletteptr[t];
02021     scanline[1][s++] = paletteptr[t2];
02022 
02023     d+=220/2; // jump to read byte directly below in screenbuffer
02024     }
02025     s=0;
02026     // draw scanlines
02027 
02028     #ifdef PROJ_SHOW_FPS_COUNTER
02029     if (x<8) continue;
02030     setDRAMptr(x, 0);
02031     #endif
02032 
02033     for (s=0;s<176;) {
02034         setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
02035         setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
02036         setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
02037         setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
02038         setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
02039         setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
02040         setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
02041         setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
02042     }
02043 
02044     for (s=0;s<176;) {
02045         setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
02046         setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
02047         setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
02048         setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
02049         setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
02050         setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
02051         setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
02052         setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
02053     }
02054   }
02055 }
02056 #endif //ADEKTOSMODE15
02057 
02058 void Pokitto::blitWord(uint16_t c) {
02059     setup_data_16(c);CLR_WR;SET_WR;
02060 }
02061 
02062