1use super::types::{
6 ChiselAnalysisCache, ChiselAnnotationKind, ChiselBackend, ChiselConstantFoldingHelper,
7 ChiselDepGraph, ChiselDominatorTree, ChiselExpr, ChiselInterfaceTemplate, ChiselLivenessInfo,
8 ChiselModule, ChiselPassConfig, ChiselPassPhase, ChiselPassRegistry, ChiselPassStats,
9 ChiselPipelineRegisterChain, ChiselPort, ChiselReadyValidBundle, ChiselSRAMWrapper,
10 ChiselStreamingModule, ChiselType, ChiselWorklist, PipelineStage, StreamDirection,
11};
12
13#[cfg(test)]
14mod tests {
15 use super::*;
16 #[test]
17 pub(super) fn test_type_uint() {
18 assert_eq!(ChiselType::UInt(8).to_string(), "UInt(8.W)");
19 }
20 #[test]
21 pub(super) fn test_type_sint() {
22 assert_eq!(ChiselType::SInt(16).to_string(), "SInt(16.W)");
23 }
24 #[test]
25 pub(super) fn test_type_bool() {
26 assert_eq!(ChiselType::Bool.to_string(), "Bool()");
27 }
28 #[test]
29 pub(super) fn test_type_clock() {
30 assert_eq!(ChiselType::Clock.to_string(), "Clock()");
31 }
32 #[test]
33 pub(super) fn test_type_reset() {
34 assert_eq!(ChiselType::Reset.to_string(), "Reset()");
35 }
36 #[test]
37 pub(super) fn test_type_async_reset() {
38 assert_eq!(ChiselType::AsyncReset.to_string(), "AsyncReset()");
39 }
40 #[test]
41 pub(super) fn test_type_vec() {
42 let t = ChiselType::Vec(4, Box::new(ChiselType::UInt(32)));
43 assert_eq!(t.to_string(), "Vec(4, UInt(32.W))");
44 }
45 #[test]
46 pub(super) fn test_type_bundle() {
47 let b = ChiselType::Bundle(vec![
48 ("data".to_string(), Box::new(ChiselType::UInt(8))),
49 ("valid".to_string(), Box::new(ChiselType::Bool)),
50 ]);
51 let s = b.to_string();
52 assert!(s.contains("val data = Output(UInt(8.W))"));
53 assert!(s.contains("val valid = Output(Bool())"));
54 }
55 #[test]
56 pub(super) fn test_port_input() {
57 let p = ChiselPort::input("clk", ChiselType::Clock);
58 assert_eq!(p.name, "clk");
59 assert!(!p.is_output);
60 assert_eq!(p.direction(), "Input");
61 }
62 #[test]
63 pub(super) fn test_port_output() {
64 let p = ChiselPort::output("out", ChiselType::UInt(8));
65 assert_eq!(p.name, "out");
66 assert!(p.is_output);
67 assert_eq!(p.direction(), "Output");
68 }
69 #[test]
70 pub(super) fn test_expr_ulit() {
71 let e = ChiselExpr::ULit(42, 8);
72 assert_eq!(e.to_string(), "42.U(8.W)");
73 }
74 #[test]
75 pub(super) fn test_expr_slit() {
76 let e = ChiselExpr::SLit(-1, 8);
77 assert_eq!(e.to_string(), "-1.S(8.W)");
78 }
79 #[test]
80 pub(super) fn test_expr_bool_lit() {
81 assert_eq!(ChiselExpr::BoolLit(true).to_string(), "true.B");
82 assert_eq!(ChiselExpr::BoolLit(false).to_string(), "false.B");
83 }
84 #[test]
85 pub(super) fn test_expr_var() {
86 let e = ChiselExpr::Var("myReg".to_string());
87 assert_eq!(e.to_string(), "myReg");
88 }
89 #[test]
90 pub(super) fn test_expr_io() {
91 let e = ChiselExpr::Io("in_data".to_string());
92 assert_eq!(e.to_string(), "io.in_data");
93 }
94 #[test]
95 pub(super) fn test_expr_binop() {
96 let lhs = ChiselExpr::Io("a".to_string());
97 let rhs = ChiselExpr::Io("b".to_string());
98 let e = ChiselExpr::BinOp(Box::new(lhs), "+".to_string(), Box::new(rhs));
99 assert_eq!(e.to_string(), "(io.a + io.b)");
100 }
101 #[test]
102 pub(super) fn test_expr_unop() {
103 let inner = ChiselExpr::Io("x".to_string());
104 let e = ChiselExpr::UnOp("~".to_string(), Box::new(inner));
105 assert_eq!(e.to_string(), "(~(io.x))");
106 }
107 #[test]
108 pub(super) fn test_expr_mux() {
109 let e = ChiselExpr::Mux(
110 Box::new(ChiselExpr::Io("sel".to_string())),
111 Box::new(ChiselExpr::ULit(1, 1)),
112 Box::new(ChiselExpr::ULit(0, 1)),
113 );
114 assert_eq!(e.to_string(), "Mux(io.sel, 1.U(1.W), 0.U(1.W))");
115 }
116 #[test]
117 pub(super) fn test_expr_bitslice() {
118 let e = ChiselExpr::BitSlice(Box::new(ChiselExpr::Var("data".to_string())), 7, 0);
119 assert_eq!(e.to_string(), "data(7, 0)");
120 }
121 #[test]
122 pub(super) fn test_expr_cat() {
123 let e = ChiselExpr::Cat(vec![
124 ChiselExpr::Io("msb".to_string()),
125 ChiselExpr::Io("lsb".to_string()),
126 ]);
127 assert_eq!(e.to_string(), "Cat(io.msb, io.lsb)");
128 }
129 #[test]
130 pub(super) fn test_expr_method_call() {
131 let e = ChiselExpr::MethodCall(
132 Box::new(ChiselExpr::Var("fifo".to_string())),
133 "enq".to_string(),
134 vec![ChiselExpr::Io("data".to_string())],
135 );
136 assert_eq!(e.to_string(), "fifo.enq(io.data)");
137 }
138 #[test]
139 pub(super) fn test_connect() {
140 let b = ChiselBackend::new();
141 assert_eq!(b.connect("io.out", "reg_data"), "io.out := reg_data");
142 }
143 #[test]
144 pub(super) fn test_when_stmt() {
145 let b = ChiselBackend::new();
146 let result = b.when_stmt("io.en", "reg_q := io.d");
147 assert!(result.contains("when (io.en)"));
148 assert!(result.contains("reg_q := io.d"));
149 }
150 #[test]
151 pub(super) fn test_when_otherwise() {
152 let b = ChiselBackend::new();
153 let result = b.when_otherwise("io.rst", "reg_q := 0.U", "reg_q := io.d");
154 assert!(result.contains("when (io.rst)"));
155 assert!(result.contains(".otherwise"));
156 assert!(result.contains("reg_q := 0.U"));
157 assert!(result.contains("reg_q := io.d"));
158 }
159 #[test]
160 pub(super) fn test_reg_init() {
161 let b = ChiselBackend::new();
162 let result = b.reg_init("counter", &ChiselType::UInt(8), "0");
163 assert!(result.contains("val counter = RegInit("));
164 assert!(result.contains("UInt(8.W)"));
165 }
166 #[test]
167 pub(super) fn test_reg_no_reset() {
168 let b = ChiselBackend::new();
169 let result = b.reg_no_reset("data_reg", &ChiselType::UInt(32));
170 assert_eq!(result, "val data_reg = Reg(UInt(32.W))");
171 }
172 #[test]
173 pub(super) fn test_wire_decl() {
174 let b = ChiselBackend::new();
175 let result = b.wire_decl("tmp", &ChiselType::Bool);
176 assert_eq!(result, "val tmp = Wire(Bool())");
177 }
178 #[test]
179 pub(super) fn test_printf() {
180 let b = ChiselBackend::new();
181 let r1 = b.printf("val=%d", &["x"]);
182 assert!(r1.contains("printf(\"val=%d\\n\", x)"));
183 let r2 = b.printf("hello", &[]);
184 assert!(r2.contains("printf(\"hello\\n\")"));
185 }
186 #[test]
187 pub(super) fn test_assert_stmt() {
188 let b = ChiselBackend::new();
189 let result = b.assert_stmt("io.valid", "input must be valid");
190 assert_eq!(result, "assert(io.valid, \"input must be valid\")");
191 }
192 #[test]
193 pub(super) fn test_mux_expr() {
194 let b = ChiselBackend::new();
195 assert_eq!(b.mux_expr("sel", "a", "b"), "Mux(sel, a, b)");
196 }
197 #[test]
198 pub(super) fn test_cat_expr() {
199 let b = ChiselBackend::new();
200 assert_eq!(b.cat_expr(&["msb", "lsb"]), "Cat(msb, lsb)");
201 }
202 #[test]
203 pub(super) fn test_fill_expr() {
204 let b = ChiselBackend::new();
205 assert_eq!(b.fill_expr(8, "0.U(1.W)"), "Fill(8, 0.U(1.W))");
206 }
207 #[test]
208 pub(super) fn test_instantiate() {
209 let b = ChiselBackend::new();
210 assert_eq!(
211 b.instantiate("Adder", "u_adder"),
212 "val u_adder = Module(new Adder())"
213 );
214 }
215 #[test]
216 pub(super) fn test_emit_expr() {
217 let b = ChiselBackend::new();
218 let e = ChiselExpr::ULit(255, 8);
219 assert_eq!(b.emit_expr(&e), "255.U(8.W)");
220 }
221 #[test]
222 pub(super) fn test_io_bundle_basic() {
223 let b = ChiselBackend::new();
224 let ports = vec![
225 ChiselPort::input("clk", ChiselType::Clock),
226 ChiselPort::input("in", ChiselType::UInt(8)),
227 ChiselPort::output("out", ChiselType::UInt(8)),
228 ];
229 let result = b.io_bundle(&ports);
230 assert!(result.contains("val io = IO(new Bundle {"));
231 assert!(result.contains("val clk = Input(Clock())"));
232 assert!(result.contains("val in = Input(UInt(8.W))"));
233 assert!(result.contains("val out = Output(UInt(8.W))"));
234 }
235 #[test]
236 pub(super) fn test_io_bundle_empty() {
237 let b = ChiselBackend::new();
238 let result = b.io_bundle(&[]);
239 assert!(result.contains("val io = IO(new Bundle {"));
240 assert!(result.ends_with("})"));
241 }
242 #[test]
243 pub(super) fn test_emit_simple_passthrough() {
244 let b = ChiselBackend::new();
245 let mut m = ChiselModule::new("Passthrough");
246 m.add_input("in", ChiselType::UInt(8));
247 m.add_output("out", ChiselType::UInt(8));
248 m.add_stmt(b.connect("io.out", "io.in"));
249 let code = b.emit_module(&m);
250 assert!(code.contains("class Passthrough extends Module"));
251 assert!(code.contains("import chisel3._"));
252 assert!(code.contains("val io = IO(new Bundle {"));
253 assert!(code.contains("io.out := io.in"));
254 assert!(code.ends_with("}\n"));
255 }
256 #[test]
257 pub(super) fn test_emit_d_flip_flop() {
258 let b = ChiselBackend::new();
259 let mut m = ChiselModule::new("DFlipFlop");
260 m.add_input("d", ChiselType::Bool);
261 m.add_output("q", ChiselType::Bool);
262 m.add_stmt(b.reg_init("reg_q", &ChiselType::Bool, "false"));
263 m.add_stmt(b.connect("reg_q", "io.d"));
264 m.add_stmt(b.connect("io.q", "reg_q"));
265 let code = b.emit_module(&m);
266 assert!(code.contains("class DFlipFlop extends Module"));
267 assert!(code.contains("RegInit("));
268 assert!(code.contains("io.q := reg_q"));
269 }
270 #[test]
271 pub(super) fn test_emit_module_no_ports() {
272 let b = ChiselBackend::new();
273 let m = ChiselModule::new("EmptyMod");
274 let code = b.emit_module(&m);
275 assert!(code.contains("class EmptyMod extends Module"));
276 assert!(code.ends_with("}\n"));
277 }
278 #[test]
279 pub(super) fn test_emit_counter() {
280 let b = ChiselBackend::new();
281 let mut m = ChiselModule::new("Counter");
282 m.add_input("en", ChiselType::Bool);
283 m.add_output("count", ChiselType::UInt(8));
284 m.add_stmt(b.reg_init("cnt", &ChiselType::UInt(8), "0"));
285 m.add_stmt(b.when_stmt("io.en", "cnt := cnt + 1.U"));
286 m.add_stmt(b.connect("io.count", "cnt"));
287 let code = b.emit_module(&m);
288 assert!(code.contains("class Counter extends Module"));
289 assert!(code.contains("when (io.en)"));
290 assert!(code.contains("cnt := cnt + 1.U"));
291 assert!(code.contains("io.count := cnt"));
292 }
293 #[test]
294 pub(super) fn test_chisel_module_add_helpers() {
295 let mut m = ChiselModule::new("Test");
296 m.add_input("a", ChiselType::UInt(4));
297 m.add_output("b", ChiselType::UInt(4));
298 m.add_stmt("val x = Wire(UInt(4.W))");
299 assert_eq!(m.ports.len(), 2);
300 assert_eq!(m.body.len(), 1);
301 }
302 #[test]
303 pub(super) fn test_chisel_backend_default() {
304 let b = ChiselBackend::default();
305 let m = ChiselModule::new("Default");
306 let code = b.emit_module(&m);
307 assert!(code.contains("class Default extends Module"));
308 }
309}
310#[cfg(test)]
311mod chisel_new_tests {
312 use super::*;
313 #[test]
314 pub(super) fn test_ready_valid_bundle_basic() {
315 let rv = ChiselReadyValidBundle::new(ChiselType::UInt(32));
316 let s = rv.emit_decoupled("out_port", true);
317 assert!(s.contains("Decoupled"));
318 assert!(s.contains("out_port"));
319 }
320 #[test]
321 pub(super) fn test_ready_valid_bundle_with_last() {
322 let rv = ChiselReadyValidBundle::new(ChiselType::UInt(8)).with_last();
323 let s = rv.emit_decoupled("stream", true);
324 assert!(s.contains("stream_last"));
325 }
326 #[test]
327 pub(super) fn test_ready_valid_bundle_with_keep() {
328 let rv = ChiselReadyValidBundle::new(ChiselType::UInt(64)).with_keep(8);
329 let s = rv.emit_decoupled("data", true);
330 assert!(s.contains("data_keep"));
331 assert!(s.contains("8.W"));
332 }
333 #[test]
334 pub(super) fn test_ready_valid_fire() {
335 let rv = ChiselReadyValidBundle::new(ChiselType::UInt(32));
336 let s = rv.emit_fire("ch");
337 assert!(s.contains("ch_fire"));
338 assert!(s.contains("ch.valid && ch.ready"));
339 }
340 #[test]
341 pub(super) fn test_ready_valid_queue() {
342 let rv = ChiselReadyValidBundle::new(ChiselType::UInt(8));
343 let s = rv.emit_queue("inp", "out", 16);
344 assert!(s.contains("Queue"));
345 assert!(s.contains("16"));
346 }
347 #[test]
348 pub(super) fn test_streaming_producer_emit() {
349 let m = ChiselStreamingModule::producer("Src", 32).with_tlast();
350 let s = m.emit();
351 assert!(s.contains("class Src extends Module"));
352 assert!(s.contains("tdata"));
353 assert!(s.contains("tvalid"));
354 assert!(s.contains("tready"));
355 assert!(s.contains("tlast"));
356 }
357 #[test]
358 pub(super) fn test_streaming_consumer_emit() {
359 let m = ChiselStreamingModule::consumer("Sink", 64);
360 let s = m.emit();
361 assert!(s.contains("class Sink extends Module"));
362 assert!(s.contains("Input(Bool())"));
363 }
364 #[test]
365 pub(super) fn test_streaming_with_tid_and_tuser() {
366 let m = ChiselStreamingModule::producer("Src2", 128)
367 .with_tid(4)
368 .with_tuser(8);
369 let s = m.emit();
370 assert!(s.contains("tid"));
371 assert!(s.contains("tuser"));
372 assert!(s.contains("4.W"));
373 assert!(s.contains("8.W"));
374 }
375 #[test]
376 pub(super) fn test_streaming_with_body() {
377 let m = ChiselStreamingModule::producer("Gen", 32).add_stmt("val cnt = RegInit(0.U(32.W))");
378 let s = m.emit();
379 assert!(s.contains("val cnt"));
380 }
381 #[test]
382 pub(super) fn test_interface_sram_master() {
383 let t = ChiselInterfaceTemplate::SramPort {
384 addr_bits: 10,
385 data_bits: 32,
386 };
387 let s = t.emit_ports("sram", true);
388 assert!(s.contains("sram_addr"));
389 assert!(s.contains("sram_wdata"));
390 assert!(s.contains("10.W"));
391 }
392 #[test]
393 pub(super) fn test_interface_apb_master() {
394 let t = ChiselInterfaceTemplate::ApbPort {
395 addr_bits: 32,
396 data_bits: 32,
397 };
398 let s = t.emit_ports("apb", true);
399 assert!(s.contains("apb_paddr"));
400 assert!(s.contains("apb_pready"));
401 assert!(s.contains("pwrite"));
402 }
403 #[test]
404 pub(super) fn test_interface_ahb_lite() {
405 let t = ChiselInterfaceTemplate::AhbLitePort {
406 addr_bits: 32,
407 data_bits: 32,
408 };
409 let s = t.emit_ports("bus", true);
410 assert!(s.contains("bus_haddr"));
411 assert!(s.contains("htrans"));
412 }
413 #[test]
414 pub(super) fn test_interface_axi4_lite() {
415 let t = ChiselInterfaceTemplate::Axi4LitePort {
416 addr_bits: 32,
417 data_bits: 32,
418 };
419 let s = t.emit_ports("axi", true);
420 assert!(s.contains("awvalid"));
421 assert!(s.contains("arready"));
422 assert!(s.contains("wstrb"));
423 }
424 #[test]
425 pub(super) fn test_annotation_dont_touch() {
426 let ann = ChiselAnnotationKind::DontTouch;
427 let s = ann.scala_annotation("io.sig");
428 assert!(s.contains("DontTouch"));
429 assert!(s.contains("io.sig"));
430 }
431 #[test]
432 pub(super) fn test_annotation_load_memory() {
433 let ann = ChiselAnnotationKind::LoadMemoryAnnotation {
434 file: "mem.hex".into(),
435 };
436 let s = ann.scala_annotation("mem_module");
437 assert!(s.contains("loadMemoryFromFile"));
438 assert!(s.contains("mem.hex"));
439 }
440 #[test]
441 pub(super) fn test_annotation_inline_instance() {
442 let ann = ChiselAnnotationKind::InlineInstance;
443 let s = ann.scala_annotation("sub");
444 assert!(s.contains("Inline"));
445 }
446 #[test]
447 pub(super) fn test_pipeline_stage_chain() {
448 let chain = ChiselPipelineRegisterChain::new("0")
449 .stage(PipelineStage::new("s0", ChiselType::UInt(32)).with_valid())
450 .stage(
451 PipelineStage::new("s1", ChiselType::UInt(32))
452 .with_valid()
453 .with_stall(),
454 );
455 let s = chain.emit_registers();
456 assert!(s.contains("s0"));
457 assert!(s.contains("s1"));
458 assert!(s.contains("s0_valid"));
459 assert!(s.contains("s1_stall"));
460 }
461 #[test]
462 pub(super) fn test_pipeline_stage_count() {
463 let chain = ChiselPipelineRegisterChain::new("0")
464 .stage(PipelineStage::new("a", ChiselType::Bool))
465 .stage(PipelineStage::new("b", ChiselType::Bool))
466 .stage(PipelineStage::new("c", ChiselType::Bool));
467 assert_eq!(chain.stage_count(), 3);
468 }
469 #[test]
470 pub(super) fn test_sram_wrapper_single_port_emit() {
471 let sram = ChiselSRAMWrapper::single_port("RegFile", 1024, 64);
472 let s = sram.emit();
473 assert!(s.contains("class RegFile extends Module"));
474 assert!(s.contains("SyncReadMem(1024"));
475 assert!(s.contains("64.W"));
476 assert!(s.contains("wen"));
477 }
478 #[test]
479 pub(super) fn test_sram_wrapper_addr_width() {
480 let sram = ChiselSRAMWrapper::single_port("M", 256, 32);
481 assert_eq!(sram.addr_width(), 8);
482 }
483 #[test]
484 pub(super) fn test_sram_wrapper_with_mask() {
485 let sram = ChiselSRAMWrapper::single_port("M", 64, 32).with_mask(8);
486 assert_eq!(sram.mask_width(), 4);
487 let s = sram.emit();
488 assert!(s.contains("wmask"));
489 }
490 #[test]
491 pub(super) fn test_sram_wrapper_sdp() {
492 let sram = ChiselSRAMWrapper::simple_dual_port("Sdp", 512, 32);
493 let s = sram.emit();
494 assert!(s.contains("raddr"));
495 assert!(s.contains("rdata"));
496 }
497 #[test]
498 pub(super) fn test_sram_wrapper_pipeline_read() {
499 let sram = ChiselSRAMWrapper::single_port("PL", 64, 8).with_pipeline_read();
500 let s = sram.emit();
501 assert!(s.contains("raddr_r"));
502 assert!(s.contains("RegNext"));
503 }
504 #[test]
505 pub(super) fn test_backend_dont_care() {
506 let b = ChiselBackend::new();
507 let s = b.dont_care("io.out");
508 assert!(s.contains("DontCare"));
509 assert!(s.contains("io.out"));
510 }
511 #[test]
512 pub(super) fn test_backend_irrevocable_port() {
513 let b = ChiselBackend::new();
514 let s = b.irrevocable_port("out", &ChiselType::UInt(8), true);
515 assert!(s.contains("Irrevocable"));
516 assert!(s.contains("out"));
517 }
518 #[test]
519 pub(super) fn test_backend_comb_rom() {
520 let b = ChiselBackend::new();
521 let s = b.comb_rom("lut", &ChiselType::UInt(8), &["0", "1", "2", "255"]);
522 assert!(s.contains("VecInit"));
523 assert!(s.contains("255.U"));
524 }
525 #[test]
526 pub(super) fn test_backend_mux1h() {
527 let b = ChiselBackend::new();
528 let s = b.mux1h("sel", &[("sel(0)", "a"), ("sel(1)", "b")]);
529 assert!(s.contains("Mux1H"));
530 assert!(s.contains("sel(0)"));
531 }
532 #[test]
533 pub(super) fn test_backend_log2_ceil() {
534 let b = ChiselBackend::new();
535 assert_eq!(b.log2_ceil(1), 1);
536 assert_eq!(b.log2_ceil(8), 3);
537 assert_eq!(b.log2_ceil(9), 4);
538 }
539 #[test]
540 pub(super) fn test_backend_log2_floor() {
541 let b = ChiselBackend::new();
542 assert_eq!(b.log2_floor(8), 3);
543 assert_eq!(b.log2_floor(9), 3);
544 }
545 #[test]
546 pub(super) fn test_backend_is_pow2() {
547 let b = ChiselBackend::new();
548 assert!(b.is_pow2(1));
549 assert!(b.is_pow2(64));
550 assert!(!b.is_pow2(0));
551 assert!(!b.is_pow2(3));
552 }
553 #[test]
554 pub(super) fn test_backend_cover_stmt() {
555 let b = ChiselBackend::new();
556 let s = b.cover_stmt("io.valid", "valid_active");
557 assert!(s.contains("cover"));
558 assert!(s.contains("io.valid"));
559 }
560 #[test]
561 pub(super) fn test_backend_assume_stmt() {
562 let b = ChiselBackend::new();
563 let s = b.assume_stmt("io.en");
564 assert!(s.contains("assume"));
565 }
566 #[test]
567 pub(super) fn test_backend_cat() {
568 let b = ChiselBackend::new();
569 let s = b.cat(&["a", "b", "c"]);
570 assert!(s.contains("Cat(a, b, c)"));
571 }
572 #[test]
573 pub(super) fn test_backend_popcount() {
574 let b = ChiselBackend::new();
575 let s = b.popcount("mask");
576 assert!(s.contains("PopCount(mask)"));
577 }
578 #[test]
579 pub(super) fn test_backend_oh_to_uint() {
580 let b = ChiselBackend::new();
581 let s = b.oh_to_uint("oh_sig");
582 assert!(s.contains("OHToUInt(oh_sig)"));
583 }
584 #[test]
585 pub(super) fn test_backend_mux_case() {
586 let b = ChiselBackend::new();
587 let s = b.mux_case("0.U", &[("a === 1.U", "x"), ("a === 2.U", "y")]);
588 assert!(s.contains("MuxCase"));
589 assert!(s.contains("a === 1.U"));
590 }
591 #[test]
592 pub(super) fn test_backend_shift_register() {
593 let b = ChiselBackend::new();
594 let s = b.shift_register("io.in", 4, "0");
595 assert!(s.contains("ShiftRegister"));
596 assert!(s.contains("io.in"));
597 assert!(s.contains(", 4,"));
598 }
599 #[test]
600 pub(super) fn test_backend_rr_arbiter() {
601 let b = ChiselBackend::new();
602 let s = b.round_robin_arbiter("arb", &ChiselType::UInt(8), 4);
603 assert!(s.contains("RRArbiter"));
604 assert!(s.contains("arb"));
605 }
606 #[test]
607 pub(super) fn test_backend_priority_arbiter() {
608 let b = ChiselBackend::new();
609 let s = b.priority_arbiter("parb", &ChiselType::Bool, 2);
610 assert!(s.contains("Arbiter"));
611 }
612 #[test]
613 pub(super) fn test_backend_queue_module() {
614 let b = ChiselBackend::new();
615 let s = b.queue_module("fifo", &ChiselType::UInt(32), 8);
616 assert!(s.contains("Queue"));
617 assert!(s.contains("fifo"));
618 assert!(s.contains(", 8)"));
619 }
620 #[test]
621 pub(super) fn test_backend_when_chain() {
622 let b = ChiselBackend::new();
623 let s = b.when_chain(&[("a", "x := 1.U"), ("b", "x := 2.U")], Some("x := 0.U"));
624 assert!(s.contains("when (a)"));
625 assert!(s.contains("elsewhen (b)"));
626 assert!(s.contains("otherwise"));
627 }
628 #[test]
629 pub(super) fn test_backend_counter() {
630 let b = ChiselBackend::new();
631 let s = b.counter("cyc", 99, "true.B");
632 assert!(s.contains("Counter"));
633 assert!(s.contains("cyc_count"));
634 }
635 #[test]
636 pub(super) fn test_backend_reset_sync() {
637 let b = ChiselBackend::new();
638 let s = b.reset_sync("rst", "io.async_rst");
639 assert!(s.contains("rst_sync"));
640 assert!(s.contains("asAsyncReset"));
641 }
642 #[test]
643 pub(super) fn test_backend_cdc_comment() {
644 let b = ChiselBackend::new();
645 let s = b.cdc_handshake_comment("clk_a", "clk_b");
646 assert!(s.contains("CDC"));
647 assert!(s.contains("clk_a"));
648 }
649 #[test]
650 pub(super) fn test_backend_blackbox_stub_no_params() {
651 let b = ChiselBackend::new();
652 let s = b.blackbox_stub("MyIp", &[]);
653 assert!(s.contains("BlackBox"));
654 assert!(s.contains("class MyIp"));
655 }
656 #[test]
657 pub(super) fn test_backend_blackbox_stub_with_params() {
658 let b = ChiselBackend::new();
659 let s = b.blackbox_stub("ParamIp", &[("WIDTH", "32"), ("DEPTH", "16")]);
660 assert!(s.contains("Map("));
661 assert!(s.contains("WIDTH"));
662 assert!(s.contains("32"));
663 }
664 #[test]
665 pub(super) fn test_backend_fill() {
666 let b = ChiselBackend::new();
667 let s = b.fill(8, "io.bit");
668 assert!(s.contains("Fill(8, io.bit)"));
669 }
670 #[test]
671 pub(super) fn test_backend_reverse() {
672 let b = ChiselBackend::new();
673 let s = b.reverse("io.data");
674 assert!(s.contains("Reverse(io.data)"));
675 }
676 #[test]
677 pub(super) fn test_backend_uint_to_oh() {
678 let b = ChiselBackend::new();
679 let s = b.uint_to_oh("io.sel", 8);
680 assert!(s.contains("UIntToOH"));
681 assert!(s.contains("io.sel"));
682 }
683 #[test]
684 pub(super) fn test_pipeline_stage_no_valid() {
685 let s = PipelineStage::new("s", ChiselType::UInt(8));
686 assert!(!s.has_valid);
687 assert!(!s.has_stall);
688 }
689 #[test]
690 pub(super) fn test_streaming_direction_producer() {
691 let m = ChiselStreamingModule::producer("P", 8);
692 assert_eq!(m.direction, StreamDirection::Producer);
693 }
694 #[test]
695 pub(super) fn test_streaming_direction_consumer() {
696 let m = ChiselStreamingModule::consumer("C", 8);
697 assert_eq!(m.direction, StreamDirection::Consumer);
698 }
699 #[test]
700 pub(super) fn test_sram_mask_granularity_byte() {
701 let sram = ChiselSRAMWrapper::single_port("M", 64, 64).with_mask(8);
702 assert_eq!(sram.mask_width(), 8);
703 }
704 #[test]
705 pub(super) fn test_interface_template_sram_slave() {
706 let t = ChiselInterfaceTemplate::SramPort {
707 addr_bits: 12,
708 data_bits: 16,
709 };
710 let s = t.emit_ports("mem", false);
711 assert!(s.contains("mem_addr"));
712 assert!(s.contains("12.W"));
713 }
714}
715#[cfg(test)]
716mod Chisel_infra_tests {
717 use super::*;
718 #[test]
719 pub(super) fn test_pass_config() {
720 let config = ChiselPassConfig::new("test_pass", ChiselPassPhase::Transformation);
721 assert!(config.enabled);
722 assert!(config.phase.is_modifying());
723 assert_eq!(config.phase.name(), "transformation");
724 }
725 #[test]
726 pub(super) fn test_pass_stats() {
727 let mut stats = ChiselPassStats::new();
728 stats.record_run(10, 100, 3);
729 stats.record_run(20, 200, 5);
730 assert_eq!(stats.total_runs, 2);
731 assert!((stats.average_changes_per_run() - 15.0).abs() < 0.01);
732 assert!((stats.success_rate() - 1.0).abs() < 0.01);
733 let s = stats.format_summary();
734 assert!(s.contains("Runs: 2/2"));
735 }
736 #[test]
737 pub(super) fn test_pass_registry() {
738 let mut reg = ChiselPassRegistry::new();
739 reg.register(ChiselPassConfig::new("pass_a", ChiselPassPhase::Analysis));
740 reg.register(ChiselPassConfig::new("pass_b", ChiselPassPhase::Transformation).disabled());
741 assert_eq!(reg.total_passes(), 2);
742 assert_eq!(reg.enabled_count(), 1);
743 reg.update_stats("pass_a", 5, 50, 2);
744 let stats = reg.get_stats("pass_a").expect("stats should exist");
745 assert_eq!(stats.total_changes, 5);
746 }
747 #[test]
748 pub(super) fn test_analysis_cache() {
749 let mut cache = ChiselAnalysisCache::new(10);
750 cache.insert("key1".to_string(), vec![1, 2, 3]);
751 assert!(cache.get("key1").is_some());
752 assert!(cache.get("key2").is_none());
753 assert!((cache.hit_rate() - 0.5).abs() < 0.01);
754 cache.invalidate("key1");
755 assert!(!cache.entries["key1"].valid);
756 assert_eq!(cache.size(), 1);
757 }
758 #[test]
759 pub(super) fn test_worklist() {
760 let mut wl = ChiselWorklist::new();
761 assert!(wl.push(1));
762 assert!(wl.push(2));
763 assert!(!wl.push(1));
764 assert_eq!(wl.len(), 2);
765 assert_eq!(wl.pop(), Some(1));
766 assert!(!wl.contains(1));
767 assert!(wl.contains(2));
768 }
769 #[test]
770 pub(super) fn test_dominator_tree() {
771 let mut dt = ChiselDominatorTree::new(5);
772 dt.set_idom(1, 0);
773 dt.set_idom(2, 0);
774 dt.set_idom(3, 1);
775 assert!(dt.dominates(0, 3));
776 assert!(dt.dominates(1, 3));
777 assert!(!dt.dominates(2, 3));
778 assert!(dt.dominates(3, 3));
779 }
780 #[test]
781 pub(super) fn test_liveness() {
782 let mut liveness = ChiselLivenessInfo::new(3);
783 liveness.add_def(0, 1);
784 liveness.add_use(1, 1);
785 assert!(liveness.defs[0].contains(&1));
786 assert!(liveness.uses[1].contains(&1));
787 }
788 #[test]
789 pub(super) fn test_constant_folding() {
790 assert_eq!(ChiselConstantFoldingHelper::fold_add_i64(3, 4), Some(7));
791 assert_eq!(ChiselConstantFoldingHelper::fold_div_i64(10, 0), None);
792 assert_eq!(ChiselConstantFoldingHelper::fold_div_i64(10, 2), Some(5));
793 assert_eq!(
794 ChiselConstantFoldingHelper::fold_bitand_i64(0b1100, 0b1010),
795 0b1000
796 );
797 assert_eq!(ChiselConstantFoldingHelper::fold_bitnot_i64(0), -1);
798 }
799 #[test]
800 pub(super) fn test_dep_graph() {
801 let mut g = ChiselDepGraph::new();
802 g.add_dep(1, 2);
803 g.add_dep(2, 3);
804 g.add_dep(1, 3);
805 assert_eq!(g.dependencies_of(2), vec![1]);
806 let topo = g.topological_sort();
807 assert_eq!(topo.len(), 3);
808 assert!(!g.has_cycle());
809 let pos: std::collections::HashMap<u32, usize> =
810 topo.iter().enumerate().map(|(i, &n)| (n, i)).collect();
811 assert!(pos[&1] < pos[&2]);
812 assert!(pos[&1] < pos[&3]);
813 assert!(pos[&2] < pos[&3]);
814 }
815}