I needed these to get a 3COM Etherlink III working in the Indigo2. I
don't know if anyone else could use them, but here they are. I might be
able to come up with an algorithm that uses one or two fewer instructions.
The can probably be optimised to only use 3 registers instead of 4. But
thay are still a lot better than four consecutive insb/outsb. If other
people are planning on using these I'll do it sooner rather than later.
I'll try and sneak them into the CVS archive sometime soon ;)
/*
* Byte swapping versions of insl and outsl. I needed these to get the
* Etherlink III working efficiently on the Indigo2. They might be useful
* in porting other ISA drivers to big-endian architectures
*
* -Andrew
*/
extern inline void insl_sw(unsigned int port, void * addr, unsigned long count)
{
if (count) __asm__ __volatile__ (
".set\tnoreorder\n\t"
".set\tnoat\n"
"1:\tlw\t$1,%4(%5)\n\t"
"subu\t%1,1\n\t"
"sll\t$2,$1,24\n\t"
"srl\t$3,$1,24\n\t"
"or\t$4,$2,$3\n\t"
"sll\t$2,$1,8\n\t"
"srl\t$1,$2,16\n\t"
"andi\t$2,$1,65280\n\t"
"andi\t$3,$1,255\n\t"
"sll\t$1,$3,16\n\t"
"or\t$3,$2,$1\n\t"
"or\t$1,$4,$3\n\t"
"sw\t$1,(%0)\n\t"
"bne\t$0,%1,1b\n\t"
"addiu\t%0,%6\n\t"
".set\tat\n\t"
".set\treorder"
: "=r" (addr), "=r" (count)
: "0" (addr), "1" (count), "i" (0), "r" (mips_io_port_base+port), "I"
( 4 )
: "$1", "$2", "$3", "$4" );
}
extern inline void outsl_sw(unsigned int port, void * addr, unsigned long count)
{
if (count) __asm__ __volatile__ (
".set\tnoreorder\n\t"
".set\tnoat\n"
"1:\tlw\t$1,(%0)\n\t"
"subu\t%1,1\n\t"
"sll\t$2,$1,24\n\t"
"srl\t$3,$1,24\n\t"
"or\t$4,$2,$3\n\t"
"sll\t$2,$1,8\n\t"
"srl\t$1,$2,16\n\t"
"andi\t$2,$1,65280\n\t"
"andi\t$3,$1,255\n\t"
"sll\t$1,$3,16\n\t"
"or\t$3,$2,$1\n\t"
"or\t$1,$4,$3\n\t"
"sw\t$1,%4(%5)\n\t"
"bne\t$0,%1,1b\n\t"
"addiu\t%0,%6\n\t"
".set\tat\n\t"
".set\treorder"
: "=r" (addr), "=r" (count)
: "0" (addr), "1" (count), "i" (0), "r" (mips_io_port_base+port), "I"
( 4 )
: "$1", "$2", "$3", "$4" );
}