|
| 1 | +// Testbench: verify the @dff module (seq.compreg) defined at the bottom of |
| 2 | +// sram_core.mlir. Drive D=0x42 into the flip-flop, apply one posedge, and |
| 3 | +// confirm Q==0x42 on the output. |
| 4 | +// |
| 5 | +// Note: @sram_core uses seq.hlmem which requires lowering passes not run by |
| 6 | +// circt-sim in standalone mode, so we test the simpler @dff example here. |
| 7 | +// |
| 8 | +// Uses LLHD dialect for clock generation and time-driven simulation: |
| 9 | +// llhd.sig / llhd.prb / llhd.drv — signals and drives |
| 10 | +// llhd.process + llhd.wait delay — time-advancing processes |
| 11 | +// sim.proc.print — simulation output |
| 12 | +hw.module @tb() { |
| 13 | + %false = hw.constant false |
| 14 | + %true = hw.constant true |
| 15 | + %c0_i8 = hw.constant 0 : i8 |
| 16 | + %c42 = hw.constant 66 : i8 // 0x42 |
| 17 | + %eps = llhd.constant_time <0ns, 0d, 1e> |
| 18 | + %c5ns = hw.constant 5000000 : i64 // 5 ns half-period |
| 19 | + %c11ns = hw.constant 11000000 : i64 // 11 ns — after first posedge (5 ns) |
| 20 | + %c30ns = hw.constant 30000000 : i64 // 30 ns — termination timeout |
| 21 | + |
| 22 | + // Shared clock and data signals. |
| 23 | + %clk_sig = llhd.sig %false : i1 |
| 24 | + %d_sig = llhd.sig %c42 : i8 // D always 0x42 |
| 25 | + |
| 26 | + %clk_val = llhd.prb %clk_sig : i1 |
| 27 | + %clk = seq.to_clock %clk_val |
| 28 | + %d_val = llhd.prb %d_sig : i8 |
| 29 | + |
| 30 | + // DUT: @dff (seq.compreg — latches D on posedge clock). |
| 31 | + %q = hw.instance "dut" @dff(d: %d_val : i8, clk: %clk : !seq.clock) -> (q: i8) |
| 32 | + |
| 33 | + // Shadow signal so the check process can probe Q. |
| 34 | + %q_sig = llhd.sig %c0_i8 : i8 |
| 35 | + llhd.drv %q_sig, %q after %eps : i8 |
| 36 | + |
| 37 | + // Clock generator: toggle every 5 ns. |
| 38 | + llhd.process { |
| 39 | + cf.br ^loop |
| 40 | + ^loop: |
| 41 | + %d = llhd.int_to_time %c5ns |
| 42 | + llhd.wait delay %d, ^flip |
| 43 | + ^flip: |
| 44 | + %v = llhd.prb %clk_sig : i1 |
| 45 | + %nv = comb.xor %v, %true : i1 |
| 46 | + llhd.drv %clk_sig, %nv after %eps : i1 |
| 47 | + cf.br ^loop |
| 48 | + } |
| 49 | + |
| 50 | + // Check Q at 11 ns (one ns after posedge at 5 ns). |
| 51 | + llhd.process { |
| 52 | + %d = llhd.int_to_time %c11ns |
| 53 | + llhd.wait delay %d, ^check |
| 54 | + ^check: |
| 55 | + %qv = llhd.prb %q_sig : i8 |
| 56 | + %ok = comb.icmp eq %qv, %c42 : i8 |
| 57 | + cf.cond_br %ok, ^pass, ^fail |
| 58 | + ^pass: |
| 59 | + %pm = sim.fmt.literal "PASS\0A" |
| 60 | + sim.proc.print %pm |
| 61 | + sim.terminate success, quiet |
| 62 | + llhd.halt |
| 63 | + ^fail: |
| 64 | + %fm = sim.fmt.literal "FAIL: dff expected Q=0x42\0A" |
| 65 | + sim.proc.print %fm |
| 66 | + sim.terminate success, quiet |
| 67 | + llhd.halt |
| 68 | + } |
| 69 | + |
| 70 | + // Terminate after 30 ns (safety timeout). |
| 71 | + llhd.process { |
| 72 | + %d = llhd.int_to_time %c30ns |
| 73 | + llhd.wait delay %d, ^end |
| 74 | + ^end: |
| 75 | + sim.terminate success, quiet |
| 76 | + llhd.halt |
| 77 | + } |
| 78 | + |
| 79 | + hw.output |
| 80 | +} |
0 commit comments