简体   繁体   中英

Shifts in 2 32-bit registers

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:

  1. take the most significant rotateCnt bits from the high-order register, shift them right 32-rotateCnt bits, and stash the result somewhere

  2. shift the high-order register left by rotateCnt bits

  3. 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

  4. 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM