-2

我将如何在 C 代码中实现从 16 位到 32 位的符号扩展?
我应该使用按位运算符。我还需要加减;谁能指出我正确的方向?我做了前4个,但对其余部分感到困惑。对于其中一种情况,我还必须在某处合并一个for循环。

我不允许使用任何算术运算符(+, -, /, *),也不允许使用任何if语句。

这是我当前正在编辑的 switch 语句的代码:

unsigned int csc333ALU(const unsigned int opcode,
               const unsigned int argument1,
               const unsigned int argument2) {
unsigned int result;

switch(opcode) {
  case(0x01): // result = NOT argument1
    result = ~(argument1);
    break;
  case(0x02): // result = argument 1 OR argument 2
    result = argument1 | argument2;
    break;
  case(0x03): // result = argument 1 AND argument 2
    result = argument1 & argument2;
    break;
  case(0x04): // result = argument 1 XOR argument 2
    result = argument1 ^ argument2;
    break;
  case(0x05): // result = 16 bit argument 1 sign extended to 32 bits
    result = 0x00000000;
    break;
  case(0x06): // result = argument1 + argument2
    result = 0x00000000;
    break;
  case(0x07): // result = -argument1. In two's complement, negate and add 1.
    result = 0x00000000;
    break;
  default:
    printf("Invalid opcode: %X\n", opcode);
    result = 0xFFFFFFFF;
  }
4

3 回答 3

1

要将 16 位数字符号扩展为 32 位,您需要将第 15 位复制到高位。最简单的方法是使用 16 条指令,将第 15 位复制到第 16 位,然后是 17 位,然后是 18 位,依此类推。但是您可以通过使用以前复制的位并将每次复制的位数加倍来更有效地执行此操作,如下所示:

unsigned int ext = (argument1 & 0x8000U) << 1;
ext |= ext << 1;
ext |= ext << 2;
ext |= ext << 4;
ext |= ext << 8;
result = (argument1 & 0xffffU) | ext;

要“手动”添加两个 32 位数字,您可以简单地一点一点地添加。

unsigned carry = 0;
result = 0;
for (int i = 0; i < 32; i++) {
    // Extract the ith bit from argument1 and argument 2.
    unsigned a1 = (argument1 >> i) & 1;
    unsigned a2 = (argument2 >> i) & 1;
    // The ith bit of result is set if 1 or 3 of a1, a2, carry is set.
    unsigned v = a1 ^ a2 ^ carry;
    result |= v << i;
    // The new carry is 1 if at least two of a1, a2, carry is set.
    carry = (a1 & a2) | (a1 & carry) | (a2 & carry);
}

减法使用几乎完全相同的代码:a - ba + (~b+1)二进制补码算术相同。因为不允许简单地加 1,所以可以通过初始化carry1而不是0.

unsigned carry = 1;
result = 0;
for (int i = 0; i < 32; i++) {
    unsigned a1 = (argument1 >> i) & 1;
    unsigned a2 = (~argument2 >> i) & 1;
    unsigned v = a1 ^ a2 ^ carry;
    result |= v << i;
    carry = (a1 & a2) | (a1 & carry) | (a2 & carry);
}

要在不进行否定的情况下找到二进制补码,类似的想法也适用。按位取反,然后加1. 添加1比添加更简单argument2,因此代码也相应更简单。

result = ~argument1;
unsigned carry = 1;
for (int i = 0; i < 32 && carry; i++) {
    carry &= (result >> i);
    result |= (1 << i);        
}
于 2015-03-30T02:32:50.323 回答
1

符号扩展的部分答案:

result = (argument1 & 0x8000) == 0x8000 ? 0xFFFF0000 | argument1 : argument1;
于 2015-03-25T03:38:16.830 回答
0

将符号扩展名short intint....

short int iShort = value;

int i = iShort;  // compiler automatically creates code that performs sign extension

注意:从i到 iShort 将生成编译器警告。

但是,对于其他情况...

无需进行比较,&将导致单个位为 0 或 1,并确保将计算的部分转换为 int

int i = (short int argument&0x8000)? (int)(0xFFFF000 | (int)argument) : (int)argument;
于 2015-03-25T04:36:41.047 回答