Skip to content

Commit

Permalink
[Seq] Add get_initial_value
Browse files Browse the repository at this point in the history
  • Loading branch information
uenoku committed Oct 3, 2024
1 parent 0703098 commit bd4cd4a
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 8 deletions.
16 changes: 16 additions & 0 deletions include/circt/Dialect/Seq/SeqOps.td
Original file line number Diff line number Diff line change
Expand Up @@ -749,3 +749,19 @@ def FromImmutableOp : SeqOp<"from_immutable", [Pure]> {

let assemblyFormat = "$input attr-dict `:` functional-type(operands, results)";
}

def GetInitialValueOp : SeqOp<"get_initial_value", [Pure]> {
let summary = "Get an initial value of the input";
let description = [{
This operation freezes a HW value while the initialization phase and
returns the frozen value as `seq.immutable` type. The input value must be valid
at the initialization and immutable through the initialization phase and otherwise
the result value is undefined. In other words time-variant values such as registers
cannot be used as an input.
}];

let arguments = (ins AnyType:$input);
let results = (outs ImmutableType:$output);

let assemblyFormat = "$input attr-dict `:` functional-type(operands, results)";
}
18 changes: 15 additions & 3 deletions lib/Conversion/SeqToSV/SeqToSV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,21 @@ ModuleLoweringState::ImmutableValueLowering::lower(seq::InitialOp initialOp) {
OpBuilder builder = OpBuilder::atBlockBegin(module.getBodyBlock());
if (!svInitialOp)
svInitialOp = builder.create<sv::InitialOp>(initialOp->getLoc());
// Initial ops are merged to single one and must not have operands.
assert(initialOp.getNumOperands() == 0 &&
"initial op should have no operands");
// Replace immutable operands passed to initial op with already lowered
// values.
for (auto [blockArgument, operand] :
llvm::zip(initialOp.getBodyBlock()->getArguments(),
initialOp->getOpOperands())) {

auto immut = operand.get().getDefiningOp<seq::GetInitialValueOp>();
if (!immut)
return initialOp.emitError()
<< "invalid operand to initial op: " << operand.get();
blockArgument.replaceAllUsesWith(immut.getInput());
operand.drop();
if (immut.use_empty())
immut.erase();
}

auto loc = initialOp.getLoc();
llvm::SmallVector<Value> results;
Expand Down
16 changes: 11 additions & 5 deletions test/Dialect/Seq/compreg.mlir
Original file line number Diff line number Diff line change
Expand Up @@ -140,15 +140,21 @@ hw.module @reg_of_clock_type(in %clk: !seq.clock, in %rst: i1, in %i: !seq.clock
hw.module @init_with_call(in %clk: !seq.clock, in %rst: i1, in %i: i32, in %s: !hw.struct<foo: i32>, out o: i32) {
// SV: sv.initial {
// SV-NEXT: [[V0:%.+]] = sv.system "random"() : () -> i32
// SV-NEXT: [[V1:%.+]] = comb.add [[V0]], [[V0]] : i32
// SV-NEXT: sv.bpassign %reg, [[V0]] : i32
// SV-NEXT: [[C:%.+]] = hw.constant 0
// SV-NEXT: [[MUX:%.+]] = comb.mux %rst, [[C]], [[V0]]
// SV-NEXT: [[V1:%.+]] = comb.add [[MUX]], [[MUX]] : i32
// SV-NEXT: sv.bpassign %reg, [[MUX]] : i32
// SV-NEXT: sv.bpassign %reg2, [[V1]] : i32
// SV-NEXT: sv.bpassign [[REG:%.+]], [[V1]] : i32
// SV-NEXT: }
%init = seq.initial () {
%reset_immut = seq.get_initial_value %rst : (i1) -> (!seq.immutable<i1>)
%init = seq.initial (%reset_immut) {
^bb0(%r: i1):
%rand = sv.system "random"() : () -> i32
seq.yield %rand : i32
} : () -> !seq.immutable<i32>
%c0_i32 = hw.constant 0 : i32
%mux = comb.mux %r, %c0_i32, %rand : i32
seq.yield %mux : i32
} : (!seq.immutable<i1>) -> !seq.immutable<i32>

%add = seq.initial (%init) {
^bb0(%arg0 : i32):
Expand Down

0 comments on commit bd4cd4a

Please sign in to comment.