hg80 1.0.0

Z80 and Z80N CPU core, stepped one clock edge at a time
Documentation
use super::*;

#[test]
fn setting_the_carry_reports_the_undocumented_flags_from_the_accumulator_and_the_flags() {
    let (cpu, _, _) = run_from(&[0x37], |cpu| cpu.registers_mut().af = 0x00FF, 1);
    assert_eq!(cpu.registers().af, 0x00ED);

    let (cpu, _, _) = run_from(&[0x37], |cpu| cpu.registers_mut().af = 0xFF00, 1);
    assert_eq!(cpu.registers().af, 0xFF29);
}

#[test]
fn complementing_the_carry_reports_them_the_same_way() {
    let (cpu, _, _) = run_from(&[0x3F], |cpu| cpu.registers_mut().af = 0x005B, 1);
    assert_eq!(cpu.registers().af, 0x0058);
}

#[test]
fn a_displaced_bit_test_takes_its_undocumented_flags_from_the_address() {
    let mut program = vec![0xDD, 0xCB, 0x00, 0x46];
    program.resize(0x2801, 0);
    program[0x2800] = 0x01;
    let (cpu, _, t) = run_from(
        &program,
        |cpu| {
            cpu.registers_mut().ix = 0x2800;
        },
        1,
    );
    assert_eq!(t, 20);
    assert_eq!(cpu.flags() & crate::flag::Z_MASK, 0);
    assert_eq!(cpu.flags() & crate::flag::XY_MASK, crate::flag::XY_MASK);
    assert_eq!(cpu.flags() & crate::flag::H_MASK, crate::flag::H_MASK);
    assert_eq!(cpu.flags() & crate::flag::N_MASK, 0);
}

#[test]
fn a_displaced_bit_test_reports_a_clear_bit_through_the_zero_flag() {
    let mut program = vec![0xDD, 0xCB, 0x00, 0x4E];
    program.resize(0x2801, 0);
    program[0x2800] = 0x01;
    let (cpu, _, _) = run_from(
        &program,
        |cpu| {
            cpu.registers_mut().ix = 0x2800;
        },
        1,
    );
    assert_eq!(cpu.flags() & crate::flag::Z_MASK, crate::flag::Z_MASK);
    assert_eq!(cpu.flags() & crate::flag::P_MASK, crate::flag::P_MASK);
}

#[test]
fn a_bit_test_on_a_register_still_takes_its_flags_from_the_operand() {
    let (cpu, _, _) = run(&[0x3E, 0x28, 0xCB, 0x47], 2);
    assert_eq!(cpu.flags() & crate::flag::XY_MASK, crate::flag::XY_MASK);

    let (cpu, _, _) = run(&[0x3E, 0x01, 0xCB, 0x47], 2);
    assert_eq!(cpu.flags() & crate::flag::XY_MASK, 0);
}

#[test]
fn taking_the_carry_flags_from_the_accumulator_alone_discards_the_incoming_bits() {
    let from_accumulator = |cpu: &mut Cpu| {
        cpu.set_undocumented_flags(crate::UndocumentedFlags::Accumulator);
    };

    let (cpu, _, _) = run_from(
        &[0x37],
        |cpu| {
            from_accumulator(cpu);
            cpu.registers_mut().af = 0x00FF;
        },
        1,
    );
    assert_eq!(cpu.registers().af, 0x00C5);

    let (cpu, _, _) = run_from(
        &[0x3F],
        |cpu| {
            from_accumulator(cpu);
            cpu.registers_mut().af = 0x005B;
        },
        1,
    );
    assert_eq!(cpu.flags() & crate::flag::XY_MASK, 0);

    for opcode in [0x37u8, 0x3F] {
        let (cpu, _, _) = run_from(
            &[opcode],
            |cpu| {
                from_accumulator(cpu);
                cpu.registers_mut().af = 0x0028;
            },
            1,
        );
        assert_eq!(cpu.flags() & crate::flag::XY_MASK, 0, "{opcode:#04X}");

        let (cpu, _, _) = run_from(
            &[opcode],
            |cpu| {
                from_accumulator(cpu);
                cpu.registers_mut().af = 0x2800;
            },
            1,
        );
        assert_eq!(
            cpu.flags() & crate::flag::XY_MASK,
            crate::flag::XY_MASK,
            "{opcode:#04X}"
        );
    }
}

#[test]
fn the_two_flag_sources_are_independent_of_the_instruction_set() {
    let (cpu, _, _) = run_from(
        &[0x37],
        |cpu| {
            cpu.set_z80n_enabled(true);
            cpu.registers_mut().af = 0x00FF;
        },
        1,
    );
    assert_eq!(cpu.registers().af, 0x00ED);
    assert_eq!(cpu.undocumented_flags(), crate::UndocumentedFlags::Combined);
}