Subject: Byte swapping versions of insl & outsl

From: "Andrew R. Baker" <[email-masked]>
Date: Thu, 21 Oct 1999 18:14:15 -0500 (CDT)

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" );
}