Reputation: 75
In assembly, when they say "immediate data" is that signed or unsigned??
I'm writing a Gameboy emulator and am using the opcodes here:
http://www.pastraiser.com/cpu/gameboy/gameboy_opcodes.html
Opcode 0xC6 for example is ADD A, d8.
My guess is that it's unsigned else why would they need "SUB A, d8" but I thought that I'd ask just while I'm checking over my code...
Upvotes: 1
Views: 1870
Reputation: 84745
I'd already written a response saying that immediate data on the Gameboy's CPU, which appears to be based on the Z-80, is signed, when I noticed that this is probably not entirely accurate:
Let's assume that this CPU, since there don't seem to be separate opcodes for signed and unsigned operands, doesn't actually distinguish between signed and unsigned values. That would mean that negative numbers are simply encoded using two's complement form. Using that form, the addition operation works exactly the same way for both signed or unsigned numbers; the CPU simply won't care.
However, you will care when you're interpreting the result. If the above assumption is correct, it means that you can interpret the result of an 8-bit addition however you want, because the addition operation is exactly the same for both signed or unsigned data.
If you added two values that you assume are unsigned, the result will lie in the range 0–255.
If you added two values that you assume are signed (and negative numbers were encoded in two's complement form), the result will lie in the range -128–127.
See e.g. this page on Z-80 assembler.
Upvotes: 3
Reputation: 23783
It seems like it's an unsigned int. Look at MAME's LR35902 CPU emulator, they use UINT8 for the immediate.
Some relevant code:
/* ... */
case 0xC6: /* ADD A,n8 */
x = mem_ReadByte (cpustate, cpustate->w.PC++);
ADD_A_X (x)
break;
/* ... */
#define ADD_A_X(x) \
{ \
register UINT16 r1,r2; \
register UINT8 f; \
r1=(UINT16)((cpustate->b.A&0xF)+((x)&0xF)); \
r2=(UINT16)(cpustate->b.A+(x)); \
cpustate->b.A=(UINT8)r2; \
if( ((UINT8)r2)==0 ) f=FLAG_Z; \
else f=0; \
if( r2>0xFF ) f|=FLAG_C; \
if( r1>0xF ) f|=FLAG_H; \
cpustate->b.F=f; \
}
Now, the routine for LD HL,SP+n8
is
case 0xF8: /* LD HL,SP+n8 */
/*
* n = one UINT8 signed immediate value.
*/
{
register INT32 n;
n = (INT32) ((INT8) mem_ReadByte (cpustate, cpustate->w.PC++));
Here the immediate is cast to an signed 8-bit int (INT8)
, so I imagine it's otherwise unsigned.
Upvotes: 3
Reputation: 20609
In a two's compliment system, it doesn't actually matter of it is signed or unsigned.
Interpretation of the value (and overflow) happens when you do a comparison instruction. Until that point it is just bits. Adding 0x8000 to 0x0001 gives 0x8001 whether or not either of the values is signed or unsigned.
You should look at the opcodes for ADD and SUB. It could be that there are not actually two different operations. It could be that SUB just negates the operand and then issues an ADD instruction.
Upvotes: 6