Swaping in Assembly

dsptl's Avatar, Join Date: Jun 2009
Light Poster
How can you exchange(swap) the first bit and the last bit of register %o0 in Assembly?
xpi0t0s's Avatar, Join Date: Aug 2004
Mentor
Here's a quick test program I wrote in C; compile to assembler to get the result for your specific hardware:
Code:
void swapbits()
{
	for (int i=0; i<4; i++)
	{
		int reg=0, exp=0, reg1;

		switch (i)
		{
		case 0: reg=0xffff0000; exp=0x7fff0001; break; // 1xx0 -> 0xx1
		case 1: reg=0xffff0001; exp=0xffff0001; break; // 1xx1 -> 1xx1
		case 2: reg=0x7fff0001; exp=0xffff0000; break; // 0xx1 -> 1xx0
		case 3: reg=0x7fff0000; exp=0x7fff0000; break; // 0xx0 -> 0xx0
		}
		reg1=reg;
		if (reg>0 && reg&1 || reg<0 && !(reg&1))
			reg ^= 0x80000001;
		printf("Swap 0x%04x, expect 0x%04x, result 0x%04x, %s\n", reg1, exp, reg,
			(exp==reg) ? "OK" : "NOK");		
	}
}
Most of it is just a testbed for the calculation itself, which is just:
Code:
		if (reg>0 && reg&1 || reg<0 && !(reg&1))
			reg ^= 0x80000001;
xpi0t0s's Avatar, Join Date: Aug 2004
Mentor
Here's another expression that doesn't use "if" statements and should execute in constant time regardless of the bit values, unlike the previous one. Execution in constant time is useful for programming embedded systems. With disassembly, as generated by Visual Studio 2008:
Code:
		reg ^= (- ( (reg&0x00000001) ^ ((reg&0x80000000)>>31) )) & 0x80000001;
00413B6B  mov         eax,dword ptr [reg] 
00413B6E  and         eax,1 
00413B71  mov         ecx,dword ptr [reg] 
00413B74  and         ecx,80000000h 
00413B7A  shr         ecx,1Fh 
00413B7D  xor         eax,ecx 
00413B7F  neg         eax  
00413B81  and         eax,80000001h 
00413B86  xor         eax,dword ptr [reg] 
00413B89  mov         dword ptr [reg],eax
And here's a hand coded one in 9 pseudocode instructions that uses one register for the two bits, and assumes that <<= shifts the carry flag C into bit 0 and bit 31 into C, and >>= works the same way, AND not only doesn't require C to be set to anything specific but preserves its value (u) throughout:

Code:
            reg1  reg2  C
reg2=reg1;  axxb  axxb    ; goal: reg1=bxxa
reg1&=0110; 0xx0        u
reg1>>=1;   u0xx        0
reg2<<=1;         xxb0  a
reg1<<=1;   0xxa        u
reg1<<=1;   xxau        0
reg2>>=1;         0xxb  0
reg2>>=1;         00xx  b
reg1>>=1;   bxxa        u
This can be reduced to 7 instructions if two consecutive <<=1's and >>=1's have exactly the same effect as a single <<=2 or >>=2. Note <<= and >>= are NOT equivalent to the C instructions because these shift a zero bit into the register and lose the bit that drops off the end.
xpi0t0s's Avatar, Join Date: Aug 2004
Mentor
And here's one in just six (realised the &=0110 wasn't necessary):
Code:
reg2=reg1   axxb  axxb  u
reg1<<=1    xxbu        a
reg2>>=1          aaxx  b
reg1>>=2    ubxx        b
reg2<<=1          axxb  a
reg1<<=1    bxxa        u