What's new

Question about SBC z80 opcode

roig

New member
I'm trying to emulate the Z80 of the GameBoy but I have questions (my first real attempt to write a GB emulator :) )

I have this this function that handles the SBC:


{
T_8bit l_regvalue; // Value to SUB (T_8bit is unsigned char )
T_8bit l_accvalue; // ACC value (T_8bit is unsigned char )
l_regvalue = GetHigh(l_RegX); // Value from a Register
l_accvalue = GetHigh(m_AF);


if ( IsCFlagSet() ) //If the Carry flag is set it is +1 to the value to sub.
++l_regvalue;


(l_accvalue < l_regvalue) ? SetCFlag(): ClearCFlag(); // SET THE CARRY FLAG... THIS IS WHAT I THINK IS WRONG!..

l_accvalue -= l_regvalue; // do the SUB operation A = A - X


l_accvalue ? ClearZFlag() : SetZFlag(); // If the result is zero.. clear the Z flag else set it.
SetNFlag(); // Set the N Flag

//Set the value in the ACC
SetHigh(m_AF,l_accvalue);
}

The question is how the Z80 handles the negative values in registers? And how to check exactly if there Carry/borro in SBC opcodes with negative / positive values? I'm a bit lost here...

And another question.. It's true that to emulate the Z80 we don't need to calculate the Half CArry flag? I can't find any opcode that uses it..

Sorry for my english!

Thanks!
 

mrmudlord

New member
Well, from what I see how a good emu like Zboy does it, negative values are done by setting the carry flag and then incrementing the register by 0xFF

inline void SbcA(uint8_t ValToSub) {
/* Subtract content of ValToSub along with the Carry flag from A, and sets some Z80 flags */
/*static uint8_t UbyteBuff, FlagC; */
static signed int IntBuff, FlagC;
if (GetFlagC() != 0) FlagC = 1; else FlagC = 0; /* UbyteBuff--; */
IntBuff = Register.A - (ValToSub + FlagC);
if (IntBuff < 0) {
SetFlagC();
IntBuff += 256;
} else {
ResetFlagC();
}
if (((Register.A & bx00001111) - (ValToSub & bx00001111) - FlagC) < 0) {
SetFlagH();
} else {
ResetFlagH();
}
Register.A = IntBuff;
SetFlagN();
if (Register.A == 0) {
SetFlagZ();
} else {
ResetFlagZ();
}
}
 

WingsORC

New member
be careful, the suggestion from mrmudlord involves using integers and not bytes.

and also, intbuff += 256 is equivalent to intbuff &=0xff ; //i.e. wraparound
 

Cyberman

Moderator
Moderator
H flag

The GB doesn't use a Z80 you should look at the gb emulation thread.

I use to have a book on the Z80 in any case only certain instructions set the carry (it's carry or borrow depending on what opcode you use).

Half Carry Flag
The Half-Carry flag is set (1) or cleared (0) depending on the Carry Borrow status between bits 3 and 4 of an 8bit arithmetic operation. This flag is used by the Decimal Adjust Accumulator instruction (DAA) to correct the result of a packed BCD add or substract operation. The H flag is set (1) or cleared (0) according to the following table:

H flag
Add
Substract
1
A Carry occurs from bit 3 to bit 4
A Borrow from bit 4 occurs
0
No Carry occurs from bit 3 to bit 4
No Borrow from Bit 4 occurs






That's what the H flag is for according to Zilog.

Cyb
 
OP
R

roig

New member
Ok I can't find an opcode that use this flag in the Gameboy. For now i'm not implementing it, I just ended with this:

inline void Z80CPU::ALU_SBC(const T_8bit & l_value)
{
ALU_SUB( IsCFlagSet() ? static_cast<T_8bit>(l_value + 0x01) : l_value );
}

inline void Z80CPU::ALU_SUB(const T_8bit & l_valueToSub )
{
// FLAGS Z 1 H C (ZERO - OP - HALFCARRYBIT - CARRY BIT)

l_valueToSub > RegGetAcc() ? SetCFlag() : ClearCFlag(); // C

RegSub(m_AF, l_valueToSub, E_HIGHREG) ? ClearZFlag() : SetZFlag(); // Z
SetNFlag(); // N = 1
}

Thanks for the answers!
 

Top