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 register file, and the two operand buses that read it.

use super::{Cpu, Wide, high_byte, low_byte, wide_value};
use crate::control::{bus, step};
use crate::mcode::IndexState;

impl Cpu {
    pub(super) fn accumulator(&self) -> u8 {
        high_byte(self.registers.af)
    }

    pub(super) fn flags(&self) -> u8 {
        low_byte(self.registers.af)
    }

    pub(super) fn index_register(&self) -> Wide {
        match self.index_state {
            IndexState::Iy => Wide::Iy,
            _ => Wide::Ix,
        }
    }

    pub(super) fn addressed_pair(&self, field: u8, substitute_index: bool) -> Wide {
        let indexed = substitute_index
            && !self.index_displaced()
            && !matches!(self.index_state, IndexState::None);

        match field & 0b11 {
            0b00 => Wide::Bc,
            0b01 => Wide::De,
            0b10 => {
                if indexed {
                    self.index_register()
                } else {
                    Wide::Hl
                }
            }
            _ => Wide::Ix,
        }
    }

    pub(super) fn wide(&self, register: Wide) -> u16 {
        match register {
            Wide::Bc => self.registers.bc,
            Wide::De => self.registers.de,
            Wide::Hl => self.registers.hl,
            Wide::Ix => self.registers.ix,
            Wide::Iy => self.registers.iy,
        }
    }

    pub(super) fn set_wide(&mut self, register: Wide, value: u16) {
        let slot = match register {
            Wide::Bc => &mut self.registers.bc,
            Wide::De => &mut self.registers.de,
            Wide::Hl => &mut self.registers.hl,
            Wide::Ix => &mut self.registers.ix,
            Wide::Iy => &mut self.registers.iy,
        };
        *slot = value;
    }

    pub(super) fn set_wide_high(&mut self, register: Wide, value: u8) {
        let low = low_byte(self.wide(register));
        self.set_wide(register, wide_value(value, low));
    }

    pub(super) fn set_wide_low(&mut self, register: Wide, value: u8) {
        let high = high_byte(self.wide(register));
        self.set_wide(register, wide_value(high, value));
    }

    pub(super) fn first_operand(&self, selector: u8) -> u8 {
        let pair = self.wide(self.addressed_pair(selector >> 1, true));

        match selector & bus::MASK {
            0..=bus::REGISTER_LAST => {
                if selector & 1 == 1 {
                    low_byte(pair)
                } else {
                    high_byte(pair)
                }
            }
            bus::DATA_LATCH => self.data_latch,
            bus::ACCUMULATOR => self.accumulator(),
            bus::STACK_LOW => low_byte(self.registers.sp),
            bus::STACK_HIGH => high_byte(self.registers.sp),
            _ => 0x00,
        }
    }

    pub(super) fn second_operand(&self, selector: u8) -> u8 {
        let pair = self.wide(self.addressed_pair(selector >> 1, true));

        match selector & bus::MASK {
            0..=bus::REGISTER_LAST => {
                if selector & 1 == 1 {
                    low_byte(pair)
                } else {
                    high_byte(pair)
                }
            }
            bus::DATA_LATCH => self.data_latch,
            bus::ACCUMULATOR => self.accumulator(),
            bus::STACK_LOW => low_byte(self.registers.sp),
            bus::STACK_HIGH => high_byte(self.registers.sp),
            bus::ONE => 1,
            bus::FLAGS => self.flags(),
            bus::PROGRAM_COUNTER_LOW => low_byte(self.registers.pc),
            bus::PROGRAM_COUNTER_HIGH => high_byte(self.registers.pc),
            _ => 0x00,
        }
    }

    pub(super) fn operands(&self, first: u8, second: u8, displaced_bit: bool) -> (u8, u8) {
        if displaced_bit {
            (self.data_latch, self.data_latch)
        } else {
            (self.first_operand(first), self.second_operand(second))
        }
    }

    pub(super) fn step_pair(&mut self, control: u8) {
        if !step::enabled(control) {
            return;
        }

        let field = step::pair(control);
        let decrement = step::counts_down(control);

        if step::is_stack_pointer(control) {
            self.registers.sp = if decrement {
                self.registers.sp.wrapping_sub(1)
            } else {
                self.registers.sp.wrapping_add(1)
            };
            return;
        }

        let register = self.addressed_pair(field, true);
        let stepped = if decrement {
            self.wide(register).wrapping_sub(1)
        } else {
            self.wide(register).wrapping_add(1)
        };
        self.set_wide(register, stepped);
    }
}