use crate::consts::flag;
use crate::types::UndocumentedFlags;
pub(crate) const fn take_undocumented(flags: u8, source: u8) -> u8 {
(flags & !flag::XY_MASK) | (source & flag::XY_MASK)
}
pub(crate) fn report_byte(flags: u8, value: u8, parity: bool) -> u8 {
let mut flags =
flags & !(flag::N_MASK | flag::H_MASK | flag::S_MASK | flag::Z_MASK | flag::P_MASK);
if value & 0x80 != 0 {
flags |= flag::S_MASK;
}
if value == 0 {
flags |= flag::Z_MASK;
}
if parity {
flags |= flag::P_MASK;
}
flags
}
pub(crate) const fn condition_holds(flags: u8, code: u8) -> bool {
let mask = match (code >> 1) & 0x03 {
0b00 => flag::Z_MASK,
0b01 => flag::C_MASK,
0b10 => flag::P_MASK,
_ => flag::S_MASK,
};
(flags & mask != 0) == (code & 0x01 != 0)
}
pub(crate) const fn undocumented_carry_source(
mode: UndocumentedFlags,
accumulator: u8,
flags: u8,
) -> u8 {
match mode {
UndocumentedFlags::Accumulator => accumulator,
UndocumentedFlags::Combined => accumulator | flags,
}
}
pub(crate) fn port_block(flags: u8, bc: u16, hl: u16, ir: u8, value: u8) -> u8 {
let count = bc.to_be_bytes()[0];
let addend = if ir & 0x01 == 0 {
let port = bc.to_be_bytes()[1];
if ir & 0x08 == 0 {
port.wrapping_add(1)
} else {
port.wrapping_sub(1)
}
} else {
hl.to_be_bytes()[1]
};
let sum = u16::from(value) + u16::from(addend);
let carried = sum & 0x100 != 0;
let parity = ((sum.to_be_bytes()[1] & 0x07) ^ count)
.count_ones()
.is_multiple_of(2);
let mut flags = take_undocumented(report_byte(flags, count, parity), count);
if value & 0x80 != 0 {
flags |= flag::N_MASK;
}
if carried {
flags |= flag::H_MASK | flag::C_MASK;
} else {
flags &= !(flag::H_MASK | flag::C_MASK);
}
flags
}