mirror of https://github.com/llvm/circt.git
426 lines
14 KiB
MLIR
426 lines
14 KiB
MLIR
// RUN: circt-opt %s | FileCheck %s
|
|
// RUN: circt-opt %s | circt-opt | FileCheck %s
|
|
|
|
sv.macro.decl @RANDOM
|
|
sv.macro.decl @PRINTF_COND_
|
|
sv.macro.decl @SYNTHESIS
|
|
|
|
// CHECK-LABEL: hw.module @test1(in %arg0 : i1, in %arg1 : i1, in %arg8 : i8) {
|
|
hw.module @test1(in %arg0: i1, in %arg1: i1, in %arg8: i8) {
|
|
// CHECK: [[FD:%.*]] = hw.constant -2147483646 : i32
|
|
%fd = hw.constant 0x80000002 : i32
|
|
|
|
// CHECK: %param_x = sv.localparam {value = 11 : i42} : i42
|
|
%param_x = sv.localparam {value = 11 : i42} : i42
|
|
|
|
|
|
// This corresponds to this block of system verilog code:
|
|
// always @(posedge arg0) begin
|
|
// `ifndef SYNTHESIS
|
|
// if (`PRINTF_COND_ && arg1) $fwrite(32'h80000002, "Hi\n");
|
|
// `endif
|
|
// end // always @(posedge)
|
|
|
|
sv.always posedge %arg0 {
|
|
sv.ifdef.procedural @SYNTHESIS {
|
|
} else {
|
|
%tmp = sv.macro.ref.expr @PRINTF_COND_() : () -> i1
|
|
%tmpx = sv.constantX : i1
|
|
%tmpz = sv.constantZ : i1
|
|
%tmp2 = comb.and %tmp, %tmpx, %tmpz, %arg1 : i1
|
|
sv.if %tmp2 {
|
|
sv.fwrite %fd, "Hi\n"
|
|
}
|
|
sv.if %tmp2 {
|
|
// Test fwrite with operands.
|
|
sv.fwrite %fd, "%x"(%tmp2) : i1
|
|
} else {
|
|
sv.fwrite %fd, "There\n"
|
|
}
|
|
}
|
|
}
|
|
|
|
// CHECK-NEXT: sv.always posedge %arg0 {
|
|
// CHECK-NEXT: sv.ifdef.procedural @SYNTHESIS {
|
|
// CHECK-NEXT: } else {
|
|
// CHECK-NEXT: %PRINTF_COND_ = sv.macro.ref.expr @PRINTF_COND
|
|
// CHECK-NEXT: %x_i1 = sv.constantX : i1
|
|
// CHECK-NEXT: %z_i1 = sv.constantZ : i1
|
|
// CHECK-NEXT: [[COND:%.*]] = comb.and %PRINTF_COND_, %x_i1, %z_i1, %arg1 : i1
|
|
// CHECK-NEXT: sv.if [[COND]] {
|
|
// CHECK-NEXT: sv.fwrite [[FD]], "Hi\0A"
|
|
// CHECK-NEXT: }
|
|
// CHECK-NEXT: sv.if [[COND]] {
|
|
// CHECK-NEXT: sv.fwrite [[FD]], "%x"([[COND]]) : i1
|
|
// CHECK-NEXT: } else {
|
|
// CHECK-NEXT: sv.fwrite [[FD]], "There\0A"
|
|
// CHECK-NEXT: }
|
|
// CHECK-NEXT: }
|
|
// CHECK-NEXT: }
|
|
|
|
sv.alwaysff(posedge %arg0) {
|
|
sv.fwrite %fd, "Yo\n"
|
|
}
|
|
|
|
// CHECK-NEXT: sv.alwaysff(posedge %arg0) {
|
|
// CHECK-NEXT: sv.fwrite [[FD]], "Yo\0A"
|
|
// CHECK-NEXT: }
|
|
|
|
sv.alwaysff(posedge %arg0) {
|
|
sv.fwrite %fd, "Sync Main Block\n"
|
|
} ( syncreset : posedge %arg1) {
|
|
sv.fwrite %fd, "Sync Reset Block\n"
|
|
}
|
|
|
|
// CHECK-NEXT: sv.alwaysff(posedge %arg0) {
|
|
// CHECK-NEXT: sv.fwrite [[FD]], "Sync Main Block\0A"
|
|
// CHECK-NEXT: }(syncreset : posedge %arg1) {
|
|
// CHECK-NEXT: sv.fwrite [[FD]], "Sync Reset Block\0A"
|
|
// CHECK-NEXT: }
|
|
|
|
sv.alwaysff (posedge %arg0) {
|
|
sv.fwrite %fd, "Async Main Block\n"
|
|
} ( asyncreset : negedge %arg1) {
|
|
sv.fwrite %fd, "Async Reset Block\n"
|
|
}
|
|
|
|
// CHECK-NEXT: sv.alwaysff(posedge %arg0) {
|
|
// CHECK-NEXT: sv.fwrite [[FD]], "Async Main Block\0A"
|
|
// CHECK-NEXT: }(asyncreset : negedge %arg1) {
|
|
// CHECK-NEXT: sv.fwrite [[FD]], "Async Reset Block\0A"
|
|
// CHECK-NEXT: }
|
|
|
|
// Smoke test generic syntax.
|
|
sv.initial {
|
|
"sv.if"(%arg0) ( {
|
|
^bb0:
|
|
}, {
|
|
}) : (i1) -> ()
|
|
}
|
|
|
|
// CHECK-NEXT: sv.initial {
|
|
// CHECK-NEXT: sv.if %arg0 {
|
|
// CHECK-NEXT: }
|
|
// CHECK-NEXT: }
|
|
|
|
// CHECK-NEXT: sv.initial {
|
|
// CHECK-NEXT: sv.case casez %arg8 : i8
|
|
// CHECK-NEXT: case b0000001x: {
|
|
// CHECK-NEXT: sv.fwrite [[FD]], "x"
|
|
// CHECK-NEXT: }
|
|
// CHECK-NEXT: case b000000x1: {
|
|
// CHECK-NEXT: sv.fwrite [[FD]], "y"
|
|
// CHECK-NEXT: }
|
|
// CHECK-NEXT: default: {
|
|
// CHECK-NEXT: sv.fwrite [[FD]], "z"
|
|
// CHECK-NEXT: }
|
|
// CHECK-NEXT: }
|
|
sv.initial {
|
|
sv.case casez %arg8 : i8
|
|
case b0000001x: {
|
|
sv.fwrite %fd, "x"
|
|
}
|
|
case b000000x1: {
|
|
sv.fwrite %fd, "y"
|
|
}
|
|
default: {
|
|
sv.fwrite %fd, "z"
|
|
}
|
|
}
|
|
|
|
// CHECK-NEXT: sv.initial {
|
|
// CHECK-NEXT: sv.case %arg1 : i1
|
|
// CHECK-NEXT: case b0: {
|
|
// CHECK-NEXT: sv.fwrite [[FD]], "zero"
|
|
// CHECK-NEXT: }
|
|
// CHECK-NEXT: case b1: {
|
|
// CHECK-NEXT: sv.fwrite [[FD]], "one"
|
|
// CHECK-NEXT: }
|
|
// CHECK-NEXT: sv.case %arg1 : i1
|
|
// CHECK-NEXT: case b0: {
|
|
// CHECK-NEXT: sv.fwrite [[FD]], "zero"
|
|
// CHECK-NEXT: }
|
|
// CHECK-NEXT: case b1: {
|
|
// CHECK-NEXT: sv.fwrite [[FD]], "one"
|
|
// CHECK-NEXT: }
|
|
// CHECK-NEXT: sv.case casex %arg1 : i1
|
|
// CHECK-NEXT: case b0: {
|
|
// CHECK-NEXT: sv.fwrite [[FD]], "zero"
|
|
// CHECK-NEXT: }
|
|
// CHECK-NEXT: case b1: {
|
|
// CHECK-NEXT: sv.fwrite [[FD]], "one"
|
|
// CHECK-NEXT: }
|
|
// CHECK-NEXT: sv.case casez %arg1 : i1
|
|
// CHECK-NEXT: case b0: {
|
|
// CHECK-NEXT: sv.fwrite [[FD]], "zero"
|
|
// CHECK-NEXT: }
|
|
// CHECK-NEXT: case b1: {
|
|
// CHECK-NEXT: sv.fwrite [[FD]], "one"
|
|
// CHECK-NEXT: }
|
|
// CHECK-NEXT: }
|
|
sv.initial {
|
|
sv.case %arg1 : i1
|
|
case b0: {
|
|
sv.fwrite %fd, "zero"
|
|
}
|
|
case b1: {
|
|
sv.fwrite %fd, "one"
|
|
}
|
|
sv.case case %arg1 : i1
|
|
case b0: {
|
|
sv.fwrite %fd, "zero"
|
|
}
|
|
case b1: {
|
|
sv.fwrite %fd, "one"
|
|
}
|
|
sv.case casex %arg1 : i1
|
|
case b0: {
|
|
sv.fwrite %fd, "zero"
|
|
}
|
|
case b1: {
|
|
sv.fwrite %fd, "one"
|
|
}
|
|
sv.case casez %arg1 : i1
|
|
case b0: {
|
|
sv.fwrite %fd, "zero"
|
|
}
|
|
case b1: {
|
|
sv.fwrite %fd, "one"
|
|
}
|
|
}
|
|
|
|
// CHECK-NEXT: %combWire = sv.reg {sv.attributes = [#sv.attribute<"dont_merge">]} : !hw.inout<i1>
|
|
%combWire = sv.reg {sv.attributes=[#sv.attribute<"dont_merge">]} : !hw.inout<i1>
|
|
// CHECK-NEXT: %selReg = sv.reg {sv.attributes = [#sv.attribute<"dont_merge">, #sv.attribute<"dont_retime" = "true">]} : !hw.inout<i10>
|
|
%selReg = sv.reg {sv.attributes = [#sv.attribute<"dont_merge">, #sv.attribute<"dont_retime" ="true">]} : !hw.inout<i10>
|
|
// CHECK-NEXT: %combWire2 = sv.wire : !hw.inout<i1>
|
|
%combWire2 = sv.wire : !hw.inout<i1>
|
|
// CHECK-NEXT: %regForce = sv.reg : !hw.inout<i1>
|
|
%regForce = sv.reg : !hw.inout<i1>
|
|
// CHECK-NEXT: sv.alwayscomb {
|
|
sv.alwayscomb {
|
|
// CHECK-NEXT: %x_i1 = sv.constantX : i1
|
|
%tmpx = sv.constantX : i1
|
|
// CHECK-NEXT: sv.passign %combWire, %x_i1 : i1
|
|
sv.passign %combWire, %tmpx : i1
|
|
// CHECK-NEXT: %[[c2_i3:.+]] = hw.constant 2 : i3
|
|
// CHECK-NEXT: %[[v0:.+]] = sv.indexed_part_select_inout %selReg[%[[c2_i3]] : 1] : !hw.inout<i10>, i3
|
|
// CHECK-NEXT: sv.passign %[[v0]], %x_i1 : i1
|
|
%c2 = hw.constant 2 : i3
|
|
%xx1 = sv.indexed_part_select_inout %selReg[%c2:1] : !hw.inout<i10>, i3
|
|
sv.passign %xx1, %tmpx : i1
|
|
// CHECK-NEXT: sv.force %combWire2, %x_i1 : i1
|
|
sv.force %combWire2, %tmpx : i1
|
|
// CHECK-NEXT: sv.force %regForce, %x_i1 : i1
|
|
sv.force %regForce, %tmpx : i1
|
|
sv.release %combWire2 : !hw.inout<i1>
|
|
sv.release %regForce : !hw.inout<i1>
|
|
// CHECK-NEXT: sv.release %combWire2 : !hw.inout<i1>
|
|
// CHECK-NEXT: sv.release %regForce : !hw.inout<i1>
|
|
// CHECK-NEXT: }
|
|
}
|
|
|
|
// CHECK-NEXT: %reg23 = sv.reg : !hw.inout<i23>
|
|
// CHECK-NEXT: %regStruct23 = sv.reg : !hw.inout<struct<foo: i23>>
|
|
// CHECK-NEXT: %reg24 = sv.reg sym @regSym1 : !hw.inout<i23>
|
|
// CHECK-NEXT: %wire25 = sv.wire sym @wireSym1 : !hw.inout<i23>
|
|
%reg23 = sv.reg : !hw.inout<i23>
|
|
%regStruct23 = sv.reg : !hw.inout<struct<foo: i23>>
|
|
%reg24 = sv.reg sym @regSym1 : !hw.inout<i23>
|
|
%wire25 = sv.wire sym @wireSym1 : !hw.inout<i23>
|
|
|
|
// Simulation Control Tasks
|
|
// CHECK-NEXT: sv.initial {
|
|
// CHECK-NEXT: sv.stop 1
|
|
// CHECK-NEXT: sv.finish 1
|
|
// CHECK-NEXT: sv.exit
|
|
// CHECK-NEXT: }
|
|
sv.initial {
|
|
sv.stop 1
|
|
sv.finish 1
|
|
sv.exit
|
|
}
|
|
|
|
// Severity Message Tasks
|
|
// CHECK-NEXT: sv.initial {
|
|
// CHECK-NEXT: sv.fatal 1
|
|
// CHECK-NEXT: sv.fatal 1, "hello"
|
|
// CHECK-NEXT: sv.fatal 1, "hello %d"(%arg0) : i1
|
|
// CHECK-NEXT: sv.error
|
|
// CHECK-NEXT: sv.error "hello"
|
|
// CHECK-NEXT: sv.error "hello %d"(%arg0) : i1
|
|
// CHECK-NEXT: sv.warning
|
|
// CHECK-NEXT: sv.warning "hello"
|
|
// CHECK-NEXT: sv.warning "hello %d"(%arg0) : i1
|
|
// CHECK-NEXT: sv.info
|
|
// CHECK-NEXT: sv.info "hello"
|
|
// CHECK-NEXT: sv.info "hello %d"(%arg0) : i1
|
|
// CHECK-NEXT: }
|
|
sv.initial {
|
|
sv.fatal 1
|
|
sv.fatal 1, "hello"
|
|
sv.fatal 1, "hello %d"(%arg0) : i1
|
|
sv.error
|
|
sv.error "hello"
|
|
sv.error "hello %d"(%arg0) : i1
|
|
sv.warning
|
|
sv.warning "hello"
|
|
sv.warning "hello %d"(%arg0) : i1
|
|
sv.info
|
|
sv.info "hello"
|
|
sv.info "hello %d"(%arg0) : i1
|
|
}
|
|
|
|
// Tests for ReadMemOp ($readmemb/$readmemh)
|
|
// CHECK-NEXT: sv.initial {
|
|
// CHECK-NEXT: %memForReadMem = sv.reg
|
|
// CHECK-NEXT: sv.readmem %memForReadMem, "file1.txt", MemBaseBin
|
|
// CHECK-NEXT: sv.readmem %memForReadMem, "file2.txt", MemBaseHex
|
|
// CHECK-NEXT: }
|
|
sv.initial {
|
|
%memForReadMem = sv.reg sym @MemForReadMem : !hw.inout<uarray<8xi32>>
|
|
sv.readmem %memForReadMem, "file1.txt", MemBaseBin : !hw.inout<uarray<8xi32>>
|
|
sv.readmem %memForReadMem, "file2.txt", MemBaseHex : !hw.inout<uarray<8xi32>>
|
|
}
|
|
|
|
// CHECK-NEXT: hw.output
|
|
hw.output
|
|
}
|
|
|
|
//CHECK-LABEL: sv.bind <@AB::@a1>
|
|
//CHECK-NEXT: sv.bind <@AB::@b1>
|
|
sv.bind <@AB::@a1>
|
|
sv.bind <@AB::@b1>
|
|
|
|
|
|
hw.module.extern @ExternDestMod(in %a: i1, in %b: i2)
|
|
hw.module @InternalDestMod(in %a: i1, in %b: i2) {}
|
|
//CHECK-LABEL: hw.module @AB(in %a : i1, in %b : i2) {
|
|
//CHECK-NEXT: hw.instance "whatever" sym @a1 @ExternDestMod(a: %a: i1, b: %b: i2) -> () {doNotPrint = 1 : i64}
|
|
//CHECK-NEXT: hw.instance "yo" sym @b1 @InternalDestMod(a: %a: i1, b: %b: i2) -> () {doNotPrint = 1 : i64}
|
|
|
|
hw.module @AB(in %a: i1, in %b: i2) {
|
|
hw.instance "whatever" sym @a1 @ExternDestMod(a: %a: i1, b: %b: i2) -> () {doNotPrint=1}
|
|
hw.instance "yo" sym @b1 @InternalDestMod(a: %a: i1, b: %b: i2) -> () {doNotPrint=1}
|
|
}
|
|
|
|
//CHECK-LABEL: hw.module @XMR_src
|
|
hw.module @XMR_src(in %a : i23) {
|
|
//CHECK-NEXT: sv.xmr isRooted "a", "b", "c" : !hw.inout<i23>
|
|
%xmr1 = sv.xmr isRooted a,b,c : !hw.inout<i23>
|
|
//CHECK-NEXT: sv.xmr "a", "b", "c" : !hw.inout<i3>
|
|
%xmr2 = sv.xmr "a",b,c : !hw.inout<i3>
|
|
%r = sv.read_inout %xmr1 : !hw.inout<i23>
|
|
sv.assign %xmr1, %a : i23
|
|
}
|
|
|
|
hw.module @part_select(in %in4 : i4, in %in8 : i8, out a : i3, out b : i5) {
|
|
// CHECK-LABEL: hw.module @part_select
|
|
|
|
%myReg2 = sv.reg : !hw.inout<i18>
|
|
%c2_i3 = hw.constant 7 : i4
|
|
// CHECK: = sv.indexed_part_select_inout %myReg2[%[[c7_i4:.+]] : 8] : !hw.inout<i18>, i4
|
|
%a1 = sv.indexed_part_select_inout %myReg2 [%c2_i3:8] : !hw.inout<i18>, i4
|
|
sv.assign %a1, %in8 : i8
|
|
// CHECK: = sv.indexed_part_select_inout %myReg2[%[[c7_i4]] decrement : 8] : !hw.inout<i18>, i4
|
|
%b1 = sv.indexed_part_select_inout %myReg2 [%c2_i3 decrement:8] : !hw.inout<i18>, i4
|
|
sv.assign %b1, %in8 : i8
|
|
%c3_i3 = hw.constant 3 : i4
|
|
%rc = sv.read_inout %myReg2 : !hw.inout<i18>
|
|
%c = sv.indexed_part_select %rc [%c3_i3:3] : i18, i4
|
|
// CHECK: %[[v2:.+]] = sv.read_inout %myReg2 : !hw.inout<i18>
|
|
// CHECK: = sv.indexed_part_select %[[v2]][%[[c3_i4:.+]] : 3] : i18, i4
|
|
%rd = sv.read_inout %myReg2 : !hw.inout<i18>
|
|
%d = sv.indexed_part_select %rd [%in4 decrement:5] : i18, i4
|
|
// CHECK: %[[v4:.+]] = sv.read_inout %myReg2 : !hw.inout<i18>
|
|
// CHECK: = sv.indexed_part_select %[[v4]][%[[in4:.+]] decrement : 5] : i18, i4
|
|
hw.output %c, %d : i3, i5
|
|
}
|
|
|
|
// CHECK-LABEL: sv.macro.decl @foo
|
|
sv.macro.decl @foo
|
|
// CHECK-LABEL: sv.macro.decl @bar
|
|
sv.macro.decl @bar
|
|
|
|
// CHECK-LABEL: hw.module @nested_wire
|
|
hw.module @nested_wire(in %a: i1) {
|
|
// CHECK: sv.ifdef @foo
|
|
sv.ifdef @foo {
|
|
// CHECK: sv.wire
|
|
%wire = sv.wire : !hw.inout<i1>
|
|
// CHECK: sv.assign
|
|
sv.assign %wire, %a : i1
|
|
}
|
|
}
|
|
|
|
|
|
// CHECK-LABEL: hw.module @ordered_region
|
|
hw.module @ordered_region(in %a: i1) {
|
|
// CHECK: sv.ordered
|
|
sv.ordered {
|
|
// CHECK: sv.ifdef @foo
|
|
sv.ifdef @foo {
|
|
// CHECK: sv.wire
|
|
%wire = sv.wire : !hw.inout<i1>
|
|
// CHECK: sv.assign
|
|
sv.assign %wire, %a : i1
|
|
}
|
|
sv.ifdef @bar {
|
|
// CHECK: sv.wire
|
|
%wire = sv.wire : !hw.inout<i1>
|
|
// CHECK: sv.assign
|
|
sv.assign %wire, %a : i1
|
|
}
|
|
}
|
|
}
|
|
|
|
// CHECK-LABEL: hw.module @XMRRefOp
|
|
hw.hierpath private @ref [@XMRRefOp::@foo, @XMRRefFoo::@a]
|
|
hw.hierpath @ref2 [@XMRRefOp::@bar]
|
|
hw.module.extern @XMRRefBar()
|
|
hw.module @XMRRefFoo() {
|
|
%a = sv.wire sym @a : !hw.inout<i2>
|
|
}
|
|
hw.module @XMRRefOp() {
|
|
hw.instance "foo" sym @foo @XMRRefFoo() -> ()
|
|
hw.instance "bar" sym @bar @XMRRefBar() -> ()
|
|
// CHECK: %0 = sv.xmr.ref @ref : !hw.inout<i2>
|
|
%0 = sv.xmr.ref @ref : !hw.inout<i2>
|
|
// CHECK: %1 = sv.xmr.ref @ref2 ".x.y.z[42]" : !hw.inout<i8>
|
|
%1 = sv.xmr.ref @ref2 ".x.y.z[42]" : !hw.inout<i8>
|
|
}
|
|
|
|
// Functions.
|
|
// CHECK-LABEL: sv.func private @function_declare(in %in_0 : i2, in %in_1 : i2, out out_0 : i1, in %in_2 : !hw.array<2xi2>)
|
|
sv.func private @function_declare(in %in_0 : i2, in %in_1 : i2, out out_0 : i1, in %in_2 : !hw.array<2xi2>)
|
|
// CHECK-NEXT: sv.func.dpi.import linkage "c_func_name" @function_declare
|
|
sv.func.dpi.import linkage "c_func_name" @function_declare
|
|
|
|
// CHECK-LABEL: sv.func private @function_define(in %in_0 : i2, in %in_1 : i2, out out_0 : i1, in %in_2 : !hw.array<2xi2>)
|
|
sv.func private @function_define(in %in_0 : i2, in %in_1 : i2, out out_0 : i1, in %in_2 : !hw.array<2xi2>) attributes {test = "foo"} {
|
|
%0 = comb.icmp eq %in_0, %in_1: i2
|
|
// CHECK: sv.return %{{.+}} : i1
|
|
sv.return %0 : i1
|
|
}
|
|
|
|
// CHECK-LABEL: sv.func @recurse(in %n : i32, out out : i32) {
|
|
// CHECK: %0 = sv.func.call.procedural @recurse(%n) : (i32) -> i32
|
|
// CHECK-NEXT: sv.return %0
|
|
sv.func @recurse(in %n : i32, out out : i32) {
|
|
%v = sv.func.call.procedural @recurse(%n) : (i32) -> i32
|
|
sv.return %v : i32
|
|
}
|
|
|
|
// CHECK-LABEL: sv.func private @open_array(in %array : !sv.open_uarray<i8>)
|
|
// CHECK-LABEL:hw.module @test_open_array
|
|
// CHECK: %[[OPEN_ARRAY:.+]] = sv.unpacked_array_create %in_1, %in_0 : (i8, i8) -> !hw.uarray<2xi8>
|
|
// CHECK-NEXT: sv.unpacked_open_array_cast %[[OPEN_ARRAY:.+]] : (!hw.uarray<2xi8>) -> !sv.open_uarray<i8>
|
|
sv.func private @open_array(in %array : !sv.open_uarray<i8>)
|
|
hw.module @test_open_array(in %clock : i1, in %in_0 : i8, in %in_1 : i8) {
|
|
%0 = sv.unpacked_array_create %in_1, %in_0 : (i8, i8) -> !hw.uarray<2xi8>
|
|
%1 = sv.unpacked_open_array_cast %0 : (!hw.uarray<2xi8>) -> !sv.open_uarray<i8>
|
|
sv.always posedge %clock {
|
|
sv.func.call.procedural @open_array(%1) : (!sv.open_uarray<i8>) -> ()
|
|
}
|
|
}
|