fix Simulator panicking when you use PhantomConst
All checks were successful
/ test (pull_request) Successful in 5m2s
/ test (push) Successful in 5m38s

This commit is contained in:
Jacob Lifshay 2025-11-05 22:44:43 -08:00
parent 840c5e1895
commit 0b77d1bea0
Signed by: programmerjake
SSH key fingerprint: SHA256:HnFTLGpSm4Q4Fj502oCFisjZSoakwEuTsJJMSke63RQ
11 changed files with 756 additions and 55 deletions

View file

@ -2244,3 +2244,41 @@ fn test_sim_resettable_counter_async_immediate_reset() {
panic!();
}
}
#[hdl_module(outline_generated)]
pub fn phantom_const() {
#[hdl]
let out: Array<PhantomConst<Vec<String>>, 2> =
m.output(Array::new_static(PhantomConst::new_sized(vec![
"a".into(),
"b".into(),
])));
let _ = out;
#[hdl]
let mut mem = memory(PhantomConst::new("mem_element"));
mem.depth(1);
let port = mem.new_read_port();
connect_any(port.addr, 0u8);
connect(port.clk, false.to_clock());
connect(port.en, false);
}
#[test]
fn test_phantom_const() {
let _n = SourceLocation::normalize_files_for_tests();
let mut sim = Simulation::new(phantom_const());
let mut writer = RcWriter::default();
sim.add_trace_writer(VcdWriterDecls::new(writer.clone()));
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/phantom_const.vcd") {
panic!();
}
let sim_debug = format!("{sim:#?}");
println!("#######\n{sim_debug}\n#######");
if sim_debug != include_str!("sim/expected/phantom_const.txt") {
panic!();
}
}

View file

@ -0,0 +1,514 @@
Simulation {
state: State {
insns: Insns {
state_layout: StateLayout {
ty: TypeLayout {
small_slots: StatePartLayout<SmallSlots> {
len: 5,
debug_data: [
SlotDebugData {
name: "",
ty: Bool,
},
SlotDebugData {
name: "",
ty: Bool,
},
SlotDebugData {
name: "",
ty: Bool,
},
SlotDebugData {
name: "",
ty: Bool,
},
SlotDebugData {
name: "",
ty: UInt<0>,
},
],
..
},
big_slots: StatePartLayout<BigSlots> {
len: 7,
debug_data: [
SlotDebugData {
name: "InstantiatedModule(phantom_const: phantom_const).phantom_const::mem::r0.addr",
ty: UInt<0>,
},
SlotDebugData {
name: "InstantiatedModule(phantom_const: phantom_const).phantom_const::mem::r0.en",
ty: Bool,
},
SlotDebugData {
name: "InstantiatedModule(phantom_const: phantom_const).phantom_const::mem::r0.clk",
ty: Clock,
},
SlotDebugData {
name: "",
ty: UInt<8>,
},
SlotDebugData {
name: "",
ty: UInt<0>,
},
SlotDebugData {
name: "",
ty: Bool,
},
SlotDebugData {
name: "",
ty: Clock,
},
],
..
},
sim_only_slots: StatePartLayout<SimOnlySlots> {
len: 0,
debug_data: [],
layout_data: [],
..
},
},
memories: StatePartLayout<Memories> {
len: 1,
debug_data: [
(),
],
layout_data: [
MemoryData {
array_type: Array<PhantomConst("mem_element"), 1>,
data: [
// len = 0x1
[0x0]: 0x0,
],
},
],
..
},
},
insns: [
// at: module-XXXXXXXXXX.rs:1:1
0: Const {
dest: StatePartIndex<BigSlots>(5), // (0x0) SlotDebugData { name: "", ty: Bool },
value: 0x0,
},
1: Copy {
dest: StatePartIndex<BigSlots>(6), // (0x0) SlotDebugData { name: "", ty: Clock },
src: StatePartIndex<BigSlots>(5), // (0x0) SlotDebugData { name: "", ty: Bool },
},
// at: module-XXXXXXXXXX.rs:6:1
2: Copy {
dest: StatePartIndex<BigSlots>(2), // (0x0) SlotDebugData { name: "InstantiatedModule(phantom_const: phantom_const).phantom_const::mem::r0.clk", ty: Clock },
src: StatePartIndex<BigSlots>(6), // (0x0) SlotDebugData { name: "", ty: Clock },
},
// at: module-XXXXXXXXXX.rs:7:1
3: Copy {
dest: StatePartIndex<BigSlots>(1), // (0x0) SlotDebugData { name: "InstantiatedModule(phantom_const: phantom_const).phantom_const::mem::r0.en", ty: Bool },
src: StatePartIndex<BigSlots>(5), // (0x0) SlotDebugData { name: "", ty: Bool },
},
// at: module-XXXXXXXXXX.rs:1:1
4: Const {
dest: StatePartIndex<BigSlots>(3), // (0x0) SlotDebugData { name: "", ty: UInt<8> },
value: 0x0,
},
5: CastToUInt {
dest: StatePartIndex<BigSlots>(4), // (0x0) SlotDebugData { name: "", ty: UInt<0> },
src: StatePartIndex<BigSlots>(3), // (0x0) SlotDebugData { name: "", ty: UInt<8> },
dest_width: 0,
},
// at: module-XXXXXXXXXX.rs:5:1
6: Copy {
dest: StatePartIndex<BigSlots>(0), // (0x0) SlotDebugData { name: "InstantiatedModule(phantom_const: phantom_const).phantom_const::mem::r0.addr", ty: UInt<0> },
src: StatePartIndex<BigSlots>(4), // (0x0) SlotDebugData { name: "", ty: UInt<0> },
},
// at: module-XXXXXXXXXX.rs:3:1
7: CastBigToArrayIndex {
dest: StatePartIndex<SmallSlots>(4), // (0x0 0) SlotDebugData { name: "", ty: UInt<0> },
src: StatePartIndex<BigSlots>(0), // (0x0) SlotDebugData { name: "InstantiatedModule(phantom_const: phantom_const).phantom_const::mem::r0.addr", ty: UInt<0> },
},
8: IsNonZeroDestIsSmall {
dest: StatePartIndex<SmallSlots>(3), // (0x0 0) SlotDebugData { name: "", ty: Bool },
src: StatePartIndex<BigSlots>(1), // (0x0) SlotDebugData { name: "InstantiatedModule(phantom_const: phantom_const).phantom_const::mem::r0.en", ty: Bool },
},
9: BranchIfSmallZero {
target: 11,
value: StatePartIndex<SmallSlots>(3), // (0x0 0) SlotDebugData { name: "", ty: Bool },
},
10: Branch {
target: 11,
},
11: IsNonZeroDestIsSmall {
dest: StatePartIndex<SmallSlots>(2), // (0x0 0) SlotDebugData { name: "", ty: Bool },
src: StatePartIndex<BigSlots>(2), // (0x0) SlotDebugData { name: "InstantiatedModule(phantom_const: phantom_const).phantom_const::mem::r0.clk", ty: Clock },
},
12: AndSmall {
dest: StatePartIndex<SmallSlots>(1), // (0x0 0) SlotDebugData { name: "", ty: Bool },
lhs: StatePartIndex<SmallSlots>(2), // (0x0 0) SlotDebugData { name: "", ty: Bool },
rhs: StatePartIndex<SmallSlots>(0), // (0x1 1) SlotDebugData { name: "", ty: Bool },
},
13: BranchIfSmallZero {
target: 14,
value: StatePartIndex<SmallSlots>(1), // (0x0 0) SlotDebugData { name: "", ty: Bool },
},
14: XorSmallImmediate {
dest: StatePartIndex<SmallSlots>(0), // (0x1 1) SlotDebugData { name: "", ty: Bool },
lhs: StatePartIndex<SmallSlots>(2), // (0x0 0) SlotDebugData { name: "", ty: Bool },
rhs: 0x1,
},
// at: module-XXXXXXXXXX.rs:1:1
15: Return,
],
..
},
pc: 15,
memory_write_log: [],
memories: StatePart {
value: [
MemoryData {
array_type: Array<PhantomConst("mem_element"), 1>,
data: [
// len = 0x1
[0x0]: 0x0,
],
},
],
},
small_slots: StatePart {
value: [
1,
0,
0,
0,
0,
],
},
big_slots: StatePart {
value: [
0,
0,
0,
0,
0,
0,
0,
],
},
sim_only_slots: StatePart {
value: [],
},
},
io: Instance {
name: <simulator>::phantom_const,
instantiated: Module {
name: phantom_const,
..
},
},
main_module: SimulationModuleState {
base_targets: [
Instance {
name: <simulator>::phantom_const,
instantiated: Module {
name: phantom_const,
..
},
}.out,
],
uninitialized_ios: {},
io_targets: {
Instance {
name: <simulator>::phantom_const,
instantiated: Module {
name: phantom_const,
..
},
}.out,
Instance {
name: <simulator>::phantom_const,
instantiated: Module {
name: phantom_const,
..
},
}.out[0],
Instance {
name: <simulator>::phantom_const,
instantiated: Module {
name: phantom_const,
..
},
}.out[1],
},
did_initial_settle: true,
},
extern_modules: [],
trace_decls: TraceModule {
name: "phantom_const",
children: [
TraceModuleIO {
name: "out",
child: TraceArray {
name: "out",
elements: [
TracePhantomConst {
location: TraceScalarId(0),
name: "[0]",
ty: PhantomConst(
["a","b"],
),
flow: Sink,
},
TracePhantomConst {
location: TraceScalarId(1),
name: "[1]",
ty: PhantomConst(
["a","b"],
),
flow: Sink,
},
],
ty: Array<PhantomConst(["a","b"]), 2>,
flow: Sink,
},
ty: Array<PhantomConst(["a","b"]), 2>,
flow: Sink,
},
TraceMem {
id: TraceMemoryId(0),
name: "mem",
stride: 0,
element_type: TracePhantomConst {
location: TraceMemoryLocation {
id: TraceMemoryId(0),
depth: 1,
stride: 0,
start: 0,
len: 0,
},
name: "mem",
ty: PhantomConst(
"mem_element",
),
flow: Duplex,
},
ports: [
TraceMemPort {
name: "r0",
bundle: TraceBundle {
name: "r0",
fields: [
TraceUInt {
location: TraceScalarId(2),
name: "addr",
ty: UInt<0>,
flow: Sink,
},
TraceBool {
location: TraceScalarId(3),
name: "en",
flow: Sink,
},
TraceClock {
location: TraceScalarId(4),
name: "clk",
flow: Sink,
},
TracePhantomConst {
location: TraceScalarId(5),
name: "data",
ty: PhantomConst(
"mem_element",
),
flow: Source,
},
],
ty: Bundle {
/* offset = 0 */
addr: UInt<0>,
/* offset = 0 */
en: Bool,
/* offset = 1 */
clk: Clock,
#[hdl(flip)] /* offset = 2 */
data: PhantomConst(
"mem_element",
),
},
flow: Sink,
},
ty: Bundle {
/* offset = 0 */
addr: UInt<0>,
/* offset = 0 */
en: Bool,
/* offset = 1 */
clk: Clock,
#[hdl(flip)] /* offset = 2 */
data: PhantomConst(
"mem_element",
),
},
},
],
array_type: Array<PhantomConst("mem_element"), 1>,
},
],
},
traces: [
SimTrace {
id: TraceScalarId(0),
kind: PhantomConst {
ty: PhantomConst(
["a","b"],
),
},
state: PhantomConst,
last_state: PhantomConst,
},
SimTrace {
id: TraceScalarId(1),
kind: PhantomConst {
ty: PhantomConst(
["a","b"],
),
},
state: PhantomConst,
last_state: PhantomConst,
},
SimTrace {
id: TraceScalarId(2),
kind: BigUInt {
index: StatePartIndex<BigSlots>(0),
ty: UInt<0>,
},
state: 0x0,
last_state: 0x0,
},
SimTrace {
id: TraceScalarId(3),
kind: BigBool {
index: StatePartIndex<BigSlots>(1),
},
state: 0x0,
last_state: 0x0,
},
SimTrace {
id: TraceScalarId(4),
kind: BigClock {
index: StatePartIndex<BigSlots>(2),
},
state: 0x0,
last_state: 0x0,
},
SimTrace {
id: TraceScalarId(5),
kind: PhantomConst {
ty: PhantomConst(
"mem_element",
),
},
state: PhantomConst,
last_state: PhantomConst,
},
],
trace_memories: {
StatePartIndex<Memories>(0): TraceMem {
id: TraceMemoryId(0),
name: "mem",
stride: 0,
element_type: TracePhantomConst {
location: TraceMemoryLocation {
id: TraceMemoryId(0),
depth: 1,
stride: 0,
start: 0,
len: 0,
},
name: "mem",
ty: PhantomConst(
"mem_element",
),
flow: Duplex,
},
ports: [
TraceMemPort {
name: "r0",
bundle: TraceBundle {
name: "r0",
fields: [
TraceUInt {
location: TraceScalarId(2),
name: "addr",
ty: UInt<0>,
flow: Sink,
},
TraceBool {
location: TraceScalarId(3),
name: "en",
flow: Sink,
},
TraceClock {
location: TraceScalarId(4),
name: "clk",
flow: Sink,
},
TracePhantomConst {
location: TraceScalarId(5),
name: "data",
ty: PhantomConst(
"mem_element",
),
flow: Source,
},
],
ty: Bundle {
/* offset = 0 */
addr: UInt<0>,
/* offset = 0 */
en: Bool,
/* offset = 1 */
clk: Clock,
#[hdl(flip)] /* offset = 2 */
data: PhantomConst(
"mem_element",
),
},
flow: Sink,
},
ty: Bundle {
/* offset = 0 */
addr: UInt<0>,
/* offset = 0 */
en: Bool,
/* offset = 1 */
clk: Clock,
#[hdl(flip)] /* offset = 2 */
data: PhantomConst(
"mem_element",
),
},
},
],
array_type: Array<PhantomConst("mem_element"), 1>,
},
},
trace_writers: [
Running(
VcdWriter {
finished_init: true,
timescale: 1 ps,
..
},
),
],
clocks_triggered: [
StatePartIndex<SmallSlots>(1),
],
event_queue: EventQueue(EventQueueData {
instant: 1 μs,
events: {},
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
..
}

View file

@ -0,0 +1,31 @@
$timescale 1 ps $end
$scope module phantom_const $end
$scope struct out $end
$var string 1 ! \[0] $end
$var string 1 " \[1] $end
$upscope $end
$scope struct mem $end
$scope struct contents $end
$scope struct \[0] $end
$var string 1 ' mem $end
$upscope $end
$upscope $end
$scope struct r0 $end
$var string 0 # addr $end
$var wire 1 $ en $end
$var wire 1 % clk $end
$var string 1 & data $end
$upscope $end
$upscope $end
$upscope $end
$enddefinitions $end
$dumpvars
s0 '
sPhantomConst([\"a\",\"b\"]) !
sPhantomConst([\"a\",\"b\"]) "
s0 #
0$
0%
sPhantomConst(\"mem_element\") &
$end
#1000000