2017-02-02 21 views
2

シフトを行いながら符号を保持しながら、16進数を10進数に変換しようとしています。署名された指示を適切に逆アセンブルするために私の 'simm'変数を得ることに問題がある。ここで符号付きビットシフト

void disassembleInstr(uint32_t pc, uint32_t instr) { 
    uint32_t opcode;  // opcode field 
    uint32_t rs, rt, rd; // register specifiers 
    uint32_t shamt;  // shift amount (R-type) 
    uint32_t funct;  // funct field (R-type) 
    uint32_t uimm;  // unsigned version of immediate (I-type) 
    int32_t simm;   // signed version of immediate (I-type) 
    uint32_t addr;  // jump address offset field (J-type) 

    opcode = instr >> 26; 
    rs = (instr >> 21) & 0x1f; 
    rt = (instr >> 16) & 0x1f; 
    rd = (instr >> 11) & 0x1f; 
    shamt = (instr >> 6) & 0x1f; 
    funct = (instr & 0x3f); 
    uimm = instr & 0xffff; 
    simm = (instr << 16) >> 16; // shift sign bit to left to 
    addr = instr & 0x3ffffff; //masked with one 

    cout << hex << setw(8) << pc << ": "; 
    switch(opcode) { 
     case 0x00: 
     switch(funct) { 
      case 0x00: cout << "sll " << regNames[rd] << ", " <<    regNames[rs] << ", " << dec << shamt; break; 
      case 0x03: cout << "sra " << regNames[rd] << ", " << regNames[rs] << ", " << dec << shamt; break; 
      case 0x08: cout << "jr " << regNames[rs]; break; 
      case 0x10: cout << "mfhi " << regNames[rd]; break; 
      case 0x12: cout << "mflo " << regNames[rd]; break; 
      case 0x18: cout << "mult " << regNames[rs] << ", " << regNames[rt]; break; 
      case 0x1a: cout << "div " << regNames[rs] << ", " << regNames[rt]; break; 
      case 0x21: cout << " addu " << regNames[rd] << ", " << regNames[rs] << ", " << regNames[rt]; break; 
      case 0x23: cout << " subu " << regNames[rd] << ", " << regNames[rs] << ", " << regNames[rt]; break; 
      case 0x2a: cout << " slt " << regNames[rd] << ", " << regNames[rs] << ", " << regNames[rt]; break; 
      default: cout << "unimplemented"; 
     } 
     break; 
     case 0x02: cout << "j " << hex << ((pc + 4) & 0xf0000000) + addr * 4; break; 
     case 0x03: cout << "jal " << hex << ((pc + 4) & 0xf0000000) + addr * 4; break; 
//  case 0x04: cout << "beq " << regNames[rs] << ", " << regNames[rt] << ", " << + uimm; break; 
//  case 0x05: cout << "bne " << regNames[rs] << ", " << regNames[rt] << ", " << + uimm; break; 
//  case 0x09: cout << "addiu " << regNames[rt] << ", " << regNames[rs] << dec << simm; break; 
//  case 0x0c: cout << "andi " << regNames[rt] << ", " << regNames[rs] << dec << simm; break; 
     case 0x0f: /* lui */ break; 
     case 0x1a: cout << "trap " << hex << addr; break; 
     case 0x23: /* lw */ break; 
     case 0x2b: /* sw */ break; 
     default: cout << "unimplemented"; 
    } 
    cout << endl; 
} 

は私が取得しています間違った出力の例です:

ここ
400000: j 400114 
400004: sw $ra, fffc($sp) 
400008: sw $fp, fff8($sp) 
40000c: addiu $fp, $sp, 65528 
400010: addiu $sp, $fp, 65124 
400014: addiu $k1, $zero, 1 

は、目的の出力です:

400000: j 400114 
400004: sw $ra, -4($sp) 
400008: sw $fp, -8($sp) 
40000c: addiu $fp, $sp, -8 
400010: addiu $sp, $fp, -412 
400014: addiu $k1, $zero, 1 

編集:実装の提案で新しい出力:

400000: j 400114 
400004: sw $ra, fffffffc($sp) 
400008: sw $fp, fffffff8($sp) 
40000c: addiu $fp, $sp, -8 
400010: addiu $sp, $fp, -412 
400014: addiu $k1, $zero, 1 
+0

ISAを?アセンブラ? – awiebe

+0

C++を使用してバイナリをアセンブリに変換する – Nathan1324

答えて

1

instrは符号なしのタイプ(uint32_t)なので、それを左にシフトし、次にそれを右にシフトするだけで最上位ビットがクリアされます。あなたが望んでいた標識拡張はできません。

実際、符号付き整数の符号ビットに1を左シフトすることは、C標準に従って未定義の動作です。たとえinstrが署名された番号だったとしても、左シフト/右シフトのトリックは許されませんでした。

任意のルールに違反せずにタスクを達成するために、これを置き換えます。これで

uimm = instr & 0xffff; 
simm = (instr << 16) >> 16; // shift sign bit to left to 

uimm = instr & 0xffff; 
simm = uimm; 
if (simm & 0x8000) 
    simm -= 65536; 
+0

また、simm =(int16_t)uimm; – fuz

+0

私はあなたの提案を試みました、そして、私はすべてのオフセットのためにほぼすべて0を得ました...任意のアイデア? – Nathan1324

+0

また、整数65536を使用するように提案したのは不思議ですね。 – Nathan1324

関連する問題