mirror of https://github.com/llvm/circt.git
1471 lines
58 KiB
MLIR
1471 lines
58 KiB
MLIR
// RUN: circt-opt %s --test-apply-lowering-options='options=emittedLineLength=100,emitBindComments' -export-verilog -verify-diagnostics -o %t.mlir | FileCheck %s
|
|
|
|
// CHECK-NOT: module E
|
|
hw.module.extern @E(in %a: i1, in %b: i1, in %c: i1)
|
|
hw.module.extern @Array(in %a: !hw.array<2xi4>)
|
|
|
|
hw.module @TESTSIMPLE(in %a: i4, in %b: i4, in %c: i2, in %cond: i1,
|
|
in %array2d: !hw.array<12 x array<10xi4>>,
|
|
in %uarray: !hw.uarray<16xi8>,
|
|
in %postUArray: i8,
|
|
in %structA: !hw.struct<foo: i2, bar:i4>,
|
|
in %arrOfStructA: !hw.array<5 x struct<foo: i2>>,
|
|
in %array1: !hw.array<1xi1>,
|
|
out r0: i4, out r2: i4, out r4: i4, out r6: i4, out r7: i4,
|
|
out r8: i4, out r9: i4, out r10: i4, out r11: i4,
|
|
out r12: i4, out r13: i4, out r14: i4, out r15: i4,
|
|
out r16: i1, out r17: i1, out r18: i1, out r19: i1,
|
|
out r20: i1, out r21: i1, out r22: i1, out r23: i1,
|
|
out r24: i1, out r25: i1, out r26: i1, out r27: i1,
|
|
out r28: i1, out r29: i12, out r30: i2, out r31: i9,
|
|
out r33: i4, out r34: i4, out r35: !hw.array<3xi4>,
|
|
out r36: !hw.array<6xi4>, out r37: i4, out r38: i12,
|
|
out r39: !hw.struct<a: i1, b: i1>, out r40: !hw.array<4xi2>,
|
|
out r41: !hw.uarray<1xi1>, out r42: !hw.struct<a: !hw.array<1xi1>>,
|
|
out r43: i4, out r44: !hw.struct<foo: i2, bar: i4>,
|
|
out r45: !hw.struct<foo: i2, bar: i4>,
|
|
out r46: !hw.struct<foo: i2, bar: i4>, out r47: i1
|
|
) attributes {sv.attributes = [#sv.attribute<"svAttr">]} {
|
|
|
|
%0 = comb.add %a, %b : i4
|
|
%2 = comb.sub %a, %b : i4
|
|
%4 = comb.mul %a, %b : i4
|
|
%6 = comb.divu %a, %b : i4
|
|
%7 = comb.divs %a, %b : i4
|
|
%8 = comb.modu %a, %b : i4
|
|
%9 = comb.mods %a, %b : i4
|
|
%10 = comb.shl %a, %b : i4
|
|
%11 = comb.shru %a, %b : i4
|
|
%12 = comb.shrs %a, %b : i4
|
|
%13 = comb.or %a, %b : i4
|
|
%14 = comb.and %a, %b : i4
|
|
%15 = comb.xor %a, %b : i4
|
|
%16 = comb.icmp eq %a, %b : i4
|
|
%17 = comb.icmp ne %a, %b : i4
|
|
%18 = comb.icmp slt %a, %b : i4
|
|
%19 = comb.icmp sle %a, %b : i4
|
|
%20 = comb.icmp sgt %a, %b : i4
|
|
%21 = comb.icmp sge %a, %b : i4
|
|
%22 = comb.icmp ult %a, %b : i4
|
|
%23 = comb.icmp ule %a, %b : i4
|
|
%24 = comb.icmp ugt %a, %b : i4
|
|
%25 = comb.icmp uge %a, %b : i4
|
|
%one4 = hw.constant -1 : i4
|
|
%26 = comb.icmp eq %a, %one4 : i4
|
|
%zero4 = hw.constant 0 : i4
|
|
%27 = comb.icmp ne %a, %zero4 : i4
|
|
%28 = comb.parity %a : i4
|
|
%29 = comb.concat %a, %a, %b : i4, i4, i4
|
|
%30 = comb.extract %a from 1 : (i4) -> i2
|
|
|
|
%tmp = comb.extract %a from 3 : (i4) -> i1
|
|
%tmp2 = comb.replicate %tmp : (i1) -> i5
|
|
%31 = comb.concat %tmp2, %a : i5, i4
|
|
%33 = comb.mux %cond, %a, %b : i4
|
|
|
|
%allone = hw.constant 15 : i4
|
|
%34 = comb.xor %a, %allone : i4
|
|
|
|
// Having "sv.namehint" (and checking that it works) anywhere will inherently
|
|
// make tests brittle. This line breaking does not mean your change is no
|
|
// good! You'll just have to find a new place for `sv.namehint`.
|
|
%arrCreated = hw.array_create %allone, %allone, %allone, %allone, %allone, %allone, %allone, %allone, %allone { sv.namehint="name_hint" } : i4
|
|
%slice1 = hw.array_slice %arrCreated[%a] : (!hw.array<9xi4>) -> !hw.array<3xi4>
|
|
%slice2 = hw.array_slice %arrCreated[%b] : (!hw.array<9xi4>) -> !hw.array<3xi4>
|
|
%35 = comb.mux %cond, %slice1, %slice2 {sv.attributes = [#sv.attribute<"svAttr">]} : !hw.array<3xi4>
|
|
|
|
%ab = comb.add %a, %b : i4
|
|
%subArr = hw.array_create %allone, %ab, %allone : i4
|
|
|
|
%36 = hw.array_concat %subArr, %subArr : !hw.array<3 x i4>, !hw.array<3 x i4>
|
|
%elem2d = hw.array_get %array2d[%a] : !hw.array<12 x array<10xi4>>, i4
|
|
%37 = hw.array_get %elem2d[%b] {sv.attributes = [#sv.attribute<"svAttr">]}: !hw.array<10xi4>, i4
|
|
|
|
%38 = comb.replicate %a : (i4) -> i12
|
|
|
|
%39 = hw.aggregate_constant [false, true] : !hw.struct<a: i1, b: i1>
|
|
%40 = hw.aggregate_constant [0 : i2, 1 : i2, -2 : i2, -1 : i2] : !hw.array<4xi2>
|
|
%41 = hw.aggregate_constant [false] : !hw.uarray<1xi1>
|
|
%42 = hw.aggregate_constant [[false]] : !hw.struct<a: !hw.array<1xi1>>
|
|
|
|
%43 = hw.struct_extract %structA["bar"] : !hw.struct<foo: i2, bar: i4>
|
|
%44 = hw.struct_inject %structA["bar"], %a : !hw.struct<foo: i2, bar: i4>
|
|
%45 = hw.struct_create (%c, %a) : !hw.struct<foo: i2, bar: i4>
|
|
%46 = hw.struct_inject %45["bar"], %b : !hw.struct<foo: i2, bar: i4>
|
|
%none = hw.constant 0 : i0
|
|
%47 = hw.array_get %array1[%none] : !hw.array<1xi1>, i0
|
|
|
|
hw.output %0, %2, %4, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17,
|
|
%18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30,
|
|
%31, %33, %34, %35, %36, %37, %38, %39, %40, %41, %42, %43, %44,
|
|
%45, %46, %47:
|
|
i4, i4, i4, i4, i4, i4, i4, i4, i4, i4, i4, i4, i4, i1, i1, i1, i1, i1, i1,
|
|
i1, i1, i1, i1, i1, i1, i1, i12, i2, i9, i4, i4, !hw.array<3xi4>,
|
|
!hw.array<6xi4>, i4, i12, !hw.struct<a: i1, b: i1>, !hw.array<4xi2>,
|
|
!hw.uarray<1xi1>, !hw.struct<a: !hw.array<1xi1>>, i4,
|
|
!hw.struct<foo: i2, bar: i4>, !hw.struct<foo: i2, bar: i4>,
|
|
!hw.struct<foo: i2, bar: i4>, i1
|
|
}
|
|
|
|
// CHECK-LABEL: (* svAttr *)
|
|
// CHECK-NEXT: module TESTSIMPLE(
|
|
// CHECK-NEXT: input [3:0] a,
|
|
// CHECK-NEXT: b,
|
|
// CHECK-NEXT: input [1:0] c,
|
|
// CHECK-NEXT: input cond,
|
|
// CHECK-NEXT: input [11:0][9:0][3:0] array2d,
|
|
// CHECK-NEXT: input [7:0] uarray[0:15],
|
|
// CHECK-NEXT: postUArray,
|
|
// CHECK-NEXT: input struct packed {logic [1:0] foo; logic [3:0] bar; } structA,
|
|
// CHECK-NEXT: input struct packed {logic [1:0] foo; }[4:0] arrOfStructA,
|
|
// CHECK-NEXT: input [0:0] array1,
|
|
// CHECK-NEXT: output [3:0] r0,
|
|
// CHECK-NEXT: r2,
|
|
// CHECK-NEXT: r4,
|
|
// CHECK-NEXT: r6,
|
|
// CHECK-NEXT: r7,
|
|
// CHECK-NEXT: r8,
|
|
// CHECK-NEXT: r9,
|
|
// CHECK-NEXT: r10,
|
|
// CHECK-NEXT: r11,
|
|
// CHECK-NEXT: r12,
|
|
// CHECK-NEXT: r13,
|
|
// CHECK-NEXT: r14,
|
|
// CHECK-NEXT: r15,
|
|
// CHECK-NEXT: output r16,
|
|
// CHECK-NEXT: r17,
|
|
// CHECK-NEXT: r18,
|
|
// CHECK-NEXT: r19,
|
|
// CHECK-NEXT: r20,
|
|
// CHECK-NEXT: r21,
|
|
// CHECK-NEXT: r22,
|
|
// CHECK-NEXT: r23,
|
|
// CHECK-NEXT: r24,
|
|
// CHECK-NEXT: r25,
|
|
// CHECK-NEXT: r26,
|
|
// CHECK-NEXT: r27,
|
|
// CHECK-NEXT: r28,
|
|
// CHECK-NEXT: output [11:0] r29,
|
|
// CHECK-NEXT: output [1:0] r30,
|
|
// CHECK-NEXT: output [8:0] r31,
|
|
// CHECK-NEXT: output [3:0] r33,
|
|
// CHECK-NEXT: r34,
|
|
// CHECK-NEXT: output [2:0][3:0] r35,
|
|
// CHECK-NEXT: output [5:0][3:0] r36,
|
|
// CHECK-NEXT: output [3:0] r37,
|
|
// CHECK-NEXT: output [11:0] r38,
|
|
// CHECK-NEXT: output struct packed {logic a; logic b; } r39,
|
|
// CHECK-NEXT: output [3:0][1:0] r40,
|
|
// CHECK-NEXT: output r41[0:0],
|
|
// CHECK-NEXT: output struct packed {logic [0:0] a; } r42,
|
|
// CHECK-NEXT: output [3:0] r43,
|
|
// CHECK-NEXT: output struct packed {logic [1:0] foo; logic [3:0] bar; } r44,
|
|
// CHECK-NEXT: r45,
|
|
// CHECK-NEXT: r46,
|
|
// CHECK-NEXT: output r47
|
|
// CHECK-NEXT: );
|
|
// CHECK{LITERAL}: wire [8:0][3:0] name_hint = {9{4'hF}};
|
|
// CHECK-NEXT: wire [2:0][3:0] [[WIRE0:.+]] = {{[{}][{}]}}4'hF}, {a + b}, {4'hF}};
|
|
// CHECK-NEXT: wire struct packed {logic [1:0] foo; logic [3:0] bar; } [[WIRE1:.+]] = '{foo: c, bar: a};
|
|
// CHECK-NEXT: assign r0 = a + b;
|
|
// CHECK-NEXT: assign r2 = a - b;
|
|
// CHECK-NEXT: assign r4 = a * b;
|
|
// CHECK-NEXT: assign r6 = a / b;
|
|
// CHECK-NEXT: assign r7 = $signed($signed(a) / $signed(b));
|
|
// CHECK-NEXT: assign r8 = a % b;
|
|
// CHECK-NEXT: assign r9 = $signed($signed(a) % $signed(b));
|
|
// CHECK-NEXT: assign r10 = a << b;
|
|
// CHECK-NEXT: assign r11 = a >> b;
|
|
// CHECK-NEXT: assign r12 = $signed($signed(a) >>> b);
|
|
// CHECK-NEXT: assign r13 = a | b;
|
|
// CHECK-NEXT: assign r14 = a & b;
|
|
// CHECK-NEXT: assign r15 = a ^ b;
|
|
// CHECK-NEXT: assign r16 = a == b;
|
|
// CHECK-NEXT: assign r17 = a != b;
|
|
// CHECK-NEXT: assign r18 = $signed(a) < $signed(b);
|
|
// CHECK-NEXT: assign r19 = $signed(a) <= $signed(b);
|
|
// CHECK-NEXT: assign r20 = $signed(a) > $signed(b);
|
|
// CHECK-NEXT: assign r21 = $signed(a) >= $signed(b);
|
|
// CHECK-NEXT: assign r22 = a < b;
|
|
// CHECK-NEXT: assign r23 = a <= b;
|
|
// CHECK-NEXT: assign r24 = a > b;
|
|
// CHECK-NEXT: assign r25 = a >= b;
|
|
// CHECK-NEXT: assign r26 = &a;
|
|
// CHECK-NEXT: assign r27 = |a;
|
|
// CHECK-NEXT: assign r28 = ^a;
|
|
// CHECK-NEXT: assign r29 = {a, a, b};
|
|
// CHECK-NEXT: assign r30 = a[2:1];
|
|
// CHECK-NEXT: assign r31 = {{[{}][{}]}}5{a[3]}}, a};
|
|
// CHECK-NEXT: assign r33 = cond ? a : b;
|
|
// CHECK-NEXT: assign r34 = ~a;
|
|
// CHECK-NEXT: assign r35 = cond ? (* svAttr *) name_hint[a +: 3] : name_hint[b +: 3];
|
|
// CHECK-NEXT: assign r36 = {[[WIRE0]], [[WIRE0]]};
|
|
// CHECK-NEXT: assign r37 = array2d[a][b] (* svAttr *);
|
|
// CHECK-NEXT: assign r38 = {3{a}};
|
|
// CHECK-NEXT: assign r39 = '{a: 1'h0, b: 1'h1};
|
|
// CHECK-NEXT: assign r40 = '{2'h0, 2'h1, 2'h2, 2'h3};
|
|
// CHECK-NEXT: assign r41 = '{1'h0};
|
|
// CHECK-NEXT: assign r42 = '{a: '{1'h0}};
|
|
// CHECK-NEXT: assign r43 = structA.bar;
|
|
// CHECK-NEXT: assign r44 = '{foo: structA.foo, bar: a};
|
|
// CHECK-NEXT: assign r45 = _GEN_0;
|
|
// CHECK-NEXT: assign r46 = '{foo: [[WIRE1]].foo, bar: b};
|
|
// CHECK-NEXT: assign r47 = array1[/*Zero width*/ 1'b0];
|
|
// CHECK-NEXT: endmodule
|
|
|
|
hw.module @i0Inst() {
|
|
%c0_i0 = hw.constant 0 : i0
|
|
hw.instance "i0" sym @i0Module @i0Module(arg1: %c0_i0: i0) -> ()
|
|
}
|
|
hw.module @i0Module(in %arg1: i0) {}
|
|
// CHECK-LABEL: module i0Inst();
|
|
// CHECK-NEXT: i0Module i0 (
|
|
// CHECK-NEXT: //.arg1 (/* Zero width */)
|
|
// CHECK-NEXT: );
|
|
// CHECK-NEXT: endmodule
|
|
// CHECK-LABEL: module i0Module(
|
|
// CHECK-NEXT: // input /*Zero Width*/ arg1
|
|
// CHECK-NEXT: );
|
|
// CHECK-EMPTY:
|
|
// CHECK-NEXT: endmodule
|
|
|
|
hw.module @B(in %a: i1, out b: i1, out c: i1) {
|
|
%0 = comb.or %a, %a : i1
|
|
%1 = comb.and %a, %a : i1
|
|
hw.output %0, %1 : i1, i1
|
|
}
|
|
// CHECK-LABEL: module B(
|
|
// CHECK-NEXT: input a, //
|
|
// CHECK-NEXT: output b, //
|
|
// CHECK-NEXT: c //
|
|
// CHECK-NEXT: );
|
|
// CHECK-EMPTY:
|
|
// CHECK-NEXT: assign b = a | a;
|
|
// CHECK-NEXT: assign c = a & a;
|
|
// CHECK-NEXT: endmodule
|
|
|
|
hw.module @A(in %d: i1, in %e: i1, out f: i1) {
|
|
%1 = comb.mux %d, %d, %e : i1
|
|
hw.output %1 : i1
|
|
}
|
|
// CHECK-LABEL: module A(
|
|
// CHECK-NEXT: input d,
|
|
// CHECK-NEXT: e,
|
|
// CHECK-NEXT: output f
|
|
// CHECK-NEXT: );
|
|
// CHECK-EMPTY:
|
|
// CHECK-NEXT: assign f = d ? d : e;
|
|
// CHECK-NEXT: endmodule
|
|
|
|
hw.module @AAA(in %d: i1, in %e: i1, out f: i1) {
|
|
%z = hw.constant 0 : i1
|
|
hw.output %z : i1
|
|
}
|
|
// CHECK-LABEL: module AAA(
|
|
// CHECK-NEXT: input d,
|
|
// CHECK-NEXT: e,
|
|
// CHECK-NEXT: output f
|
|
// CHECK-NEXT: );
|
|
// CHECK-EMPTY:
|
|
// CHECK-NEXT: assign f = 1'h0;
|
|
// CHECK-NEXT: endmodule
|
|
|
|
|
|
/// TODO: Specify parameter declarations.
|
|
hw.module.extern @EXT_W_PARAMS<DEFAULT: i64, DEPTH: f64, FORMAT: none,
|
|
WIDTH: i8>(in %a: i1, in %b: i0, out out: i1)
|
|
attributes { verilogName="FooModule" }
|
|
|
|
hw.module.extern @EXT_W_PARAMS2<DEFAULT: i32>(in %a: i2, out out: i1)
|
|
attributes { verilogName="FooModule" }
|
|
|
|
hw.module @AB(in %w: i1, in %x: i1, in %i2: i2, in %i3: i0, out y: i1, out z: i1, out p: i1, out p2: i1) {
|
|
%w2 = hw.instance "a1" @AAA(d: %w: i1, e: %w1: i1) -> (f: i1)
|
|
%w1, %y = hw.instance "b1" @B(a: %w2: i1) -> (b: i1, c: i1)
|
|
|
|
%p = hw.instance "paramd" @EXT_W_PARAMS<
|
|
DEFAULT: i64 = 14000240888948784983, DEPTH: f64 = 3.242000e+01,
|
|
FORMAT: none = "xyz_timeout=%d\0A", WIDTH: i8 = 32
|
|
>(a: %w: i1, b: %i3: i0) -> (out: i1)
|
|
|
|
%p2 = hw.instance "paramd2" @EXT_W_PARAMS2<DEFAULT: i32 = 1>(a: %i2: i2) -> (out: i1)
|
|
|
|
hw.output %y, %x, %p, %p2 : i1, i1, i1, i1
|
|
}
|
|
// CHECK-LABEL: module AB(
|
|
// CHECK-NEXT: input w,
|
|
// CHECK-NEXT: x,
|
|
// CHECK-NEXT: input [1:0] i2,
|
|
// CHECK-NEXT: // input /*Zero Width*/ i3,
|
|
// CHECK-NEXT: output y,
|
|
// CHECK-NEXT: z,
|
|
// CHECK-NEXT: p,
|
|
// CHECK-NEXT: p2
|
|
// CHECK-NEXT: );
|
|
// CHECK-EMPTY:
|
|
// CHECK-NEXT: wire _b1_b;
|
|
// CHECK-NEXT: wire _a1_f;
|
|
// CHECK: AAA a1 (
|
|
// CHECK-NEXT: .d (w),
|
|
// CHECK-NEXT: .e (_b1_b),
|
|
// CHECK-NEXT: .f (_a1_f)
|
|
// CHECK-NEXT: );
|
|
// CHECK-NEXT: B b1 (
|
|
// CHECK-NEXT: .a (_a1_f),
|
|
// CHECK-NEXT: .b (_b1_b),
|
|
// CHECK-NEXT: .c (y)
|
|
// CHECK-NEXT: );
|
|
// CHECK-NEXT: FooModule #(
|
|
// CHECK-NEXT: .DEFAULT(-64'd4446503184760766633),
|
|
// CHECK-NEXT: .DEPTH(3.242000e+01),
|
|
// CHECK-NEXT: .FORMAT("xyz_timeout=%d\n"),
|
|
// CHECK-NEXT: .WIDTH(32)
|
|
// CHECK-NEXT: ) paramd (
|
|
// CHECK-NEXT: .a (w),
|
|
// CHECK-NEXT: //.b (i3),
|
|
// CHECK-NEXT: .out (p)
|
|
// CHECK-NEXT: );
|
|
// CHECK-NEXT: FooModule #(
|
|
// CHECK-NEXT: .DEFAULT(1)
|
|
// CHECK-NEXT: ) paramd2 (
|
|
// CHECK-NEXT: .a (i2),
|
|
// CHECK-NEXT: .out (p2)
|
|
// CHECK-NEXT: );
|
|
// CHECK-NEXT: assign z = x;
|
|
// CHECK-NEXT: endmodule
|
|
|
|
|
|
|
|
hw.module @shl(in %a: i1, out b: i1) {
|
|
%0 = comb.shl %a, %a : i1
|
|
hw.output %0 : i1
|
|
}
|
|
// CHECK-LABEL: module shl(
|
|
// CHECK-NEXT: input a,
|
|
// CHECK-NEXT: output b
|
|
// CHECK-NEXT: );
|
|
// CHECK-EMPTY:
|
|
// CHECK-NEXT: assign b = a << a;
|
|
// CHECK-NEXT: endmodule
|
|
|
|
|
|
hw.module @inout_0(inout %a: i42, out out: i42) {
|
|
%aget = sv.read_inout %a: !hw.inout<i42>
|
|
hw.output %aget : i42
|
|
}
|
|
// CHECK-LABEL: module inout_0(
|
|
// CHECK-NEXT: inout [41:0] a,
|
|
// CHECK-NEXT: output [41:0] out
|
|
// CHECK-NEXT: );
|
|
// CHECK-EMPTY:
|
|
// CHECK-NEXT: assign out = a;
|
|
// CHECK-NEXT: endmodule
|
|
|
|
// https://github.com/llvm/circt/issues/316
|
|
// FIXME: The MLIR parser doesn't accept an i0 even though it is valid IR,
|
|
// this needs to be fixed upstream.
|
|
//hw.module @issue316(in %inp_0: i0) {
|
|
// hw.output
|
|
//}
|
|
|
|
// https://github.com/llvm/circt/issues/318
|
|
// This shouldn't generate invalid Verilog
|
|
hw.module @extract_all(in %tmp85: i1, out tmp106: i1) {
|
|
%1 = comb.extract %tmp85 from 0 : (i1) -> i1
|
|
hw.output %1 : i1
|
|
}
|
|
// CHECK-LABEL: module extract_all
|
|
// CHECK: assign tmp106 = tmp85;
|
|
|
|
hw.module @wires(in %in4: i4, in %in8: i8, out a: i4, out b: i8, out c: i8) {
|
|
// CHECK-LABEL: module wires( //
|
|
// CHECK-NEXT: input [3:0] in4, //
|
|
// CHECK-NEXT: input [7:0] in8, //
|
|
// CHECK-NEXT: output [3:0] a, //
|
|
// CHECK-NEXT: output [7:0] b, //
|
|
// CHECK-NEXT: c //
|
|
// CHECK-NEXT: );
|
|
|
|
// CHECK-EMPTY:
|
|
|
|
// Wires.
|
|
// CHECK-NEXT: wire [3:0] myWire = in4;
|
|
%myWire = sv.wire : !hw.inout<i4>
|
|
|
|
// Packed arrays.
|
|
|
|
// CHECK-NEXT: wire [41:0][7:0] myArray1;
|
|
%myArray1 = sv.wire : !hw.inout<array<42 x i8>>
|
|
// CHECK-NEXT: wire [2:0][41:0][3:0] myWireArray2;
|
|
%myWireArray2 = sv.wire : !hw.inout<array<3 x array<42 x i4>>>
|
|
|
|
// Unpacked arrays, and unpacked arrays of packed arrays.
|
|
|
|
// CHECK-NEXT: wire [7:0] myUArray1[0:41];
|
|
%myUArray1 = sv.wire : !hw.inout<uarray<42 x i8>>
|
|
|
|
// CHECK-NEXT: wire [9:0][7:0] myUArray2[0:13][0:11];
|
|
%myUArray2 = sv.wire : !hw.inout<uarray<14 x uarray<12 x array<10 x i8>>>>
|
|
|
|
// Wires.
|
|
sv.assign %myWire, %in4 : i4
|
|
%wireout = sv.read_inout %myWire : !hw.inout<i4>
|
|
|
|
// Packed arrays.
|
|
|
|
%subscript = sv.array_index_inout %myArray1[%in4] : !hw.inout<array<42 x i8>>, i4
|
|
// CHECK-NEXT: assign myArray1[in4] = in8;
|
|
sv.assign %subscript, %in8 : i8
|
|
|
|
%memout1 = sv.read_inout %subscript : !hw.inout<i8>
|
|
|
|
// Unpacked arrays, and unpacked arrays of packed arrays.
|
|
%subscriptu = sv.array_index_inout %myUArray1[%in4] : !hw.inout<uarray<42 x i8>>, i4
|
|
// CHECK-NEXT: assign myUArray1[in4] = in8;
|
|
sv.assign %subscriptu, %in8 : i8
|
|
|
|
%memout2 = sv.read_inout %subscriptu : !hw.inout<i8>
|
|
|
|
// CHECK-NEXT: assign a = myWire;
|
|
// CHECK-NEXT: assign b = myArray1[in4];
|
|
// CHECK-NEXT: assign c = myUArray1[in4];
|
|
hw.output %wireout, %memout1, %memout2 : i4, i8, i8
|
|
}
|
|
|
|
// CHECK-LABEL: module signs
|
|
hw.module @signs(in %in1: i4, in %in2: i4, in %in3: i4, in %in4: i4) {
|
|
%awire = sv.wire : !hw.inout<i4>
|
|
// CHECK: wire [3:0] awire;
|
|
|
|
// CHECK: assign awire =
|
|
// CHECK-NEXT: $unsigned($signed($signed(in1) / $signed(in2)))
|
|
// CHECK-NEXT: / $unsigned($signed($signed(in3) / $signed(in4)));
|
|
%a1 = comb.divs %in1, %in2: i4
|
|
%a2 = comb.divs %in3, %in4: i4
|
|
%a3 = comb.divu %a1, %a2: i4
|
|
sv.assign %awire, %a3: i4
|
|
|
|
// CHECK: assign awire =
|
|
// CHECK-NEXT: $unsigned($signed($signed(in1) / $signed(in2)) + $signed($signed(in1) / $signed(in2)))
|
|
// CHECK-NEXT: / $unsigned($signed($signed(in1) / $signed(in2)) * $signed($signed(in1) / $signed(in2)));
|
|
%b1a = comb.divs %in1, %in2: i4
|
|
%b1b = comb.divs %in1, %in2: i4
|
|
%b1c = comb.divs %in1, %in2: i4
|
|
%b1d = comb.divs %in1, %in2: i4
|
|
%b2 = comb.add %b1a, %b1b: i4
|
|
%b3 = comb.mul %b1c, %b1d: i4
|
|
%b4 = comb.divu %b2, %b3: i4
|
|
sv.assign %awire, %b4: i4
|
|
|
|
// https://github.com/llvm/circt/issues/369
|
|
// CHECK: assign awire = $signed(4'sh5 / -4'sh3);
|
|
%c5_i4 = hw.constant 5 : i4
|
|
%c-3_i4 = hw.constant -3 : i4
|
|
%divs = comb.divs %c5_i4, %c-3_i4 : i4
|
|
sv.assign %awire, %divs: i4
|
|
|
|
hw.output
|
|
}
|
|
|
|
|
|
// CHECK-LABEL: module casts(
|
|
// CHECK-NEXT: input [6:0] in1,
|
|
// CHECK-NEXT: input [7:0][3:0] in2,
|
|
// CHECK-NEXT: output [6:0] r1,
|
|
// CHECK-NEXT: output [31:0] r2
|
|
// CHECK-NEXT: );
|
|
hw.module @casts(in %in1: i7, in %in2: !hw.array<8xi4>, out r1: !hw.array<7xi1>, out r2: i32) {
|
|
// CHECK-EMPTY:
|
|
%r1 = hw.bitcast %in1 : (i7) -> !hw.array<7xi1>
|
|
%r2 = hw.bitcast %in2 : (!hw.array<8xi4>) -> i32
|
|
|
|
// CHECK-NEXT: assign r1 = in1;
|
|
// CHECK-NEXT: assign r2 = /*cast(bit[31:0])*/in2;
|
|
hw.output %r1, %r2 : !hw.array<7xi1>, i32
|
|
}
|
|
|
|
// CHECK-LABEL: module TestZero(
|
|
// CHECK-NEXT: input [3:0] a,
|
|
// CHECK-NEXT: // input /*Zero Width*/ zeroBit,
|
|
// CHECK-NEXT: // input [2:0]/*Zero Width*/ arrZero,
|
|
// CHECK-NEXT: output [3:0] r0
|
|
// CHECK-NEXT: // output /*Zero Width*/ rZero
|
|
// CHECK-NEXT: // output [2:0]/*Zero Width*/ arrZero_0
|
|
// CHECK-NEXT: );
|
|
// CHECK-EMPTY:
|
|
hw.module @TestZero(in %a: i4, in %zeroBit: i0, in %arrZero: !hw.array<3xi0>,
|
|
out r0: i4, out rZero: i0, out arrZero_0: !hw.array<3xi0>) {
|
|
|
|
%b = comb.add %a, %a : i4
|
|
hw.output %b, %zeroBit, %arrZero : i4, i0, !hw.array<3xi0>
|
|
|
|
// CHECK-NEXT: assign r0 = a + a;
|
|
// CHECK-NEXT: // Zero width: assign rZero = zeroBit;
|
|
// CHECK-NEXT: // Zero width: assign arrZero_0 = arrZero;
|
|
// CHECK-NEXT: endmodule
|
|
}
|
|
|
|
// CHECK-LABEL: TestZeroInstance
|
|
hw.module @TestZeroInstance(in %aa: i4, in %azeroBit: i0, in %aarrZero: !hw.array<3xi0>,
|
|
out r0: i4, out rZero: i0, out arrZero_0: !hw.array<3xi0>) {
|
|
|
|
// CHECK: TestZero iii (
|
|
// CHECK-NEXT: .a (aa),
|
|
// CHECK-NEXT: //.zeroBit (azeroBit),
|
|
// CHECK-NEXT: //.arrZero (aarrZero),
|
|
// CHECK-NEXT: .r0 (r0)
|
|
// CHECK-NEXT: //.rZero (rZero)
|
|
// CHECK-NEXT: //.arrZero_0 (arrZero_0)
|
|
// CHECK-NEXT: );
|
|
// CHECK-NEXT: endmodule
|
|
|
|
%o1, %o2, %o3 = hw.instance "iii" @TestZero(a: %aa: i4, zeroBit: %azeroBit: i0, arrZero: %aarrZero: !hw.array<3xi0>) -> (r0: i4, rZero: i0, arrZero_0: !hw.array<3xi0>)
|
|
|
|
hw.output %o1, %o2, %o3 : i4, i0, !hw.array<3xi0>
|
|
}
|
|
|
|
// CHECK: module TestZeroStruct(
|
|
// CHECK-NEXT: // input /*Zero Width*/ structZero,
|
|
// CHECK-NEXT: // input /*Zero Width*/ structZeroNest,
|
|
// CHECK-NEXT: // output /*Zero Width*/ structZero_0,
|
|
// CHECK-NEXT: // output /*Zero Width*/ structZeroNest_0
|
|
// CHECK-NEXT: );
|
|
hw.module @TestZeroStruct(in %structZero: !hw.struct<>, in %structZeroNest: !hw.struct<a: !hw.struct<>>,
|
|
out structZero_0: !hw.struct<>, out structZeroNest_0: !hw.struct<a: !hw.struct<>>) {
|
|
|
|
hw.output %structZero, %structZeroNest : !hw.struct<>, !hw.struct<a: !hw.struct<>>
|
|
// CHECK: // Zero width: assign structZero_0 = structZero;
|
|
// CHECK-NEXT: // Zero width: assign structZeroNest_0 = structZeroNest;
|
|
// CHECK-NEXT: endmodule
|
|
}
|
|
|
|
// CHECK-LABEL: module zeroElements
|
|
// CHECK-NEXT: // input /*Zero Width*/ in0,
|
|
// CHECK-NEXT: input [31:0] in1,
|
|
// CHECK-NEXT: output struct packed {/*z1: Zero Width;*/ logic [31:0] a; /*z2: Zero Width;*/ logic [31:0] b; /*c: Zero Width;*/ struct packed {logic [31:0] d1; /*z: Zero Width;*/ } d; } out0
|
|
// CHECK-NEXT: );
|
|
hw.module @zeroElements(in %in0: i0, in %in1: i32, out out0: !hw.struct<z1: i0, a: i32, z2: i0, b: i32, c: !hw.struct<z: i0>, d: !hw.struct<d1:i32, z:i0>>) {
|
|
// CHECK: // Zero width: wire /*Zero Width*/
|
|
// CHECK-SAME: _GEN = '{};
|
|
// CHECK-NEXT: wire struct packed {logic [31:0] d1; /*z: Zero Width;*/ } _GEN_0 = '{d1: in1};
|
|
// CHECK: wire
|
|
// CHECK-NEXT: struct packed {/*z1: Zero Width;*/ logic [31:0] a; /*z2: Zero Width;*/ logic [31:0] b; /*c: Zero Width;*/ struct packed {logic [31:0] d1; /*z: Zero Width;*/ } d; }
|
|
// CHECK-NEXT: _GEN_1 = '{a: in1, b: in1, d: _GEN_0};
|
|
// CHECK-NEXT: assign out0 = '{a: in1, b: _GEN_1.b, d: _GEN_1.d};
|
|
%0 = hw.struct_create (%in0) : !hw.struct<z: i0>
|
|
%1 = hw.struct_create (%in1, %in0) : !hw.struct<d1:i32, z:i0>
|
|
%2 = hw.struct_create (%in0, %in1, %in0, %in1, %0, %1) : !hw.struct<z1: i0, a: i32, z2: i0, b: i32, c: !hw.struct<z: i0>, d: !hw.struct<d1:i32, z:i0>>
|
|
%3 = hw.struct_inject %2["a"], %in1 : !hw.struct<z1: i0, a: i32, z2: i0, b: i32, c: !hw.struct<z: i0>, d: !hw.struct<d1:i32, z:i0>>
|
|
hw.output %3 : !hw.struct<z1: i0, a: i32, z2: i0, b: i32, c: !hw.struct<z: i0>, d: !hw.struct<d1:i32, z:i0>>
|
|
}
|
|
|
|
// CHECK-LABEL: TestZeroStructInstance
|
|
hw.module @TestZeroStructInstance(in %structZero: !hw.struct<>, in %structZeroNest: !hw.struct<a: !hw.struct<>>,
|
|
out structZero_0: !hw.struct<>, out structZeroNest_0: !hw.struct<a: !hw.struct<>>) {
|
|
|
|
// CHECK: TestZeroStruct iii (
|
|
// CHECK-NEXT: //.structZero (structZero)
|
|
// CHECK-NEXT: //.structZeroNest (structZeroNest)
|
|
// CHECK-NEXT: //.structZero_0 (structZero_0)
|
|
// CHECK-NEXT: //.structZeroNest_0 (structZeroNest_0)
|
|
// CHECK-NEXT: );
|
|
|
|
%o1, %o2 = hw.instance "iii" @TestZeroStruct(structZero: %structZero: !hw.struct<>, structZeroNest: %structZeroNest: !hw.struct<a: !hw.struct<>>)
|
|
-> (structZero_0: !hw.struct<>, structZeroNest_0: !hw.struct<a: !hw.struct<>>)
|
|
|
|
hw.output %o1, %o2 : !hw.struct<>, !hw.struct<a: !hw.struct<>>
|
|
}
|
|
|
|
// CHECK-LABEL: module testZeroArrayGet(
|
|
// CHECK-NEXT: // input /*Zero Width*/ arg0,
|
|
// CHECK-NEXT: input [0:0][31:0] arg1,
|
|
// CHECK-NEXT: output [31:0] out,
|
|
// CHECK-NEXT: out1
|
|
// CHECK-NEXT: // output /*Zero Width*/ out2
|
|
// CHECK-NEXT: );
|
|
|
|
// CHECK: assign out = arg1[/*Zero width*/ 1'b0];
|
|
// CHECK-NEXT: assign out1 = arg1[/*Zero width*/ 1'b0];
|
|
// CHECK-NEXT: // Zero width: assign out2 = arg0;
|
|
|
|
hw.module @testZeroArrayGet(in %arg0: i0, in %arg1 : !hw.array<1xi32>, out out: i32, out out1: i32, out out2: i0) {
|
|
// Using an expression as index.
|
|
%idx = comb.add %arg0, %arg0 : i0
|
|
%0 = hw.array_get %arg1[%idx] : !hw.array<1xi32>, i0
|
|
|
|
// Using an argument as index.
|
|
%1 = hw.array_get %arg1[%arg0] : !hw.array<1xi32>, i0
|
|
hw.output %0, %1, %arg0 : i32, i32, i0
|
|
}
|
|
|
|
// https://github.com/llvm/circt/issues/438
|
|
// CHECK-LABEL: module cyclic
|
|
hw.module @cyclic(in %a: i1, out b: i1) {
|
|
// CHECK: wire _GEN;
|
|
|
|
// CHECK: wire _GEN_0 = _GEN + _GEN;
|
|
%1 = comb.add %0, %0 : i1
|
|
// CHECK: assign _GEN = a << a;
|
|
%0 = comb.shl %a, %a : i1
|
|
// CHECK: assign b = _GEN_0 - _GEN_0;
|
|
%2 = comb.sub %1, %1 : i1
|
|
hw.output %2 : i1
|
|
}
|
|
|
|
|
|
// https://github.com/llvm/circt/issues/668
|
|
// CHECK-LABEL: module longExpressions
|
|
hw.module @longExpressions(in %a: i8, in %a2: i8, out b: i8) {
|
|
// CHECK: assign b =
|
|
// CHECK-NEXT: (a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a)
|
|
// CHECK-NEXT: * (a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a)
|
|
// CHECK-NEXT: | (a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a)
|
|
// CHECK-NEXT: * (a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a);
|
|
|
|
%1 = comb.add %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a : i8
|
|
%2 = comb.add %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a : i8
|
|
%3 = comb.add %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a : i8
|
|
%4 = comb.add %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a : i8
|
|
%5 = comb.mul %1, %2 : i8
|
|
%6 = comb.mul %3, %4 : i8
|
|
%7 = comb.or %5, %6 : i8
|
|
hw.output %7 : i8
|
|
}
|
|
|
|
// https://github.com/llvm/circt/issues/668
|
|
// CHECK-LABEL: module longvariadic
|
|
hw.module @longvariadic(in %a: i8, out b: i8) {
|
|
// CHECK: assign b =
|
|
// CHECK-NEXT: a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a
|
|
// CHECK-COUNT-9: + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a
|
|
// CHECK-NEXT: + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a;
|
|
|
|
%1 = comb.add %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a,
|
|
%a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a,
|
|
%a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a,
|
|
%a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a,
|
|
%a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a,
|
|
%a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a,
|
|
%a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a,
|
|
%a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a,
|
|
%a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a,
|
|
%a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a,
|
|
%a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a,
|
|
%a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a,
|
|
%a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a,
|
|
%a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a,
|
|
%a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a,
|
|
%a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a, %a : i8
|
|
hw.output %1 : i8
|
|
}
|
|
|
|
// https://github.com/llvm/circt/issues/736
|
|
// Can't depend on left associativeness since ops can have args with different sizes
|
|
// CHECK-LABEL: module eqIssue(
|
|
// CHECK-NEXT: input [8:0] a,
|
|
// CHECK-NEXT: c,
|
|
// CHECK-NEXT: input [3:0] d,
|
|
// CHECK-NEXT: e,
|
|
// CHECK-NEXT: output r
|
|
// CHECK-NEXT: );
|
|
// CHECK-EMPTY:
|
|
// CHECK-NEXT: assign r = a == c == (d == e);
|
|
hw.module @eqIssue(in %a: i9, in %c :i9, in %d: i4, in %e: i4, out r : i1){
|
|
%1 = comb.icmp eq %a, %c : i9
|
|
%2 = comb.icmp eq %d, %e : i4
|
|
%4 = comb.icmp eq %1, %2 : i1
|
|
hw.output %4 : i1
|
|
}
|
|
|
|
// https://github.com/llvm/circt/issues/750
|
|
// Always get array indexes on the lhs
|
|
// CHECK-LABEL: module ArrayLHS
|
|
// CHECK-NEXT: input clock
|
|
// CHECK-NEXT: );
|
|
// CHECK-EMPTY:
|
|
// CHECK-NEXT: reg memory_r_en_pipe[0:0];
|
|
// CHECK: always_ff @(posedge clock)
|
|
// CHECK-NEXT: memory_r_en_pipe[1'h0] <= 1'h0;
|
|
// CHECK-NEXT: initial
|
|
// CHECK-NEXT: memory_r_en_pipe[1'h0] = 1'h0;
|
|
// CHECK-NEXT: endmodule
|
|
hw.module @ArrayLHS(in %clock: i1) {
|
|
%false = hw.constant false
|
|
%memory_r_en_pipe = sv.reg : !hw.inout<uarray<1xi1>>
|
|
%3 = sv.array_index_inout %memory_r_en_pipe[%false] : !hw.inout<uarray<1xi1>>, i1
|
|
sv.alwaysff(posedge %clock) {
|
|
sv.passign %3, %false : i1
|
|
}
|
|
sv.initial {
|
|
sv.bpassign %3, %false : i1
|
|
}
|
|
}
|
|
|
|
// CHECK-LABEL: module noTemporaryIfReadInOutIsAfterUse
|
|
hw.module @noTemporaryIfReadInOutIsAfterUse(in %clock: i1, in %x: i1) {
|
|
// CHECK: wire aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;
|
|
|
|
%0 = comb.and %1, %x : i1
|
|
// CHECK: always_ff @(posedge clock) begin
|
|
sv.alwaysff(posedge %clock) {
|
|
// CHECK: if (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa & x) begin
|
|
sv.if %0 {
|
|
sv.verbatim "// hello"
|
|
}
|
|
}
|
|
|
|
// CHECK: end // always_ff @(posedge)
|
|
%aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = sv.wire : !hw.inout<i1>
|
|
%1 = sv.read_inout %aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa : !hw.inout<i1>
|
|
}
|
|
|
|
// CHECK-LABEL: module largeConstant
|
|
hw.module @largeConstant(in %a: i100000, in %b: i16, out x: i100000, out y: i16) {
|
|
// Large constant is inlined on multiple lines.
|
|
|
|
// CHECK: assign x =
|
|
// CHECK-NEXT: a + 100000'h2CD76FE086B93CE2F768A00B22A00000000000
|
|
// CHECK-NEXT: + 100000'h2CD76FE086B93CE2F768A00B22A00000000000
|
|
// CHECK-NEXT: + 100000'h2CD76FE086B93CE2F768A00B22A00000000000
|
|
// CHECK-NEXT: + 100000'h2CD76FE086B93CE2F768A00B22A00000000000
|
|
// CHECK-NEXT: + 100000'h2CD76FE086B93CE2F768A00B22A00000000000
|
|
// CHECK-NEXT: + 100000'h2CD76FE086B93CE2F768A00B22A00000000000
|
|
// CHECK-NEXT: + 100000'h2CD76FE086B93CE2F768A00B22A00000000000
|
|
// CHECK-NEXT: + 100000'h2CD76FE086B93CE2F768A00B22A00000000000;
|
|
%c = hw.constant 1000000000000000000000000000000000000000000000 : i100000
|
|
%1 = comb.add %a, %c, %c, %c, %c, %c, %c, %c, %c : i100000
|
|
|
|
// Small constants are emitted inline.
|
|
|
|
// CHECK: assign y = b + 16'hA + 16'hA + 16'hA + 16'hA + 16'hA + 16'hA + 16'hA + 16'hA;
|
|
%c2 = hw.constant 10 : i16
|
|
%2 = comb.add %b, %c2, %c2, %c2, %c2, %c2, %c2, %c2, %c2 : i16
|
|
|
|
hw.output %1, %2 : i100000, i16
|
|
}
|
|
// CHECK-LABEL: StructExtractExtract
|
|
hw.module @StructExtractExtract(in %a: !hw.struct<b: i4>, out r: i2) {
|
|
%0 = hw.struct_extract %a["b"] : !hw.struct<b: i4>
|
|
%1 = comb.extract %0 from 1 : (i4) -> i2
|
|
// CHECK: assign r = a.b[2:1];
|
|
hw.output %1 : i2
|
|
}
|
|
|
|
// CHECK-LABEL: StrurctExtractInline
|
|
hw.module @StrurctExtractInline(in %a: !hw.struct<v: i1>, out b: i1, out c: i1) {
|
|
%0 = hw.struct_extract %a["v"] : !hw.struct<v: i1>
|
|
// CHECK: assign b = a.v;
|
|
// CHECK-NEXT: assign c = a.v;
|
|
hw.output %0, %0 : i1, i1
|
|
}
|
|
|
|
// CHECK-LABEL: NoExtraTemporaryWireForAssign
|
|
hw.module @NoExtraTemporaryWireForAssign(in %a: i2, in %b: i4) {
|
|
// CHECK: wire struct packed {logic [1:0] foo; logic [3:0] bar; } _GEN = '{foo: a, bar: b};
|
|
%0 = hw.struct_create (%a, %b) : !hw.struct<foo: i2, bar: i4>
|
|
%1 = sv.wire : !hw.inout<!hw.struct<foo: i2, bar: i4>>
|
|
sv.assign %1, %0: !hw.struct<foo: i2, bar: i4>
|
|
}
|
|
|
|
hw.module.extern @DifferentResultMod(out out1: i1, out out2: i2)
|
|
|
|
// CHECK-LABEL: module out_of_order_multi_result(
|
|
hw.module @out_of_order_multi_result(out b: i1, out c: i2) {
|
|
// CHECK: wire _b1_out1;
|
|
// CHECK: wire [1:0] _b1_out2;
|
|
%b = comb.add %out1, %out1 : i1
|
|
%c = comb.add %out2, %out2 : i2
|
|
|
|
%out1, %out2 = hw.instance "b1" @DifferentResultMod() -> (out1: i1, out2: i2)
|
|
|
|
// CHECK: assign b = _b1_out1 + _b1_out1;
|
|
// CHECK: assign c = _b1_out2 + _b1_out2;
|
|
hw.output %b, %c : i1, i2
|
|
}
|
|
|
|
hw.module.extern @single_result(out res: i3)
|
|
// CHECK-LABEL: module instance_result_reuse_wires(
|
|
hw.module @instance_result_reuse_wires(out b: i3) {
|
|
// CHECK: wire {{.*}} some_wire;
|
|
// CHECK: single_result b1 (
|
|
// CHECK-NEXT: .res (some_wire)
|
|
// CHECK-NEXT: );
|
|
// CHECK-NEXT: assign b = some_wire;
|
|
%some_wire = sv.wire : !hw.inout<i3>
|
|
%read = sv.read_inout %some_wire : !hw.inout<i3>
|
|
|
|
%out1 = hw.instance "b1" @single_result() -> (res: i3)
|
|
sv.assign %some_wire, %out1 : i3
|
|
|
|
hw.output %read : i3
|
|
}
|
|
|
|
hw.module.extern @ExternDestMod(in %a: i1, in %b: i2, out c: i3, out d: i4)
|
|
hw.module @InternalDestMod(in %a: i1, in %b: i3, in %c: i1) {}
|
|
// CHECK-LABEL: module ABC
|
|
hw.module @ABC(in %a: i1, in %b: i2, out c: i4) {
|
|
%0,%1 = hw.instance "whatever" sym @a1 @ExternDestMod(a: %a: i1, b: %b: i2) -> (c: i3, d: i4) {doNotPrint}
|
|
%2 = sv.xmr "whatever", "a" : !hw.inout<i1>
|
|
%3 = sv.read_inout %2: !hw.inout<i1>
|
|
hw.instance "yo" sym @b1 @InternalDestMod(a: %a: i1, b: %0: i3, c: %3: i1) -> () {doNotPrint}
|
|
hw.output %1 : i4
|
|
}
|
|
|
|
// CHECK: wire [2:0] _whatever_c;
|
|
// CHECK: /* This instance is elsewhere emitted as a bind statement
|
|
// CHECK-NEXT: ExternDestMod whatever (
|
|
// CHECK-NEXT: .a (a),
|
|
// CHECK-NEXT: .b (b),
|
|
// CHECK-NEXT: .c (_whatever_c),
|
|
// CHECK-NEXT: .d (c)
|
|
// CHECK-NEXT: );
|
|
// CHECK-NEXT: */
|
|
// CHECK-NEXT: /* This instance is elsewhere emitted as a bind statement
|
|
// CHECK-NEXT: InternalDestMod yo (
|
|
// CHECK-NEXT: .a (a),
|
|
// CHECK-NEXT: .b (_whatever_c)
|
|
// CHECK-NEXT: .c (whatever.a)
|
|
// CHECK-NEXT: );
|
|
// CHECK-NEXT: */
|
|
// CHECK-NEXT: endmodule
|
|
|
|
|
|
hw.module.extern @Uwu(out uwu_output : i32)
|
|
hw.module.extern @Owo(in %owo_in : i32)
|
|
|
|
// CHECK-LABEL: module Nya(
|
|
hw.module @Nya(out nya_output : i32) {
|
|
%0 = hw.instance "uwu" @Uwu() -> (uwu_output: i32)
|
|
// CHECK: wire [31:0] _uwu_uwu_output;
|
|
// CHECK: Uwu uwu (
|
|
// CHECK: .uwu_output (_uwu_uwu_output)
|
|
// CHECK: );
|
|
|
|
hw.instance "owo" @Owo(owo_in: %0: i32) -> ()
|
|
// CHECK: Owo owo (
|
|
// CHECK: .owo_in (_uwu_uwu_output)
|
|
// CHECK: );
|
|
|
|
hw.output %0 : i32
|
|
// CHECK: assign nya_output = _uwu_uwu_output;
|
|
// CHECK: endmodule
|
|
}
|
|
|
|
// CHECK-LABEL: module Nya2(
|
|
hw.module @Nya2(out nya2_output : i32) {
|
|
%0 = hw.instance "uwu" @Uwu() -> (uwu_output: i32)
|
|
// CHECK: Uwu uwu (
|
|
// CHECK: .uwu_output (nya2_output)
|
|
// CHECK: );
|
|
|
|
hw.output %0 : i32
|
|
// CHECK: endmodule
|
|
}
|
|
|
|
hw.module.extern @Ni(out ni_output : i0)
|
|
hw.module.extern @San(in %san_input : i0)
|
|
|
|
// CHECK-LABEL: module Ichi(
|
|
hw.module @Ichi(out Ichi_output : i0) {
|
|
%0 = hw.instance "ni" @Ni() -> (ni_output: i0)
|
|
// CHECK: Ni ni (
|
|
// CHECK: //.ni_output (Ichi_output)
|
|
// CHECK-NEXT: );
|
|
|
|
hw.output %0 : i0
|
|
// CHECK: endmodule
|
|
}
|
|
|
|
// CHECK-LABEL: module Chi(
|
|
hw.module @Chi(out Chi_output : i0) {
|
|
%0 = hw.instance "ni" @Ni() -> (ni_output: i0)
|
|
// CHECK: Ni ni (
|
|
// CHECK: //.ni_output (_ni_ni_output)
|
|
// CHECK-NEXT: );
|
|
|
|
hw.instance "san" @San(san_input: %0: i0) -> ()
|
|
// CHECK: San san (
|
|
// CHECK: //.san_input (_ni_ni_output)
|
|
// CHECK-NEXT: );
|
|
|
|
// CHECK: // Zero width: assign Chi_output = _ni_ni_output;
|
|
hw.output %0 : i0
|
|
// CHECK: endmodule
|
|
}
|
|
|
|
// CHECK-LABEL: module Choochoo(
|
|
hw.module @Choochoo(out out : i0) {
|
|
%0 = hw.constant 0 : i0
|
|
// CHECK: // Zero width: assign out = /*Zero width*/;
|
|
hw.output %0 : i0
|
|
}
|
|
|
|
// CHECK-LABEL: module Foo1360(
|
|
// Issue #1360: https://github.com/llvm/circt/issues/1360
|
|
|
|
hw.module @Foo1360() {
|
|
// CHECK: RealBar #(
|
|
// CHECK-NEXT: .WIDTH0(0),
|
|
// CHECK-NEXT: .WIDTH1(4),
|
|
// CHECK-NEXT: .WIDTH2(40'd6812312123),
|
|
// CHECK-NEXT: .WIDTH3(-1),
|
|
// CHECK-NEXT: .WIDTH4(-68'sd88888888888888888),
|
|
// CHECK-NEXT: .Wtricky(40'd4294967295)
|
|
// CHECK-NEXT: ) bar ();
|
|
|
|
hw.instance "bar" @Bar1360<
|
|
WIDTH0: i32 = 0, WIDTH1: i4 = 4, WIDTH2: i40 = 6812312123, WIDTH3: si4 = -1,
|
|
WIDTH4: si68 = -88888888888888888, Wtricky: i40 = 4294967295
|
|
>() -> ()
|
|
hw.output
|
|
}
|
|
hw.module.extern @Bar1360<
|
|
WIDTH0: i32, WIDTH1: i4, WIDTH2: i40, WIDTH3: si4, WIDTH4: si68, Wtricky: i40
|
|
>() attributes {verilogName = "RealBar"}
|
|
|
|
// CHECK-LABEL: module Issue1563(
|
|
hw.module @Issue1563(in %a: i32, out out : i32) {
|
|
// CHECK: assign out = a + a;{{.*}}//{{.*}}XX.scala:123:19, YY.haskell:309:14, ZZ.swift:3:4
|
|
%0 = comb.add %a, %a : i32 loc(fused["XX.scala":123:19, "YY.haskell":309:14, "ZZ.swift":3:4])
|
|
hw.output %0 : i32
|
|
// CHECK: endmodule
|
|
}
|
|
|
|
// CHECK-LABEL: module Foo1587
|
|
// Issue #1587: https://github.com/llvm/circt/issues/1587
|
|
hw.module @Foo1587(in %idx: i2, in %a_0: i4, in %a_1: i4, in %a_2: i4, in %a_3: i4, out b: i4) {
|
|
%0 = hw.array_create %a_0, %a_1, %a_2, %a_3 : i4
|
|
%1 = hw.array_get %0[%idx] : !hw.array<4xi4>, i2
|
|
hw.output %1 : i4
|
|
// CHECK: wire [3:0][3:0] [[WIRE:.+]] = {{[{}][{}]}}a_0}, {a_1}, {a_2}, {a_3}};
|
|
// CHECK-NEXT: assign b = [[WIRE]][idx];
|
|
}
|
|
|
|
// CHECK-LABEL: module AddNegLiteral(
|
|
// Issue #1324: https://github.com/llvm/circt/issues/1324
|
|
hw.module @AddNegLiteral(in %a: i8, in %x: i8, in %y: i8, out o1: i8, out o2: i8) {
|
|
|
|
// CHECK: assign o1 = a - 8'h4;
|
|
%c = hw.constant -4 : i8
|
|
%1 = comb.add %a, %c : i8
|
|
|
|
// CHECK: assign o2 = x + y - 8'h4;
|
|
%2 = comb.add %x, %y, %c : i8
|
|
|
|
hw.output %1, %2 : i8, i8
|
|
}
|
|
|
|
|
|
// CHECK-LABEL: module ShiftAmountZext(
|
|
// Issue #1569: https://github.com/llvm/circt/issues/1569
|
|
hw.module @ShiftAmountZext(in %a: i8, in %b1: i4, in %b2: i4, in %b3: i4,
|
|
out o1: i8, out o2: i8, out o3: i8) {
|
|
|
|
%c = hw.constant 0 : i4
|
|
%B1 = comb.concat %c, %b1 : i4, i4
|
|
%B2 = comb.concat %c, %b2 : i4, i4
|
|
%B3 = comb.concat %c, %b3 : i4, i4
|
|
|
|
// CHECK: assign o1 = a << b1;
|
|
%r1 = comb.shl %a, %B1 : i8
|
|
|
|
// CHECK: assign o2 = a >> b2;
|
|
%r2 = comb.shru %a, %B2 : i8
|
|
|
|
// CHECK: assign o3 = $signed($signed(a) >>> b3);
|
|
%r3 = comb.shrs %a, %B3 : i8
|
|
hw.output %r1, %r2, %r3 : i8, i8, i8
|
|
}
|
|
|
|
// CHECK-LABEL: ModuleWithLocInfo
|
|
// CHECK: // Foo.bar:42:13
|
|
hw.module @ModuleWithLocInfo() {
|
|
} loc("Foo.bar":42:13)
|
|
|
|
|
|
// CHECK-LABEL: module SignedshiftResultSign
|
|
// Issue #1681: https://github.com/llvm/circt/issues/1681
|
|
hw.module @SignedshiftResultSign(in %a: i18, out b: i18) {
|
|
// CHECK: assign b = $signed($signed(a) >>> a[6:0]) ^ 18'hB28;
|
|
%c2856_i18 = hw.constant 2856 : i18
|
|
%c0_i11 = hw.constant 0 : i11
|
|
%0 = comb.extract %a from 0 : (i18) -> i7
|
|
%1 = comb.concat %c0_i11, %0 : i11, i7
|
|
%2 = comb.shrs %a, %1 : i18
|
|
%3 = comb.xor %2, %c2856_i18 : i18
|
|
hw.output %3 : i18
|
|
}
|
|
// CHECK-LABEL: module SignedShiftRightPrecendence
|
|
hw.module @SignedShiftRightPrecendence(in %p: i1, in %x: i45, out o: i45) {
|
|
// CHECK: assign o = $signed($signed(x) >>> (p ? 45'h5 : 45'h8))
|
|
%c5_i45 = hw.constant 5 : i45
|
|
%c8_i45 = hw.constant 8 : i45
|
|
%0 = comb.mux %p, %c5_i45, %c8_i45 : i45
|
|
%1 = comb.shrs %x, %0 : i45
|
|
hw.output %1 : i45
|
|
}
|
|
|
|
// CHECK-LABEL: structExtractChain
|
|
hw.module @structExtractChain(in %cond: i1, in %a: !hw.struct<c: !hw.struct<d:i1>>, out out: i1) {
|
|
%1 = hw.struct_extract %a["c"] : !hw.struct<c: !hw.struct<d:i1>>
|
|
%2 = hw.struct_extract %1["d"] : !hw.struct<d:i1>
|
|
// CHECK: assign out = a.c.d;
|
|
hw.output %2 : i1
|
|
}
|
|
|
|
// CHECK-LABEL: structExtractFromTemporary
|
|
hw.module @structExtractFromTemporary(in %cond: i1, in %a: !hw.struct<c: i1>, in %b: !hw.struct<c: i1>, out out: i1) {
|
|
%0 = comb.mux %cond, %a, %b : !hw.struct<c: i1>
|
|
%1 = hw.struct_extract %0["c"] : !hw.struct<c: i1>
|
|
// CHECK: wire struct packed {logic c; } _GEN = cond ? a : b;
|
|
// CHECK-NEXT: assign out = _GEN.c;
|
|
hw.output %1 : i1
|
|
}
|
|
|
|
// CHECK-LABEL: module unionCreateNoPadding(
|
|
// CHECK-NEXT: input [1:0] in,
|
|
// CHECK-NEXT: output union packed { struct packed {logic a; logic [0:0] __post_padding_a;} a;logic [1:0] b;} out
|
|
hw.module @unionCreateNoPadding(in %in: i2, out out: !hw.union<a: i1, b: i2>) {
|
|
// CHECK: assign out = in + in;
|
|
%add = comb.add %in, %in : i2
|
|
%0 = hw.union_create "b", %add : !hw.union<a: i1, b: i2>
|
|
hw.output %0 : !hw.union<a: i1, b: i2>
|
|
}
|
|
|
|
// CHECK-LABEL: module unionCreatePadding(
|
|
// CHECK-NEXT: input in,
|
|
// CHECK-NEXT: output union packed { struct packed {logic a; logic [0:0] __post_padding_a;} a;logic [1:0] b;} out
|
|
hw.module @unionCreatePadding(in %in: i1, out out: !hw.union<a: i1, b: i2>) {
|
|
// CHECK: assign out = {in, 1'h0};
|
|
%0 = hw.union_create "a", %in : !hw.union<a: i1, b: i2>
|
|
hw.output %0 : !hw.union<a: i1, b: i2>
|
|
}
|
|
|
|
// CHECK-LABEL: module unionCreateZeroWidthElement(
|
|
// CHECK-NEXT: // input /*Zero Width*/ in,
|
|
// CHECK-NEXT: output union packed {/*a: Zero Width;*/ logic [1:0] b;} out
|
|
hw.module @unionCreateZeroWidthElement(in %in: i0, out out: !hw.union<a: i0, b: i2>) {
|
|
// CHECK: assign out = 2'h0;
|
|
%0 = hw.union_create "a", %in : !hw.union<a: i0, b: i2>
|
|
hw.output %0 : !hw.union<a: i0, b: i2>
|
|
}
|
|
|
|
// CHECK-LABEL: unionExtractFromTemporary
|
|
hw.module @unionExtractFromTemporary(in %cond: i1, in %a: !hw.union<c: i1>, in %b: !hw.union<c: i1>, out out: i1) {
|
|
%0 = comb.mux %cond, %a, %b : !hw.union<c: i1>
|
|
%1 = hw.union_extract %0["c"] : !hw.union<c: i1>
|
|
// CHECK: wire union packed {logic c;} _GEN = cond ? a : b;
|
|
// CHECK-NEXT: assign out = _GEN.c;
|
|
hw.output %1 : i1
|
|
}
|
|
|
|
// CHECK-LABEL: structExplodeLowering
|
|
hw.module @structExplodeLowering(in %a: !hw.struct<a: i1, b: i1>, out outA: i1, out outB: i1) {
|
|
// CHECK: assign outA = a.a;
|
|
// CHECK: assign outB = a.b;
|
|
%0:2 = hw.struct_explode %a : !hw.struct<a: i1, b: i1>
|
|
hw.output %0#0, %0#1 : i1, i1
|
|
}
|
|
|
|
|
|
// Rename field names
|
|
// CHECK-LABEL: renameKeyword(
|
|
// CHECK-NEXT: input struct packed {logic repeat_0; logic repeat_0_0; } a,
|
|
// CHECK-NEXT: output struct packed {logic repeat_0; logic repeat_0_0; } r1
|
|
// CHECK-NEXT: );
|
|
hw.module @renameKeyword(in %a: !hw.struct<repeat: i1, repeat_0: i1>, out r1: !hw.struct<repeat: i1, repeat_0: i1>){
|
|
hw.output %a : !hw.struct<repeat: i1, repeat_0: i1>
|
|
}
|
|
|
|
// CHECK-LABEL: useRenamedStruct(
|
|
// CHECK-NEXT: inout struct packed {logic repeat_0; logic repeat_0_0; } a,
|
|
// CHECK-NEXT: output r1,
|
|
// CHECK-NEXT: r2,
|
|
// CHECK-NEXT: output struct packed {logic repeat_0; logic repeat_0_0; } r3,
|
|
// CHECK-NEXT: r4
|
|
// CHECK-NEXT: );
|
|
hw.module @useRenamedStruct(inout %a: !hw.struct<repeat: i1, repeat_0: i1>, out r1: i1, out r2: i1, out r3: !hw.struct<repeat: i1, repeat_0: i1>, out r4: !hw.struct<repeat: i1, repeat_0: i1>) {
|
|
%read = sv.read_inout %a : !hw.inout<struct<repeat: i1, repeat_0: i1>>
|
|
|
|
%i0 = hw.instance "inst1" @renameKeyword(a: %read: !hw.struct<repeat: i1, repeat_0: i1>) -> (r1: !hw.struct<repeat: i1, repeat_0: i1>)
|
|
// CHECK: renameKeyword inst1 (
|
|
// CHECK-NEXT: .a (a),
|
|
// CHECK-NEXT: .r1 (r4)
|
|
// CHECK-NEXT: )
|
|
|
|
%0 = sv.struct_field_inout %a["repeat"] : !hw.inout<struct<repeat: i1, repeat_0: i1>>
|
|
%1 = sv.read_inout %0 : !hw.inout<i1>
|
|
// CHECK: assign r1 = a.repeat_0;
|
|
%2 = hw.struct_extract %read["repeat_0"] : !hw.struct<repeat: i1, repeat_0: i1>
|
|
// CHECK: assign r2 = a.repeat_0_0
|
|
%true = hw.constant true
|
|
%3 = hw.struct_inject %read["repeat_0"], %true : !hw.struct<repeat: i1, repeat_0: i1>
|
|
// CHECK: assign r3 = '{repeat_0: a.repeat_0, repeat_0_0: (1'h1)};
|
|
hw.output %1, %2, %3, %i0 : i1, i1, !hw.struct<repeat: i1, repeat_0: i1>, !hw.struct<repeat: i1, repeat_0: i1>
|
|
}
|
|
|
|
|
|
// CHECK-LABEL: module replicate
|
|
hw.module @replicate(in %arg0: i7, in %arg1: i1, out r1: i21, out r2: i9, out r3: i16, out r4: i16) {
|
|
// CHECK: assign r1 = {3{arg0}};
|
|
%r1 = comb.replicate %arg0 : (i7) -> i21
|
|
|
|
// CHECK: assign r2 = {9{arg1}};
|
|
%r2 = comb.replicate %arg1 : (i1) -> i9
|
|
|
|
// CHECK: assign r3 = {{[{]}}{9{arg0[6]}}, arg0};
|
|
%0 = comb.extract %arg0 from 6 : (i7) -> i1
|
|
%1 = comb.replicate %0 : (i1) -> i9
|
|
%r3 = comb.concat %1, %arg0 : i9, i7
|
|
|
|
// CHECK: assign r4 = {2{arg0, arg1}};
|
|
%2 = comb.concat %arg0, %arg1 : i7, i1
|
|
%r4 = comb.replicate %2 : (i8) -> i16
|
|
|
|
hw.output %r1, %r2, %r3, %r4 : i21, i9, i16, i16
|
|
}
|
|
|
|
// CHECK-LABEL: module addParenthesesToSuccessiveOperators
|
|
hw.module @addParenthesesToSuccessiveOperators(in %a: i4, in %b: i1, in %c: i4, out o1:i1, out o2:i1, out o3:i1) {
|
|
%one4 = hw.constant -1 : i4
|
|
%zero4 = hw.constant 0 : i4
|
|
// CHECK: wire [[GEN:.+]] = &c;
|
|
|
|
%and1 = comb.icmp eq %a, %one4 : i4
|
|
%and2 = comb.icmp eq %a, %one4 : i4
|
|
%and3 = comb.icmp eq %a, %one4 : i4
|
|
%and = comb.and %and1, %b, %and2, %and3 : i1
|
|
// CHECK-NEXT: assign o1 = (&a) & b & (&a) & (&a);
|
|
|
|
%or1 = comb.icmp ne %a, %zero4 : i4
|
|
%or2 = comb.icmp ne %a, %zero4 : i4
|
|
%or3 = comb.icmp ne %a, %zero4 : i4
|
|
%or = comb.or %or1, %b, %or2, %or3 : i1
|
|
// CHECK-NEXT: assign o2 = (|a) | b | (|a) | (|a);
|
|
|
|
%3 = comb.icmp eq %c, %one4 : i4
|
|
%multiuse = comb.and %3, %3 : i1
|
|
// CHECK-NEXT: assign o3 = [[GEN]] & [[GEN]];
|
|
|
|
hw.output %and, %or, %multiuse : i1, i1, i1
|
|
}
|
|
|
|
// CHECK-LABEL: module parameters
|
|
// CHECK-NEXT: #(parameter [41:0] p1 = 42'd17
|
|
// CHECK-NEXT: parameter [0:0] p2) (
|
|
// CHECK-NEXT: input [7:0] arg0,
|
|
hw.module @parameters<p1: i42 = 17, p2: i1>(in %arg0: i8, out out: i8) {
|
|
// Local values should not conflict with output or parameter names.
|
|
// CHECK: wire [3:0] p1_0;
|
|
%p1 = sv.wire : !hw.inout<i4>
|
|
|
|
%out = sv.wire : !hw.inout<i4>
|
|
// CHECK: wire [3:0] out_0;
|
|
hw.output %arg0 : i8
|
|
}
|
|
|
|
hw.module.extern @parameters2<p1: i42 = 17, p2: i1 = 0>(in %arg0: i8, out out: i8)
|
|
|
|
// CHECK-LABEL: module parameters3
|
|
// CHECK-NEXT: #(parameter [41:0] p1 = 42'd17) (
|
|
// CHECK-NEXT: input [p1 - 1:0] arg0,
|
|
// CHECK-NEXT: output [p1 - 1:0] out
|
|
// CHECK-NEXT: );
|
|
// CHECK: assign out = arg0;
|
|
hw.module @parameters3<p1: i42 = 17>(in %arg0: !hw.int<#hw.param.decl.ref<"p1">>, out out: !hw.int<#hw.param.decl.ref<"p1">>) {
|
|
hw.output %arg0 : !hw.int<#hw.param.decl.ref<"p1">>
|
|
}
|
|
|
|
// CHECK-LABEL: module UseParameterized(
|
|
hw.module @UseParameterized(in %a: i8, out ww: i8, out xx: i8, out yy: i8, out zz: i8, out qq: i8) {
|
|
// Two parameters.
|
|
// CHECK: parameters #(
|
|
// CHECK-NEXT: .p1(42'd4),
|
|
// CHECK-NEXT: .p2(0)
|
|
// CHECK-NEXT: ) inst1 (
|
|
// CHECK-NEXT: .arg0 (a),
|
|
// CHECK-NEXT: .out (ww)
|
|
// CHECK-NEXT: );
|
|
%r0 = hw.instance "inst1" @parameters<p1: i42 = 4, p2: i1 = 0>(arg0: %a: i8) -> (out: i8)
|
|
|
|
// Two parameters.
|
|
// CHECK: parameters #(
|
|
// CHECK-NEXT: .p1(42'd11),
|
|
// CHECK-NEXT: .p2(1)
|
|
// CHECK-NEXT: ) inst2 (
|
|
// CHECK-NEXT: .arg0 (a),
|
|
// CHECK-NEXT: .out (xx)
|
|
// CHECK-NEXT: );
|
|
%r1 = hw.instance "inst2" @parameters<p1: i42 = 11, p2: i1 = 1>(arg0: %a: i8) -> (out: i8)
|
|
|
|
// One default, don't print it
|
|
// CHECK: parameters #(
|
|
// CHECK-NEXT: .p2(0)
|
|
// CHECK-NEXT: ) inst3 (
|
|
// CHECK-NEXT: .arg0 (a),
|
|
// CHECK-NEXT: .out (yy)
|
|
// CHECK-NEXT: );
|
|
%r2 = hw.instance "inst3" @parameters<p1: i42 = 17, p2: i1 = 0>(arg0: %a: i8) -> (out: i8)
|
|
|
|
// All defaults, don't print a parameter list at all.
|
|
// CHECK: parameters2 inst4 (
|
|
// CHECK-NEXT: .arg0 (a),
|
|
// CHECK-NEXT: .out (zz)
|
|
// CHECK-NEXT: );
|
|
%r3 = hw.instance "inst4" @parameters2<p1: i42 = 17, p2: i1 = 0>(arg0: %a: i8) -> (out: i8)
|
|
|
|
// Parameterized I/O ports.
|
|
// CHECK: parameters3 #(
|
|
// CHECK-NEXT: .p1(42'd8)
|
|
// CHECK-NEXT: ) inst5 (
|
|
// CHECK-NEXT: .arg0 (a),
|
|
// CHECK-NEXT: .out (qq)
|
|
// CHECK-NEXT: );
|
|
%r4 = hw.instance "inst5" @parameters3<p1: i42 = 8>(arg0: %a: i8) -> (out: i8)
|
|
|
|
hw.output %r0, %r1, %r2, %r3, %r4: i8, i8, i8, i8, i8
|
|
}
|
|
|
|
// CHECK-LABEL: module UseParameterValue
|
|
hw.module @UseParameterValue<xx: i42>(in %arg0: i8,
|
|
out out1: i8, out out2: i8, out out3: i8, out out4: i42) {
|
|
// CHECK-NEXT: #(parameter [41:0] xx) (
|
|
|
|
// CHECK: parameters2 #(
|
|
// CHECK-NEXT: .p1(xx)
|
|
// CHECK-NEXT: ) inst1 (
|
|
%a = hw.instance "inst1" @parameters2<p1: i42 = #hw.param.decl.ref<"xx">, p2: i1 = 0>(arg0: %arg0: i8) -> (out: i8)
|
|
|
|
// CHECK: parameters2 #(
|
|
// CHECK-NEXT: .p1(xx + 42'd17)
|
|
// CHECK-NEXT: ) inst2 (
|
|
%b = hw.instance "inst2" @parameters2<p1: i42 = #hw.param.expr.add<#hw.param.verbatim<"xx">, 17>, p2: i1 = 0>(arg0: %arg0: i8) -> (out: i8)
|
|
|
|
// CHECK: parameters2 #(
|
|
// CHECK-NEXT: .p1(xx * yy + yy * 42'd17)
|
|
// CHECK-NEXT: ) inst3 (
|
|
%c = hw.instance "inst3" @parameters2<p1: i42 = #hw.param.expr.mul<#hw.param.expr.add<#hw.param.verbatim<"xx">, 17>, #hw.param.verbatim<"yy">>, p2: i1 = 0>(arg0: %arg0: i8) -> (out: i8)
|
|
|
|
// FIXME: Decl word should be localparam.
|
|
// CHECK: wire [41:0] _GEN = xx + 42'd17;
|
|
// CHECK-NEXT: assign out3 = _GEN[7:0] + _GEN[7:0];
|
|
%d = hw.param.value i42 = #hw.param.expr.add<#hw.param.decl.ref<"xx">, 17>
|
|
%e = comb.extract %d from 0 : (i42) -> i8
|
|
%f = comb.add %e, %e : i8
|
|
|
|
// CHECK-NEXT: assign out4 = $signed(42'd4) >>> $signed(xx);
|
|
%g = hw.param.value i42 = #hw.param.expr.shrs<4, #hw.param.decl.ref<"xx">>
|
|
|
|
hw.output %a, %b, %f, %g : i8, i8, i8, i42
|
|
}
|
|
|
|
// CHECK-LABEL: module VerilogCompatParameters
|
|
hw.module @VerilogCompatParameters<p1: i42, p2: i32, p3: f64 = 1.5,
|
|
p4: i32 = 4, p5: none = "foo",
|
|
p6: none>() {
|
|
// CHECK-NEXT: #(parameter [41:0] p1,
|
|
// CHECK-NEXT: parameter /*integer*/ p2,
|
|
// CHECK-NEXT: parameter p3 = 1.500000e+00,
|
|
// CHECK-NEXT: parameter p4 = 4,
|
|
// CHECK-NEXT: parameter p5 = "foo",
|
|
// CHECK-NEXT: parameter p6)
|
|
|
|
}
|
|
|
|
|
|
// CHECK-LABEL: module parameterizedTypes
|
|
// CHECK: #(parameter param = 1,
|
|
// CHECK: parameter wire_0 = 2) (
|
|
hw.module @parameterizedTypes<param: i32 = 1, wire: i32 = 2>
|
|
// CHECK: input [16:0]{{ *}}a,
|
|
(in %a: !hw.int<17>,
|
|
// CHECK: input [param - 1:0]{{ *}}b
|
|
in %b: !hw.int<#hw.param.decl.ref<"param">>,
|
|
// CHECK: input [$clog2($unsigned(param)) - 1:0]{{ *}}c
|
|
in %c: !hw.int<#hw.param.expr.clog2<#hw.param.decl.ref<"param">>>) {
|
|
|
|
// Check that the parameter name renamification propagates.
|
|
// CHECK: wire [wire_0 - 1:0] paramWire;
|
|
%paramWire = sv.wire : !hw.inout<!hw.int<#hw.param.decl.ref<"wire">>>
|
|
|
|
}
|
|
|
|
// CHECK-LABEL: // moduleWithComment has a comment
|
|
// CHECK-NEXT: // hello
|
|
// CHECK-NEXT: module moduleWithComment
|
|
hw.module @moduleWithComment()
|
|
attributes {comment = "moduleWithComment has a comment\nhello"} {}
|
|
|
|
|
|
// CHECK-LABEL: module Foo(
|
|
// https://github.com/llvm/circt/issues/2363
|
|
hw.module @Foo(in %a: i1, in %b: i1, out r1: i1, out r2: i1) {
|
|
// Make sure the temporary wire is indented correctly.
|
|
// CHECK: {{^ wire _GEN = a == b;}}
|
|
%0 = comb.icmp eq %a, %b : i1
|
|
hw.output %0, %0 : i1, i1
|
|
}
|
|
|
|
// CHECK-LABEL: module parameterizedArrays
|
|
// CHECK-NEXT: #(parameter /*integer*/ param,
|
|
// CHECK-NEXT: parameter /*integer*/ N) (
|
|
// CHECK-NEXT: input [41:0][param - 1:0] a,
|
|
// CHECK-NEXT: input [N - 64'd1:0][param - 1:0] b,
|
|
// CHECK-NEXT: output [N - 64'd1:0][param - 1:0] c
|
|
// CHECK-NEXT: );
|
|
hw.module @parameterizedArrays<param: i32, N: i32>
|
|
(in %a: !hw.array<42x!hw.int<#hw.param.decl.ref<"param">>>,
|
|
in %b: !hw.array<#hw.param.decl.ref<"N"> x !hw.int<#hw.param.decl.ref<"param">>>,
|
|
out c: !hw.array<#hw.param.decl.ref<"N"> x !hw.int<#hw.param.decl.ref<"param">>>) {
|
|
hw.output %b : !hw.array<#hw.param.decl.ref<"N"> x !hw.int<#hw.param.decl.ref<"param">>>
|
|
}
|
|
|
|
// CHECK-LABEL: module UseParameterizedArrays(
|
|
// CHECK-NEXT: input [41:0][11:0] a,
|
|
// CHECK-NEXT: input [23:0][11:0] b
|
|
// CHECK-NEXT: output [23:0][11:0] c
|
|
// CHECK-NEXT: );
|
|
hw.module @UseParameterizedArrays(in %a: !hw.array<42xint<12>>, in %b: !hw.array<24xint<12>>, out c: !hw.array<24xint<12>>) {
|
|
// CHECK: parameterizedArrays #(
|
|
// CHECK-NEXT: .param(12),
|
|
// CHECK-NEXT: .N(24)
|
|
// CHECK-NEXT: ) inst (
|
|
// CHECK-NEXT: .a (a),
|
|
// CHECK-NEXT: .b (b),
|
|
// CHECK-NEXT: .c (c)
|
|
// CHECK-NEXT: );
|
|
// CHECK-NEXT: endmodule
|
|
%c = hw.instance "inst" @parameterizedArrays<param: i32 = 12, N: i32 = 24>
|
|
(a: %a : !hw.array<42xint<12>>, b: %b : !hw.array<24xint<12>>) -> (c: !hw.array<24xint<12>>) {}
|
|
hw.output %c: !hw.array<24xint<12>>
|
|
}
|
|
|
|
// CHECK-LABEL: module NoneTypeParam
|
|
// CHECK: #(parameter p1) ();
|
|
// CHECK: endmodule
|
|
hw.module @NoneTypeParam<p1: none>() {}
|
|
|
|
// CHECK-LABEL: module ParamConcatInst
|
|
// CHECK: #(parameter name = "top") ();
|
|
// CHECK: NoneTypeParam #(
|
|
// CHECK: .p1({".", name, ".child"})
|
|
// CHECK: ) inst ();
|
|
// CHECK: endmodule
|
|
hw.module @ParamConcatInst<name: none = "top">() {
|
|
hw.instance "inst" @NoneTypeParam<p1: none = #hw.param.expr.str.concat<".", #hw.param.decl.ref<"name">, ".", "child">>() -> ()
|
|
}
|
|
|
|
// CHECK-LABEL: module ParamsParensPrecedence
|
|
hw.module @ParamsParensPrecedence<param: i32>(out a:i32, out b:i32, out c:i32) {
|
|
// CHECK: = $clog2($unsigned(param));
|
|
%1 = hw.param.value i32 = #hw.param.expr.clog2<#hw.param.decl.ref<"param">>
|
|
|
|
// CHECK: = $clog2($unsigned($clog2($unsigned(param + 8))));
|
|
%3 = hw.param.value i32 = #hw.param.expr.clog2<#hw.param.expr.clog2<#hw.param.expr.add<#hw.param.decl.ref<"param">,8>>>
|
|
|
|
// CHECK: = $signed(param) >>> $signed(param & 8);
|
|
%4 = hw.param.value i32 = #hw.param.expr.shrs<#hw.param.decl.ref<"param">,#hw.param.expr.and<8,#hw.param.decl.ref<"param">>>
|
|
hw.output %1, %3, %4: i32, i32, i32
|
|
}
|
|
|
|
// CHECK-LABEL: module ArrayGetInline
|
|
hw.module @ArrayGetInline(in %a: !hw.array<4xstruct<a: i32>>, in %b: !hw.array<4xi1>, in %idx: i2, inout %idx_port: i2,
|
|
out out: i32, out out2: i1, out out3: i1, out out4: i1, out out5: i1) {
|
|
%c0_i2 = hw.constant 0 : i2
|
|
%x = hw.array_get %a[%c0_i2] : !hw.array<4xstruct<a: i32>>, i2
|
|
%y = hw.struct_extract %x["a"] : !hw.struct<a: i32>
|
|
// CHECK: assign out = a[2'h0].a;
|
|
// CHECK-NEXT: assign out2 = b[idx];
|
|
// CHECK-NEXT: assign out3 = b[idx];
|
|
// CHECK-NEXT: assign out4 = b[idx_port];
|
|
// CHECK-NEXT: assign out5 = b[idx_port];
|
|
%array_get_idx = hw.array_get %b[%idx] : !hw.array<4xi1>, i2
|
|
%read = sv.read_inout %idx_port : !hw.inout<i2>
|
|
%array_get_idx_port = hw.array_get %b[%read] : !hw.array<4xi1>, i2
|
|
hw.output %y, %array_get_idx, %array_get_idx, %array_get_idx_port, %array_get_idx_port : i32, i1, i1, i1, i1
|
|
}
|
|
|
|
// CHECK-LABEL: module UniformArrayCreate
|
|
hw.module @UniformArrayCreate(out arr: !hw.array<5xi8>) {
|
|
%c0_i8 = hw.constant 0 : i8
|
|
%arr = hw.array_create %c0_i8, %c0_i8, %c0_i8, %c0_i8, %c0_i8 : i8
|
|
// CHECK: assign arr = {5{8'h0}};
|
|
hw.output %arr : !hw.array<5xi8>
|
|
}
|
|
|
|
// CHECK-LABEL: module Issue4485(
|
|
// CHECK-NEXT: input [3:0] in
|
|
// CHECK-NEXT: );
|
|
// CHECK-EMPTY:
|
|
// CHECK-NEXT: endmodule
|
|
hw.module @Issue4485(in %in: i4) {
|
|
%c0_i4 = hw.constant 0 : i4
|
|
%1 = comb.icmp eq %in, %c0_i4 : i4
|
|
%2 = sv.system.sampled %1 : i1
|
|
hw.output
|
|
}
|
|
|
|
// CHECK-LABEL: module inline_bitcast_in_concat(
|
|
// CHECK-NEXT: input [6:0] in1,
|
|
// CHECK-NEXT: input [7:0][3:0] in2,
|
|
// CHECK-NEXT: output [38:0] out
|
|
// CHECK-NEXT: );
|
|
// CHECK-EMPTY:
|
|
// CHECK-NEXT: assign out = {in1, /*cast(bit[31:0])*/in2};
|
|
// CHECK-NEXT: endmodule
|
|
hw.module @inline_bitcast_in_concat(in %in1: i7, in %in2: !hw.array<8xi4>, out out: i39) {
|
|
%r2 = hw.bitcast %in2 : (!hw.array<8xi4>) -> i32
|
|
%0 = comb.concat %in1, %r2: i7, i32
|
|
hw.output %0 : i39
|
|
}
|
|
|
|
// CHECK-LABEL: module DontInlineAggregateConstantIntoPorts(
|
|
// CHECK: wire [1:0][3:0] _GEN = '{4'h0, 4'h1};
|
|
// CHECK-NEXT: Array i0 (
|
|
// CHECK-NEXT: .a (_GEN)
|
|
// CHECK-NEXT: );
|
|
// CHECK-NEXT: endmodule
|
|
hw.module @DontInlineAggregateConstantIntoPorts() {
|
|
%0 = hw.aggregate_constant [0 : i4, 1 : i4] : !hw.array<2xi4>
|
|
hw.instance "i0" @Array(a: %0: !hw.array<2xi4>) -> ()
|
|
}
|
|
|
|
// CHECK-LABEL: module FooA(
|
|
// CHECK-NEXT: input union packed {logic [15:0] a; struct packed {logic [9:0] b; logic [5:0] __post_padding_b;} b;} test
|
|
// CHECK-NEXT: output [15:0] a,
|
|
// CHECK-NEXT: output [9:0] b
|
|
// CHECK-NEXT: );
|
|
// CHECK-EMPTY:
|
|
// CHECK-NEXT: assign a = test.a;
|
|
// CHECK-NEXT: assign b = test.b.b;
|
|
// CHECK-NEXT: endmodule
|
|
!unionA = !hw.union<a: i16, b: i10>
|
|
hw.module @FooA(in %test: !unionA, out a: i16, out b: i10) {
|
|
%0 = hw.union_extract %test["a"] : !unionA
|
|
%1 = hw.union_extract %test["b"] : !unionA
|
|
hw.output %0, %1 : i16, i10
|
|
}
|
|
|
|
// CHECK-LABEL: module FooB(
|
|
// CHECK-NEXT: input union packed {logic [15:0] a; struct packed {logic [1:0] __pre_padding_b; logic [13:0] b;} b;} test,
|
|
// CHECK-NEXT: output [15:0] a,
|
|
// CHECK-NEXT: output [13:0] b
|
|
// CHECK-NEXT: );
|
|
// CHECK-EMPTY:
|
|
// CHECK-NEXT: assign a = test.a;
|
|
// CHECK-NEXT: assign b = test.b.b;
|
|
// CHECK-NEXT: endmodule
|
|
!unionB = !hw.union<a: i16, b: i14 offset 2>
|
|
hw.module @FooB(in %test: !unionB, out a: i16, out b: i14) {
|
|
%0 = hw.union_extract %test["a"] : !unionB
|
|
%1 = hw.union_extract %test["b"] : !unionB
|
|
hw.output %0, %1 : i16, i14
|
|
}
|
|
|
|
// CHECK-LABEL: module Issue6275
|
|
hw.module @Issue6275(out z: !hw.struct<a: !hw.array<2xstruct<b: i1>>>) {
|
|
// CHECK: assign z = '{a: '{'{b: 1'h0}, '{b: 1'h1}}};
|
|
%0 = hw.aggregate_constant [[[false], [true]]] : !hw.struct<a: !hw.array<2xstruct<b: i1>>>
|
|
hw.output %0 : !hw.struct<a: !hw.array<2xstruct<b: i1>>>
|
|
}
|