Let's first analyse where the problem with your code is:
lui t0, 0xFFFFF
addi t0, t0, 0x7FF
- The
lui instruction loads into t0 the value resulting from left shifting the 20-bit immediate 0xFFFFF by 12 bits. Therefore, t0 results in 0xFFFFF000.
- The
addi sign extends the 12-bit immediate 0x7FF, and adds it to the register t0. Since the most significant bit (i.e., the sign bit) of the immediate is zero, its sign extended 32-bit value is 0x000007FF. This value is then added to t0, which was previously 0xFFFFF000. Therefore, the resulting value of t0 is 0xFFFFF7FF.
As already explained in this answer, you can optimise away the lui instruction by taking advantage of how the sign extension works: sign extension propagates the sign bit, which is the most significant bit.
The 12-bit immediate 0xFFF consists of all 1s, including the most significant bit (i.e., the sign bit). Therefore, its 32-bit sign extension is 0xFFFFFFFF, which already corresponds to the value you want:
addi t0, zero, 0xFFF
If you keep insisting on using both instructions, lui and addi, simply load all 0s into the upper bits of t0:
lui t0, 0
addi t0, t0, 0xFFF