hg80 1.0.0

Z80 and Z80N CPU core, stepped one clock edge at a time
Documentation
// Portions of this file are derived from the T80 Z80-compatible microprocessor core,
// Copyright (c) 2001-2002 Daniel Wallner, and from the T80N modifications made for the
// ZX Spectrum Next Project, Copyright 2020 Fabio Belavenuto, Victor Trucco, Charlie Ingley,
// Garry Lancaster, ACX. Redistributed under the three-clause BSD licence reproduced in NOTICE.

//! The block-instruction flag reports, and the register write-back.

use super::{Cpu, high_byte, low_byte, wide_value};
use crate::control::destination;
use crate::flags;
use crate::mcode::InstructionSet;
use crate::types::MachineCycle;

impl Cpu {
    pub(super) fn repeating_port_block(&self) -> bool {
        matches!(self.instruction_set, InstructionSet::Ed)
            && self.ir & 0xF0 == 0xB0
            && self.ir & 0b110 == 0b010
            && matches!(self.machine_cycle, MachineCycle::M3)
            && !self.end_block()
    }

    pub(super) fn counts_down_the_port_block(&self) -> bool {
        !matches!(self.instruction_set, InstructionSet::Ed) || self.ir != 0x90
    }

    pub(super) fn report_port_block(&mut self, value: u8) {
        let flags = flags::port_block(
            self.flags(),
            self.registers.bc,
            self.registers.hl,
            self.ir,
            value,
        );
        self.set_flags(flags);
    }

    pub(super) fn bit_reaches_memory(&self) -> bool {
        matches!(self.instruction_set, InstructionSet::Cb)
            && (self.ir & 0x07 == 0b110 || self.index_displaced())
    }

    pub(super) const fn take_undocumented(flags: u8, source: u8) -> u8 {
        flags::take_undocumented(flags, source)
    }

    pub(super) fn set_flags(&mut self, flags: u8) {
        self.registers.af = wide_value(self.accumulator(), flags);
    }

    pub(super) fn set_accumulator(&mut self, value: u8) {
        self.registers.af = wide_value(value, self.flags());
    }

    pub(super) fn write_back(&mut self, selector: u8, value: u8) {
        match selector {
            destination::ACCUMULATOR => self.set_accumulator(value),
            0b10110 => self.data_out = value,
            0b11000 => {
                self.registers.sp = wide_value(high_byte(self.registers.sp), value);
            }
            0b11001 => {
                self.registers.sp = wide_value(value, low_byte(self.registers.sp));
            }
            0b11011 => self.set_flags(value),
            0b10000..=0b10101 => {
                let register = self.addressed_pair((selector >> 1) & 0b11, true);
                if selector & 1 == 1 {
                    self.set_wide_low(register, value);
                } else {
                    self.set_wide_high(register, value);
                }
            }
            _ => {}
        }
    }
}