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 public accessors.

use super::{Cpu, Variant};
use crate::types::{ClockEdge, MachineCycle, Registers, UndocumentedFlags};

impl Cpu {
    /// Returns the register file.
    #[must_use]
    pub fn registers(&self) -> &Registers {
        &self.registers
    }

    /// Returns the register file for modification.
    pub fn registers_mut(&mut self) -> &mut Registers {
        &mut self.registers
    }

    /// Returns the machine cycle the sequencer is in.
    #[must_use]
    pub fn machine_cycle(&self) -> MachineCycle {
        self.machine_cycle
    }

    /// Returns the T-state within the current machine cycle, counting from one.
    #[must_use]
    pub fn t_state(&self) -> u8 {
        self.t_state
    }

    /// Returns the clock edge the next [`Cpu::tick`] will perform.
    #[must_use]
    pub fn clock_edge(&self) -> ClockEdge {
        self.clock_edge
    }

    /// Returns whether the core has executed `HALT` and is waiting for an interrupt.
    #[must_use]
    pub fn is_halted(&self) -> bool {
        self.halted()
    }

    /// Sets or clears the halted state.
    ///
    /// The hardware leaves `HALT` only on reset or on accepting an interrupt. A caller that moves
    /// the program counter to run code of its own needs to clear it explicitly, since the core
    /// would otherwise execute the halt again on the next fetch.
    pub fn set_halted(&mut self, halted: bool) {
        self.set_halted_to(halted);
    }

    /// Sets the state of the maskable interrupt line.
    ///
    /// The line is level sensitive: while it is asserted the core accepts an interrupt at every
    /// instruction boundary at which interrupts are enabled.
    pub fn set_interrupt_requested(&mut self, requested: bool) {
        self.set_interrupt_requested_to(requested);
    }

    /// Returns whether the maskable interrupt line is asserted.
    #[must_use]
    pub fn is_interrupt_requested(&self) -> bool {
        self.interrupt_requested()
    }

    /// Signals a non-maskable interrupt.
    ///
    /// The line is edge sensitive: one call causes one interrupt, which is accepted at the next
    /// instruction boundary regardless of whether interrupts are enabled.
    pub fn request_nmi(&mut self) {
        self.set_nmi_requested_to(true);
    }

    /// Returns whether a non-maskable interrupt is waiting to be accepted.
    #[must_use]
    pub fn is_nmi_requested(&self) -> bool {
        self.nmi_requested()
    }

    /// Selects whether the Z80N instructions are decoded.
    ///
    /// When disabled the extended `ED`-prefixed opcodes they occupy decode as the no-operation
    /// forms a Z80 gives them, so the same instance models a plain Z80.
    pub fn set_z80n_enabled(&mut self, enabled: bool) {
        self.variant = if enabled { Variant::Z80n } else { Variant::Z80 };
    }

    /// Returns whether the Z80N instructions are decoded.
    #[must_use]
    pub fn is_z80n_enabled(&self) -> bool {
        matches!(self.variant, Variant::Z80n)
    }

    /// Selects where `SCF` and `CCF` take the two undocumented flags from.
    pub fn set_undocumented_flags(&mut self, source: UndocumentedFlags) {
        self.undocumented_flags = source;
    }

    /// Returns where `SCF` and `CCF` take the two undocumented flags from.
    #[must_use]
    pub fn undocumented_flags(&self) -> UndocumentedFlags {
        self.undocumented_flags
    }

    /// Exchanges `BC`, `DE` and `HL` with their alternates, as `EXX` does.
    pub fn exchange_register_set(&mut self) {
        core::mem::swap(&mut self.registers.bc, &mut self.registers.bc_alt);
        core::mem::swap(&mut self.registers.de, &mut self.registers.de_alt);
        core::mem::swap(&mut self.registers.hl, &mut self.registers.hl_alt);
    }

    /// Exchanges `AF` with its alternate, as `EX AF, AF'` does.
    pub fn exchange_accumulator(&mut self) {
        core::mem::swap(&mut self.registers.af, &mut self.registers.af_alt);
    }
}