diff options
author | Jörg Hohensohn <hohensoh@rockbox.org> | 2004-01-16 09:02:21 +0000 |
---|---|---|
committer | Jörg Hohensohn <hohensoh@rockbox.org> | 2004-01-16 09:02:21 +0000 |
commit | 88faf38ef7bdca708e3134f127d5c3e2a1b44d1e (patch) | |
tree | 601a830398720e0d43ed1fbe1852c3af0051212e /firmware | |
parent | 89d2039367279aece429b1e86be263578a763a3d (diff) |
Optimized the sector read loop as much as C allows. I measured an overall speed improvement for file reading of 12.5% for 16-bit aligned and 35% for misaligned. I took the rest of ata_read_sectors() out of IRAM, it's sufficient if only the copy loop stays there.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@4247 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/drivers/ata.c | 49 |
1 files changed, 34 insertions, 15 deletions
diff --git a/firmware/drivers/ata.c b/firmware/drivers/ata.c index 725d33e4a0..45eb1a5963 100644 --- a/firmware/drivers/ata.c +++ b/firmware/drivers/ata.c @@ -161,9 +161,39 @@ static int wait_for_end_of_transfer(void) return (ATA_ALT_STATUS & (STATUS_RDY|STATUS_DRQ)) == STATUS_RDY; } -int ata_read_sectors(unsigned long start, - int count, - void* buf) __attribute__ ((section (".icode"))); + +/* the tight loop of ata_read_sectors(), to avoid the whole in IRAM */ +static void copy_read_sectors(unsigned char* buf, + int wordcount) + __attribute__ ((section (".icode"))); +static void copy_read_sectors(unsigned char* buf, int wordcount) +{ + int j; + + if (wordcount <= 0) + return; /* should never happen, but to protect my tail loop */ + + if ( (unsigned int)buf & 1 ) + { + unsigned char* bufend = buf + wordcount*2; + do + { /* loop compiles to 8 assembler instructions */ + unsigned short tmp = ATA_DATA; + *buf++ = tmp & 0xff; /* I assume big endian */ + *buf++ = tmp >> 8; /* and don't use the SWAB16 macro */ + } while (buf < bufend); /* tail loop is faster */ + } + else + { + unsigned short* wbuf = (unsigned short*)buf; + unsigned short* wbufend = wbuf + wordcount; + do + { /* loop compiles to 7 assembler instructions */ + *wbuf = SWAB16(ATA_DATA); + } while (++wbuf < wbufend); /* tail loop is faster */ + } +} + int ata_read_sectors(unsigned long start, int incount, void* inbuf) @@ -235,7 +265,6 @@ int ata_read_sectors(unsigned long start, asm volatile ("nop"); while (count) { - int j; int sectors; int wordcount; int status; @@ -265,17 +294,7 @@ int ata_read_sectors(unsigned long start, wordcount = sectors * SECTOR_SIZE / 2; - if ( (unsigned int)buf & 1 ) { - for (j=0; j < wordcount; j++) { - unsigned short tmp = SWAB16(ATA_DATA); - ((unsigned char*)buf)[j*2] = tmp >> 8; - ((unsigned char*)buf)[j*2+1] = tmp & 0xff; - } - } - else { - for (j=0; j < wordcount; j++) - ((unsigned short*)buf)[j] = SWAB16(ATA_DATA); - } + copy_read_sectors(buf, wordcount); /* "Device errors encountered during READ MULTIPLE commands are |