void rotate( unsigned long mask[], int rotateCnt );
This function rotates the current 64-bit mask (mask[]) by rotateCnt
places. If the rotateCnt
is positive, rotate left; if the rotateCnt
is negative, rotate right. Only the lower 6 bits of the rotateCnt
should be used for the rotateCnt
.
But I have to do the rotate, in 2 32-bit registers that simulates 1 64 bit register, logically performing 64 bit operations across two 32-bit registers. They told me to do 2 loops, but I can't figure this out? Any h
As you're using x86, take a look at shld and shrd . You won't need loops (why they asked for loops is beyond me).
Update
Here's a DevStudio 2005 style function that uses inline assembler to do what you want. Do not present this as a solution without fully understanding how it all works (especially how the negative counts do a right rotate) because it will be incredibly easy for your teachers to spot that you copied this without knowing how it works (ie Teacher: "How does this work?", You: "Errr..." => FAIL).
void Rotate
(
unsigned *value, // pointer to two 32bit integers
int count // number of bits to rotate: >= 0 left, < 0 = right
)
{
__asm
{
mov esi,value
mov eax,[esi]
mov edx,[esi+4]
mov ecx,count
mov ebx,eax
shld eax,edx,cl
shld edx,ebx,cl
test cl,32
jz noswap
xchg edx,eax
noswap:
mov [esi],eax
mov [esi+4],edx
}
}
There are probably quicker instructions for this, but here's the idea... If you're rotating left:
take the most significant rotateCnt
bits from the high-order register, shift them right 32-rotateCnt
bits, and stash the result somewhere
shift the high-order register left by rotateCnt
bits
take the most significant rotateCnt
bits from the low-order register, shift them left 32-rotateCnt
bits, and add the result to the high-order register
shift the remaining bits in the low-order register left by rotateCnt
bits and add the bits that you saved in step 1
I'm sure you can see how to extend this process to any number of registers. If rotateCnt
can be larger than 32 bits, you'll have to work a little harder, especially in the general case (n registers instead of just 2). One thing that may help is to notice that shifting left by n bits is the same as shifting right by (size-n) bits.
From your comments, I see that you're supposed to use a loop. You can always apply the rotate procedure described above 1 bit at a time for rotateCnt iterations. In that case, you'd obviously change rotateCnt
in the description above to 1
.
A single bit rotate is simply a single bit shift with carries out of one word being applied to the next word with a special case that a carry out of the high word gets applied to the low word.
It may help you to consider a picture of what needs to happen in certain scenarios. I'll use 4-bit words below and I'll assume the rotate is to the left; the same concepts apply to whatever word size you might use:
// Note '-' in the carry column means "don't care"
//
// starting value (in binary):
'high' 'low'
carry word carry word
- 1 0 0 0 - 1 0 0 1
// after shift left of each word:
1 0 0 0 0 1 0 0 1 0
// apply the carry out of the low word
// to the high word:
1 0 0 0 1 - 0 0 1 0
// apply the carry out of the high word
// to the low word
- 0 0 0 1 - 0 0 1 1
To use this basic operation to rotate multiple positions, just loop the appropriate number of times.
Note that this can be done without any loops at all by applying the right set of bitmasks and shifts. Basically you can get all the bits that will carry out of a word in one shot without looping. A looping version is probably more straightforward to implement - you might consider doing that first and using it as a verification test if you decide to improve it to a non-looping version.
think about how you would do this in C for example, then translate that to asm.
Using 32 bit variables to do a single bit shift left for example, assuming ra is the upper 32 bits and rb the lower
if(rb&0x80000000) { ra<<=1; ra|=1; rb<<=1 }
else { ra<<=1; rb<<=1; }
For a rotate you might do something along these lines
if(rb&0x80000000)
{
if(ra&0x80000000) { ra<<=1; ra|=1; rb<<=1: rb|=1; }
else { ra<<=1; ra|=1; rb<<=1; }
}
else
{
if(ra&0x80000000) { ra<<=1; rb<<=1: rb|=1; }
else { ra<<=1; rb<<=1; }
}
You can then wrap a loop around one of those and do it N times.
Or say an 8 bit shift left
ra=(ra<<8)|(rb>>(32-8));
rb<<=8;
Or say an N bit shift left
ra=(ra<<=n)|(rb>>(32-n));
rb<<=n;
Or an n bit rotate left (which is the same as a 32-n bit rotate right)(there is a reason why some processors only have a rotate right and the left is virtual or vice versa).
temp=ra>>(32-n);
ra=(ra<<=n)|(rb>>(32-n));
rb=(rb<<<=n)|temp;
Then look at the instruction set and see what is available and matches what you are doing.
In short to shift bits you need to take the bit on one side and put it in the next bit. If you align yourself on some boundary like a variable or register there is no difference you take the bit from one side and shift it into the other, it may take more code as the instruction set or programming language doesnt support it directly doesnt mean you cant do it. Just like you can perform a 2048 bit multiply on an 8 bit processor with no multiply instruction, just takes more code than other processors, but it is very doable.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.