Today you implement JR NZ, e, the first conditional branch, which only jumps when the Z flag is clear and costs a different number of cycles depending on whether the branch is taken - the mechanism behind every if and loop test.
Implement JR NZ, e so it jumps only when the Z flag is clear, and make sure it reports the correct cycle count whether the branch is taken or not.
Real decisions come from conditional branches. JR NZ, e (opcode 0x20)
jumps only when the Z flag is clear (“not zero”); otherwise it reads past
the offset and falls through. The four conditions - NZ, Z, NC, C - pair
with the flags a CP or DEC just set, which is how if and loop tests
execute.
There is a timing wrinkle unique to conditional instructions: they cost more
cycles when the branch is taken (12) than when it is not (8), because taking
the branch does extra work. You must fetch the operand in both cases so PC
advances correctly on a fall-through. Return the right cycle count for each path
case 0x20: // JR NZ, ee := int8(c.fetch())if c.F&FlagZ == 0 {c.PC = uint16(int(c.PC) + int(e))return 12}return 8
Conditional jumps (NZ, Z, NC, C) and their taken/not-taken cycle counts.