From ca759168ff1af50d63c2353dded566e7d5d6ab13 Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Tue, 10 Dec 2024 23:37:26 -0800 Subject: [PATCH] tests/sim: add WIP test for enums --- crates/fayalite/tests/sim.rs | 201 ++++++++++++++++++- crates/fayalite/tests/sim/expected/enums.txt | 0 crates/fayalite/tests/sim/expected/enums.vcd | 0 3 files changed, 200 insertions(+), 1 deletion(-) create mode 100644 crates/fayalite/tests/sim/expected/enums.txt create mode 100644 crates/fayalite/tests/sim/expected/enums.vcd diff --git a/crates/fayalite/tests/sim.rs b/crates/fayalite/tests/sim.rs index 914e64f..db20df2 100644 --- a/crates/fayalite/tests/sim.rs +++ b/crates/fayalite/tests/sim.rs @@ -293,5 +293,204 @@ fn test_shift_register() { } } -// TODO: add tests for enums +#[hdl_module(outline_generated)] +pub fn enums() { + #[hdl] + let cd: ClockDomain = m.input(); + #[hdl] + let en: Bool = m.input(); + #[hdl] + let which_in: UInt<2> = m.input(); + #[hdl] + let data_in: UInt<4> = m.input(); + #[hdl] + let which_out: UInt<2> = m.output(); + #[hdl] + let data_out: UInt<4> = m.output(); + + #[hdl] + struct MyStruct { + a: T, + b: SInt<2>, + } + + #[hdl] + enum MyEnum { + A, + B((UInt<1>, Bool)), + C(MyStruct, 2>>), + } + + #[hdl] + let the_reg = reg_builder().clock_domain(cd).reset(MyEnum.A()); + + #[hdl] + if en { + #[hdl] + if which_in.cmp_eq(0_hdl_u2) { + connect(the_reg, MyEnum.A()); + } else if which_in.cmp_eq(1_hdl_u2) { + connect(the_reg, MyEnum.B((data_in[0].cast_to_static(), data_in[1]))); + } else { + connect( + the_reg, + MyEnum.C( + #[hdl] + MyStruct { + a: #[hdl] + [data_in[0].cast_to_static(), data_in[1].cast_to_static()], + b: data_in[2..4].cast_to_static(), + }, + ), + ); + } + } + + #[hdl] + match the_reg { + MyEnum::A => { + connect(which_out, 0_hdl_u2); + connect(data_out, 0_hdl_u4); + } + MyEnum::B(v) => { + connect(which_out, 1_hdl_u2); + connect_any(data_out, v.0 | (v.1.cast_to_static::>() << 1)); + } + MyEnum::C(v) => { + connect(which_out, 2_hdl_u2); + connect_any(data_out, v.cast_to_bits()); + } + } +} + +#[cfg(todo)] // FIXME: enum lowering currently broken +#[hdl] +#[test] +fn test_enums() { + let _n = SourceLocation::normalize_files_for_tests(); + let mut sim = Simulation::new(enums()); + 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().en, false); + sim.write_bool_or_int(sim.io().which_in, 0_hdl_u2); + sim.write_bool_or_int(sim.io().data_in, 0_hdl_u4); + 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)); + #[derive(Debug, PartialEq, Eq)] + struct IO { + en: bool, + which_in: u8, + data_in: u8, + which_out: u8, + data_out: u8, + } + let io_cycles = [ + IO { + en: false, + which_in: 0, + data_in: 0, + which_out: 0, + data_out: 0, + }, + IO { + en: true, + which_in: 1, + data_in: 0, + which_out: 0, + data_out: 0, + }, + IO { + en: false, + which_in: 0, + data_in: 0, + which_out: 1, + data_out: 0, + }, + IO { + en: true, + which_in: 1, + data_in: 0xF, + which_out: 1, + data_out: 0, + }, + IO { + en: true, + which_in: 1, + data_in: 0xF, + which_out: 1, + data_out: 0x3, + }, + IO { + en: true, + which_in: 2, + data_in: 0xF, + which_out: 1, + data_out: 0x3, + }, + IO { + en: true, + which_in: 2, + data_in: 0xF, + which_out: 2, + data_out: 0xF, + }, + ]; + for ( + cycle, + expected @ IO { + en, + which_in, + data_in, + which_out: _, + data_out: _, + }, + ) in io_cycles.into_iter().enumerate() + { + sim.write_bool(sim.io().en, en); + sim.write_bool_or_int(sim.io().which_in, which_in.cast_to_static()); + sim.write_bool_or_int(sim.io().data_in, data_in.cast_to_static()); + let io = IO { + en, + which_in, + data_in, + which_out: sim + .read_bool_or_int(sim.io().which_out) + .to_bigint() + .try_into() + .expect("known to be in range"), + data_out: sim + .read_bool_or_int(sim.io().data_out) + .to_bigint() + .try_into() + .expect("known to be in range"), + }; + assert_eq!( + expected, + io, + "cycle: {cycle}\nvcd:\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/enums.vcd") { + panic!(); + } + let sim_debug = format!("{sim:#?}"); + println!("#######\n{sim_debug}\n#######"); + if sim_debug != include_str!("sim/expected/enums.txt") { + panic!(); + } +} + // TODO: add tests for memories diff --git a/crates/fayalite/tests/sim/expected/enums.txt b/crates/fayalite/tests/sim/expected/enums.txt new file mode 100644 index 0000000..e69de29 diff --git a/crates/fayalite/tests/sim/expected/enums.vcd b/crates/fayalite/tests/sim/expected/enums.vcd new file mode 100644 index 0000000..e69de29