forked from libre-chip/fayalite
298 lines
9.6 KiB
Rust
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
|