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 internal address latch, and the per-instruction rules that write it.

use super::{Cpu, low_byte, wide_value};
use crate::mcode::{Decoded, IndexState, InstructionSet};

impl Cpu {
    pub(super) fn immediate_address(&self) -> u16 {
        wide_value(self.data_latch, low_byte(self.tmp_addr))
    }

    pub(super) fn set_latch(&mut self, value: u16) {
        self.registers.wz = value;
    }

    pub(super) fn set_latch_from_accumulator(&mut self, address: u16) {
        let low = low_byte(address.wrapping_add(1));
        self.registers.wz = wide_value(self.accumulator(), low);
    }

    #[allow(clippy::too_many_lines)]
    pub(super) fn update_latch(&mut self, decoded: &Decoded, cycle: u8) {
        if !matches!(self.index_state, IndexState::None) && self.index_displaced() {
            self.registers.wz = self.tmp_addr;
        }

        match self.instruction_set {
            InstructionSet::Cb => {}
            InstructionSet::Ed => self.update_latch_extended(decoded, cycle),
            _ => self.update_latch_base(decoded, cycle),
        }
    }

    pub(super) fn update_latch_base(&mut self, decoded: &Decoded, cycle: u8) {
        let ir = self.ir;
        let indexed = !matches!(self.index_state, IndexState::None);

        match ir {
            0x0A if cycle == 1 => self.set_latch(self.registers.bc.wrapping_add(1)),
            0x1A if cycle == 1 => self.set_latch(self.registers.de.wrapping_add(1)),
            0x02 if cycle == 1 => self.set_latch_from_accumulator(self.registers.bc),
            0x12 if cycle == 1 => self.set_latch_from_accumulator(self.registers.de),
            0x3A if cycle == 3 => self.set_latch(self.immediate_address().wrapping_add(1)),
            0x32 if cycle == 3 => self.set_latch_from_accumulator(self.immediate_address()),
            0x2A | 0x22 if cycle == 3 => self.set_latch(self.tmp_addr.wrapping_add(1)),
            0x09 | 0x19 | 0x29 | 0x39 if cycle == 1 => {
                let base = if indexed {
                    self.wide(self.index_register())
                } else {
                    self.registers.hl
                };
                self.set_latch(base.wrapping_add(1));
            }
            0xC3 | 0xC2 | 0xCA | 0xD2 | 0xDA | 0xE2 | 0xEA | 0xF2 | 0xFA | 0xC9 | 0xC0 | 0xC8
            | 0xD0 | 0xD8 | 0xE0 | 0xE8 | 0xF0 | 0xF8
                if cycle == 3 =>
            {
                self.set_latch(self.immediate_address());
            }
            0xCD | 0xC4 | 0xCC | 0xD4 | 0xDC | 0xE4 | 0xEC | 0xF4 | 0xFC | 0xC7 | 0xCF | 0xD7
            | 0xDF | 0xE7 | 0xEF | 0xF7 | 0xFF
                if cycle == 3 =>
            {
                self.set_latch(self.tmp_addr);
            }
            0x18 | 0x20 | 0x28 | 0x30 | 0x38 | 0x10 if cycle == 3 && decoded.jump_e() => {
                self.set_latch(self.registers.pc);
            }
            0xDB if cycle == 2 => self.set_latch(self.address.wrapping_add(1)),
            0xD3 if cycle == 2 => self.set_latch_from_accumulator(self.address),
            0xE3 if cycle == 5 => self.set_latch(self.tmp_addr),
            _ => {}
        }
    }

    pub(super) fn update_latch_extended(&mut self, decoded: &Decoded, cycle: u8) {
        let ir = self.ir;
        let _ = decoded;

        match ir {
            0x4B | 0x5B | 0x6B | 0x7B | 0x43 | 0x53 | 0x63 | 0x73 if cycle == 3 => {
                self.set_latch(self.tmp_addr.wrapping_add(1));
            }
            0x4A | 0x5A | 0x6A | 0x7A | 0x42 | 0x52 | 0x62 | 0x72 if cycle == 1 => {
                self.set_latch(self.registers.hl.wrapping_add(1));
            }
            0x40 | 0x48 | 0x50 | 0x58 | 0x60 | 0x68 | 0x70 | 0x78 | 0x41 | 0x49 | 0x51 | 0x59
            | 0x61 | 0x69 | 0x71 | 0x79
                if cycle == 1 =>
            {
                self.set_latch(self.registers.bc.wrapping_add(1));
            }
            0x4D | 0x45 | 0x55 | 0x5D | 0x65 | 0x6D | 0x75 | 0x7D if cycle == 3 => {
                self.set_latch(self.immediate_address());
            }
            0x67 | 0x6F if cycle == 1 => self.set_latch(self.registers.hl.wrapping_add(1)),
            0xA1 | 0xA9 | 0xB1 | 0xB9 if cycle == 1 => {
                let stepped = if ir & 0x08 == 0 {
                    self.registers.wz.wrapping_add(1)
                } else {
                    self.registers.wz.wrapping_sub(1)
                };
                self.set_latch(stepped);
            }
            0xA2 | 0xAA | 0xB2 | 0xBA if cycle == 1 => {
                let stepped = if ir & 0x08 == 0 {
                    self.registers.bc.wrapping_add(1)
                } else {
                    self.registers.bc.wrapping_sub(1)
                };
                self.set_latch(stepped);
            }
            0xA3 | 0xAB | 0xB3 | 0xBB if cycle == 3 => {
                let stepped = if ir & 0x08 == 0 {
                    self.registers.bc.wrapping_add(1)
                } else {
                    self.registers.bc.wrapping_sub(1)
                };
                self.set_latch(stepped);
            }
            0xB0 | 0xB8 | 0xB1 | 0xB9 if cycle == 4 => {
                self.set_latch(self.registers.pc.wrapping_add(1));
            }
            _ => {}
        }
    }
}