use super::{Cpu, Wide, high_byte, low_byte, wide_value};
use crate::consts::flag;
use crate::control::mask;
use crate::extended::{self};
use crate::host::Host;
use crate::mcode::Decoded;
use crate::types::Z80nCommand;
impl Cpu {
pub(super) fn run_extended(&mut self, decoded: &Decoded) {
let Some(command) = decoded.z80n_command else {
return;
};
let cycle = self.machine_cycle.number();
let last = self.t_state == 4;
match command {
Z80nCommand::SwapNibbleA if self.t_state == 3 => {
let swapped = extended::swap_nibbles(self.accumulator());
self.set_accumulator(swapped);
}
Z80nCommand::MirrorA if self.t_state == 3 => {
let mirrored = extended::mirror(self.accumulator());
self.set_accumulator(mirrored);
}
Z80nCommand::MulDe if last => {
let product = extended::multiply(self.registers.de);
self.registers.de = product;
}
Z80nCommand::AddHlA | Z80nCommand::AddDeA | Z80nCommand::AddBcA if last => {
let register = match command {
Z80nCommand::AddHlA => Wide::Hl,
Z80nCommand::AddDeA => Wide::De,
_ => Wide::Bc,
};
let sum = extended::add_accumulator(self.wide(register), self.accumulator());
self.set_wide(register, sum);
self.set_flags(self.flags() & !flag::C_MASK);
}
Z80nCommand::SetAE if last => {
let selected = extended::bit_from_low_three(low_byte(self.registers.de));
self.set_accumulator(selected);
}
Z80nCommand::PixelAddress if last => {
self.registers.hl = extended::pixel_address(self.registers.de);
}
Z80nCommand::PixelDown if last => {
self.registers.hl = extended::pixel_down(self.registers.hl);
}
Z80nCommand::BslaDeB
| Z80nCommand::BsraDeB
| Z80nCommand::BsrlDeB
| Z80nCommand::BsrfDeB
| Z80nCommand::BrlcDeB
if last =>
{
let kind = match command {
Z80nCommand::BslaDeB => extended::Barrel::Left,
Z80nCommand::BsraDeB => extended::Barrel::ArithmeticRight,
Z80nCommand::BsrlDeB => extended::Barrel::LogicalRight,
Z80nCommand::BsrfDeB => extended::Barrel::FillRight,
_ => extended::Barrel::Rotate,
};
let count = high_byte(self.registers.bc);
self.registers.de = extended::barrel(self.registers.de, count, kind);
}
Z80nCommand::AddHlImmediate
| Z80nCommand::AddDeImmediate
| Z80nCommand::AddBcImmediate
if cycle == 3 && last =>
{
let register = match command {
Z80nCommand::AddHlImmediate => Wide::Hl,
Z80nCommand::AddDeImmediate => Wide::De,
_ => Wide::Bc,
};
let sum = extended::add_immediate(self.wide(register), self.tmp_addr);
self.set_wide(register, sum);
}
Z80nCommand::LdPirx => {
if cycle == 1 && last {
self.address = (self.registers.hl & mask::PATTERN_BASE)
| (self.registers.de & mask::PATTERN_OFFSET);
} else if cycle == 2 {
self.address = self.registers.de;
}
}
Z80nCommand::JpC if cycle == 2 && last => {
let target = (u16::from(self.data_latch) << mask::JUMP_SHIFT) & mask::JUMP_TARGET;
self.registers.pc = (self.registers.pc & mask::JUMP_REGION) | target;
self.address = self.registers.pc;
}
_ => {}
}
}
pub(super) fn intercepts_its_own_cycle(command: Z80nCommand) -> bool {
matches!(
command,
Z80nCommand::NmiAcknowledgeHigh
| Z80nCommand::NmiAcknowledgeLow
| Z80nCommand::ReturnFromNmiLow
| Z80nCommand::ReturnFromNmiHigh
)
}
pub(super) fn report_intercepted<H: Host>(&mut self, decoded: &Decoded, host: &mut H) {
let Some(command) = decoded.z80n_command else {
return;
};
if Self::intercepts_its_own_cycle(command) && self.last_command != decoded.z80n_command {
self.last_command = decoded.z80n_command;
host.z80n_command(command, self.z80n_operand);
}
}
pub(super) fn export_extended<H: Host>(&mut self, decoded: &Decoded, host: &mut H) {
if decoded.z80n_strobe_lo() {
self.z80n_operand = wide_value(high_byte(self.z80n_operand), decoded.z80n_data);
}
if decoded.z80n_strobe_hi() {
self.z80n_operand = wide_value(decoded.z80n_data, low_byte(self.z80n_operand));
}
if decoded.z80n_command != self.last_command {
self.last_command = decoded.z80n_command;
if let Some(command) = decoded.z80n_command {
host.z80n_command(command, self.z80n_operand);
}
}
}
}