[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:
Hideto Ueno 2022-04-30 15:11:04 +09:00 committed by GitHub
parent 021c74ab3d
commit 5285d244fb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 49 additions and 5 deletions

View File

@ -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 &region);
@ -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();
}

View File

@ -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>