mirror of https://github.com/llvm/circt.git
605 lines
22 KiB
MLIR
605 lines
22 KiB
MLIR
// RUN: circt-opt -prettify-verilog %s | FileCheck %s
|
|
// RUN: circt-opt -prettify-verilog %s | circt-opt --export-verilog | FileCheck %s --check-prefix=VERILOG
|
|
|
|
// CHECK-LABEL: hw.module @unary_ops
|
|
hw.module @unary_ops(in %arg0: i8, in %arg1: i8, in %arg2: i8, in %arg3: i1,
|
|
out a: i8, out b: i8, out c: i1) {
|
|
%c-1_i8 = hw.constant -1 : i8
|
|
|
|
// CHECK: [[XOR1:%.+]] = comb.xor %arg0
|
|
%unary = comb.xor %arg0, %c-1_i8 : i8
|
|
// CHECK: %1 = comb.add [[XOR1]], %arg1
|
|
%a = comb.add %unary, %arg1 : i8
|
|
|
|
// CHECK: [[XOR2:%.+]] = comb.xor %arg0
|
|
// CHECK: %3 = comb.add [[XOR2]], %arg2
|
|
%b = comb.add %unary, %arg2 : i8
|
|
|
|
|
|
// Multi-use arith.xori gets duplicated, and we need to make sure there is a local
|
|
// constant as well.
|
|
%true = hw.constant true
|
|
%c = comb.xor %arg3, %true : i1
|
|
|
|
// CHECK: [[TRUE1:%.+]] = hw.constant true
|
|
sv.initial {
|
|
// CHECK: [[TRUE2:%.+]] = hw.constant true
|
|
// CHECK: [[XOR3:%.+]] = comb.xor %arg3, [[TRUE2]]
|
|
// CHECK: sv.if [[XOR3]]
|
|
sv.if %c {
|
|
sv.fatal 1
|
|
}
|
|
}
|
|
|
|
// CHECK: [[XOR4:%.+]] = comb.xor %arg3, [[TRUE1]]
|
|
// CHECK: hw.output %1, %3, [[XOR4]]
|
|
hw.output %a, %b, %c : i8, i8, i1
|
|
}
|
|
|
|
// VERILOG: assign a = ~arg0 + arg1;
|
|
// VERILOG: assign b = ~arg0 + arg2;
|
|
|
|
// CHECK-LABEL: sv.macro.decl @FOO
|
|
sv.macro.decl @FOO
|
|
|
|
/// The pass should sink constants in to the block where they are used.
|
|
// CHECK-LABEL: @sink_constants
|
|
// VERILOG-LABEL: sink_constants
|
|
hw.module @sink_constants(in %clock :i1, out out : i1){
|
|
// CHECK: %false = hw.constant false
|
|
%false = hw.constant false
|
|
|
|
// CHECK-NOT: %fd = hw.constant -2147483646 : i32
|
|
%fd = hw.constant 0x80000002 : i32
|
|
|
|
/// Constants not used should be removed.
|
|
// CHECK-NOT: %true = hw.constant true
|
|
%true = hw.constant true
|
|
|
|
/// Simple constant sinking.
|
|
sv.ifdef @FOO {
|
|
sv.initial {
|
|
// CHECK: [[FALSE:%.*]] = hw.constant false
|
|
// CHECK: [[FD:%.*]] = hw.constant -2147483646 : i32
|
|
// CHECK: [[TRUE:%.*]] = hw.constant true
|
|
// CHECK: sv.fwrite [[FD]], "%x"([[TRUE]]) : i1
|
|
sv.fwrite %fd, "%x"(%true) : i1
|
|
// CHECK: sv.fwrite [[FD]], "%x"([[FALSE]]) : i1
|
|
sv.fwrite %fd, "%x"(%false) : i1
|
|
}
|
|
}
|
|
|
|
/// Multiple uses in the same block should use the same constant.
|
|
sv.ifdef @FOO {
|
|
sv.initial {
|
|
// CHECK: [[FD:%.*]] = hw.constant -2147483646 : i32
|
|
// CHECK: [[TRUE:%.*]] = hw.constant true
|
|
// CHECK: sv.fwrite [[FD]], "%x"([[TRUE]]) : i1
|
|
// CHECK: sv.fwrite [[FD]], "%x"([[TRUE]]) : i1
|
|
sv.fwrite %fd, "%x"(%true) : i1
|
|
sv.fwrite %fd, "%x"(%true) : i1
|
|
}
|
|
}
|
|
|
|
// CHECK: hw.output %false : i1
|
|
hw.output %false : i1
|
|
}
|
|
|
|
// VERILOG: `ifdef FOO
|
|
// VERILOG: $fwrite(32'h80000002, "%x", 1'h1);
|
|
// VERILOG: $fwrite(32'h80000002, "%x", 1'h0);
|
|
// VERILOG: `endif
|
|
// VERILOG: `ifdef FOO
|
|
// VERILOG: $fwrite(32'h80000002, "%x", 1'h1);
|
|
// VERILOG: $fwrite(32'h80000002, "%x", 1'h1);
|
|
// VERILOG: `endif
|
|
|
|
// Prettify should always sink ReadInOut to its usage.
|
|
// CHECK-LABEL: @sinkReadInOut
|
|
// VERILOG-LABEL: sinkReadInOut
|
|
hw.module @sinkReadInOut(in %clk: i1) {
|
|
%myreg = sv.reg : !hw.inout<array<1xstruct<a: i48, b: i48>>>
|
|
%false = hw.constant false
|
|
%0 = sv.array_index_inout %myreg[%false]: !hw.inout<array<1xstruct<a: i48, b: i48>>>, i1
|
|
%a = sv.struct_field_inout %0["a"]: !hw.inout<struct<a: i48, b: i48>>
|
|
%b = sv.struct_field_inout %0["b"]: !hw.inout<struct<a: i48, b: i48>>
|
|
%2 = sv.read_inout %b : !hw.inout<i48>
|
|
sv.alwaysff(posedge %clk) {
|
|
sv.passign %a, %2 : i48
|
|
}
|
|
}
|
|
// CHECK: %myreg = sv.reg
|
|
// CHECK: sv.alwaysff(posedge %clk)
|
|
// CHECK: sv.array_index_inout
|
|
// CHECK: sv.struct_field_inout
|
|
// CHECK: sv.read_inout
|
|
|
|
// VERILOG: struct packed {logic [47:0] a; logic [47:0] b; }[0:0] myreg;
|
|
// VERILOG: always_ff @(posedge clk)
|
|
// VERILOG: myreg[1'h0].a <= myreg[1'h0].b;
|
|
|
|
// CHECK-LABEL: sv.macro.decl @SOMETHING
|
|
sv.macro.decl @SOMETHING
|
|
|
|
// CHECK-LABEL: @sink_expression
|
|
// VERILOG-LABEL: sink_expression
|
|
hw.module @sink_expression(in %clock: i1, in %a: i1, in %a2: i1, in %a3: i1, in %a4: i1) {
|
|
// This or is used in one place.
|
|
%0 = comb.or %a2, %a3 : i1
|
|
// This and/xor chain is used in two. Both should be sunk.
|
|
%1 = comb.and %a2, %a3 : i1
|
|
%2 = comb.xor %1, %a4 : i1
|
|
// CHECK: sv.always
|
|
sv.always posedge %clock {
|
|
// CHECK: [[AND:%.*]] = comb.and %a2, %a3 : i1
|
|
// CHECK: [[XOR:%.*]] = comb.xor [[AND]], %a4 : i1
|
|
|
|
// CHECK: sv.ifdef.procedural
|
|
sv.ifdef.procedural @SOMETHING {
|
|
// CHECK: [[OR:%.*]] = comb.or %a2, %a3 : i1
|
|
// CHECK: sv.if [[OR]]
|
|
sv.if %0 {
|
|
sv.fatal 1
|
|
}
|
|
// CHECK: sv.if [[XOR]]
|
|
sv.if %2 {
|
|
sv.fatal 1
|
|
}
|
|
}
|
|
|
|
// CHECK: sv.if [[XOR]]
|
|
sv.if %2 {
|
|
sv.fatal 1
|
|
}
|
|
}
|
|
hw.output
|
|
}
|
|
|
|
// CHECK-LABEL: @dont_sink_se_expression
|
|
hw.module @dont_sink_se_expression(in %clock: i1, in %a: i1, in %a2: i1, in %a3: i1, in %a4: i1) {
|
|
|
|
// CHECK: [[DONT_TOUCH:%.*]] = sv.verbatim.expr.se "DONT_TOUCH"
|
|
%0 = sv.verbatim.expr "SINK_ME" : () -> i1
|
|
%1 = sv.verbatim.expr.se "DONT_TOUCH" : () -> i1
|
|
|
|
// CHECK: sv.always
|
|
sv.always posedge %clock {
|
|
// CHECK: [[SINK:%.*]] = sv.verbatim.expr "SINK_ME"
|
|
// CHECK: sv.if [[SINK]]
|
|
sv.if %0 {
|
|
sv.fatal 1
|
|
}
|
|
|
|
// CHECK: sv.if [[DONT_TOUCH]]
|
|
sv.if %1 {
|
|
sv.fatal 1
|
|
}
|
|
}
|
|
hw.output
|
|
}
|
|
|
|
hw.module.extern @MyExtModule(in %in: i8)
|
|
|
|
// CHECK-LABEL: hw.module @MoveInstances
|
|
// VERILOG-LABEL: module MoveInstances
|
|
hw.module @MoveInstances(in %a_in: i8) {
|
|
// CHECK: %0 = comb.add %a_in, %a_in : i8
|
|
// CHECK: hw.instance "xyz3" @MyExtModule(in: %0: i8)
|
|
// VERILOG: MyExtModule xyz3 (
|
|
// VERILOG: .in (a_in + a_in)
|
|
// VERILOG: );
|
|
hw.instance "xyz3" @MyExtModule(in: %b: i8) -> ()
|
|
|
|
%b = comb.add %a_in, %a_in : i8
|
|
}
|
|
|
|
|
|
// CHECK-LABEL: hw.module @unary_sink_crash
|
|
hw.module @unary_sink_crash(in %arg0: i1) {
|
|
%true = hw.constant true
|
|
%c = comb.xor %arg0, %true : i1
|
|
// CHECK-NOT: hw.constant
|
|
// CHECK-NOT: comb.xor
|
|
// CHECK: sv.initial
|
|
sv.initial {
|
|
// CHECK: [[TRUE1:%.+]] = hw.constant true
|
|
// CHECK: [[XOR1:%.+]] = comb.xor %arg0, [[TRUE1]]
|
|
// CHECK: sv.if [[XOR1]]
|
|
sv.if %c {
|
|
sv.fatal 1
|
|
}
|
|
|
|
// CHECK: [[TRUE2:%.+]] = hw.constant true
|
|
// CHECK: [[XOR2:%.+]] = comb.xor %arg0, [[TRUE2]]
|
|
// CHECK: sv.if [[XOR2]]
|
|
sv.if %c {
|
|
sv.fatal 1
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// CHECK-LABEL: hw.module @unary_sink_no_duplicate
|
|
// https://github.com/llvm/circt/issues/2097
|
|
hw.module @unary_sink_no_duplicate(in %arg0: i4, out result: i4) {
|
|
%ones = hw.constant 15: i4
|
|
|
|
// CHECK-NOT: comb.xor
|
|
|
|
// We normally duplicate unary operations like this one so they can be inlined
|
|
// into the using expressions. However, not all users can be inlined *into*.
|
|
// Things like extract/sext do not support this, so do not duplicate if used
|
|
// by one of them.
|
|
|
|
// CHECK: comb.xor %arg0,
|
|
%0 = comb.xor %arg0, %ones : i4
|
|
|
|
// CHECK-NOT: comb.xor
|
|
|
|
%a = comb.extract %0 from 0 : (i4) -> i1
|
|
%b = comb.extract %0 from 1 : (i4) -> i1
|
|
%c = comb.extract %0 from 2 : (i4) -> i2
|
|
|
|
|
|
// CHECK: hw.output
|
|
%r = comb.concat %a, %b, %c : i1, i1, i2
|
|
hw.output %r : i4
|
|
}
|
|
|
|
// CHECK-LABEL: hw.module private @ConnectToAllFields
|
|
hw.module private @ConnectToAllFields(in %clock: i1, in %reset: i1, in %value: i2, inout %base: !hw.struct<a: i2>) {
|
|
%r = sv.reg : !hw.inout<!hw.struct<a: i2>>
|
|
%val = sv.read_inout %r : !hw.inout<!hw.struct<a: i2>>
|
|
sv.always posedge %clock {
|
|
sv.passign %r, %1 : !hw.struct<a: i2>
|
|
}
|
|
|
|
%0 = sv.read_inout %base : !hw.inout<!hw.struct<a: i2>>
|
|
%1 = hw.struct_inject %0["a"], %value : !hw.struct<a: i2>
|
|
// CHECK: sv.always posedge %clock {
|
|
// CHECK: [[FIELD_A:%.+]] = sv.struct_field_inout %r["a"] : !hw.inout<struct<a: i2>>
|
|
// CHECK: sv.passign [[FIELD_A]], %value : i2
|
|
// CHECK: }
|
|
|
|
// VERILOG: always @(posedge clock)
|
|
// VERILOG-NEXT: r.a <= value;
|
|
}
|
|
|
|
// CHECK-LABEL: hw.module private @ConnectSubfield
|
|
hw.module private @ConnectSubfield(in %clock: i1, in %reset: i1, in %value: i2) {
|
|
%r = sv.reg : !hw.inout<!hw.struct<a: i2>>
|
|
%val = sv.read_inout %r : !hw.inout<!hw.struct<a: i2>>
|
|
sv.always posedge %clock {
|
|
sv.passign %r, %0 : !hw.struct<a: i2>
|
|
}
|
|
|
|
%0 = hw.struct_inject %val["a"], %value : !hw.struct<a: i2>
|
|
// CHECK: sv.always posedge %clock {
|
|
// CHECK: [[FIELD_A:%.+]] = sv.struct_field_inout %r["a"] : !hw.inout<struct<a: i2>>
|
|
// CHECK: sv.passign [[FIELD_A]], %value : i2
|
|
// CHECK: }
|
|
|
|
//VERILOG: always @(posedge clock)
|
|
//VERILOG-NEXT: r.a <= value;
|
|
}
|
|
|
|
// CHECK-LABEL: hw.module private @ConnectSubfields
|
|
hw.module private @ConnectSubfields(in %clock: i1, in %reset: i1, in %value2: i2, in %value3: i3) {
|
|
%r = sv.reg : !hw.inout<!hw.struct<a: i2, b: i3>>
|
|
%val = sv.read_inout %r : !hw.inout<!hw.struct<a: i2, b: i3>>
|
|
sv.always posedge %clock {
|
|
sv.passign %r, %1 : !hw.struct<a: i2, b: i3>
|
|
}
|
|
|
|
%0 = hw.struct_inject %val["a"], %value2 : !hw.struct<a: i2, b: i3>
|
|
%1 = hw.struct_inject %0["b"], %value3 : !hw.struct<a: i2, b: i3>
|
|
// CHECK: sv.always posedge %clock {
|
|
// CHECK: [[FIELD_A:%.+]] = sv.struct_field_inout %r["a"] : !hw.inout<struct<a: i2, b: i3>>
|
|
// CHECK: sv.passign [[FIELD_A]], %value2 : i2
|
|
// CHECK: [[FIELD_B:%.+]] = sv.struct_field_inout %r["b"] : !hw.inout<struct<a: i2, b: i3>>
|
|
// CHECK: sv.passign [[FIELD_B]], %value3 : i3
|
|
// CHECK: }
|
|
|
|
// VERILOG: always @(posedge clock) begin
|
|
// VERILOG-NEXT: r.a <= value2;
|
|
// VERILOG-NEXT: r.b <= value3;
|
|
// VERILOG-NEXT: end
|
|
}
|
|
|
|
// CHECK-LABEL: hw.module private @ConnectSubfieldOverwrite
|
|
hw.module private @ConnectSubfieldOverwrite(in %clock: i1, in %reset: i1, in %value2: i2, in %value3: i2) {
|
|
%r = sv.reg : !hw.inout<!hw.struct<a: i2, b: i3>>
|
|
%val = sv.read_inout %r : !hw.inout<!hw.struct<a: i2, b: i3>>
|
|
sv.always posedge %clock {
|
|
sv.passign %r, %1 : !hw.struct<a: i2, b: i3>
|
|
}
|
|
|
|
%0 = hw.struct_inject %val["a"], %value2 : !hw.struct<a: i2, b: i3>
|
|
%1 = hw.struct_inject %0["a"], %value3 : !hw.struct<a: i2, b: i3>
|
|
// CHECK: sv.always posedge %clock {
|
|
// CHECK: [[FIELD:%.+]] = sv.struct_field_inout %r["a"] : !hw.inout<struct<a: i2, b: i3>>
|
|
// CHECK: sv.passign [[FIELD]], %value3 : i2
|
|
// CHECK: }
|
|
|
|
// VERILOG: always @(posedge clock)
|
|
// VERILOG-NEXT: r.a <= value3;
|
|
}
|
|
|
|
// CHECK-LABEL: hw.module private @ConnectNestedSubfield
|
|
hw.module private @ConnectNestedSubfield(in %clock: i1, in %reset: i1, in %value: i2) {
|
|
%r = sv.reg : !hw.inout<!hw.struct<a: !hw.struct<b: i2>>>
|
|
%val = sv.read_inout %r : !hw.inout<!hw.struct<a: !hw.struct<b: i2>>>
|
|
sv.always posedge %clock {
|
|
sv.passign %r, %2 : !hw.struct<a: !hw.struct<b: i2>>
|
|
}
|
|
%0 = hw.struct_extract %val["a"] : !hw.struct<a: !hw.struct<b: i2>>
|
|
%1 = hw.struct_inject %0["b"], %value : !hw.struct<b: i2>
|
|
%2 = hw.struct_inject %val["a"], %1 : !hw.struct<a: !hw.struct<b: i2>>
|
|
|
|
// CHECK: sv.always posedge %clock {
|
|
// CHECK: [[FIELD_A:%.+]] = sv.struct_field_inout %r["a"] : !hw.inout<struct<a: !hw.struct<b: i2>>>
|
|
// CHECK: [[FIELD_B:%.+]] = sv.struct_field_inout [[FIELD_A]]["b"] : !hw.inout<struct<b: i2>>
|
|
// CHECK: sv.passign [[FIELD_B]], %value : i2
|
|
// CHECK: }
|
|
|
|
// VERILOG: always @(posedge clock)
|
|
// VERILOG-NEXT: r.a.b <= value;
|
|
}
|
|
|
|
|
|
// CHECK-LABEL: hw.module private @ConnectSubindexMid
|
|
hw.module private @ConnectSubindexMid(in %clock: i1, in %reset: i1, in %value: i2) {
|
|
%c0_i2 = hw.constant 0 : i2
|
|
%c-2_i2 = hw.constant -2 : i2
|
|
%r = sv.reg : !hw.inout<!hw.array<3xi2>>
|
|
%val = sv.read_inout %r : !hw.inout<!hw.array<3xi2>>
|
|
sv.always posedge %clock {
|
|
sv.passign %r, %3 : !hw.array<3xi2>
|
|
}
|
|
|
|
%0 = hw.array_slice %val[%c0_i2] : (!hw.array<3xi2>) -> !hw.array<1xi2>
|
|
%1 = hw.array_create %value : i2
|
|
%2 = hw.array_slice %val[%c-2_i2] : (!hw.array<3xi2>) -> !hw.array<1xi2>
|
|
%3 = hw.array_concat %2, %1, %0 : !hw.array<1xi2>, !hw.array<1xi2>, !hw.array<1xi2>
|
|
// CHECK: sv.always posedge %clock {
|
|
// CHECK: [[FIELD:%.+]] = sv.array_index_inout %r[%c1_i2] : !hw.inout<array<3xi2>>, i2
|
|
// CHECK: sv.passign [[FIELD]], %value : i2
|
|
// CHECK: }
|
|
|
|
// VERILOG: always @(posedge clock)
|
|
// VERILOG-NEXT: r[2'h1] <= value;
|
|
}
|
|
|
|
// CHECK-LABEL: hw.module private @ConnectSubindexSingleton
|
|
hw.module private @ConnectSubindexSingleton(in %clock: i1, in %reset: i1, in %value: i2) {
|
|
%none = hw.constant 0 : i0
|
|
%r = sv.reg : !hw.inout<!hw.array<1xi2>>
|
|
%val = sv.read_inout %r : !hw.inout<!hw.array<1xi2>>
|
|
sv.always posedge %clock {
|
|
sv.passign %r, %1 : !hw.array<1xi2>
|
|
}
|
|
%0 = hw.array_get %val[%none] : !hw.array<1xi2>, i0
|
|
%1 = hw.array_create %value : i2
|
|
|
|
// VERILOG: always @(posedge clock)
|
|
// VERILOG-NEXT: r[1'h0] <= value;
|
|
}
|
|
|
|
// CHECK-LABEL: hw.module private @ConnectSubindexLeft
|
|
hw.module private @ConnectSubindexLeft(in %clock: i1, in %reset: i1, in %value: i2) {
|
|
%c0_i2 = hw.constant 0 : i2
|
|
|
|
%r = sv.reg : !hw.inout<!hw.array<3xi2>>
|
|
%val = sv.read_inout %r : !hw.inout<!hw.array<3xi2>>
|
|
sv.always posedge %clock {
|
|
sv.passign %r, %2 : !hw.array<3xi2>
|
|
}
|
|
|
|
%0 = hw.array_slice %val[%c0_i2] : (!hw.array<3xi2>) -> !hw.array<2xi2>
|
|
%1 = hw.array_create %value : i2
|
|
%2 = hw.array_concat %1, %0 : !hw.array<1xi2>, !hw.array<2xi2>
|
|
// CHECK: sv.always posedge %clock {
|
|
// CHECK: [[FIELD_1:%.+]] = sv.array_index_inout %r[%c-2_i2] : !hw.inout<array<3xi2>>, i2
|
|
// CHECK: sv.passign [[FIELD_1]], %value : i2
|
|
// CHECK: }
|
|
|
|
// VERILOG: always @(posedge clock)
|
|
// VERILOG-NEXT: r[2'h2] <= value;
|
|
}
|
|
|
|
// CHECK-LABEL: hw.module private @ConnectSubindexRight
|
|
hw.module private @ConnectSubindexRight(in %clock: i1, in %reset: i1, in %value: i2) {
|
|
%c1_i2 = hw.constant 1 : i2
|
|
%r = sv.reg : !hw.inout<!hw.array<3xi2>>
|
|
%val = sv.read_inout %r : !hw.inout<!hw.array<3xi2>>
|
|
sv.always posedge %clock {
|
|
sv.passign %r, %2 : !hw.array<3xi2>
|
|
}
|
|
|
|
%0 = hw.array_create %value : i2
|
|
%1 = hw.array_slice %val[%c1_i2] : (!hw.array<3xi2>) -> !hw.array<2xi2>
|
|
%2 = hw.array_concat %1, %0 : !hw.array<2xi2>, !hw.array<1xi2>
|
|
// CHECK: sv.always posedge %clock {
|
|
// CHECK: [[FIELD_0:%.+]] = sv.array_index_inout %r[%c0_i2] : !hw.inout<array<3xi2>>, i2
|
|
// CHECK: sv.passign [[FIELD_0]], %value : i2
|
|
// CHECK: }
|
|
|
|
// VERILOG: always @(posedge clock)
|
|
// VERILOG-NEXT: r[2'h0] <= value;
|
|
}
|
|
|
|
// CHECK-LABEL: hw.module private @ConnectSubindices
|
|
hw.module private @ConnectSubindices(in %clock: i1, in %reset: i1, in %value: i2) {
|
|
%c0_i3 = hw.constant 0 : i3
|
|
%c2_i3 = hw.constant 2 : i3
|
|
%c3_i3 = hw.constant 3 : i3
|
|
|
|
%r = sv.reg : !hw.inout<!hw.array<5xi2>>
|
|
%val = sv.read_inout %r : !hw.inout<!hw.array<5xi2>>
|
|
sv.always posedge %clock {
|
|
sv.passign %r, %8 : !hw.array<5xi2>
|
|
}
|
|
|
|
%0 = hw.array_slice %val[%c0_i3] : (!hw.array<5xi2>) -> !hw.array<1xi2>
|
|
%1 = hw.array_create %value : i2
|
|
%2 = hw.array_slice %val[%c2_i3] : (!hw.array<5xi2>) -> !hw.array<3xi2>
|
|
%3 = hw.array_concat %2, %1, %0 : !hw.array<3xi2>, !hw.array<1xi2>, !hw.array<1xi2>
|
|
%4 = hw.array_slice %3[%c0_i3] : (!hw.array<5xi2>) -> !hw.array<2xi2>
|
|
%5 = hw.array_slice %3[%c3_i3] : (!hw.array<5xi2>) -> !hw.array<2xi2>
|
|
%6 = hw.array_concat %5, %1, %4 : !hw.array<2xi2>, !hw.array<1xi2>, !hw.array<2xi2>
|
|
%7 = hw.array_slice %6[%c0_i3] : (!hw.array<5xi2>) -> !hw.array<4xi2>
|
|
%8 = hw.array_concat %1, %7 : !hw.array<1xi2>, !hw.array<4xi2>
|
|
// CHECK: sv.always posedge %clock {
|
|
// CHECK: [[IDX_1:%.+]] = sv.array_index_inout %r[%c1_i3] : !hw.inout<array<5xi2>>, i3
|
|
// CHECK: sv.passign [[IDX_1]], %value : i2
|
|
// CHECK: [[IDX_2:%.+]] = sv.array_index_inout %r[%c2_i3] : !hw.inout<array<5xi2>>, i3
|
|
// CHECK: sv.passign [[IDX_2:%.+]], %value : i2
|
|
// CHECK: [[IDX_4:%.+]] = sv.array_index_inout %r[%c-4_i3] : !hw.inout<array<5xi2>>, i3
|
|
// CHECK: sv.passign [[IDX_4]], %value : i2
|
|
// CHECK: }
|
|
|
|
// VERILOG: always @(posedge clock) begin
|
|
// VERILOG-NEXT: r[3'h1] <= value;
|
|
// VERILOG-NEXT: r[3'h2] <= value;
|
|
// VERILOG-NEXT: r[3'h4] <= value;
|
|
// VERILOG-NEXT: end
|
|
}
|
|
|
|
// CHECK-LABEL: hw.module private @ConnectSubindicesOverwrite
|
|
hw.module private @ConnectSubindicesOverwrite(in %clock: i1, in %reset: i1, in %value: i2, in %value2: i2) {
|
|
%c0_i3 = hw.constant 0 : i3
|
|
%c2_i3 = hw.constant 2 : i3
|
|
%r = sv.reg : !hw.inout<!hw.array<5xi2>>
|
|
%val = sv.read_inout %r : !hw.inout<!hw.array<5xi2>>
|
|
sv.always posedge %clock {
|
|
sv.passign %r, %10 : !hw.array<5xi2>
|
|
}
|
|
|
|
%0 = hw.array_slice %val[%c0_i3] : (!hw.array<5xi2>) -> !hw.array<1xi2>
|
|
%1 = hw.array_create %value : i2
|
|
%2 = hw.array_slice %val[%c2_i3] : (!hw.array<5xi2>) -> !hw.array<3xi2>
|
|
%3 = hw.array_concat %2, %1, %0 : !hw.array<3xi2>, !hw.array<1xi2>, !hw.array<1xi2>
|
|
%4 = hw.array_slice %3[%c0_i3] : (!hw.array<5xi2>) -> !hw.array<1xi2>
|
|
%5 = hw.array_slice %3[%c2_i3] : (!hw.array<5xi2>) -> !hw.array<3xi2>
|
|
%6 = hw.array_concat %5, %1, %4: !hw.array<3xi2>, !hw.array<1xi2>, !hw.array<1xi2>
|
|
%7 = hw.array_slice %6[%c0_i3] : (!hw.array<5xi2>) -> !hw.array<1xi2>
|
|
%8 = hw.array_create %value2 : i2
|
|
%9 = hw.array_slice %6[%c2_i3] : (!hw.array<5xi2>) -> !hw.array<3xi2>
|
|
%10 = hw.array_concat %9, %8, %7 : !hw.array<3xi2>, !hw.array<1xi2>, !hw.array<1xi2>
|
|
// CHECK: sv.always posedge %clock {
|
|
// CHECK: [[IDX:%.+]] = sv.array_index_inout %r[%c1_i3] : !hw.inout<array<5xi2>>, i3
|
|
// CHECK: sv.passign [[IDX]], %value2 : i2
|
|
// CHECK: }
|
|
|
|
|
|
// VERILOG: always @(posedge clock)
|
|
// VERILOG-NEXT: r[3'h1] <= value2;
|
|
}
|
|
|
|
// CHECK-LABEL: hw.module private @ConnectNestedSubindex
|
|
hw.module private @ConnectNestedSubindex(in %clock: i1, in %reset: i1, in %value: i2) {
|
|
%c1_i2 = hw.constant 1 : i2
|
|
%c0_i2 = hw.constant 0 : i2
|
|
%c-2_i2 = hw.constant -2 : i2
|
|
|
|
%r = sv.reg : !hw.inout<!hw.array<3xarray<3xi2>>>
|
|
%val = sv.read_inout %r : !hw.inout<!hw.array<3xarray<3xi2>>>
|
|
sv.always posedge %clock {
|
|
sv.passign %r, %8 : !hw.array<3xarray<3xi2>>
|
|
}
|
|
%0 = hw.array_get %val[%c1_i2] : !hw.array<3xarray<3xi2>>, i2
|
|
%1 = hw.array_slice %val[%c0_i2] : (!hw.array<3xarray<3xi2>>) -> !hw.array<1xarray<3xi2>>
|
|
%2 = hw.array_slice %0[%c0_i2] : (!hw.array<3xi2>) -> !hw.array<1xi2>
|
|
%3 = hw.array_create %value : i2
|
|
%4 = hw.array_slice %0[%c-2_i2] : (!hw.array<3xi2>) -> !hw.array<1xi2>
|
|
%5 = hw.array_concat %4, %3, %2 : !hw.array<1xi2>, !hw.array<1xi2>, !hw.array<1xi2>
|
|
%6 = hw.array_create %5 : !hw.array<3xi2>
|
|
%7 = hw.array_slice %val[%c-2_i2] : (!hw.array<3xarray<3xi2>>) -> !hw.array<1xarray<3xi2>>
|
|
%8 = hw.array_concat %7, %6, %1 : !hw.array<1xarray<3xi2>>, !hw.array<1xarray<3xi2>>, !hw.array<1xarray<3xi2>>
|
|
// CHECK: sv.always posedge %clock {
|
|
// CHECK: [[FIELD_INNER:%.+]] = sv.array_index_inout %r[%c1_i2] : !hw.inout<array<3xarray<3xi2>>>, i2
|
|
// CHECK: [[FIELD_OUTER:%.+]] = sv.array_index_inout [[FIELD_INNER]][%c1_i2_0] : !hw.inout<array<3xi2>>, i2
|
|
// CHECK: sv.passign [[FIELD_OUTER:%.+]], %value : i2
|
|
// CHECK: }
|
|
|
|
// VERILOG: always @(posedge clock)
|
|
// VERILOG-NEXT: r[2'h1][2'h1] <= value;
|
|
}
|
|
|
|
// CHECK-LABEL: hw.module private @ConnectNestedFieldsAndIndices
|
|
hw.module private @ConnectNestedFieldsAndIndices(in %clock: i1, in %reset: i1, in %value: i2) {
|
|
%c2_i3 = hw.constant 2 : i3
|
|
%c0_i3 = hw.constant 0 : i3
|
|
%c-2_i2 = hw.constant -2 : i2
|
|
%c0_i2 = hw.constant 0 : i2
|
|
%c1_i2 = hw.constant 1 : i2
|
|
%c1_i3 = hw.constant 1 : i3
|
|
|
|
%r = sv.reg : !hw.inout<!hw.array<5xstruct<a: !hw.array<3xstruct<b: i2>>>>>
|
|
%val = sv.read_inout %r : !hw.inout<!hw.array<5xstruct<a: !hw.array<3xstruct<b: i2>>>>>
|
|
sv.always posedge %clock {
|
|
sv.passign %r, %17 : !hw.array<5xstruct<a: !hw.array<3xstruct<b: i2>>>>
|
|
}
|
|
|
|
%c1_i3_0 = hw.constant 1 : i3
|
|
%5 = hw.array_get %val[%c1_i3_0] : !hw.array<5xstruct<a: !hw.array<3xstruct<b: i2>>>>, i3
|
|
%6 = hw.struct_extract %5["a"] : !hw.struct<a: !hw.array<3xstruct<b: i2>>>
|
|
%c1_i2_1 = hw.constant 1 : i2
|
|
%7 = hw.array_get %6[%c1_i2_1] : !hw.array<3xstruct<b: i2>>, i2
|
|
%8 = hw.struct_inject %7["b"], %value : !hw.struct<b: i2>
|
|
%9 = hw.array_slice %6[%c0_i2] : (!hw.array<3xstruct<b: i2>>) -> !hw.array<1xstruct<b: i2>>
|
|
%10 = hw.array_create %8 : !hw.struct<b: i2>
|
|
%11 = hw.array_slice %6[%c-2_i2] : (!hw.array<3xstruct<b: i2>>) -> !hw.array<1xstruct<b: i2>>
|
|
%12 = hw.array_concat %11, %10, %9 : !hw.array<1xstruct<b: i2>>, !hw.array<1xstruct<b: i2>>, !hw.array<1xstruct<b: i2>>
|
|
%13 = hw.struct_inject %5["a"], %12 : !hw.struct<a: !hw.array<3xstruct<b: i2>>>
|
|
%14 = hw.array_slice %val[%c0_i3] : (!hw.array<5xstruct<a: !hw.array<3xstruct<b: i2>>>>) -> !hw.array<1xstruct<a: !hw.array<3xstruct<b: i2>>>>
|
|
%15 = hw.array_create %13 : !hw.struct<a: !hw.array<3xstruct<b: i2>>>
|
|
%16 = hw.array_slice %val[%c2_i3] : (!hw.array<5xstruct<a: !hw.array<3xstruct<b: i2>>>>) -> !hw.array<3xstruct<a: !hw.array<3xstruct<b: i2>>>>
|
|
%17 = hw.array_concat %16, %15, %14 : !hw.array<3xstruct<a: !hw.array<3xstruct<b: i2>>>>, !hw.array<1xstruct<a: !hw.array<3xstruct<b: i2>>>>, !hw.array<1xstruct<a: !hw.array<3xstruct<b: i2>>>>
|
|
|
|
// CHECK: sv.always posedge %clock {
|
|
// CHECK: [[ARR_1:%.+]] = sv.array_index_inout %r[%c1_i3] : !hw.inout<array<5xstruct<a: !hw.array<3xstruct<b: i2>>>>>, i3
|
|
// CHECK: [[STRUCT_A:%.+]] = sv.struct_field_inout [[ARR_1]]["a"] : !hw.inout<struct<a: !hw.array<3xstruct<b: i2>>>>
|
|
// CHECK: [[ARR_1:%.+]] = sv.array_index_inout [[STRUCT_A]][%c1_i2] : !hw.inout<array<3xstruct<b: i2>>>, i2
|
|
// CHECK: [[STRUCT_B:%.+]] = sv.struct_field_inout [[ARR_1]]["b"] : !hw.inout<struct<b: i2>>
|
|
// CHECK: sv.passign [[STRUCT_B]], %value : i2
|
|
// CHECK: }
|
|
|
|
// VERILOG: always @(posedge clock)
|
|
// VERILOG-NEXT: r[3'h1].a[2'h1].b <= value;
|
|
}
|
|
|
|
|
|
// CHECK-LABEL: hw.module private @SelfConnect
|
|
hw.module private @SelfConnect(in %clock: i1, in %reset: i1) {
|
|
%r = sv.reg : !hw.inout<i2>
|
|
%val = sv.read_inout %r : !hw.inout<i2>
|
|
sv.always posedge %clock {
|
|
sv.passign %r, %val : i2
|
|
}
|
|
|
|
// CHECK: %r = sv.reg : !hw.inout<i2>
|
|
// CHECK: sv.always posedge %clock {
|
|
// CHECK: [[READ:%.+]] = sv.read_inout %r : !hw.inout<i2>
|
|
// CHECK: sv.passign %r, [[READ]] : i2
|
|
// CHECK: }
|
|
|
|
//VERILOG: reg [1:0] r;
|
|
//VERILOG: always @(posedge clock)
|
|
//VERILOG: r <= r;
|
|
}
|
|
|
|
// CHECK-LABEL: Issue4030
|
|
hw.module @Issue4030(in %a: i1, in %clock: i1, in %in1: !hw.array<2xi1>, out b: !hw.array<5xi1>) {
|
|
%c0_i3 = hw.constant 0 : i3
|
|
%false = hw.constant false
|
|
%0 = hw.array_get %in1[%false] : !hw.array<2xi1>, i1
|
|
%r = sv.reg : !hw.inout<array<5xi1>>
|
|
%1 = sv.array_index_inout %r[%c0_i3] : !hw.inout<array<5xi1>>, i3
|
|
%2 = sv.read_inout %r : !hw.inout<array<5xi1>>
|
|
sv.always posedge %clock {
|
|
sv.passign %1, %0 : i1
|
|
}
|
|
hw.output %2 : !hw.array<5xi1>
|
|
}
|