Home > database >  Branch riscv instruction offset calculation on my emulator
Branch riscv instruction offset calculation on my emulator

Time:01-09

I have wrote a riscv64 emulator but I have an issue on offset calculation for branch instructions (especially for bge).

For me , the formula to calculate offset to add to pc when condition is meet is : PC = PC IMM; Immediate is extract from instruction : there is my C code :



void BNE(unsigned long instr) {

unsigned long IMM1 = instr >>7 & 0b11111;
unsigned long IMM2 = instr >> 25 & 0b1111111;

unsigned long first = IMM1 & 0b1; // 11 eme bits IMM\[11\]  
unsigned long second = IMM1 >> 1 & 0b1111; // IMM\[4:1\]
unsigned long third = IMM2 & 0b111111;  //imm\[10:5\]   
unsigned long fourth = IMM2 >> 6 & 0b1; // IMM\[12\]

// after extract assemble :
unsigned long imm = second | third << 5 |  first <<7 | fourth << 9; // \<- I think here is the problem

}



When the program get this simply program code :



// I have simplified the code :
00000000000100e8 \<init\>:

10130:  fd843783            ld  a5,-40(s0)

1018c:  fae7d2e3            bge a5,a4,10130 \<init 0x48\> # note that the condition is always met on my code

I got : 0x7a2.

The pc adress is : 0x1018c

When I add 0x1018c to 0x7a2 , I got :0x1092E There is an issue but I don't know where. I think the extract on imm variable have some issue.

I have tried to modify the imm variable bits shift and mask. But I don't have any luck.

I have try this :


unsigned long imm = second | third << 4 |  first << 5 | fourth << 6; // output wrong data
unsigned long imm = second | third << 6 |  first << 11 | fourth << 12; // output the same data as imm 
unsigned long imm = second | third << 5 |  first << 7 | fourth << 9; // actual version
unsigned long   imm = second | third <<  6 |  first << 7 | fourth <<8; // output the same data as imm 

CodePudding user response:

You're close, but a few points:

  1. Your variable, second, has bits 4:1 but you're applying them to 3:0 by failing to shift by 1 bit (or by doing that extra >> 1, note that IMM1 & 0b11110 would work).
  2. Your variable, fourth, has bit 12, though that is the sign bit and must be sign extended out to 32 bits for use as the immediate.

Otherwise, just recheck your shifts by the following pattern: [m:n] must << n.  So, assuming each field is right justified in some variable:

  • [4:1] << 1
  • [11] << 11
  • [10:5] << 5
  • [12] << 12 — but with sign extension — so on 32-bit machine, [12] << 31, then taken as signed >> 19, or else use [12] ? 0xFFFFF000 : 0 or [12] ? -4096 : 0.

With that you'll have an SB-Type immediate of 32 bits expanded from the mangled 12 bits in the instruction and suitable for adding to the PC.


The immediate value encoded in that bge instruction, 0xfae7d2e3, is -92 (0xFFFFFFA4).

  • Related