summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJörg Hohensohn <hohensoh@rockbox.org>2004-01-16 09:02:21 +0000
committerJörg Hohensohn <hohensoh@rockbox.org>2004-01-16 09:02:21 +0000
commit88faf38ef7bdca708e3134f127d5c3e2a1b44d1e (patch)
tree601a830398720e0d43ed1fbe1852c3af0051212e
parent89d2039367279aece429b1e86be263578a763a3d (diff)
downloadrockbox-88faf38ef7bdca708e3134f127d5c3e2a1b44d1e.tar.gz
rockbox-88faf38ef7bdca708e3134f127d5c3e2a1b44d1e.zip
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
-rw-r--r--firmware/drivers/ata.c49
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