I have a short, instr
, that looks like this:
1110xxx111111111
I need to pull out bits 0-9, which I do with (instr & 0x1FF)
. This quantity is then stored in a new short. The problem is that when this occurs, it becomes 0x0000000111111111
, not 0x1111111111111111
like I want. How can I fix this? Thanks!
Here's the code:
short instr = state->mem[state->pc]; unsigned int reg = instr >> 9 & 7; // 0b111 state->regs[reg] = state->pc + (instr & 0x1FF);
This is a simulator that reads in assembly. state
is the machine, regs[]
are the registers and pc
is the address of the current instruction in mem[]
.
This is fine if the last nine bits represent a positive number, but if they're representing -1, it's stored as all 1's, which is interpreted as a positive value by my code.
Sign-extending means copying the sign bit of the unextended value to all bits on the left side of the larger-size value. The same way as leading zeroes do not affect values of a positive numbers, leading 1s do not affect values of a negative numbers. Sign-extend operation is often abbreviated SEXT.
A BIT file is an . MP3 audio file with the . bit file extension, which was used in the early 1990s before being replaced by the . mp3 extension in 1995.
Sign extension is used for signed loads of bytes (8 bits using the lb instruction) and halfwords (16 bits using the lh instruction). Sign extension replicates the most significant bit loaded into the remaining bits. Zero extension is used for unsigned loads of bytes ( lbu ) and halfwords ( lhu ).
When a two's complement number is extended to more bits, the sign bit must be copied into the most significant bit positions. This process is called sign extension. For example, the numbers 3 and −3 are written as 4-bit two's complement numbers 0011 and 1101, respectively.
Assuming a short is 16 bits:
You can do it manually: (instr & 0x1FF) | ((instr & 0x100) ? 0xFE00 : 0)
. This tests the sign bit (the uppermost bit you are retaining, 0x100
) and sets all the bits above it if the sign bit is set. You can extend this to 5 bits by adapting the masks to 0x1F
, 0x10
and 0xFFE0
, being the lower 5 bits, the 5th bit itself and all the bits 5-16 respectively.
Or you can find some excuse to assign the bits to the upper part of a signed short and shift them down (getting a sign-extension in the process): short x = (instr & 0x1FF) << 7; x >>= 7;
The latter may actually end up being more straightforward in assembly and will not involve a branch. If instr
is signed this can be done in a single expression: (instr & 0x1FF) << 7 >> 7
. Since that already removes the upper bits it simplifies to instr << 7 >> 7
. Replace 7 with 11 for 5 bits (16-5).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With