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

Dependents:   YATTT sd_map_test cPong SnowDemo ... more

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