// 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() { #[hdl] let cd: ClockDomain = 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::()); 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::()); 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 = 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