use super::{AddressSource, AluOp, Context, Decoded, IndexState, source};
use crate::control::bus;
fn read_modify_write(out: &mut Decoded, cycle: u8, op: AluOp) {
out.machine_cycles = 3;
match cycle {
1 | 7 => out.set_addr_to = AddressSource::IndexOrHl,
2 => {
out.alu_op = op;
out.set_read_to_reg();
out.set_save_alu();
out.set_addr_to = AddressSource::IndexOrHl;
out.t_states = 4;
}
3 => out.set_write(),
_ => {}
}
}
fn read_and_test(out: &mut Decoded, cycle: u8) {
out.machine_cycles = 2;
match cycle {
1 | 7 => out.set_addr_to = AddressSource::IndexOrHl,
2 => {
out.alu_op = AluOp::Bit;
out.t_states = 4;
}
_ => {}
}
}
pub(super) fn bit(context: Context, out: &mut Decoded) {
let ir = context.ir;
let sss = source(ir);
let cycle = context.machine_cycle.number();
let indexed = !matches!(context.index_state, IndexState::None);
out.set_bus_a_to = sss;
out.set_bus_b_to = sss;
match ir {
0x00..=0x3F if sss != bus::DATA_LATCH => {
if indexed {
out.set_xy_bit_undoc();
read_modify_write(out, cycle, AluOp::Rotate);
} else if cycle == 1 || cycle == 7 {
out.alu_op = AluOp::Rotate;
out.set_read_to_reg();
out.set_save_alu();
}
}
0x06 | 0x0E | 0x16 | 0x1E | 0x26 | 0x2E | 0x36 | 0x3E => {
read_modify_write(out, cycle, AluOp::Rotate);
}
0x40..=0x7F if sss != bus::DATA_LATCH => {
if indexed {
out.set_xy_bit_undoc();
read_and_test(out, cycle);
} else if cycle == 1 || cycle == 7 {
out.set_bus_b_to = sss;
out.alu_op = AluOp::Bit;
}
}
0x46 | 0x4E | 0x56 | 0x5E | 0x66 | 0x6E | 0x76 | 0x7E => read_and_test(out, cycle),
0xC0..=0xFF if sss != bus::DATA_LATCH => bit_write_back(context, out, AluOp::Set),
0xC6 | 0xCE | 0xD6 | 0xDE | 0xE6 | 0xEE | 0xF6 | 0xFE => {
read_modify_write(out, cycle, AluOp::Set);
}
0x80..=0xBF if sss != bus::DATA_LATCH => bit_write_back(context, out, AluOp::Res),
0x86 | 0x8E | 0x96 | 0x9E | 0xA6 | 0xAE | 0xB6 | 0xBE => {
read_modify_write(out, cycle, AluOp::Res);
}
_ => {}
}
}
fn bit_write_back(context: Context, out: &mut Decoded, op: AluOp) {
let cycle = context.machine_cycle.number();
if matches!(context.index_state, IndexState::None) {
if cycle == 1 {
out.alu_op = op;
out.set_read_to_reg();
out.set_save_alu();
} else {
out.machine_cycles = 4;
match cycle {
2 => {
out.set_bus_b_to = bus::DATA_LATCH;
out.alu_op = op;
out.set_read_to_reg();
out.set_save_alu();
out.set_addr_to = AddressSource::IndexOrHl;
out.t_states = 4;
}
3 | 7 => out.set_addr_to = AddressSource::IndexOrHl,
4 => out.set_write(),
_ => {}
}
}
} else {
out.set_xy_bit_undoc();
read_modify_write(out, cycle, op);
}
}