How does LUI/ORI on MIPS work to create a 32-bit constant value?
Asked Answered
B

2

5

I have this risc v code :

lui S0, 0x1234
ori S1, S0, 0x5678
add S2, S1, S1

and the question asks me, "What does the register S2 hold?" The question explains that lui and I quote:

"Load the lower half word of the immediate imm into the upper halfword of register rt. The lower bits of the register are set to 0"

I don't know how to 'compile this program' and what does 0x1234 mean?


Note: This question was originally titled/tagged , but the code can only assemble for MIPS, and the accepted answer is also only correct for MIPS. So lets just make it a MIPS question.

MIPS uses 16-bit immediates for lui and all other immediate instructions, and zero-extends bitwise boolean immediates (ori/andi/xori). Other MIPS instructions do sign-extend their immediate, like RISC-V does for everything.

RISC-V lui takes a 20-bit immediate, while other instructions only take a 12-bit sign-extended immediate, so lui and/or addi can still materialize any 32-bit constant in 1 or 2 RISC-V instructions, like MIPS and all(?) other 32-bit RISC ISAs.

Bonesetter answered 14/11, 2018 at 17:37 Comment(6)
0x1234 is a hexadecimal number equal to 4660 (decimal).Saltwater
ok and what does the lui doBonesetter
You state what it does in the question.Saltwater
https://mcmap.net/q/615361/-risc-v-build-32-bit-constants-with-lui-and-addi/995714Asbury
Error: illegal operands ori s1,s0,0x5678 -- immediate operand is 12 bits only (sign extended)Lamar
That looks like MIPS, not RISC-V. In MIPS, I-type instructions have 16-bit immediates, (and LUI is I-type). And bitwise boolean instructions including ori zero-extend their immediates instead of sign-extending like most MIPS instructions (and all RISC-V instructions). @PavelSmirnov is correct, that ori isn't encodeable for RV32.Stalder
P
8

Take the instructions one at a time. First the load-upper-immediate, take the immediate (0x1234) and "load" it into the upper half of the S0 register and zero out the lower half:

lui S0, 0x1234 

S0 = 0x12340000

Next the or-immediate, we OR the value in S0 with the value 0x5678:

ori S1, S0, 0x5678

   0x12340000
OR 0x00005678
   ----------
   0x12345678 = S1

Finally the add, we are adding the value in S1 to itself or, equivalently, multiplying the value in S1 by 2:

add S2, S1, S1

  0x12345678
+ 0x12345678
  ----------
  0x2468ACF0 = S2

So the value in S2 register is 0x2468ACF0. Note, I am assuming 32-bit words. An immediate is like a constant, so lui is an instruction that places a constant into the upper half of a register. In combination with ori, you can load an entire word-immediate into a register.

Person answered 15/11, 2018 at 2:50 Comment(10)
thank you so much sir , finally i understand how to compile thanks to you. very usefulBonesetter
can i ask you one tiny question ? i have read that the lui instruction moves the 16 bits to the higher and the other 16 bits to the lower . how did you determine which side is higher and which is lower . also the 0x1234 does it contain 4 bits ? (1234) i have problem understanding thisBonesetter
becuase we should have written it like that : 0x1234 0000 0000 0000 0000 0000 0000 0000 which is 32 bits half of it higher whiich is far left and half of it lower far right , Is it like that ?Bonesetter
0x1234 is base 16 (or hexadecimal), so each "digit" is four bits. 0x1234 (base 16) = 0001_0010_0011_0100 (base 2). A register has 32-bits or 8 hex digits. The spec fig2.1 shows the most-significant-bit (XLEN-1) to the left-side. So upper is left, lower is right.Person
Also, these instructions are technically "assembled" by an "assembler". Basically the Risc-V assembler takes the instructions (or mnemonics) and encodes them into binary words which are "fed" to the cpu. The instructions that an assembler understands make up an "assembly language". Compiling is a term used for higher level languages like C/C++.Person
Illegal instruction ori S1, S0, 0x5678: 1) immediate value (12bits) overflow, 2) no such registers S0, S1 (use s0, s1).Lamar
I am rather certain that this is answer is not correct. lui S0, 0x1234 should result in S0 = 0x0123 4000. Your answer is correct in MIPS assemblerCoblenz
@SirHawrk: At this point we might as well just edit the question to match the accepted (and only upvoted) answer, or delete the whole thing since there are existing duplicates for MIPS and RV32. But maybe not ones that show it nicely with diagrams of hex digits slotting together (which works in the general case for MIPS, because boolean instructions like ori zero-extend their immediates, but not RISC-V which sign-extends all immediate so it would fail for 0xFF0FF:0xFFF (I left a 0 in the high part so we can't create it with ori or addi with the zero reg.) So I'll edit.Stalder
@PeterCordes We could and that would make sense. I was just trying to clarify this for future readers. Because I did not know about this distinction for quite some time myself when learningCoblenz
@SirHawrk: Yeah, you were correct to point out that problem. At the time the question was still tagged [risc-v] (and as other comments pointed out, it wouldn't assemble). I was mostly commenting to explain my edit to future readers, although I ended up deciding to leave a note right in the question itself, due to there being multiple comments in multiple places about the problems that caused.Stalder
K
0

"LUI places the U-immediate value in the top 20 bits of the destination register rd, filling in the lowest 12 bits with zeros." -- riscv-spec-v2.2

so, lui s0, 0x1234

s0 should be 0x01234000

Korenblat answered 23/11, 2018 at 2:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.