hg80 1.0.0

Z80 and Z80N CPU core, stepped one clock edge at a time
Documentation
use super::{
    Barrel, add_accumulator, add_immediate, barrel, bit_from_low_three, mirror, multiply,
    pixel_address, pixel_down, swap_nibbles,
};
use std::prelude::rust_2024::*;

#[test]
fn swapping_the_nibbles_exchanges_the_two_halves() {
    assert_eq!(swap_nibbles(0x12), 0x21);
    assert_eq!(swap_nibbles(0xAB), 0xBA);
    assert_eq!(swap_nibbles(0x00), 0x00);
    assert_eq!(swap_nibbles(0xFF), 0xFF);
}

#[test]
fn mirroring_reverses_the_bit_order() {
    assert_eq!(mirror(0b1000_0000), 0b0000_0001);
    assert_eq!(mirror(0b0000_0001), 0b1000_0000);
    assert_eq!(mirror(0b1010_0000), 0b0000_0101);
    assert_eq!(mirror(0xFF), 0xFF);
    assert_eq!(mirror(0x00), 0x00);
}

#[test]
fn multiplying_takes_both_halves_of_the_pair_and_fills_it_with_the_product() {
    assert_eq!(multiply(0x0000), 0);
    assert_eq!(multiply(0x0304), 12);
    assert_eq!(multiply(0xFFFF), 0xFE01);
    assert_eq!(multiply(0x1000), 0);
    assert_eq!(multiply(0x0110), 0x0010);
}

#[test]
fn adding_the_accumulator_wraps_rather_than_overflowing() {
    assert_eq!(add_accumulator(0x1000, 0x34), 0x1034);
    assert_eq!(add_accumulator(0xFFFF, 0x02), 0x0001);
    assert_eq!(add_accumulator(0x0000, 0x00), 0x0000);
}

#[test]
fn adding_an_immediate_wraps_the_same_way() {
    assert_eq!(add_immediate(0x1234, 0x1111), 0x2345);
    assert_eq!(add_immediate(0xFFFF, 0x0001), 0x0000);
}

#[test]
fn the_bit_set_from_a_register_counts_down_from_the_top() {
    assert_eq!(bit_from_low_three(0), 0x80);
    assert_eq!(bit_from_low_three(1), 0x40);
    assert_eq!(bit_from_low_three(2), 0x20);
    assert_eq!(bit_from_low_three(3), 0x10);
    assert_eq!(bit_from_low_three(4), 0x08);
    assert_eq!(bit_from_low_three(5), 0x04);
    assert_eq!(bit_from_low_three(6), 0x02);
    assert_eq!(bit_from_low_three(7), 0x01);
}

#[test]
fn only_the_low_three_bits_of_the_register_select_the_bit() {
    assert_eq!(bit_from_low_three(0xF8), 0x80);
    assert_eq!(bit_from_low_three(0xFF), 0x01);
}

#[test]
fn a_pixel_address_is_assembled_from_the_coordinate_pair() {
    assert_eq!(pixel_address(0x0000), 0x4000);
    assert_eq!(pixel_address(0xFFFF), 0x5FFF);
    assert_eq!(pixel_address(0x00F8), 0x401F);
    assert_eq!(pixel_address(0xC000), 0x5800);
    assert_eq!(pixel_address(0x0700), 0x4700);
    assert_eq!(pixel_address(0x3800), 0x40E0);
}

#[test]
fn stepping_a_pixel_row_down_carries_between_the_three_fields() {
    assert_eq!(pixel_down(0x4000), 0x4100);
    assert_eq!(pixel_down(0x40E0), 0x41E0);
    assert_eq!(pixel_down(0x4700), 0x4020);
    assert_eq!(pixel_down(0x47E0), 0x4800);
}

#[test]
fn stepping_a_pixel_row_leaves_the_untouched_bits_alone() {
    let stepped = pixel_down(0x401F);
    assert_eq!(stepped & 0x001F, 0x001F);
    assert_eq!(stepped & 0xE000, 0x4000);
}

#[test]
fn a_left_barrel_shift_empties_the_pair_once_it_passes_its_width() {
    assert_eq!(barrel(0x1234, 0, Barrel::Left), 0x1234);
    assert_eq!(barrel(0x1234, 4, Barrel::Left), 0x2340);
    assert_eq!(barrel(0x1234, 16, Barrel::Left), 0x0000);
    assert_eq!(barrel(0x1234, 31, Barrel::Left), 0x0000);
}

#[test]
fn a_logical_right_barrel_shift_brings_in_zeroes() {
    assert_eq!(barrel(0x8000, 1, Barrel::LogicalRight), 0x4000);
    assert_eq!(barrel(0x8000, 15, Barrel::LogicalRight), 0x0001);
    assert_eq!(barrel(0x8000, 16, Barrel::LogicalRight), 0x0000);
}

#[test]
fn an_arithmetic_right_barrel_shift_keeps_the_sign() {
    assert_eq!(barrel(0x8000, 1, Barrel::ArithmeticRight), 0xC000);
    assert_eq!(barrel(0x8000, 16, Barrel::ArithmeticRight), 0xFFFF);
    assert_eq!(barrel(0x4000, 1, Barrel::ArithmeticRight), 0x2000);
    assert_eq!(barrel(0x4000, 16, Barrel::ArithmeticRight), 0x0000);
}

#[test]
fn a_filling_right_barrel_shift_brings_in_ones() {
    assert_eq!(barrel(0x0000, 0, Barrel::FillRight), 0x0000);
    assert_eq!(barrel(0x0000, 1, Barrel::FillRight), 0x8000);
    assert_eq!(barrel(0x0000, 4, Barrel::FillRight), 0xF000);
    assert_eq!(barrel(0x0000, 16, Barrel::FillRight), 0xFFFF);
}

#[test]
fn a_rotating_barrel_shift_wraps_within_the_pair() {
    assert_eq!(barrel(0x1234, 0, Barrel::Rotate), 0x1234);
    assert_eq!(barrel(0x8001, 1, Barrel::Rotate), 0x0003);
    assert_eq!(barrel(0x1234, 16, Barrel::Rotate), 0x1234);
    assert_eq!(barrel(0x1234, 4, Barrel::Rotate), 0x2341);
}

#[test]
fn only_the_low_five_bits_of_the_count_are_used() {
    assert_eq!(barrel(0x1234, 0x20, Barrel::Left), 0x1234);
    assert_eq!(
        barrel(0x1234, 0xE4, Barrel::Left),
        barrel(0x1234, 4, Barrel::Left)
    );
}