Shouldn't sign_extend() return a int16_t instead of a uint16_t?
AndrejMitrovic opened this issue · 4 comments
According to the spec:
PCoffset9 A 9-bit value; bits [8:0] of an instruction; used with the PC+offset addressing mode.
Bits [8:0] are taken as a 9-bit signed 2’s complement integer, sign-extended to 16
bits and then added to the incremented PC to form an address. Range −256..255.
In the LDI implementation example the memory read will always be positively offsetted compared to the PC because the return value of sign_extend is an unsigned type:
{
/* destination register (DR) */
uint16_t r0 = (instr >> 9) & 0x7;
/* PCoffset 9*/
uint16_t pc_offset = sign_extend(instr & 0x1FF, 9);
/* add pc_offset to the current PC, look at that memory location to get the final address */
reg[r0] = mem_read(mem_read(reg[R_PC] + pc_offset));
update_flags(r0);
}We are storing 2's complement representations in the uint16_t. Think of it as a collection of bits that simulate how C represents signed numbers in the first place. When you add a negative and a positive in this way it will give the correct result, so negative offsets will work fine.
You are correct that negative "vm numbers" will appear positive in C, but we never need to use that fact.
https://en.wikipedia.org/wiki/Two%27s_complement
Adding two's-complement numbers requires no special processing even if the operands have opposite signs: the sign of the result is determined automatically. For example, adding 15 and −5:
That's right. I completely forgot this. :shame: Need to brush up on my CS 101. Thank you.
No worries. Your question made me re-examine it closely. Hope you enjoyed the article.
I forgot to say I enjoyed your article very much! Thanks for your hard work!