fayalite/crates/fayalite/tests/sim.rs

298 lines
9.6 KiB
Rust

// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
use fayalite::{
int::UIntValue,
prelude::*,
reset::ResetType,
sim::{time::SimDuration, vcd::VcdWriterDecls, Simulation},
util::RcWriter,
};
#[hdl_module(outline_generated)]
pub fn connect_const() {
#[hdl]
let o: UInt<8> = m.output();
connect(o, 5u8);
}
#[test]
fn test_connect_const() {
let _n = SourceLocation::normalize_files_for_tests();
let mut sim = Simulation::new(connect_const());
sim.settle();
let sim_debug = format!("{sim:#?}");
println!("#######\n{sim_debug}\n#######");
if sim_debug != include_str!("sim/expected/connect_const.txt") {
panic!();
}
assert_eq!(sim.read_bool_or_int(sim.io().o), UIntValue::from(5u8));
}
#[hdl_module(outline_generated)]
pub fn connect_const_reset() {
#[hdl]
let reset_out: Reset = m.output();
#[hdl]
let bit_out: Bool = m.output();
connect(reset_out, true.to_async_reset().to_reset());
connect(bit_out, reset_out.cast_to_static());
}
#[test]
fn test_connect_const_reset() {
let _n = SourceLocation::normalize_files_for_tests();
let mut sim = Simulation::new(connect_const_reset());
let mut writer = RcWriter::default();
sim.add_trace_writer(VcdWriterDecls::new(writer.clone()));
sim.settle();
sim.advance_time(SimDuration::from_micros(1));
sim.flush_traces().unwrap();
let vcd = String::from_utf8(writer.take()).unwrap();
println!("####### VCD:\n{vcd}\n#######");
if vcd != include_str!("sim/expected/connect_const_reset.vcd") {
panic!();
}
let sim_debug = format!("{sim:#?}");
println!("#######\n{sim_debug}\n#######");
if sim_debug != include_str!("sim/expected/connect_const_reset.txt") {
panic!();
}
assert_eq!(sim.read_bool_or_int(sim.io().bit_out), true);
}
#[hdl_module(outline_generated)]
pub fn mod1_child() {
#[hdl]
let i: UInt<4> = m.input();
#[hdl]
let o: SInt<2> = m.output();
#[hdl]
let i2: SInt<2> = m.input();
#[hdl]
let o2: UInt<4> = m.output();
connect(o, i.cast_to_static());
connect(o2, i2.cast_to_static());
#[hdl]
if i.cmp_gt(5_hdl_u4) {
connect(o2, 0xF_hdl_u4);
}
}
#[hdl_module(outline_generated)]
pub fn mod1() {
#[hdl]
let child = instance(mod1_child());
#[hdl]
let o: mod1_child = m.output(Expr::ty(child));
connect(o, child);
}
#[hdl]
#[test]
fn test_mod1() {
let _n = SourceLocation::normalize_files_for_tests();
let mut sim = Simulation::new(mod1());
let mut writer = RcWriter::default();
sim.add_trace_writer(VcdWriterDecls::new(writer.clone()));
sim.write_bool_or_int(sim.io().o.i, 0x3_hdl_u4);
sim.write_bool_or_int(sim.io().o.i2, -2_hdl_i2);
sim.advance_time(SimDuration::from_micros(1));
sim.write_bool_or_int(sim.io().o.i, 0xA_hdl_u4);
sim.advance_time(SimDuration::from_micros(1));
sim.flush_traces().unwrap();
let vcd = String::from_utf8(writer.take()).unwrap();
println!("####### VCD:\n{vcd}\n#######");
if vcd != include_str!("sim/expected/mod1.vcd") {
panic!();
}
let sim_debug = format!("{sim:#?}");
println!("#######\n{sim_debug}\n#######");
if sim_debug != include_str!("sim/expected/mod1.txt") {
panic!();
}
let expected = -2_hdl_i2;
assert_eq!(sim.read_bool_or_int(sim.io().o.o).to_expr(), expected);
let expected = 0xF_hdl_u4;
assert_eq!(sim.read_bool_or_int(sim.io().o.o2).to_expr(), expected);
}
#[hdl_module(outline_generated)]
pub fn counter<R: ResetType>() {
#[hdl]
let cd: ClockDomain<R> = m.input();
#[hdl]
let count_reg: UInt<4> = reg_builder().clock_domain(cd).reset(3_hdl_u4);
connect_any(count_reg, count_reg + 1_hdl_u1);
#[hdl]
let count: UInt<4> = m.output();
connect(count, count_reg);
}
#[hdl]
#[test]
fn test_counter_sync() {
let _n = SourceLocation::normalize_files_for_tests();
let mut sim = Simulation::new(counter::<SyncReset>());
let mut writer = RcWriter::default();
sim.add_trace_writer(VcdWriterDecls::new(writer.clone()));
sim.write_clock(sim.io().cd.clk, false);
sim.write_reset(sim.io().cd.rst, true);
sim.advance_time(SimDuration::from_micros(1));
sim.write_clock(sim.io().cd.clk, true);
sim.settle();
let reset_value = 3_hdl_u4;
assert_eq!(
reset_value,
sim.read_bool_or_int(sim.io().count).to_expr(),
"vcd:\n{}",
String::from_utf8(writer.take()).unwrap(),
);
sim.write_reset(sim.io().cd.rst, false);
sim.advance_time(SimDuration::from_micros(1));
for i in 0..32u32 {
assert_eq!(
UInt::<4>::new_static().from_int_wrapping(i + 3),
sim.read_bool_or_int(sim.io().count),
"vcd:\n{}",
String::from_utf8(writer.take()).unwrap(),
);
sim.write_clock(sim.io().cd.clk, false);
sim.advance_time(SimDuration::from_micros(1));
sim.write_clock(sim.io().cd.clk, true);
sim.advance_time(SimDuration::from_micros(1));
}
sim.flush_traces().unwrap();
let vcd = String::from_utf8(writer.take()).unwrap();
println!("####### VCD:\n{vcd}\n#######");
if vcd != include_str!("sim/expected/counter_sync.vcd") {
panic!();
}
let sim_debug = format!("{sim:#?}");
println!("#######\n{sim_debug}\n#######");
if sim_debug != include_str!("sim/expected/counter_sync.txt") {
panic!();
}
}
#[hdl]
#[test]
fn test_counter_async() {
let _n = SourceLocation::normalize_files_for_tests();
let mut sim = Simulation::new(counter::<AsyncReset>());
let mut writer = RcWriter::default();
sim.add_trace_writer(VcdWriterDecls::new(writer.clone()));
sim.write_clock(sim.io().cd.clk, false);
sim.write_reset(sim.io().cd.rst, false);
sim.advance_time(SimDuration::from_nanos(500));
sim.write_reset(sim.io().cd.rst, true);
let reset_value = 3_hdl_u4;
assert_eq!(
reset_value,
sim.read_bool_or_int(sim.io().count).to_expr(),
"vcd:\n{}",
String::from_utf8(writer.take()).unwrap(),
);
sim.advance_time(SimDuration::from_nanos(500));
sim.write_clock(sim.io().cd.clk, true);
sim.advance_time(SimDuration::from_nanos(500));
sim.write_reset(sim.io().cd.rst, false);
sim.advance_time(SimDuration::from_nanos(500));
for i in 0..32u32 {
assert_eq!(
UInt::<4>::new_static().from_int_wrapping(i + 3),
sim.read_bool_or_int(sim.io().count),
"vcd:\n{}",
String::from_utf8(writer.take()).unwrap(),
);
sim.write_clock(sim.io().cd.clk, false);
sim.advance_time(SimDuration::from_micros(1));
sim.write_clock(sim.io().cd.clk, true);
sim.advance_time(SimDuration::from_micros(1));
}
sim.flush_traces().unwrap();
let vcd = String::from_utf8(writer.take()).unwrap();
println!("####### VCD:\n{vcd}\n#######");
if vcd != include_str!("sim/expected/counter_async.vcd") {
panic!();
}
let sim_debug = format!("{sim:#?}");
println!("#######\n{sim_debug}\n#######");
if sim_debug != include_str!("sim/expected/counter_async.txt") {
panic!();
}
}
#[hdl_module(outline_generated)]
pub fn shift_register() {
#[hdl]
let cd: ClockDomain<SyncReset> = m.input();
#[hdl]
let d: Bool = m.input();
#[hdl]
let q: Bool = m.output();
#[hdl]
let reg0: Bool = reg_builder().clock_domain(cd).reset(false);
connect(reg0, d);
#[hdl]
let reg1: Bool = reg_builder().clock_domain(cd).reset(false);
connect(reg1, reg0);
#[hdl]
let reg2: Bool = reg_builder().clock_domain(cd).reset(false);
connect(reg2, reg1);
#[hdl]
let reg3: Bool = reg_builder().clock_domain(cd).reset(false);
connect(reg3, reg2);
connect(q, reg3);
}
#[hdl]
#[test]
fn test_shift_register() {
let _n = SourceLocation::normalize_files_for_tests();
let mut sim = Simulation::new(shift_register());
let mut writer = RcWriter::default();
sim.add_trace_writer(VcdWriterDecls::new(writer.clone()));
sim.write_clock(sim.io().cd.clk, false);
sim.write_reset(sim.io().cd.rst, true);
sim.write_bool(sim.io().d, false);
sim.advance_time(SimDuration::from_micros(1));
sim.write_clock(sim.io().cd.clk, true);
sim.advance_time(SimDuration::from_nanos(100));
sim.write_reset(sim.io().cd.rst, false);
sim.advance_time(SimDuration::from_nanos(900));
let data = [
false, true, true, false, false, true, false, true, true, true, true,
];
for cycle in 0..32usize {
if let Some(out_cycle) = cycle.checked_sub(4) {
if let Some(expected) = data.get(out_cycle) {
assert_eq!(
*expected,
sim.read_bool(sim.io().q),
"cycle: {cycle}\nvcd:\n{}",
String::from_utf8(writer.take()).unwrap(),
);
}
}
sim.write_bool(sim.io().d, data.get(cycle).copied().unwrap_or(false));
sim.write_clock(sim.io().cd.clk, false);
sim.advance_time(SimDuration::from_micros(1));
sim.write_clock(sim.io().cd.clk, true);
sim.advance_time(SimDuration::from_micros(1));
}
sim.flush_traces().unwrap();
let vcd = String::from_utf8(writer.take()).unwrap();
println!("####### VCD:\n{vcd}\n#######");
if vcd != include_str!("sim/expected/shift_register.vcd") {
panic!();
}
let sim_debug = format!("{sim:#?}");
println!("#######\n{sim_debug}\n#######");
if sim_debug != include_str!("sim/expected/shift_register.txt") {
panic!();
}
}
// TODO: add tests for enums
// TODO: add tests for memories