From 5fc856c1811715f3f5855ed41318d4c7e7d6e643 Mon Sep 17 00:00:00 2001 From: Rani Hod Date: Sun, 13 Aug 2006 21:28:22 +0000 Subject: [PATCH] Accepted FS#5807 by Michael Sevakis - ASM optimized lcd_update(). git-svn-id: svn://svn.rockbox.org/rockbox/trunk@10564 a1c6a512-1295-4272-9138-f99709370657 --- firmware/SOURCES | 1 + .../target/coldfire/iaudio/x5/lcd-as-x5.S | 206 ++++++++++++++++++ firmware/target/coldfire/iaudio/x5/lcd-x5.c | 114 ++-------- 3 files changed, 221 insertions(+), 100 deletions(-) create mode 100644 firmware/target/coldfire/iaudio/x5/lcd-as-x5.S diff --git a/firmware/SOURCES b/firmware/SOURCES index fd83c05982..fda83ee073 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES @@ -236,6 +236,7 @@ target/coldfire/iaudio/x5/power-x5.c #ifndef SIMULATOR drivers/generic_i2c.c target/coldfire/iaudio/x5/button-x5.c +target/coldfire/iaudio/x5/lcd-as-x5.S target/coldfire/iaudio/x5/lcd-x5.c target/coldfire/iaudio/x5/pcf50606-x5.c target/coldfire/iaudio/x5/adc-x5.c diff --git a/firmware/target/coldfire/iaudio/x5/lcd-as-x5.S b/firmware/target/coldfire/iaudio/x5/lcd-as-x5.S new file mode 100644 index 0000000000..323710cc57 --- /dev/null +++ b/firmware/target/coldfire/iaudio/x5/lcd-as-x5.S @@ -0,0 +1,206 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 by Michael Sevakis + * Based on lcd_write_data for H300 in lcd.S + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include "config.h" +#include "cpu.h" + + .section .icode,"ax",@progbits + + .align 2 + .global lcd_write_data + .type lcd_write_data,@function + +lcd_write_data: + move.l (4,%sp),%a0 /* data pointer */ + move.l (8,%sp),%d0 /* length in words */ + add.l %d0,%d0 /* words -> bytes */ + add.l %a0,%d0 /* -> end address */ + lea.l 0xf0008002,%a1 /* LCD data port */ + + lea.l (-24,%sp),%sp /* free up some registers */ + movem.l %d2-%d6/%a2,(%sp) + + move.l %a0,%d1 + btst.l #1,%d1 /* already longword aligned? */ + beq.b .wd_wordl_end /* yes: skip initial word copy */ + /* transfer initial word */ + move.w (%a0)+,%d1 /* |????????|????????|rrrrrggg|gggbbbbb| */ + move.l %d1,%d2 + and.l #0xfffff800,%d2 /* |????????|????????|rrrrr000|00000000| */ + add.l %d2,%d1 /* |????????|???????r|rrrr0ggg|gggbbbbb| */ + move.l %d1,%d2 + lsr.l #8,%d1 /* |00000000|????????|???????r|rrrr0ggg| */ + move.w %d1,(%a1) + lsl.l #1,%d2 /* |????????|??????rr|rrr0gggg|ggbbbbb0| */ + move.w %d2,(%a1) + +.wd_wordl_end: /* now longword aligned */ + moveq.l #28,%d1 + add.l %a0,%d1 + and.l #0xFFFFFFF0,%d1 /* %d1 = second line bound */ + cmp.l %d1,%d0 /* at least one full line to send? */ + blo.w .wd_long2_start /* no: skip to trailing longword handling */ + + subq.l #8,%d1 + subq.l #8,%d1 /* %d1 = first line bound */ + + cmp.l %a0,%d1 /* any leading longwords? */ + bls.b .wd_long1_end /* no: skip leading long loop */ + +.wd_long1_loop: + move.l (%a0)+,%d2 /* read longword */ + swap %d2 /* unstuff two pixels and correct order */ + move.l %d2,%d5 + and.l #0xff00ff00,%d5 /* |rrrrrggg|00000000|rrrrrggg|00000000| */ + eor.l %d5,%d2 /* |00000000|gggbbbbb|00000000|gggbbbbb| */ + lsr.l #8,%d5 /* |00000000|rrrrrggg|00000000|rrrrrggg| */ + move.l %d5,%d6 + and.l #0x00f800f8,%d5 /* |00000000|rrrrr000|00000000|rrrrr000| */ + add.l %d6,%d5 /* |0000000r|rrrr0ggg|0000000r|rrrr0ggg| */ + move.w %d5,(%a1) + lsl.l #1,%d2 /* |0000000g|ggbbbbb0|0000000g|ggbbbbb0| */ + move.w %d2,(%a1) + swap %d5 + move.w %d5,(%a1) + swap %d2 + move.w %d2,(%a1) + cmp.l %a0,%d1 + bhi.b .wd_long1_loop + +.wd_long1_end: + move.l %d0,%a2 + lea.l (-14,%a2),%a2 + +.wd_line_loop: + movem.l (%a0),%d1-%d4 /* burst-read eight words */ + lea.l (16,%a0),%a0 /* increment address */ + + /* transfer four pairs of longs to display */ + /* same procedure for each as in leading long loop */ + swap %d1 + move.l %d1,%d5 + and.l #0xff00ff00,%d5 + eor.l %d5,%d1 + lsr.l #8,%d5 + move.l %d5,%d6 + and.l #0x00f800f8,%d5 + add.l %d6,%d5 + move.w %d5,(%a1) + lsl.l #1,%d1 + move.w %d1,(%a1) + swap %d5 + move.w %d5,(%a1) + swap %d1 + move.w %d1,(%a1) + + swap %d2 + move.l %d2,%d5 + and.l #0xff00ff00,%d5 + eor.l %d5,%d2 + lsr.l #8,%d5 + move.l %d5,%d6 + and.l #0x00f800f8,%d5 + add.l %d6,%d5 + move.w %d5,(%a1) + lsl.l #1,%d2 + move.w %d2,(%a1) + swap %d5 + move.w %d5,(%a1) + swap %d2 + move.w %d2,(%a1) + + swap %d3 + move.l %d3,%d5 + and.l #0xff00ff00,%d5 + eor.l %d5,%d3 + lsr.l #8,%d5 + move.l %d5,%d6 + and.l #0x00f800f8,%d5 + add.l %d6,%d5 + move.w %d5,(%a1) + lsl.l #1,%d3 + move.w %d3,(%a1) + swap %d5 + move.w %d5,(%a1) + swap %d3 + move.w %d3,(%a1) + + swap %d4 + move.l %d4,%d5 + and.l #0xff00ff00,%d5 + eor.l %d5,%d4 + lsr.l #8,%d5 + move.l %d5,%d6 + and.l #0x00f800f8,%d5 + add.l %d6,%d5 + move.w %d5,(%a1) + lsl.l #1,%d4 + move.w %d4,(%a1) + swap %d5 + move.w %d5,(%a1) + swap %d4 + move.w %d4,(%a1) + + cmp.l %a0,%a2 /* run %a0 up to last line bound */ + bhi.w .wd_line_loop + +.wd_long2_start: + subq.l #2,%d0 /* account for handling 2 words per loop */ + cmp.l %a0,%d0 /* any (trailing longwords? */ + bls.b .wd_long2_end /* no: skip trailing longword loop */ + +.wd_long2_loop: + move.l (%a0)+,%d2 /* read longword */ + swap %d2 + move.l %d2,%d5 + and.l #0xff00ff00,%d5 + eor.l %d5,%d2 + lsr.l #8,%d5 + move.l %d5,%d6 + and.l #0x00f800f8,%d5 + add.l %d6,%d5 + move.w %d5,(%a1) + lsl.l #1,%d2 + move.w %d2,(%a1) + swap %d5 + move.w %d5,(%a1) + swap %d2 + move.w %d2,(%a1) + cmp.l %a0,%d0 /* run %a0 up to last long bound */ + bhi.b .wd_long2_loop + +.wd_long2_end: + blo.b .wd_word2_end /* no final word: skip */ + + move.w (%a0),%d1 /* transfer final word */ + move.l %d1,%d2 + and.l #0xfffff800,%d2 + add.l %d2,%d1 + move.l %d1,%d2 + lsr.l #8,%d1 + move.w %d1,(%a1) + lsl.l #1,%d2 + move.w %d2,(%a1) + +.wd_word2_end: + movem.l (%sp),%d2-%d6/%a2 + lea.l (24,%sp),%sp /* restore registers */ + rts +/* end lcd_write_data */ diff --git a/firmware/target/coldfire/iaudio/x5/lcd-x5.c b/firmware/target/coldfire/iaudio/x5/lcd-x5.c index 57b4789070..240b1db586 100755 --- a/firmware/target/coldfire/iaudio/x5/lcd-x5.c +++ b/firmware/target/coldfire/iaudio/x5/lcd-x5.c @@ -531,7 +531,7 @@ void lcd_yuv_blit(unsigned char * const src[3], ysrc += stride; } while (++y < y_end); -} +} /* lcd_yuv_blit */ /* Update the display. This must be called after all other LCD functions that change the @@ -539,9 +539,6 @@ void lcd_yuv_blit(unsigned char * const src[3], void lcd_update(void) ICODE_ATTR; void lcd_update(void) { - /* Optimized for full-screen write. */ - const unsigned long *ptr, *ptr_end; - if (!display_on) return; @@ -552,36 +549,16 @@ void lcd_update(void) lcd_begin_write_gram(); - ptr = (unsigned long *)lcd_framebuffer; - ptr_end = ptr + LCD_WIDTH*LCD_HEIGHT/2; - - do - { - /* 16 words per turns out to be about optimal according to - test_fps. */ - lcd_write_two(*ptr++); -#ifndef BOOTLOADER - lcd_write_two(*ptr++); - lcd_write_two(*ptr++); - lcd_write_two(*ptr++); - lcd_write_two(*ptr++); - lcd_write_two(*ptr++); - lcd_write_two(*ptr++); - lcd_write_two(*ptr++); -#endif - } - while (ptr < ptr_end); + lcd_write_data((unsigned short *)lcd_framebuffer, + LCD_WIDTH*LCD_HEIGHT); } /* lcd_update */ /* Update a fraction of the display. */ void lcd_update_rect(int, int, int, int) ICODE_ATTR; void lcd_update_rect(int x, int y, int width, int height) { - int y_end; - int odd_lead, odd_trail; - int duff; - const unsigned long *ptr, *duff_end; - int stride; /* Actually end of currline -> start of next */ + int ymax; + const unsigned short *ptr; if (!display_on) return; @@ -593,12 +570,12 @@ void lcd_update_rect(int x, int y, int width, int height) if (width <= 0) return; /* nothing left to do */ - y_end = y + height; - if (y_end > LCD_HEIGHT) - y_end = LCD_HEIGHT; /* Clip bottom */ + ymax = y + height; + if (ymax > LCD_HEIGHT) + ymax = LCD_HEIGHT; /* Clip bottom */ if (y < 0) y = 0; /* Clip top */ - if (y >= y_end) + if (y >= ymax) return; /* nothing left to do */ /* Set start position and window */ @@ -608,75 +585,12 @@ void lcd_update_rect(int x, int y, int width, int height) lcd_begin_write_gram(); - ptr = (unsigned long *)&lcd_framebuffer[y][x]; - - /* Aligning source reads to long boundaries helps 2% - 3% with IRAM - buffer. DK with DRAM. */ - odd_lead = x & 1; - - if (odd_lead) - { - duff = width - 1; - odd_trail = duff & 1; - duff >>= 1; - } - else - { - duff = width >> 1; - odd_trail = width & 1; - } - - duff_end = ptr + duff; -#ifndef BOOTLOADER - duff &= 7; -#endif - - stride = LCD_WIDTH - width + odd_trail; /* See odd_trail below */ + ptr = (unsigned short *)&lcd_framebuffer[y][x]; do { - if (odd_lead) - { - /* Write odd start pixel. */ - lcd_write_one(*(unsigned short *)ptr); - ptr = (unsigned long *)((short *)ptr + 1); - } - - if (ptr < duff_end) - { -#ifdef BOOTLOADER - do - lcd_write_two(*ptr); - while (++ptr < duff_end); -#else - switch (duff) - { - do - { - case 0: lcd_write_two(*ptr++); - case 7: lcd_write_two(*ptr++); - case 6: lcd_write_two(*ptr++); - case 5: lcd_write_two(*ptr++); - case 4: lcd_write_two(*ptr++); - case 3: lcd_write_two(*ptr++); - case 2: lcd_write_two(*ptr++); - case 1: lcd_write_two(*ptr++); - } - while (ptr < duff_end); - } /* end switch */ -#endif /* BOOTLOADER */ - - duff_end += LCD_WIDTH/2; - } - - if (odd_trail) - { - /* Finish remaining odd pixel. */ - lcd_write_one(*(unsigned short *)ptr); - /* Stride increased by one pixel. */ - } - - ptr = (unsigned long *)((short *)ptr + stride); + lcd_write_data(ptr, width); + ptr += LCD_WIDTH; } - while (++y < y_end); -} + while (++y < ymax); +} /* lcd_update_rect */