mirror of https://github.com/llvm/circt.git
[FIRRTL][LowerToHW] Insert extra initialization for async regs (#3000)
This commit adds an extra initialization for async registers so that they are set to initial values if reset signal is enabled at an initial randomization phase. This matches SFC's behaviour. Close #2999.
This commit is contained in:
parent
021c74ab3d
commit
5285d244fb
|
@ -1324,7 +1324,8 @@ struct FIRRTLLowering : public FIRRTLVisitor<FIRRTLLowering, LogicalResult> {
|
|||
template <typename ResultOpType, typename... CtorArgTypes>
|
||||
LogicalResult setLoweringTo(Operation *orig, CtorArgTypes... args);
|
||||
void emitRandomizePrologIfNeeded();
|
||||
void initializeRegister(Value reg);
|
||||
void initializeRegister(Value reg, llvm::Optional<std::pair<Value, Value>>
|
||||
asyncRegResetInitPair = llvm::None);
|
||||
|
||||
void runWithInsertionPointAtEndOfBlock(std::function<void(void)> fn,
|
||||
Region ®ion);
|
||||
|
@ -1532,6 +1533,10 @@ private:
|
|||
llvm::SmallDenseMap<std::pair<Block *, Attribute>, sv::IfDefOp> ifdefBlocks;
|
||||
llvm::SmallDenseMap<Block *, sv::InitialOp> initialBlocks;
|
||||
|
||||
llvm::SmallDenseMap<Block *, sv::IfDefProceduralOp> randomizeRegInitIfOp;
|
||||
llvm::SmallDenseMap<std::pair<Block *, Value>, sv::IfOp>
|
||||
asyncRegPostRandomizationIfOp;
|
||||
|
||||
/// This is a set of wires that get inserted as an artifact of the
|
||||
/// lowering process. LowerToHW should attempt to clean these up after
|
||||
/// lowering.
|
||||
|
@ -2365,7 +2370,8 @@ void FIRRTLLowering::emitRandomizePrologIfNeeded() {
|
|||
randomizePrologEmitted = true;
|
||||
}
|
||||
|
||||
void FIRRTLLowering::initializeRegister(Value reg) {
|
||||
void FIRRTLLowering::initializeRegister(
|
||||
Value reg, llvm::Optional<std::pair<Value, Value>> asyncRegResetInitPair) {
|
||||
typedef std::pair<Attribute, std::pair<unsigned, unsigned>> SymbolAndRange;
|
||||
|
||||
// The point in the design where we should add randomization register
|
||||
|
@ -2505,7 +2511,30 @@ void FIRRTLLowering::initializeRegister(Value reg) {
|
|||
addToInitialBlock([&]() {
|
||||
emitRandomizePrologIfNeeded();
|
||||
circuitState.used_RANDOMIZE_REG_INIT = 1;
|
||||
addToIfDefProceduralBlock("RANDOMIZE_REG_INIT", [&]() { randomInit(); });
|
||||
auto *block = builder.getBlock();
|
||||
|
||||
// Randomized values are assigned to registers in `ifdef
|
||||
// RANDOMIZE_REG_INIT block.
|
||||
auto &op = randomizeRegInitIfOp[block];
|
||||
if (!op)
|
||||
op = builder.create<sv::IfDefProceduralOp>("RANDOMIZE_REG_INIT",
|
||||
[&]() {});
|
||||
runWithInsertionPointAtEndOfBlock(randomInit, op.thenRegion());
|
||||
|
||||
// If the register is async reset, we need to insert extra initialization
|
||||
// in post-randomization so that we can set the reset value to register if
|
||||
// the reset signal is enabled.
|
||||
if (asyncRegResetInitPair.hasValue()) {
|
||||
Value resetSignal, resetValue;
|
||||
std::tie(resetSignal, resetValue) = *asyncRegResetInitPair;
|
||||
// Merge if op if their reset values are same.
|
||||
auto &op = asyncRegPostRandomizationIfOp[{block, resetSignal}];
|
||||
if (!op)
|
||||
op = builder.create<sv::IfOp>(resetSignal, [&]() {});
|
||||
runWithInsertionPointAtEndOfBlock(
|
||||
[&]() { builder.create<sv::BPAssignOp>(reg, resetValue); },
|
||||
op.thenRegion());
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -2579,7 +2608,10 @@ LogicalResult FIRRTLLowering::visitDecl(RegResetOp op) {
|
|||
::ResetType::SyncReset, sv::EventControl::AtPosEdge,
|
||||
resetSignal, std::function<void()>(), resetFn);
|
||||
}
|
||||
initializeRegister(regResult);
|
||||
llvm::Optional<std::pair<Value, Value>> asyncRegResetInitPair;
|
||||
if (op.resetSignal().getType().isa<AsyncResetType>())
|
||||
asyncRegResetInitPair = {resetSignal, resetValue};
|
||||
initializeRegister(regResult, asyncRegResetInitPair);
|
||||
return success();
|
||||
}
|
||||
|
||||
|
|
|
@ -747,8 +747,10 @@ firrtl.circuit "Simple" attributes {annotations = [{class =
|
|||
firrtl.module private @InitReg1(in %clock: !firrtl.clock, in %reset: !firrtl.uint<1>,
|
||||
in %io_d: !firrtl.uint<32>, in %io_en: !firrtl.uint<1>,
|
||||
out %io_q: !firrtl.uint<32>) {
|
||||
// CHECK: %c0_i32 = hw.constant 0 : i32
|
||||
// CHECK: %c1_i32 = hw.constant 1 : i32
|
||||
// CHECK-NEXT: %c0_i32 = hw.constant 0 : i32
|
||||
%c0_ui32 = firrtl.constant 0 : !firrtl.uint<32>
|
||||
%c1_ui32 = firrtl.constant 1 : !firrtl.uint<32>
|
||||
|
||||
%4 = firrtl.asAsyncReset %reset : (!firrtl.uint<1>) -> !firrtl.asyncreset
|
||||
|
||||
|
@ -762,11 +764,13 @@ firrtl.circuit "Simple" attributes {annotations = [{class =
|
|||
// CHECK-NEXT: } else {
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: %reg3 = sv.reg sym @[[reg3_sym:.+]] : !hw.inout<i32
|
||||
// CHECK-NEXT: sv.ifdef "SYNTHESIS" {
|
||||
// CHECK-NEXT: } else {
|
||||
// CHECK-NEXT: sv.ifdef "RANDOMIZE_REG_INIT" {
|
||||
// CHECK-NEXT: %[[RANDOM:.+]] = sv.reg sym @[[RANDOM_SYM:[_A-Za-z0-9]+]] {{.+}}
|
||||
// CHECK-NEXT: %[[RANDOM_2:.+]] = sv.reg sym @[[RANDOM_2_SYM:[_A-Za-z0-9]+]] {{.+}}
|
||||
// CHECK-NEXT: %[[RANDOM_3:.+]] = sv.reg sym @[[RANDOM_3_SYM:[_A-Za-z0-9]+]] {{.+}}
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: sv.initial {
|
||||
// CHECK-NEXT: sv.verbatim "`INIT_RANDOM_PROLOG_"
|
||||
|
@ -775,6 +779,12 @@ firrtl.circuit "Simple" attributes {annotations = [{class =
|
|||
// CHECK-NEXT: sv.verbatim "{{[{][{]0[}][}]}} = {{[{][{]1[}][}]}};" {symbols = [#hw.innerNameRef<@InitReg1::@[[reg_sym]]>, #hw.innerNameRef<@InitReg1::@[[RANDOM_SYM]]>]}
|
||||
// CHECK-NEXT: sv.verbatim "{{[{][{]0[}][}]}} = {`RANDOM};" {symbols = [#hw.innerNameRef<@InitReg1::@[[RANDOM_2_SYM]]>]}
|
||||
// CHECK-NEXT: sv.verbatim "{{[{][{]0[}][}]}} = {{[{][{]1[}][}]}};" {symbols = [#hw.innerNameRef<@InitReg1::@[[reg2_sym]]>, #hw.innerNameRef<@InitReg1::@[[RANDOM_2_SYM]]>]}
|
||||
// CHECK-NEXT: sv.verbatim "{{[{][{]0[}][}]}} = {`RANDOM};" {symbols = [#hw.innerNameRef<@InitReg1::@[[RANDOM_3_SYM]]>]}
|
||||
// CHECK-NEXT: sv.verbatim "{{[{][{]0[}][}]}} = {{[{][{]1[}][}]}};" {symbols = [#hw.innerNameRef<@InitReg1::@[[reg3_sym]]>, #hw.innerNameRef<@InitReg1::@[[RANDOM_3_SYM]]>]}
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: sv.if %reset {
|
||||
// CHECK-NEXT: sv.bpassign %reg, %c0_i32 : i32
|
||||
// CHECK-NEXT: sv.bpassign %reg3, %c1_i32 : i32
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: }
|
||||
|
@ -786,12 +796,14 @@ firrtl.circuit "Simple" attributes {annotations = [{class =
|
|||
// CHECK-NEXT: sv.always posedge %clock, posedge %reset {
|
||||
// CHECK-NEXT: sv.if %reset {
|
||||
// CHECK-NEXT: sv.passign %reg, %c0_i32 : i32
|
||||
// CHECK-NEXT: sv.passign %reg3, %c1_i32 : i32
|
||||
// CHECK-NEXT: } else {
|
||||
// CHECK-NEXT: sv.passign %reg, %6 : i32
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: }
|
||||
%reg = firrtl.regreset %clock, %4, %c0_ui32 {name = "reg"} : !firrtl.asyncreset, !firrtl.uint<32>, !firrtl.uint<32>
|
||||
%reg2 = firrtl.regreset %clock, %reset, %c0_ui32 {name = "reg2"} : !firrtl.uint<1>, !firrtl.uint<32>, !firrtl.uint<32>
|
||||
%reg3 = firrtl.regreset %clock, %4, %c1_ui32 {name = "reg3"} : !firrtl.asyncreset, !firrtl.uint<32>, !firrtl.uint<32>
|
||||
|
||||
%sum = firrtl.add %reg, %reg2 : (!firrtl.uint<32>, !firrtl.uint<32>) -> !firrtl.uint<33>
|
||||
%shorten = firrtl.head %sum, 32 : (!firrtl.uint<33>) -> !firrtl.uint<32>
|
||||
|
|
Loading…
Reference in New Issue