mirror of https://github.com/llvm/circt.git
263 lines
8.1 KiB
MLIR
263 lines
8.1 KiB
MLIR
// RUN: circt-opt --export-verilog %s | FileCheck %s
|
|
// RUN: circt-opt --test-apply-lowering-options='options=disallowLocalVariables' --export-verilog %s | FileCheck %s --check-prefix=DISALLOW -strict-whitespace
|
|
|
|
// This checks ExportVerilog's support for "disallowLocalVariables" which
|
|
// prevents emitting 'automatic logic' and other local declarations.
|
|
|
|
sv.macro.decl @FOO_MACRO
|
|
|
|
// CHECK-LABEL: module side_effect_expr
|
|
// DISALLOW-LABEL: module side_effect_expr
|
|
hw.module @side_effect_expr(in %clock: i1, out a: i1, out a2: i1) {
|
|
|
|
// CHECK: `ifdef FOO_MACRO
|
|
// DISALLOW: `ifdef FOO_MACRO
|
|
sv.ifdef @FOO_MACRO {
|
|
// DISALLOW: logic logicOp;
|
|
// DISALLOW: {{^ }}reg [[SE_REG:[_A-Za-z0-9]+]];
|
|
|
|
// CHECK: always @(posedge clock)
|
|
// DISALLOW: always @(posedge clock)
|
|
sv.always posedge %clock {
|
|
%0 = sv.verbatim.expr "INLINE_OK" : () -> i1
|
|
// CHECK: automatic logic logicOp;
|
|
%logicOp = sv.logic : !hw.inout<i1>
|
|
|
|
// This shouldn't be pushed into a reg.
|
|
// CHECK: if (INLINE_OK)
|
|
// DISALLOW: if (INLINE_OK)
|
|
sv.if %0 {
|
|
sv.fatal 1
|
|
}
|
|
|
|
// This should go through a reg when in "disallow" mode.
|
|
// CHECK: if (SIDE_EFFECT)
|
|
// DISALLOW: [[SE_REG]] = SIDE_EFFECT;
|
|
// DISALLOW: if ([[SE_REG]])
|
|
%1 = sv.verbatim.expr.se "SIDE_EFFECT" : () -> i1
|
|
sv.if %1 {
|
|
sv.fatal 1
|
|
}
|
|
}
|
|
}
|
|
// CHECK: `endif
|
|
// DISALLOW: `endif
|
|
|
|
// Top level things should go unmodified.
|
|
%2 = sv.verbatim.expr "NO_SE" : () -> i1
|
|
%3 = sv.verbatim.expr.se "YES_SE" : () -> i1
|
|
|
|
// CHECK: assign a = NO_SE;
|
|
// CHECK: assign a2 = YES_SE;
|
|
// DISALLOW: assign a = NO_SE;
|
|
// DISALLOW: assign a2 = YES_SE;
|
|
hw.output %2, %3: i1, i1
|
|
}
|
|
|
|
// CHECK-LABEL: module hoist_expressions
|
|
// DISALLOW-LABEL: module hoist_expressions
|
|
hw.module @hoist_expressions(in %clock: i1, in %x: i8, in %y: i8, in %z: i8) {
|
|
// DISALLOW: wire [7:0] [[ADD:[_A-Za-z0-9]+]] = x + y;
|
|
|
|
%fd = hw.constant 0x80000002 : i32
|
|
|
|
// CHECK: always @(posedge clock)
|
|
// DISALLOW: always @(posedge clock)
|
|
sv.always posedge %clock {
|
|
%0 = comb.add %x, %y: i8
|
|
%1 = comb.icmp eq %0, %z : i8
|
|
|
|
// This shouldn't be touched.
|
|
// CHECK: if (_GEN == z) begin
|
|
// DISALLOW: if (_GEN == z) begin
|
|
sv.if %1 {
|
|
// CHECK: $fwrite(32'h80000002, "Hi %x\n", _GEN * z);
|
|
// DISALLOW: $fwrite(32'h80000002, "Hi %x\n", _GEN * z);
|
|
%2 = comb.mul %0, %z : i8
|
|
sv.fwrite %fd, "Hi %x\0A"(%2) : i8
|
|
sv.fatal 1
|
|
}
|
|
}
|
|
|
|
// Check out wires.
|
|
// CHECK: wire [7:0] myWire = x;
|
|
// DISALLOW: wire [7:0] myWire = x;
|
|
%myWire = sv.wire : !hw.inout<i8>
|
|
sv.assign %myWire, %x : i8
|
|
|
|
// CHECK: always @(posedge clock)
|
|
// DISALLOW: always @(posedge clock)
|
|
sv.always posedge %clock {
|
|
%wireout = sv.read_inout %myWire : !hw.inout<i8>
|
|
%3 = comb.add %x, %wireout: i8
|
|
%4 = comb.icmp eq %3, %z : i8
|
|
// CHECK: if (x + myWire == z)
|
|
// DISALLOW: if (x + myWire == z)
|
|
sv.if %4 {
|
|
sv.fatal 1
|
|
}
|
|
}
|
|
|
|
hw.output
|
|
}
|
|
|
|
// CHECK-LABEL: module always_inline_expr
|
|
// DISALLOW-LABEL: module always_inline_expr
|
|
// https://github.com/llvm/circt/issues/1705
|
|
hw.module @always_inline_expr(in %ro_clock_0: i1, in %ro_en_0: i1, in %ro_addr_0: i1, in %wo_clock_0: i1, in %wo_en_0: i1, in %wo_addr_0: i1, in %wo_mask_0: i1, in %wo_data_0: i5, out ro_data_0: i5) {
|
|
%Memory = sv.reg : !hw.inout<uarray<2xi5>>
|
|
%0 = sv.array_index_inout %Memory[%ro_addr_0] : !hw.inout<uarray<2xi5>>, i1
|
|
%1 = sv.read_inout %0 : !hw.inout<i5>
|
|
%x_i5 = sv.constantX : i5
|
|
%2 = comb.mux %ro_en_0, %1, %x_i5 : i5
|
|
sv.alwaysff(posedge %wo_clock_0) {
|
|
%3 = comb.and %wo_en_0, %wo_mask_0 : i1
|
|
// CHECK: if (wo_en_0 & wo_mask_0)
|
|
// DISALLOW: if (wo_en_0 & wo_mask_0)
|
|
sv.if %3 {
|
|
// CHECK: Memory[wo_addr_0] <= wo_data_0;
|
|
// DISALLOW: Memory[wo_addr_0] <= wo_data_0;
|
|
%4 = sv.array_index_inout %Memory[%wo_addr_0] : !hw.inout<uarray<2xi5>>, i1
|
|
sv.passign %4, %wo_data_0 : i5
|
|
}
|
|
}
|
|
hw.output %2 : i5
|
|
}
|
|
|
|
// CHECK-LABEL: module EmittedDespiteDisallowed
|
|
// DISALLOW-LABEL: module EmittedDespiteDisallowed
|
|
// https://github.com/llvm/circt/issues/2216
|
|
hw.module @EmittedDespiteDisallowed(in %clock: i1, in %reset: i1) {
|
|
%tick_value_2 = sv.reg : !hw.inout<i1>
|
|
%counter_value = sv.reg : !hw.inout<i1>
|
|
|
|
// Temporary reg gets introduced.
|
|
// DISALLOW: reg [1:0] [[TEMP:.+]];
|
|
|
|
// DISALLOW: initial begin
|
|
sv.initial {
|
|
// CHECK: automatic logic [1:0] _magic = magic;
|
|
// DISALLOW: _GEN = magic;
|
|
%RANDOM = sv.verbatim.expr.se "magic" : () -> i2 {symbols = []}
|
|
|
|
// CHECK: tick_value_2 = _magic[0];
|
|
// DISALLOW-NEXT: tick_value_2 = [[TEMP]][0];
|
|
%1 = comb.extract %RANDOM from 0 : (i2) -> i1
|
|
sv.bpassign %tick_value_2, %1 : i1
|
|
|
|
// CHECK: counter_value = _magic[1];
|
|
// DISALLOW-NEXT: counter_value = [[TEMP]][1];
|
|
%2 = comb.extract %RANDOM from 1 : (i2) -> i1
|
|
sv.bpassign %counter_value, %2 : i1
|
|
}
|
|
hw.output
|
|
}
|
|
|
|
// CHECK-LABEL: module ReadInoutAggregate(
|
|
hw.module @ReadInoutAggregate(in %clock: i1) {
|
|
%register = sv.reg : !hw.inout<array<1xstruct<a: i32>>>
|
|
sv.always posedge %clock {
|
|
%c0_i16 = hw.constant 0 : i16
|
|
%false = hw.constant false
|
|
%0 = sv.array_index_inout %register[%false] : !hw.inout<array<1xstruct<a: i32>>>, i1
|
|
%1 = sv.struct_field_inout %0["a"] : !hw.inout<struct<a: i32>>
|
|
%2 = sv.read_inout %1 : !hw.inout<i32>
|
|
%3 = comb.extract %2 from 0 : (i32) -> i16
|
|
%4 = comb.concat %c0_i16, %3 : i16, i16
|
|
sv.passign %1, %4 : i32
|
|
}
|
|
// DISALLOW: always @(
|
|
// DISALLOW-NEXT: register[1'h0].a <= {16'h0, register[1'h0].a[15:0]};
|
|
hw.output
|
|
}
|
|
|
|
sv.macro.decl @DEF
|
|
|
|
// CHECK-LABEL: DefinedInDifferentBlock
|
|
// CHECK: `ifdef DEF
|
|
// CHECK-NEXT: initial begin
|
|
// CHECK-NEXT: if (a == b)
|
|
// CHECK-NEXT: $error("error")
|
|
// DISALLOW: `ifdef DEF
|
|
// DISALLOW-NEXT: initial begin
|
|
// DISALLOW-NEXT: if (a == b)
|
|
// DISALLOW-NEXT: $error("error")
|
|
|
|
hw.module @DefinedInDifferentBlock(in %a: i1, in %b: i1) {
|
|
sv.ifdef @DEF {
|
|
%0 = comb.icmp eq %a, %b : i1
|
|
sv.initial {
|
|
sv.if %0 {
|
|
sv.error "error"
|
|
}
|
|
}
|
|
}
|
|
hw.output
|
|
}
|
|
|
|
// CHECK-LABEL: module TemporaryWireAtDifferentBlock(
|
|
// DISALLOW-LABEL: module TemporaryWireAtDifferentBlock(
|
|
hw.module @TemporaryWireAtDifferentBlock(in %a: i1, out b: i1) {
|
|
// Check that %0 and %1 are not inlined.
|
|
// CHECK: wire [[GEN1:.+]];
|
|
// CHECK: wire [[GEN2:.+]] = [[GEN1]] + [[GEN1]];
|
|
// CHECK: if ([[GEN1]])
|
|
// DISALLOW: wire [[GEN1:.+]];
|
|
// DISALLOW: wire [[GEN2:.+]] = [[GEN1]] + [[GEN1]];
|
|
// DISALLOW: if ([[GEN1]])
|
|
%1 = comb.add %0, %0 : i1
|
|
sv.initial {
|
|
sv.if %0 {
|
|
sv.error "error"
|
|
}
|
|
}
|
|
%0 = comb.shl %a, %a : i1
|
|
%2 = comb.add %1, %1 : i1
|
|
hw.output %2 : i1
|
|
}
|
|
|
|
// CHECK-LABEL: module AggregateInline(
|
|
// DISALLOW-LABEL: module AggregateInline(
|
|
hw.module @AggregateInline(in %clock: i1) {
|
|
%c0_i16 = hw.constant 0 : i16
|
|
%false = hw.constant false
|
|
// CHECK: wire [15:0]{{ *}}[[GEN:.+]];
|
|
// DISALLOW: wire [15:0]{{ *}}[[GEN:.+]];
|
|
|
|
%register = sv.reg : !hw.inout<struct<a: i32>>
|
|
sv.always posedge %clock {
|
|
// %4 can not be inlined because %3 uses %2.
|
|
%4 = comb.concat %c0_i16, %3 : i16, i16
|
|
// DISALLOW: register.a <= {16'h0, [[GEN]]};
|
|
// CHECK: register.a <= {16'h0, [[GEN]]};
|
|
sv.passign %1, %4 : i32
|
|
}
|
|
%1 = sv.struct_field_inout %register["a"] : !hw.inout<struct<a: i32>>
|
|
%2 = sv.read_inout %1 : !hw.inout<i32>
|
|
%3 = comb.extract %2 from 0 : (i32) -> i16
|
|
// DISALLOW: assign [[GEN]] = register.a[15:0]
|
|
// CHECK: assign [[GEN]] = register.a[15:0]
|
|
hw.output
|
|
}
|
|
|
|
// CHECK-LABEL: module hoist_reg
|
|
// DISALLOW-LABEL: module hoist_reg
|
|
hw.module @hoist_reg(in %dummy : i32, out out : i17) {
|
|
%res_reg = sv.reg : !hw.inout<i17>
|
|
// CHECK: initial
|
|
// CHECK: reg [31:0] tmp;
|
|
// CHECK end // initial
|
|
// DISALLOW: reg [31:0] tmp;
|
|
// DISALLOW: initial
|
|
sv.initial {
|
|
%tmp = sv.reg : !hw.inout<i32>
|
|
%17 = sv.read_inout %tmp : !hw.inout<i32>
|
|
%29 = comb.xor %dummy, %17 : i32
|
|
%32 = comb.extract %29 from 3 : (i32) -> i17
|
|
sv.passign %res_reg, %32 : i17
|
|
}
|
|
|
|
%res_reg_data = sv.read_inout %res_reg : !hw.inout<i17>
|
|
hw.output %res_reg_data : i17
|
|
}
|