From f3857abf6bdc9b2d570150b98c56e239ac4ebd1b Mon Sep 17 00:00:00 2001 From: Jens Arnold Date: Sun, 5 Feb 2006 00:24:08 +0000 Subject: H300: lcd_write_data() in pure asm, essentially the same speed as before, but working correctly for all allowed data lengths. Removed RAM waste by declaring inline functions static. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@8575 a1c6a512-1295-4272-9138-f99709370657 --- firmware/drivers/lcd-h300.c | 47 ++----------- firmware/drivers/lcd.S | 161 ++++++++++++++++++++++++++++++++------------ 2 files changed, 122 insertions(+), 86 deletions(-) diff --git a/firmware/drivers/lcd-h300.c b/firmware/drivers/lcd-h300.c index d84edd6b2e..8ee6b1c47e 100644 --- a/firmware/drivers/lcd-h300.c +++ b/firmware/drivers/lcd-h300.c @@ -77,55 +77,18 @@ static bool display_on=false; /* is the display turned on? */ /* called very frequently - inline! */ -inline void lcd_write_reg(int reg, int val) +static inline void lcd_write_reg(int reg, int val) { *(volatile unsigned short *)0xf0000000 = reg; *(volatile unsigned short *)0xf0000002 = val; } /* called very frequently - inline! */ -inline void lcd_begin_write_gram(void) +static inline void lcd_begin_write_gram(void) { *(volatile unsigned short *)0xf0000000 = R_WRITE_DATA_2_GRAM; } -/* called very frequently - inline! */ -inline void lcd_write_data(const unsigned short* p_bytes, int count) ICODE_ATTR; -inline void lcd_write_data(const unsigned short* p_bytes, int count) -{ - int precount = ((-(size_t)p_bytes) & 0xf) / 2; - count -= precount; - while(precount--) - *(volatile unsigned short *)0xf0000002 = *p_bytes++; - while((count -= 8) >= 0) asm ( - "\n\tmovem.l (%[p_bytes]),%%d1-%%d4\ - \n\tswap %%d1\ - \n\tmove.w %%d1,(%[dest])\ - \n\tswap %%d1\ - \n\tmove.w %%d1,(%[dest])\ - \n\tswap %%d2\ - \n\tmove.w %%d2,(%[dest])\ - \n\tswap %%d2\ - \n\tmove.w %%d2,(%[dest])\ - \n\tswap %%d3\ - \n\tmove.w %%d3,(%[dest])\ - \n\tswap %%d3\ - \n\tmove.w %%d3,(%[dest])\ - \n\tswap %%d4\ - \n\tmove.w %%d4,(%[dest])\ - \n\tswap %%d4\ - \n\tmove.w %%d4,(%[dest])\ - \n\tlea.l (16,%[p_bytes]),%[p_bytes]" - : [p_bytes] "+a" (p_bytes) - : [dest] "a" ((volatile unsigned short *)0xf0000002) - : "d1", "d2", "d3", "d4", "memory"); - if (count != 0) { - count += 8; - while(count--) - *(volatile unsigned short *)0xf0000002 = *p_bytes++; - } -} - /*** hardware configuration ***/ void lcd_set_contrast(int val) @@ -406,8 +369,8 @@ void lcd_update_rect(int x, int y, int width, int height) lcd_write_reg(R_HORIZ_RAM_ADDR_POS, (ymax<<8) | y); /* vert ram addr */ - lcd_write_reg(R_VERT_RAM_ADDR_POS,((x+width-1)<<8) | x); - lcd_write_reg(R_RAM_ADDR_SET, (x<<8) | y); + lcd_write_reg(R_VERT_RAM_ADDR_POS,((x+width-1)<<8) | x); + lcd_write_reg(R_RAM_ADDR_SET, (x<<8) | y); lcd_begin_write_gram(); /* Copy specified rectangle bitmap to hardware */ @@ -421,6 +384,6 @@ void lcd_update_rect(int x, int y, int width, int height) lcd_write_reg(R_HORIZ_RAM_ADDR_POS, 0xaf00); /* vert ram addr: 0 - 219 */ - lcd_write_reg(R_VERT_RAM_ADDR_POS, 0xdb00); + lcd_write_reg(R_VERT_RAM_ADDR_POS, 0xdb00); } } diff --git a/firmware/drivers/lcd.S b/firmware/drivers/lcd.S index 79c6e32f33..2b50de5190 100755 --- a/firmware/drivers/lcd.S +++ b/firmware/drivers/lcd.S @@ -313,62 +313,135 @@ _lcd_write_data: .type lcd_write_command,@function lcd_write_command: - move.l (4,%sp),%d0 - lea MBAR2,%a1 - move.l #~8,%d1 - and.l %d1,(0xb4,%a1) - move.w %d0,0xf0000000 - rts + move.l (4,%sp),%d0 + lea MBAR2,%a1 + move.l #~8,%d1 + and.l %d1,(0xb4,%a1) + move.w %d0,0xf0000000 + rts .align 2 .global lcd_write_command_ex .type lcd_write_command_ex,@function lcd_write_command_ex: - lea MBAR2,%a1 - - move.l (4,%sp),%d0 /* Command */ - - move.l #~8,%d1 /* Set A0 = 0 */ - and.l %d1,(0xb4,%a1) - move.w %d0,0xf0000000 /* Write to LCD */ - - not.l %d1 /* Set A0 = 1 */ - or.l %d1,(0xb4,%a1) - - move.l (8,%sp),%d0 /* Data */ - cmp.l #0xffffffff,%d0 /* -1? */ - beq.b .last - move.w %d0,0xf0000000 /* Write to LCD */ - - move.l (12,%sp),%d0 /* Data */ - cmp.l #0xffffffff,%d0 /* -1? */ - beq.b .last - move.w %d0,0xf0000000 /* Write to LCD */ - -.last: - rts + lea MBAR2,%a1 + + move.l (4,%sp),%d0 /* Command */ + + move.l #~8,%d1 /* Set A0 = 0 */ + and.l %d1,(0xb4,%a1) + move.w %d0,0xf0000000 /* Write to LCD */ + + not.l %d1 /* Set A0 = 1 */ + or.l %d1,(0xb4,%a1) + + move.l (8,%sp),%d0 /* Data */ + cmp.l #0xffffffff,%d0 /* -1? */ + beq.b .last + move.w %d0,0xf0000000 /* Write to LCD */ + + move.l (12,%sp),%d0 /* Data */ + cmp.l #0xffffffff,%d0 /* -1? */ + beq.b .last + move.w %d0,0xf0000000 /* Write to LCD */ + +.last: + rts .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 */ - lea MBAR2,%a1 - moveq #8,%d1 - or.l %d1,(0xb4,%a1) + move.l (4,%sp),%a0 /* Data pointer */ + move.l (8,%sp),%d0 /* Length */ + lea MBAR2,%a1 + moveq #8,%d1 + or.l %d1,(0xb4,%a1) - lea 0xf0000000,%a1 + lea 0xf0000000,%a1 .loop: - /* When running in IRAM, this loop takes 7 cycles plus the LCD write. - The 7 cycles are necessary to follow the LCD timing specs - at 140MHz */ - move.b (%a0)+,%d1 /* 3(1/0) */ - move.w %d1,(%a1) /* 1(0/1) */ - subq.l #1,%d0 /* 1(0/0) */ - nop /* 1(0/0) */ - bne .loop /* 2(0/0) */ - rts + /* When running in IRAM, this loop takes 7 cycles plus the LCD write. + The 7 cycles are necessary to follow the LCD timing specs + at 140MHz */ + move.b (%a0)+,%d1 /* 3(1/0) */ + move.w %d1,(%a1) /* 1(0/1) */ + subq.l #1,%d0 /* 1(0/0) */ + nop /* 1(0/0) */ + bne .loop /* 2(0/0) */ + rts +#elif defined(IRIVER_H300_SERIES) + .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 0xf0000002,%a1 /* LCD data port */ + + moveq.l #31,%d1 + add.l %a0,%d1 + and.l #0xFFFFFFF0,%d1 /* %d1 = first line bound + 16 */ + cmp.l %d1,%d0 /* at least one full line to send? */ + blo.b .words2_loop /* no: skip to word loop */ + + subq.l #8,%d1 + subq.l #8,%d1 /* %d1 = first line bound */ + + cmp.l %a0,%d1 /* any leading words? */ + bls.b .words1_end /* no: skip leading word loop */ + +.words1_loop: + move.w (%a0)+,(%a1) /* transfer word */ + cmp.l %a0,%d1 /* run %a0 up to first line bound */ + bhi.b .words1_loop + +.words1_end: + lea.l (-16,%sp),%sp /* free up some registers */ + movem.l %d2-%d4/%a2,(%sp) + move.l %d0,%a2 + lea.l (-15,%a2),%a2 /* %a2 = end address - 15 (one line/pass) */ + + /* burst-optimised line transfers */ +.line_loop: + movem.l (%a0),%d1-%d4 /* burst-read line */ + lea.l (16,%a0),%a0 /* increment address */ + swap %d1 /* send data to LCD in correct order... */ + move.w %d1,(%a1) + swap %d1 + move.w %d1,(%a1) + swap %d2 + move.w %d2,(%a1) + swap %d2 + move.w %d2,(%a1) + swap %d3 + move.w %d3,(%a1) + swap %d3 + move.w %d3,(%a1) + swap %d4 + move.w %d4,(%a1) + swap %d4 + move.w %d4,(%a1) + cmp.l %a0,%a2 /* run %a0 up to last line bound */ + bhi.b .line_loop + + movem.l (%sp),%d2-%d4/%a2 + lea.l (16,%sp),%sp /* restore registers */ + + cmp.l %a0,%d0 /* any trailing words? */ + bls.b .words2_end /* no: get otta here */ + +.words2_loop: + move.w (%a0)+,(%a1) /* transfer word */ + cmp.l %a0,%d0 /* run %a0 up to end address */ + bhi.b .words2_loop + +.words2_end: + rts #endif -- cgit v1.2.3