circt/test/firtool/firtool.fir

291 lines
12 KiB
Plaintext

; RUN: firtool %s --format=fir --ir-fir | circt-opt | FileCheck %s --check-prefix=MLIR
; RUN: firtool %s --format=fir --parse-only --annotation-file %s.anno.json,%s.anno.1.json | circt-opt | FileCheck %s --check-prefix=ANNOTATIONS
; RUN: firtool %s --format=fir --parse-only --annotation-file %s.anno.json --annotation-file %s.anno.1.json | circt-opt | FileCheck %s --check-prefix=ANNOTATIONS
; RUN: firtool %s --format=fir --ir-hw | circt-opt | FileCheck %s --check-prefix=MLIRLOWER
; RUN: firtool %s --format=fir -verilog | FileCheck %s --check-prefix=VERILOG
; RUN: firtool %s --format=fir --ir-verilog | circt-opt | FileCheck %s --check-prefix=VERILOG-IR
FIRRTL version 4.0.0
circuit test_mod : %[[{"class": "circt.testNT", "data": "a"}]]
; MLIR: firrtl.circuit "test_mod"
; ANNOTATIONS-LABEL: firrtl.circuit "test_mod"
; ANNOTATIONS-SAME: {class = "circt.testNT", data = "a"}
; ANNOTATIONS-SAME: {class = "circt.testNT", info = "a NoTargetAnnotation"}
; ANNOTATIONS-SAME: {class = "circt.test", info = "a CircuitTarget Annotation"}
; ANNOTATIONS-SAME: {class = "circt.test", info = "a CircuitName Annotation"}
; VERILOG-IR: sv.verbatim{{.*}}Standard header to adapt well known macros for register randomization
; VERILOG-IR: sv.macro.decl @ENABLE_INITIAL_REG_
; VERILOG-IR: sv.macro.decl @ENABLE_INITIAL_MEM_
; VERILOG-IR: sv.macro.decl @RANDOMIZE
; VERILOG-IR: sv.macro.decl @RANDOMIZE_DELAY
; VERILOG-IR: sv.macro.decl @RANDOM
; VERILOG-IR: sv.macro.decl @INIT_RANDOM
; VERILOG-IR: sv.macro.decl @INIT_RANDOM_PROLOG_
type V3 = UInt<1>[3]
type V2 = UInt<1>[2]
public module test_mod :
input clock : Clock
input a: UInt<1>
input b: UInt<2>
output c: UInt<1>
input vec: V3
output out_implicitTrunc: UInt<1>
output out_prettifyExample: UInt<1>
output out_multibitMux: UInt<1>
output out_mux2cell: V2
inst cat of Cat
connect cat.a, b
connect cat.b, b
connect cat.c, b
inst implicitTrunc of ImplicitTrunc
connect implicitTrunc.inp_1, a
connect implicitTrunc.inp_2, asSInt(cat.d)
inst prettifyExample of PrettifyExample
connect prettifyExample.inp_1, cat.d
connect prettifyExample.inp_2, cat.d
connect prettifyExample.inp_3, cat.d
inst flipFlop of FlipFlop
connect flipFlop.clock, clock
connect flipFlop.a_d, a
connect c, flipFlop.a_q
inst multibitMux of MultibitMux
connect multibitMux.a, vec
connect multibitMux.sel, b
inst unusedPortsMod of UnusedPortsMod
connect unusedPortsMod.in, a
inst mux2cell of Mux2Cell
connect mux2cell.cond, a
connect mux2cell.low, a
connect out_mux2cell, mux2cell.out
; These outputs exist to work around the aggressive removal of unused module
; ports.
;
; TODO: This test should be rewritten to not be so brittle around module
; port removal.
connect out_implicitTrunc, or(orr(implicitTrunc.out1), orr(implicitTrunc.out2))
connect out_prettifyExample, or(orr(prettifyExample.out1), orr(prettifyExample.out2))
connect out_multibitMux, multibitMux.b
; MLIR-LABEL: firrtl.module @test_mod(in %clock: !firrtl.clock, in %a: !firrtl.uint<1>, in %b: !firrtl.uint<2>, out %c: !firrtl.uint<1>, in %vec_0: !firrtl.uint<1>, in %vec_1: !firrtl.uint<1>, in %vec_2: !firrtl.uint<1>, out %out_implicitTrunc: !firrtl.uint<1>, out %out_prettifyExample: !firrtl.uint<1>, out %out_multibitMux: !firrtl.uint<1>, out %out_mux2cell_0: !firrtl.uint<1>, out %out_mux2cell_1: !firrtl.uint<1>) {{.*}}{
; MLIR: %cat_a, %cat_b, %cat_c, %cat_d = firrtl.instance cat @Cat(in a: !firrtl.uint<2>, in b: !firrtl.uint<2>, in c: !firrtl.uint<2>, out d: !firrtl.uint<6>)
; MLIR-NEXT: firrtl.matchingconnect %cat_a, %b : !firrtl.uint<2>
; MLIR-NEXT: firrtl.matchingconnect %cat_b, %b : !firrtl.uint<2>
; MLIR-NEXT: firrtl.matchingconnect %cat_c, %b : !firrtl.uint<2>
; MLIR-NEXT: %implicitTrunc_inp_1, %implicitTrunc_inp_2, %implicitTrunc_out1, %implicitTrunc_out2 = firrtl.instance implicitTrunc @ImplicitTrunc(in inp_1: !firrtl.uint<1>, in inp_2: !firrtl.sint<5>, out out1: !firrtl.sint<3>, out out2: !firrtl.sint<3>)
; MLIR-NEXT: firrtl.matchingconnect %implicitTrunc_inp_1, %a : !firrtl.uint<1>
; MLIR-NEXT: %0 = firrtl.asSInt %cat_d : (!firrtl.uint<6>) -> !firrtl.sint<6>
; MLIR-NEXT: %1 = firrtl.bits %0 4 to 0 : (!firrtl.sint<6>) -> !firrtl.uint<5>
; MLIR-NEXT: %2 = firrtl.asSInt %1 : (!firrtl.uint<5>) -> !firrtl.sint<5>
; MLIR-NEXT: firrtl.matchingconnect %implicitTrunc_inp_2, %2 : !firrtl.sint<5>
; MLIR: %prettifyExample_inp_1, %prettifyExample_inp_2, %prettifyExample_inp_3, %prettifyExample_out1, %prettifyExample_out2 = firrtl.instance prettifyExample @PrettifyExample(in inp_1: !firrtl.uint<5>, in inp_2: !firrtl.uint<5>, in inp_3: !firrtl.uint<5>, out out1: !firrtl.uint<10>, out out2: !firrtl.uint<10>)
; MLIR-NEXT: %3 = firrtl.bits %cat_d 4 to 0 : (!firrtl.uint<6>) -> !firrtl.uint<5>
; MLIR-NEXT: firrtl.matchingconnect %prettifyExample_inp_1, %3 : !firrtl.uint<5>
; MLIR-NEXT: firrtl.matchingconnect %prettifyExample_inp_2, %3 : !firrtl.uint<5>
; MLIR-NEXT: firrtl.matchingconnect %prettifyExample_inp_3, %3 : !firrtl.uint<5>
; MLIR-NEXT: %flipFlop_clock, %flipFlop_a_d, %flipFlop_a_q = firrtl.instance flipFlop @FlipFlop(in clock: !firrtl.clock, in a_d: !firrtl.uint<1>, out a_q: !firrtl.uint<1>)
; MLIR-NEXT: firrtl.matchingconnect %flipFlop_clock, %clock : !firrtl.clock
; MLIR-NEXT: firrtl.matchingconnect %flipFlop_a_d, %a : !firrtl.uint<1>
; MLIR-NEXT: firrtl.matchingconnect %c, %flipFlop_a_q : !firrtl.uint<1>
; MLIR-NEXT: %multibitMux_a_0, %multibitMux_a_1, %multibitMux_a_2, %multibitMux_sel, %multibitMux_b = firrtl.instance multibitMux @MultibitMux(in a_0: !firrtl.uint<1>, in a_1: !firrtl.uint<1>, in a_2: !firrtl.uint<1>, in sel: !firrtl.uint<2>, out b: !firrtl.uint<1>)
; MLIR-NEXT: firrtl.matchingconnect %multibitMux_a_0, %vec_0 : !firrtl.uint<1>
; MLIR-NEXT: firrtl.matchingconnect %multibitMux_a_1, %vec_1 : !firrtl.uint<1>
; MLIR-NEXT: firrtl.matchingconnect %multibitMux_a_2, %vec_2 : !firrtl.uint<1>
; MLIR-NEXT: firrtl.matchingconnect %multibitMux_sel, %b : !firrtl.uint<2>
; ANNOTATIONS-LABEL: firrtl.module @test_mod
; ANNOTATIONS-SAME: {class = "circt.test", info = "a ModuleTarget Annotation"}
; ANNOTATIONS-SAME: {class = "circt.test", info = "a ModuleName Annotation"}
; VERILOG-LABEL: module test_mod(
; Check that a fir location is stripped.
; VERILOG-NOT: .fir
; VERILOG-NEXT: input clock,
; VERILOG-NEXT: a,
; VERILOG-NEXT: input [1:0] b,
; VERILOG-NEXT: output c,
; VERILOG-NEXT: input vec_0,
; VERILOG-NEXT: vec_1,
; VERILOG-NEXT: vec_2,
; VERILOG-NEXT: output out_implicitTrunc,
; VERILOG-NEXT: out_prettifyExample,
; VERILOG-NEXT: out_multibitMux,
; VERILOG-NEXT: out_mux2cell_0,
; VERILOG-NEXT: out_mux2cell_1
; VERILOG-NEXT: );
; VERILOG-EMPTY:
; VERILOG-NEXT: wire [9:0] _prettifyExample_out1;
; VERILOG-NEXT: wire [9:0] _prettifyExample_out2;
; VERILOG-NEXT: wire [2:0] _implicitTrunc_out1;
; VERILOG-NEXT: wire [2:0] _implicitTrunc_out2;
; VERILOG-NEXT: wire [5:0] _cat_d;
; VERILOG-NEXT: Cat cat (
; VERILOG-NEXT: .a (b),
; VERILOG-NEXT: .b (b),
; VERILOG-NEXT: .c (b),
; VERILOG-NEXT: .d (_cat_d)
; VERILOG-NEXT: );
; VERILOG-NEXT: ImplicitTrunc implicitTrunc (
; VERILOG-NEXT: .inp_1 (a),
; VERILOG-NEXT: .inp_2 (_cat_d[4:0]),
; VERILOG-NEXT: .out1 (_implicitTrunc_out1),
; VERILOG-NEXT: .out2 (_implicitTrunc_out2)
; VERILOG-NEXT: );
; VERILOG-NEXT: PrettifyExample prettifyExample (
; VERILOG-NEXT: .inp_1 (_cat_d[4:0]),
; VERILOG-NEXT: .inp_2 (_cat_d[4:0]),
; VERILOG-NEXT: .inp_3 (_cat_d[4:0]),
; VERILOG-NEXT: .out1 (_prettifyExample_out1),
; VERILOG-NEXT: .out2 (_prettifyExample_out2)
; VERILOG-NEXT: );
; VERILOG-NEXT: FlipFlop flipFlop (
; VERILOG-NEXT: .clock (clock),
; VERILOG-NEXT: .a_d (a),
; VERILOG-NEXT: .a_q (c)
; VERILOG-NEXT: );
; VERILOG-NEXT: MultibitMux multibitMux (
; VERILOG-NEXT: .a_0 (vec_0),
; VERILOG-NEXT: .a_1 (vec_1),
; VERILOG-NEXT: .a_2 (vec_2),
; VERILOG-NEXT: .sel (b),
; VERILOG-NEXT: .b (out_multibitMux)
; VERILOG-NEXT: );
; VERILOG: endmodule
; Check that we canonicalize the HW output of lowering.
module Cat :
input a: UInt<2>
input b: UInt<2>
input c: UInt<2>
output d: UInt<6>
connect d, cat(cat(a, b), c)
; MLIRLOWER-LABEL: hw.module private @Cat(in %a : i2, in %b : i2, in %c : i2, out d : i6) {
; MLIRLOWER-NEXT: %0 = comb.concat %a, %b, %c : i2, i2, i2
; MLIRLOWER-NEXT: hw.output %0 : i6
; MLIRLOWER-NEXT: }
; Check that implicit truncation is working.
module ImplicitTrunc :
input inp_1: UInt<1>
input inp_2: SInt<5>
output out1: SInt<3>
output out2: SInt<3>
connect out1, dshl(inp_2, inp_1)
connect out2, inp_2
; MLIRLOWER-LABEL: hw.module private @ImplicitTrunc(in %inp_1 : i1, in %inp_2 : i5, out out1 : i3, out out2 : i3) {
; MLIRLOWER-NEXT: %c0_i5 = hw.constant 0 : i5
; MLIRLOWER-NEXT: %0 = comb.extract %inp_2 from 4 : (i5) -> i1
; MLIRLOWER-NEXT: %1 = comb.concat %0, %inp_2 : i1, i5
; MLIRLOWER-NEXT: %2 = comb.concat %c0_i5, %inp_1 : i5, i1
; MLIRLOWER-NEXT: %3 = comb.shl bin %1, %2 : i6
; MLIRLOWER-NEXT: %4 = comb.extract %3 from 0 : (i6) -> i3
; MLIRLOWER-NEXT: %5 = comb.extract %inp_2 from 0 : (i5) -> i3
; MLIRLOWER-NEXT: hw.output %4, %5 : i3, i3
; MLIRLOWER-NEXT: }
; VERILOG-LABEL: module ImplicitTrunc(
; VERILOG-NEXT: input inp_1,
; VERILOG-NEXT: input [4:0] inp_2,
; VERILOG-NEXT: output [2:0] out1,
; VERILOG-NEXT: out2
; VERILOG-NEXT: );
; VERILOG-EMPTY:
; VERILOG-NEXT: wire [5:0] _GEN = {inp_2[4], inp_2} << inp_1;
; VERILOG-NEXT: assign out1 = _GEN[2:0];
; VERILOG-NEXT: assign out2 = inp_2[2:0];
; VERILOG-NEXT: endmodule
; Check that we prettify the IR before Verilog emission.
module PrettifyExample :
input inp_1: UInt<5>
input inp_2: UInt<5>
input inp_3: UInt<5>
output out1: UInt<10>
output out2: UInt<10>
connect out1, cat(not(inp_1), inp_2)
connect out2, cat(not(inp_1), inp_3)
; VERILOG-LABEL: module PrettifyExample(
; VERILOG: assign out1 = {~inp_1, inp_2};
; VERILOG: assign out2 = {~inp_1, inp_3};
; Check output of a simple flip-flop.
module FlipFlop:
input clock: Clock
input a_d: UInt<1>
output a_q: UInt<1>
reg r: UInt<1>, clock
connect r, a_d
connect a_q, r
; VERILOG-LABEL: module FlipFlop(
; VERILOG-NEXT: input clock,
; VERILOG-NEXT: a_d,
; VERILOG-NEXT: output a_q
; VERILOG-NEXT: );
; VERILOG: always @(posedge clock)
; VERILOG-NEXT: r <= a_d;
; VERILOG: assign a_q = r;
module MultibitMux :
input a : UInt<1>[3]
input sel : UInt<2>
output b : UInt<1>
connect b, a[sel]
; VERILOG-LABEL: module MultibitMux(
; VERILOG: wire [3:0] [[T2:.*]] =
; VERILOG-SAME{LITERAL}: {{a_0}, {a_2}, {a_1}, {a_0}};
; VERILOG-NEXT: assign b = [[T2]][sel];
module UnusedPortsMod :
input in : UInt<1>
output out : UInt<1>
invalidate out
extmodule Val:
output v: UInt<1>
; VERILOG-LABEL: Mux2Cell
; Make sure that mux annotations are emitted properly.
; VERILOG: /* synopsys infer_mux_override */
; VERILOG-NEXT: assign [[OUT1:.+]] = mux2cell_in0 ? /* cadence map_to_mux */ mux2cell_in1 : mux2cell_in2;
; VERILOG: /* synopsys infer_mux_override */
; VERILOG-NEXT: assign [[OUT2:.+]] =
; VERILOG-NEXT: mux2cell_in0_0 ? /* cadence map_to_mux */ mux2cell_in1_0 : mux2cell_in2_0;
; VERILOG: assign out_0 = [[OUT1]];
; VERILOG: assign out_1 = [[OUT2]];
module Mux2Cell:
input cond: UInt<1>
input low: UInt<1>
output out: UInt<1>[2]
wire w: UInt<1>
inst ext of Val
connect w, ext.v
connect out[0], intrinsic(circt_mux2cell : UInt, xor(cond, UInt<1>(1)), w, low)
connect out[1], intrinsic(circt_mux2cell : UInt, xor(cond, UInt<1>(1)), ext.v, low)