celox 0.4.1

Celox HDL Simulator
Documentation
#![cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]

use celox::{BigUint, Simulator};

#[test]
fn native_shifts_respect_source_width_and_large_counts() {
    let code = r#"
module Top (
    sh: input logic<8>,
    u8v: input logic<8>,
    s8v: input signed logic<8>,
    shl8: output logic<8>,
    shr8: output logic<8>,
    sar8: output signed logic<8>,
    u16v: input logic<16>,
    s16v: input signed logic<16>,
    shl16: output logic<16>,
    shr16: output logic<16>,
    sar16: output signed logic<16>,
    u32v: input logic<32>,
    s32v: input signed logic<32>,
    shl32: output logic<32>,
    shr32: output logic<32>,
    sar32: output signed logic<32>,
    u64v: input logic<64>,
    s64v: input signed logic<64>,
    shl64: output logic<64>,
    shr64: output logic<64>,
    sar64: output signed logic<64>
) {
    assign shl8 = u8v << sh;
    assign shr8 = u8v >> sh;
    assign sar8 = s8v >>> sh;
    assign shl16 = u16v << sh;
    assign shr16 = u16v >> sh;
    assign sar16 = s16v >>> sh;
    assign shl32 = u32v << sh;
    assign shr32 = u32v >> sh;
    assign sar32 = s32v >>> sh;
    assign shl64 = u64v << sh;
    assign shr64 = u64v >> sh;
    assign sar64 = s64v >>> sh;
}
"#;
    let mut sim = Simulator::builder(code, "Top").build_native().unwrap();
    let sh = sim.signal("sh");
    let cases = [
        (
            8u32,
            sim.signal("u8v"),
            sim.signal("s8v"),
            sim.signal("shl8"),
            sim.signal("shr8"),
            sim.signal("sar8"),
        ),
        (
            16,
            sim.signal("u16v"),
            sim.signal("s16v"),
            sim.signal("shl16"),
            sim.signal("shr16"),
            sim.signal("sar16"),
        ),
        (
            32,
            sim.signal("u32v"),
            sim.signal("s32v"),
            sim.signal("shl32"),
            sim.signal("shr32"),
            sim.signal("sar32"),
        ),
        (
            64,
            sim.signal("u64v"),
            sim.signal("s64v"),
            sim.signal("shl64"),
            sim.signal("shr64"),
            sim.signal("sar64"),
        ),
    ];

    sim.modify(|io| {
        for (width, unsigned, signed, ..) in cases {
            let value = test_value(width);
            match width {
                8 => {
                    io.set(unsigned, value as u8);
                    io.set(signed, value as u8);
                }
                16 => {
                    io.set(unsigned, value as u16);
                    io.set(signed, value as u16);
                }
                32 => {
                    io.set(unsigned, value as u32);
                    io.set(signed, value as u32);
                }
                64 => {
                    io.set(unsigned, value);
                    io.set(signed, value);
                }
                _ => unreachable!(),
            }
        }
    })
    .unwrap();

    for count in [
        7u64, 8, 9, 15, 16, 17, 31, 32, 33, 63, 64, 65, 127, 128, 129,
    ] {
        sim.modify(|io| io.set(sh, count as u8)).unwrap();
        for (width, _, _, shl, shr, sar) in cases {
            let value = test_value(width);
            let mask = width_mask(width);
            let expected_shl = if count >= u64::from(width) {
                0
            } else {
                (value << count) & mask
            };
            let expected_shr = if count >= u64::from(width) {
                0
            } else {
                value >> count
            };
            let expected_sar = if count >= u64::from(width) {
                mask
            } else {
                (((value | !mask) as i64) >> count) as u64 & mask
            };
            assert_eq!(
                sim.get(shl),
                BigUint::from(expected_shl),
                "shl width={width} count={count}"
            );
            assert_eq!(
                sim.get(shr),
                BigUint::from(expected_shr),
                "shr width={width} count={count}"
            );
            assert_eq!(
                sim.get(sar),
                BigUint::from(expected_sar),
                "sar width={width} count={count}"
            );
        }
    }
}

fn width_mask(width: u32) -> u64 {
    if width == 64 {
        u64::MAX
    } else {
        (1u64 << width) - 1
    }
}

fn test_value(width: u32) -> u64 {
    (1u64 << (width - 1)) | 3
}