mirror of https://github.com/llvm/circt.git
[SV] Introduce SV for op (#4879)
This introduces SV for operation e.g.: ```mlir sv.for %i = %c0_i2 to %c-1_i2 step %c1_i2 : i2 { %RANDOM = sv.macro.ref.se< "RANDOM"> : i32 %index = sv.array_index_inout %_RANDOM[%i] : !hw.inout<uarray<3xi32>>, i2 sv.bpassign %index, %RANDOM : i32 } ``` which corresponds to: ```verilog for (logic [1:0] i = 2'h0; i < 2'h3; i = i + 2'h1) begin _RANDOM[i] = `RANDOM; end ``` The `sv.for` operation in System Verilog defines a for statement that requires three SSA operands: `lowerBounds`, `upperBound`, and `step`. It functions similarly to `scf.for`, where the loop iterates the induction variable from `lowerBound` to `upperBound` with a step size of `step`, i.e: ``` for (logic ... indVar = lowerBound; indVar < upperBound; indVar += step) begin end ``` It's important to note that since we are using a bit precise type instead of a Verilog `integer` type, users must be cautious about potential overflow. For example, if you wish to iterate over all 2-bit values, you must use a 3-bit value as the induction variable type.
This commit is contained in:
parent
909c6dbb21
commit
7b8f3c2a43
|
@ -11,6 +11,7 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
include "mlir/IR/EnumAttr.td"
|
||||
include "mlir/IR/OpAsmInterface.td"
|
||||
|
||||
/// Ensure symbol is one of the hw module.* types
|
||||
def isModuleSymbol : AttrConstraint<
|
||||
|
@ -748,3 +749,50 @@ def ReadMemOp : SVOp<"readmem", [ProceduralOp]> {
|
|||
let assemblyFormat =
|
||||
"$dest `,` $filename `,` $base attr-dict `:` qualified(type($dest))";
|
||||
}
|
||||
|
||||
def ForOp : SVOp<"for", [SingleBlock, NoTerminator, ProceduralOp,
|
||||
ProceduralRegion, OpAsmOpInterface,
|
||||
AllTypesMatch<["lowerBound", "upperBound", "step"]>]> {
|
||||
let summary = "System verilog for loop";
|
||||
|
||||
let description = [{
|
||||
The `sv.for` operation in System Verilog defines a for statement that requires
|
||||
three SSA operands: `lowerBounds`, `upperBound`, and `step`. It functions
|
||||
similarly to `scf.for`, where the loop iterates the induction variable from
|
||||
`lowerBound` to `upperBound` with a step size of `step`, i.e:
|
||||
|
||||
```
|
||||
for (logic ... indVar = lowerBound; indVar < upperBound; indVar += step) begin
|
||||
end
|
||||
```
|
||||
|
||||
It's important to note that since we are using a bit precise type instead of a Verilog
|
||||
`integer` type, users must be cautious about potential overflow. For example, if
|
||||
you wish to iterate over all 2-bit values, you must use a 3-bit value as the
|
||||
induction variable type.
|
||||
}];
|
||||
|
||||
let regions = (region SizedRegion<1>:$body);
|
||||
let arguments = (ins HWIntegerType:$lowerBound,
|
||||
HWIntegerType:$upperBound,
|
||||
HWIntegerType:$step,
|
||||
DefaultValuedAttr<StrAttr, "{}">:$inductionVarName);
|
||||
let results = (outs);
|
||||
let builders = [
|
||||
OpBuilder<(ins "Value":$lowerBound, "Value":$upperBound,
|
||||
"Value":$step, "StringRef":$inductionVarName,
|
||||
"llvm::function_ref<void(BlockArgument)>": $thenCtor)>,
|
||||
OpBuilder<(ins "int64_t":$lowerBound, "int64_t":$upperBound,
|
||||
"int64_t":$step, "IntegerType": $type,
|
||||
"StringRef":$inductionVarName,
|
||||
"llvm::function_ref<void(BlockArgument)>": $thenCtor)>
|
||||
];
|
||||
let hasCustomAssemblyFormat = 1;
|
||||
let hasCanonicalizeMethod = 1;
|
||||
let extraClassDeclaration = [{
|
||||
Block* getBodyBlock() { return &getBody().front(); }
|
||||
Value getInductionVar() { return getBodyBlock()->getArgument(0); }
|
||||
void getAsmBlockArgumentNames(mlir::Region ®ion,
|
||||
mlir::OpAsmSetValueNameFn setNameFn);
|
||||
}];
|
||||
}
|
||||
|
|
|
@ -57,6 +57,8 @@ public:
|
|||
ReadMemOp,
|
||||
// Generate statements
|
||||
GenerateOp, GenerateCaseOp,
|
||||
// For statements
|
||||
ForOp,
|
||||
// Sampled value functiions
|
||||
SampledOp>([&](auto expr) -> ResultType {
|
||||
return thisCast->visitSV(expr, args...);
|
||||
|
@ -165,6 +167,9 @@ public:
|
|||
HANDLE(GenerateOp, Unhandled);
|
||||
HANDLE(GenerateCaseOp, Unhandled);
|
||||
|
||||
// For loop.
|
||||
HANDLE(ForOp, Unhandled);
|
||||
|
||||
// Sampled Value Functions
|
||||
HANDLE(SampledOp, Unhandled);
|
||||
#undef HANDLE
|
||||
|
|
|
@ -813,9 +813,13 @@ StringRef getVerilogValueName(Value val) {
|
|||
if (auto *op = val.getDefiningOp())
|
||||
return getSymOpName(op);
|
||||
|
||||
if (auto port = val.dyn_cast<BlockArgument>())
|
||||
if (auto port = val.dyn_cast<BlockArgument>()) {
|
||||
// If the value is defined by for op, use its associated verilog name.
|
||||
if (auto forOp = dyn_cast<ForOp>(port.getParentBlock()->getParentOp()))
|
||||
return forOp->getAttrOfType<StringAttr>("hw.verilogName");
|
||||
return getPortVerilogName(port.getParentBlock()->getParentOp(),
|
||||
port.getArgNumber());
|
||||
}
|
||||
assert(false && "unhandled value");
|
||||
return {};
|
||||
}
|
||||
|
@ -2989,6 +2993,8 @@ private:
|
|||
LogicalResult visitSV(GenerateOp op);
|
||||
LogicalResult visitSV(GenerateCaseOp op);
|
||||
|
||||
LogicalResult visitSV(ForOp op);
|
||||
|
||||
void emitAssertionLabel(Operation *op, StringRef opName);
|
||||
void emitAssertionMessage(StringAttr message, ValueRange args,
|
||||
SmallPtrSetImpl<Operation *> &ops,
|
||||
|
@ -3541,6 +3547,30 @@ LogicalResult StmtEmitter::visitSV(GenerateCaseOp op) {
|
|||
return success();
|
||||
}
|
||||
|
||||
LogicalResult StmtEmitter::visitSV(ForOp op) {
|
||||
emitSVAttributes(op);
|
||||
llvm::SmallPtrSet<Operation *, 8> ops;
|
||||
startStatement();
|
||||
auto inductionVarName = op->getAttrOfType<StringAttr>("hw.verilogName");
|
||||
ps << "for (" << PP::ibox2 << "logic ";
|
||||
ps.invokeWithStringOS([&](auto &os) {
|
||||
emitter.emitTypeDims(op.getInductionVar().getType(), op.getLoc(), os);
|
||||
});
|
||||
ps << PP::nbsp << inductionVarName << " = ";
|
||||
emitExpression(op.getLowerBound(), ops);
|
||||
ps << "; " << PPExtString(inductionVarName) << " < ";
|
||||
emitExpression(op.getUpperBound(), ops);
|
||||
ps << "; " << PPExtString(inductionVarName) << " += ";
|
||||
emitExpression(op.getStep(), ops);
|
||||
ps << PP::end << ") begin";
|
||||
setPendingNewline();
|
||||
emitStatementBlock(op.getBody().getBlocks().front());
|
||||
startStatement();
|
||||
ps << "end";
|
||||
emitLocationInfoAndNewLine(ops);
|
||||
return success();
|
||||
}
|
||||
|
||||
/// Emit the `<label>:` portion of an immediate or concurrent verification
|
||||
/// operation. If a label has been stored for the operation through
|
||||
/// `addLegalName` in the pre-pass, that label is used. Otherwise, if the
|
||||
|
|
|
@ -175,6 +175,8 @@ static void legalizeModuleLocalNames(HWModuleOp module,
|
|||
// Otherwise, get a verilog name via `getSymOpName`.
|
||||
nameEntries.emplace_back(
|
||||
op, StringAttr::get(op->getContext(), getSymOpName(op)));
|
||||
} else if (auto forOp = dyn_cast<ForOp>(op)) {
|
||||
nameEntries.emplace_back(op, forOp.getInductionVarNameAttr());
|
||||
} else if (isa<AssertOp, AssumeOp, CoverOp, AssertConcurrentOp,
|
||||
AssumeConcurrentOp, CoverConcurrentOp>(op)) {
|
||||
// Notice and renamify the labels on verification statements.
|
||||
|
|
|
@ -373,8 +373,7 @@ static bool rewriteSideEffectingExpr(Operation *op) {
|
|||
// Check to see if this is already rewritten.
|
||||
if (op->hasOneUse()) {
|
||||
if (auto assign = dyn_cast<BPAssignOp>(*op->user_begin()))
|
||||
if (isa_and_nonnull<RegOp, LogicOp>(assign.getDest().getDefiningOp()))
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Otherwise, we have to transform it. Insert a reg at the top level, make
|
||||
|
@ -423,9 +422,15 @@ static bool hoistNonSideEffectExpr(Operation *op) {
|
|||
// the top level of the module. We can tell this quite efficiently by
|
||||
// looking for ops in a procedural region - because procedural regions
|
||||
// live in graph regions but not visa-versa.
|
||||
if (BlockArgument block = operand.dyn_cast<BlockArgument>()) {
|
||||
// References to ports are always ok.
|
||||
if (isa<hw::HWModuleOp>(block.getParentBlock()->getParentOp()))
|
||||
return false;
|
||||
|
||||
cantHoist = true;
|
||||
return true;
|
||||
}
|
||||
Operation *operandOp = operand.getDefiningOp();
|
||||
if (!operandOp) // References to ports are always ok.
|
||||
return false;
|
||||
|
||||
if (operandOp->getParentOp()->hasTrait<ProceduralRegion>()) {
|
||||
cantHoist |= operandOp->getBlock() == op->getBlock();
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "circt/Support/CustomDirectiveImpl.h"
|
||||
#include "mlir/IR/Builders.h"
|
||||
#include "mlir/IR/BuiltinTypes.h"
|
||||
#include "mlir/IR/Matchers.h"
|
||||
#include "mlir/IR/PatternMatch.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
|
@ -976,6 +977,111 @@ void OrderedOutputOp::build(OpBuilder &builder, OperationState &result,
|
|||
body();
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ForOp
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void ForOp::build(OpBuilder &builder, OperationState &result,
|
||||
int64_t lowerBound, int64_t upperBound, int64_t step,
|
||||
IntegerType type, StringRef name,
|
||||
llvm::function_ref<void(BlockArgument)> body) {
|
||||
auto lb = builder.create<hw::ConstantOp>(result.location, type, lowerBound);
|
||||
auto ub = builder.create<hw::ConstantOp>(result.location, type, upperBound);
|
||||
auto st = builder.create<hw::ConstantOp>(result.location, type, step);
|
||||
build(builder, result, lb, ub, st, name, body);
|
||||
}
|
||||
void ForOp::build(OpBuilder &builder, OperationState &result, Value lowerBound,
|
||||
Value upperBound, Value step, StringRef name,
|
||||
llvm::function_ref<void(BlockArgument)> body) {
|
||||
OpBuilder::InsertionGuard guard(builder);
|
||||
build(builder, result, lowerBound, upperBound, step, name);
|
||||
auto *region = result.regions.front().get();
|
||||
builder.createBlock(region);
|
||||
BlockArgument blockArgument =
|
||||
region->addArgument(lowerBound.getType(), result.location);
|
||||
|
||||
if (body)
|
||||
body(blockArgument);
|
||||
}
|
||||
|
||||
void ForOp::getAsmBlockArgumentNames(mlir::Region ®ion,
|
||||
mlir::OpAsmSetValueNameFn setNameFn) {
|
||||
auto *block = ®ion.front();
|
||||
setNameFn(block->getArgument(0), getInductionVarNameAttr());
|
||||
}
|
||||
|
||||
ParseResult ForOp::parse(OpAsmParser &parser, OperationState &result) {
|
||||
auto &builder = parser.getBuilder();
|
||||
Type type;
|
||||
|
||||
OpAsmParser::Argument inductionVariable;
|
||||
OpAsmParser::UnresolvedOperand lb, ub, step;
|
||||
// Parse the optional initial iteration arguments.
|
||||
SmallVector<OpAsmParser::Argument, 4> regionArgs;
|
||||
|
||||
// Parse the induction variable followed by '='.
|
||||
if (parser.parseOperand(inductionVariable.ssaName) || parser.parseEqual() ||
|
||||
// Parse loop bounds.
|
||||
parser.parseOperand(lb) || parser.parseKeyword("to") ||
|
||||
parser.parseOperand(ub) || parser.parseKeyword("step") ||
|
||||
parser.parseOperand(step) || parser.parseColon() ||
|
||||
parser.parseType(type))
|
||||
return failure();
|
||||
|
||||
regionArgs.push_back(inductionVariable);
|
||||
|
||||
// Resolve input operands.
|
||||
regionArgs.front().type = type;
|
||||
if (parser.resolveOperand(lb, type, result.operands) ||
|
||||
parser.resolveOperand(ub, type, result.operands) ||
|
||||
parser.resolveOperand(step, type, result.operands))
|
||||
return failure();
|
||||
|
||||
// Parse the body region.
|
||||
Region *body = result.addRegion();
|
||||
if (parser.parseRegion(*body, regionArgs))
|
||||
return failure();
|
||||
|
||||
// Parse the optional attribute list.
|
||||
if (parser.parseOptionalAttrDict(result.attributes))
|
||||
return failure();
|
||||
|
||||
if (!inductionVariable.ssaName.name.empty()) {
|
||||
if (!isdigit(inductionVariable.ssaName.name[1]))
|
||||
// Retrive from its SSA name.
|
||||
result.attributes.append(
|
||||
{builder.getStringAttr("inductionVarName"),
|
||||
builder.getStringAttr(inductionVariable.ssaName.name.drop_front())});
|
||||
}
|
||||
|
||||
return success();
|
||||
}
|
||||
|
||||
void ForOp::print(OpAsmPrinter &p) {
|
||||
p << " " << getInductionVar() << " = " << getLowerBound() << " to "
|
||||
<< getUpperBound() << " step " << getStep();
|
||||
p << " : " << getInductionVar().getType() << ' ';
|
||||
p.printRegion(getRegion(),
|
||||
/*printEntryBlockArgs=*/false,
|
||||
/*printBlockTerminators=*/false);
|
||||
p.printOptionalAttrDict((*this)->getAttrs(), {"inductionVarName"});
|
||||
}
|
||||
|
||||
LogicalResult ForOp::canonicalize(ForOp op, PatternRewriter &rewriter) {
|
||||
APInt lb, ub, step;
|
||||
if (matchPattern(op.getLowerBound(), mlir::m_ConstantInt(&lb)) &&
|
||||
matchPattern(op.getUpperBound(), mlir::m_ConstantInt(&ub)) &&
|
||||
matchPattern(op.getStep(), mlir::m_ConstantInt(&step)) &&
|
||||
lb + step == ub) {
|
||||
// Unroll the loop if it's executed only once.
|
||||
op.getInductionVar().replaceAllUsesWith(op.getLowerBound());
|
||||
replaceOpWithRegion(rewriter, op, op.getBodyRegion());
|
||||
rewriter.eraseOp(op);
|
||||
return success();
|
||||
}
|
||||
return failure();
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Assignment statements
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -542,25 +542,8 @@ void HWMemSimImpl::generateMemory(HWModuleOp op, FirMemory mem) {
|
|||
return;
|
||||
|
||||
constexpr unsigned randomWidth = 32;
|
||||
sv::RegOp randomMemReg;
|
||||
b.create<sv::IfDefOp>("SYNTHESIS", std::function<void()>(), [&]() {
|
||||
sv::RegOp randReg;
|
||||
StringRef initvar;
|
||||
|
||||
// Declare variables for use by memory randomization logic.
|
||||
if (!disableMemRandomization || !mem.initFilename.empty()) {
|
||||
b.create<sv::IfDefOp>("RANDOMIZE_MEM_INIT", [&]() {
|
||||
initvar = moduleNamespace.newName("initvar");
|
||||
b.create<sv::VerbatimOp>("integer " + Twine(initvar) + ";\n");
|
||||
randomMemReg = b.create<sv::RegOp>(
|
||||
b.getIntegerType(llvm::divideCeil(mem.dataWidth, randomWidth) *
|
||||
randomWidth),
|
||||
b.getStringAttr("_RANDOM_MEM"),
|
||||
b.getStringAttr(moduleNamespace.newName("_RANDOM_MEM")));
|
||||
});
|
||||
}
|
||||
|
||||
// Declare variables for use by register randomization logic.
|
||||
SmallVector<sv::RegOp> randRegs;
|
||||
if (!disableRegRandomization) {
|
||||
b.create<sv::IfDefOp>("RANDOMIZE_REG_INIT", [&]() {
|
||||
|
@ -576,36 +559,55 @@ void HWMemSimImpl::generateMemory(HWModuleOp op, FirMemory mem) {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
auto randomMemReg = b.create<sv::RegOp>(
|
||||
b.getIntegerType(llvm::divideCeil(mem.dataWidth, randomWidth) *
|
||||
randomWidth),
|
||||
b.getStringAttr("_RANDOM_MEM"));
|
||||
b.create<sv::InitialOp>([&]() {
|
||||
b.create<sv::VerbatimOp>("`INIT_RANDOM_PROLOG_");
|
||||
|
||||
// Memory randomization logic. The entire memory is randomized.
|
||||
if (!disableMemRandomization) {
|
||||
b.create<sv::IfDefProceduralOp>("RANDOMIZE_MEM_INIT", [&]() {
|
||||
std::string verbatimForLoop;
|
||||
llvm::raw_string_ostream s(verbatimForLoop);
|
||||
s << "for (" << initvar << " = 0; " << initvar << " < " << mem.depth
|
||||
<< "; " << initvar << " = " << initvar << " + 1) begin\n"
|
||||
<< " {{0}} = ";
|
||||
auto repetitionCount = llvm::divideCeil(mem.dataWidth, randomWidth);
|
||||
if (repetitionCount > 1)
|
||||
s << "{";
|
||||
for (size_t i = 0; i != repetitionCount; ++i) {
|
||||
if (i > 0)
|
||||
s << ", ";
|
||||
s << "{`RANDOM}";
|
||||
}
|
||||
if (repetitionCount > 1)
|
||||
s << "}";
|
||||
s << ";\n";
|
||||
s << " Memory[" << initvar << "] = "
|
||||
<< "{{0}}[" << mem.dataWidth - 1 << ":" << 0 << "];\n"
|
||||
<< "end";
|
||||
b.create<sv::VerbatimOp>(
|
||||
verbatimForLoop, ValueRange{},
|
||||
b.getArrayAttr({hw::InnerRefAttr::get(
|
||||
op.getNameAttr(), randomMemReg.getInnerSymAttr())}));
|
||||
auto outerLoopIndVarType =
|
||||
b.getIntegerType(llvm::Log2_64_Ceil(mem.depth + 1));
|
||||
auto innerUpperBoundWidth = randomMemReg.getType()
|
||||
.getElementType()
|
||||
.cast<IntegerType>()
|
||||
.getWidth();
|
||||
auto innerLoopIndVarType =
|
||||
b.getIntegerType(llvm::Log2_64_Ceil(innerUpperBoundWidth + 1));
|
||||
// Construct the following nested for loops:
|
||||
// ```
|
||||
// for (int i = 0; i < mem.depth; i++) begin
|
||||
// for (int j = 0; j < randomMeg.size; j += 32)
|
||||
// randomMem[j+31:j] = `RANDOM
|
||||
// Memory[i] = randomMem[mem.dataWidth - 1: 0];
|
||||
// ```
|
||||
b.create<sv::ForOp>(
|
||||
0, mem.depth, 1, outerLoopIndVarType, "i",
|
||||
[&](BlockArgument outerIndVar) {
|
||||
b.create<sv::ForOp>(
|
||||
0, innerUpperBoundWidth, randomWidth, innerLoopIndVarType,
|
||||
"j", [&](BlockArgument innerIndVar) {
|
||||
auto rhs = b.create<sv::MacroRefExprSEOp>(
|
||||
b.getIntegerType(randomWidth), "RANDOM");
|
||||
auto lhs = b.create<sv::IndexedPartSelectInOutOp>(
|
||||
randomMemReg, innerIndVar, randomWidth, false);
|
||||
b.create<sv::BPAssignOp>(lhs, rhs);
|
||||
});
|
||||
|
||||
Value iterValue = outerIndVar;
|
||||
// Truncate the induction variable if necessary.
|
||||
if (!outerIndVar.getType().isInteger(
|
||||
llvm::Log2_64_Ceil(mem.depth)))
|
||||
iterValue = b.create<comb::ExtractOp>(
|
||||
iterValue, 0, llvm::Log2_64_Ceil(mem.depth));
|
||||
auto lhs = b.create<sv::ArrayIndexInOutOp>(reg, iterValue);
|
||||
auto rhs = b.createOrFold<comb::ExtractOp>(
|
||||
b.create<sv::ReadInOutOp>(randomMemReg), 0, mem.dataWidth);
|
||||
b.create<sv::BPAssignOp>(lhs, rhs);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -267,13 +267,40 @@ void FirRegLower::lower() {
|
|||
builder.create<sv::IfDefProceduralOp>(randInitRef, [&] {
|
||||
// Create randomization vector
|
||||
SmallVector<Value> randValues;
|
||||
for (uint64_t x = 0; x < (maxBit + 31) / 32; ++x) {
|
||||
auto lhs = builder.create<sv::LogicOp>(
|
||||
loc, builder.getIntegerType(32),
|
||||
"_RANDOM_" + llvm::utostr(x));
|
||||
auto rhs = builder.create<sv::MacroRefExprSEOp>(
|
||||
loc, builder.getIntegerType(32), "RANDOM");
|
||||
builder.create<sv::BPAssignOp>(loc, lhs, rhs);
|
||||
auto numRandomCalls = (maxBit + 31) / 32;
|
||||
auto logic = builder.create<sv::LogicOp>(
|
||||
loc,
|
||||
hw::UnpackedArrayType::get(builder.getIntegerType(32),
|
||||
numRandomCalls),
|
||||
"_RANDOM");
|
||||
// Indvar's width must be equal to `ceil(log2(numRandomCalls +
|
||||
// 1))` to avoid overflow.
|
||||
auto inducionVariableWidth =
|
||||
llvm::Log2_64_Ceil(numRandomCalls + 1);
|
||||
auto arrayIndexWith = llvm::Log2_64_Ceil(numRandomCalls);
|
||||
auto lb = getOrCreateConstant(
|
||||
loc, APInt::getZero(inducionVariableWidth));
|
||||
auto ub = getOrCreateConstant(
|
||||
loc, APInt(inducionVariableWidth, numRandomCalls));
|
||||
auto step =
|
||||
getOrCreateConstant(loc, APInt(inducionVariableWidth, 1));
|
||||
auto forLoop = builder.create<sv::ForOp>(
|
||||
loc, lb, ub, step, "i", [&](BlockArgument iter) {
|
||||
auto rhs = builder.create<sv::MacroRefExprSEOp>(
|
||||
loc, builder.getIntegerType(32), "RANDOM");
|
||||
Value iterValue = iter;
|
||||
if (!iter.getType().isInteger(arrayIndexWith))
|
||||
iterValue = builder.create<comb::ExtractOp>(
|
||||
loc, iterValue, 0, arrayIndexWith);
|
||||
auto lhs = builder.create<sv::ArrayIndexInOutOp>(
|
||||
loc, logic, iterValue);
|
||||
builder.create<sv::BPAssignOp>(loc, lhs, rhs);
|
||||
});
|
||||
builder.setInsertionPointAfter(forLoop);
|
||||
for (uint64_t x = 0; x < numRandomCalls; ++x) {
|
||||
auto lhs = builder.create<sv::ArrayIndexInOutOp>(
|
||||
loc, logic,
|
||||
getOrCreateConstant(loc, APInt(arrayIndexWith, x)));
|
||||
randValues.push_back(lhs.getResult());
|
||||
}
|
||||
|
||||
|
@ -282,6 +309,7 @@ void FirRegLower::lower() {
|
|||
initialize(builder, svReg, randValues);
|
||||
});
|
||||
}
|
||||
|
||||
if (!asyncResets.empty()) {
|
||||
// If the register is async reset, we need to insert extra
|
||||
// initialization in post-randomization so that we can set the
|
||||
|
|
|
@ -1732,6 +1732,25 @@ hw.module @ConditionalComments() {
|
|||
} // CHECK-NEXT: `endif // not def BAR
|
||||
}
|
||||
|
||||
// CHECK-LABEL: module ForStatement
|
||||
hw.module @ForStatement(%a: i5) -> () {
|
||||
%_RANDOM = sv.logic : !hw.inout<uarray<3xi32>>
|
||||
sv.initial {
|
||||
%c-2_i2 = hw.constant -2 : i2
|
||||
%c1_i2 = hw.constant 1 : i2
|
||||
%c-1_i2 = hw.constant -1 : i2
|
||||
%c0_i2 = hw.constant 0 : i2
|
||||
// CHECK: for (logic [1:0] i = 2'h0; i < 2'h3; i += 2'h1) begin
|
||||
// CHECK-NEXT: _RANDOM[i] = `RANDOM;
|
||||
// CHECK-NEXT: end
|
||||
sv.for %i = %c0_i2 to %c-1_i2 step %c1_i2 : i2 {
|
||||
%RANDOM = sv.macro.ref.se< "RANDOM"> : i32
|
||||
%index = sv.array_index_inout %_RANDOM[%i] : !hw.inout<uarray<3xi32>>, i2
|
||||
sv.bpassign %index, %RANDOM : i32
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// CHECK-LABEL: module intrinsic
|
||||
hw.module @intrinsic(%clk: i1) -> (io1: i1, io2: i1, io3: i1, io4: i5) {
|
||||
|
|
|
@ -112,21 +112,23 @@ hw.module.generated @FIRRTLMem_1_1_1_16_10_0_1_0_0, @FIRRTLMem(%ro_addr_0: i4, %
|
|||
//CHECK-NEXT: }
|
||||
//CHECK-NEXT: sv.ifdef "SYNTHESIS" {
|
||||
//CHECK-NEXT: } else {
|
||||
//CHECK-NEXT: sv.ifdef "RANDOMIZE_MEM_INIT" {
|
||||
//CHECK-NEXT: sv.verbatim "integer [[INITVAR:.+]];\0A"
|
||||
//CHECK-NEXT: %[[RANDOM_MEM:.+]] = sv.reg sym @[[_RANDOM_MEM:.+]] : !hw.inout<i32>
|
||||
//CHECK-NEXT: }
|
||||
//CHECK-NEXT: sv.ifdef "RANDOMIZE_REG_INIT" {
|
||||
//CHECK-NEXT: }
|
||||
//CHECK-NEXT: %_RANDOM_MEM = sv.reg : !hw.inout<i32>
|
||||
//CHECK-NEXT: sv.initial {
|
||||
//CHECK-NEXT: sv.verbatim "`INIT_RANDOM_PROLOG_"
|
||||
//CHECK-NEXT: sv.ifdef.procedural "RANDOMIZE_MEM_INIT" {
|
||||
//CHECK-NEXT: sv.verbatim "for ([[INITVAR]] = 0; [[INITVAR]] < 10; [[INITVAR]] = [[INITVAR]] + 1) begin\0A
|
||||
//CHECK-SAME{LITERAL}: {{0}} = {`RANDOM};\0A
|
||||
//CHECK-SAME: Memory[[[INITVAR]]] =
|
||||
//CHECK-SAME{LITERAL}: {{0}}[15:0];\0A
|
||||
//CHECK-SAME: end"
|
||||
//CHECK-SAME: {symbols = [#hw.innerNameRef<@FIRRTLMem_1_1_1_16_10_0_1_0_0::@[[_RANDOM_MEM]]>]}
|
||||
//CHECK: sv.for %i = %c0_i4 to %c-6_i4 step %c1_i4 : i4 {
|
||||
//CHECK: sv.for %j = %c0_i6 to %c-32_i6 step %c-32_i6_2 : i6 {
|
||||
//CHECK: %RANDOM = sv.macro.ref.se< "RANDOM"> : i32
|
||||
//CHECK: %[[PART_SELECT:.+]] = sv.indexed_part_select_inout %_RANDOM_MEM[%j : 32] : !hw.inout<i32>, i6
|
||||
//CHECK: sv.bpassign %[[PART_SELECT]], %RANDOM : i32
|
||||
//CHECK: }
|
||||
//CHECK: %[[MEM_INDEX:.+]] = sv.array_index_inout %Memory[%i] : !hw.inout<uarray<10xi16>>, i4
|
||||
//CHECK: %[[READ:.+]] = sv.read_inout %_RANDOM_MEM : !hw.inout<i32>
|
||||
//CHECK: %[[EXTRACT:.+]] = comb.extract %[[READ]] from 0 : (i32) -> i16
|
||||
//CHECK: sv.bpassign %[[MEM_INDEX]], %[[EXTRACT]] : i16
|
||||
//CHECK: }
|
||||
//CHECK-NEXT: }
|
||||
//CHECK-NEXT: sv.ifdef.procedural "RANDOMIZE_REG_INIT" {
|
||||
//CHECK-NEXT: }
|
||||
|
@ -294,7 +296,9 @@ hw.module.generated @PR2769, @FIRRTLMem(%ro_addr_0: i4, %ro_en_0: i1, %ro_clock_
|
|||
|
||||
// COMMON-LABEL: hw.module @RandomizeWeirdWidths
|
||||
// CHECK: sv.ifdef.procedural "RANDOMIZE_MEM_INIT"
|
||||
// CHECK-NEXT{LITERAL}: sv.verbatim "for (initvar = 0; initvar < 10; initvar = initvar + 1) begin\0A {{0}} = {{`RANDOM}, {`RANDOM}, {`RANDOM}, {`RANDOM}, {`RANDOM}};\0A Memory[initvar] = {{0}}[144:0];\0Aend"
|
||||
// CHECK: %[[INOUT:.+]] = sv.array_index_inout %Memory[%i]
|
||||
// CHECK: %[[EXTRACT:.+]] = comb.extract %{{.+}} from 0 : (i160) -> i145
|
||||
// CHECK-NEXT: sv.bpassign %[[INOUT]], %[[EXTRACT]] : i145
|
||||
hw.module.generated @RandomizeWeirdWidths, @FIRRTLMem(%ro_addr_0: i4, %ro_en_0: i1, %ro_clock_0: i1,%rw_addr_0: i4, %rw_en_0: i1, %rw_clock_0: i1, %rw_wmode_0: i1, %rw_wdata_0: i145, %wo_addr_0: i4, %wo_en_0: i1, %wo_clock_0: i1, %wo_data_0: i145) -> (ro_data_0: i145, rw_rdata_0: i145) attributes {depth = 10 : i64, numReadPorts = 1 : ui32, numReadWritePorts = 1 : ui32, numWritePorts = 1 : ui32, readLatency = 2 : ui32, readUnderWrite = 0 : ui32, width = 145 : ui32, writeClockIDs = [], writeLatency = 4 : ui32, writeUnderWrite = 0 : i32, initFilename = "", initIsBinary = false, initIsInline = false}
|
||||
|
||||
// COMMON-LABEL: hw.module @ReadWriteWithHighReadLatency
|
||||
|
|
|
@ -72,46 +72,37 @@ hw.module @lowering(%clk: i1, %rst: i1, %in: i32) -> (a: i32, b: i32, c: i32, d:
|
|||
// CHECK-NEXT: sv.verbatim "`INIT_RANDOM_PROLOG_"
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: sv.ifdef.procedural "RANDOMIZE_REG_INIT" {
|
||||
// CHECK-NEXT: %_RANDOM_0 = sv.logic : !hw.inout<i32>
|
||||
// CHECK-NEXT: %RANDOM = sv.macro.ref.se< "RANDOM"> : i32
|
||||
// CHECK-NEXT: sv.bpassign %_RANDOM_0, %RANDOM : i32
|
||||
// CHECK-NEXT: %_RANDOM_1 = sv.logic : !hw.inout<i32>
|
||||
// CHECK-NEXT: %RANDOM_0 = sv.macro.ref.se< "RANDOM"> : i32
|
||||
// CHECK-NEXT: sv.bpassign %_RANDOM_1, %RANDOM_0 : i32
|
||||
// CHECK-NEXT: %_RANDOM_2 = sv.logic : !hw.inout<i32>
|
||||
// CHECK-NEXT: %RANDOM_1 = sv.macro.ref.se< "RANDOM"> : i32
|
||||
// CHECK-NEXT: sv.bpassign %_RANDOM_2, %RANDOM_1 : i32
|
||||
// CHECK-NEXT: %_RANDOM_3 = sv.logic : !hw.inout<i32>
|
||||
// CHECK-NEXT: %RANDOM_2 = sv.macro.ref.se< "RANDOM"> : i32
|
||||
// CHECK-NEXT: sv.bpassign %_RANDOM_3, %RANDOM_2 : i32
|
||||
// CHECK-NEXT: %_RANDOM_4 = sv.logic : !hw.inout<i32>
|
||||
// CHECK-NEXT: %RANDOM_3 = sv.macro.ref.se< "RANDOM"> : i32
|
||||
// CHECK-NEXT: sv.bpassign %_RANDOM_4, %RANDOM_3 : i32
|
||||
// CHECK-NEXT: %_RANDOM_5 = sv.logic : !hw.inout<i32>
|
||||
// CHECK-NEXT: %RANDOM_4 = sv.macro.ref.se< "RANDOM"> : i32
|
||||
// CHECK-NEXT: sv.bpassign %_RANDOM_5, %RANDOM_4 : i32
|
||||
// CHECK-NEXT: %_RANDOM_6 = sv.logic : !hw.inout<i32>
|
||||
// CHECK-NEXT: %RANDOM_5 = sv.macro.ref.se< "RANDOM"> : i32
|
||||
// CHECK-NEXT: sv.bpassign %_RANDOM_6, %RANDOM_5 : i32
|
||||
// CHECK-NEXT: %_RANDOM_7 = sv.logic : !hw.inout<i32>
|
||||
// CHECK-NEXT: %RANDOM_6 = sv.macro.ref.se< "RANDOM"> : i32
|
||||
// CHECK-NEXT: sv.bpassign %_RANDOM_7, %RANDOM_6 : i32
|
||||
// CHECK-NEXT: %8 = sv.read_inout %_RANDOM_0 : !hw.inout<i32>
|
||||
// CHECK-NEXT: sv.bpassign %rA, %8 : i32
|
||||
// CHECK-NEXT: %9 = sv.read_inout %_RANDOM_1 : !hw.inout<i32>
|
||||
// CHECK-NEXT: sv.bpassign %rB, %9 : i32
|
||||
// CHECK-NEXT: %10 = sv.read_inout %_RANDOM_2 : !hw.inout<i32>
|
||||
// CHECK-NEXT: sv.bpassign %rC, %10 : i32
|
||||
// CHECK-NEXT: %11 = sv.read_inout %_RANDOM_3 : !hw.inout<i32>
|
||||
// CHECK-NEXT: sv.bpassign %rD, %11 : i32
|
||||
// CHECK-NEXT: %12 = sv.read_inout %_RANDOM_4 : !hw.inout<i32>
|
||||
// CHECK-NEXT: sv.bpassign %rE, %12 : i32
|
||||
// CHECK-NEXT: %13 = sv.read_inout %_RANDOM_5 : !hw.inout<i32>
|
||||
// CHECK-NEXT: sv.bpassign %rF, %13 : i32
|
||||
// CHECK-NEXT: %14 = sv.read_inout %_RANDOM_6 : !hw.inout<i32>
|
||||
// CHECK-NEXT: sv.bpassign %rAnamed, %14 : i32
|
||||
// CHECK-NEXT: %15 = sv.read_inout %_RANDOM_7 : !hw.inout<i32>
|
||||
// CHECK-NEXT: sv.bpassign %rNoSym, %15 : i32
|
||||
// CHECK-NEXT: %_RANDOM = sv.logic : !hw.inout<uarray<8xi32>>
|
||||
// CHECK-NEXT: sv.for %i = %c0_i4 to %c-8_i4 step %c1_i4 : i4 {
|
||||
// CHECK-NEXT: %RANDOM = sv.macro.ref.se< "RANDOM"> : i32
|
||||
// CHECK-NEXT: %24 = comb.extract %i from 0 : (i4) -> i3
|
||||
// CHECK-NEXT: %25 = sv.array_index_inout %_RANDOM[%24] : !hw.inout<uarray<8xi32>>, i3
|
||||
// CHECK-NEXT: sv.bpassign %25, %RANDOM : i32
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: %8 = sv.array_index_inout %_RANDOM[%c0_i3] : !hw.inout<uarray<8xi32>>, i3
|
||||
// CHECK-NEXT: %9 = sv.array_index_inout %_RANDOM[%c1_i3] : !hw.inout<uarray<8xi32>>, i3
|
||||
// CHECK-NEXT: %10 = sv.array_index_inout %_RANDOM[%c2_i3] : !hw.inout<uarray<8xi32>>, i3
|
||||
// CHECK-NEXT: %11 = sv.array_index_inout %_RANDOM[%c3_i3] : !hw.inout<uarray<8xi32>>, i3
|
||||
// CHECK-NEXT: %12 = sv.array_index_inout %_RANDOM[%c-4_i3] : !hw.inout<uarray<8xi32>>, i3
|
||||
// CHECK-NEXT: %13 = sv.array_index_inout %_RANDOM[%c-3_i3] : !hw.inout<uarray<8xi32>>, i3
|
||||
// CHECK-NEXT: %14 = sv.array_index_inout %_RANDOM[%c-2_i3] : !hw.inout<uarray<8xi32>>, i3
|
||||
// CHECK-NEXT: %15 = sv.array_index_inout %_RANDOM[%c-1_i3] : !hw.inout<uarray<8xi32>>, i3
|
||||
// CHECK-NEXT: %16 = sv.read_inout %8 : !hw.inout<i32>
|
||||
// CHECK-NEXT: sv.bpassign %rA, %16 : i32
|
||||
// CHECK-NEXT: %17 = sv.read_inout %9 : !hw.inout<i32>
|
||||
// CHECK-NEXT: sv.bpassign %rB, %17 : i32
|
||||
// CHECK-NEXT: %18 = sv.read_inout %10 : !hw.inout<i32>
|
||||
// CHECK-NEXT: sv.bpassign %rC, %18 : i32
|
||||
// CHECK-NEXT: %19 = sv.read_inout %11 : !hw.inout<i32>
|
||||
// CHECK-NEXT: sv.bpassign %rD, %19 : i32
|
||||
// CHECK-NEXT: %20 = sv.read_inout %12 : !hw.inout<i32>
|
||||
// CHECK-NEXT: sv.bpassign %rE, %20 : i32
|
||||
// CHECK-NEXT: %21 = sv.read_inout %13 : !hw.inout<i32>
|
||||
// CHECK-NEXT: sv.bpassign %rF, %21 : i32
|
||||
// CHECK-NEXT: %22 = sv.read_inout %14 : !hw.inout<i32>
|
||||
// CHECK-NEXT: sv.bpassign %rAnamed, %22 : i32
|
||||
// CHECK-NEXT: %23 = sv.read_inout %15 : !hw.inout<i32>
|
||||
// CHECK-NEXT: sv.bpassign %rNoSym, %23 : i32
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: sv.if %rst {
|
||||
// CHECK-NEXT: sv.bpassign %rC, %c0_i32 : i32
|
||||
|
@ -161,14 +152,19 @@ hw.module private @UninitReg1(%clock: i1, %reset: i1, %cond: i1, %value: i2) {
|
|||
// CHECK-NEXT: sv.ifdef.procedural "INIT_RANDOM_PROLOG_" {
|
||||
// CHECK-NEXT: sv.verbatim "`INIT_RANDOM_PROLOG_"
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: sv.ifdef.procedural "RANDOMIZE_REG_INIT" {
|
||||
// CHECK-NEXT: %_RANDOM_0 = sv.logic : !hw.inout<i32>
|
||||
// CHECK-NEXT: %RANDOM = sv.macro.ref.se< "RANDOM"> : i32
|
||||
// CHECK-NEXT: sv.bpassign %_RANDOM_0, %RANDOM : i32
|
||||
// CHECK-NEXT: %3 = sv.read_inout %_RANDOM_0 : !hw.inout<i32>
|
||||
// CHECK-NEXT: %4 = comb.extract %3 from 0 : (i32) -> i2
|
||||
// CHECK-NEXT: sv.bpassign %count, %4 : i2
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: sv.ifdef.procedural "RANDOMIZE_REG_INIT" {
|
||||
// CHECK-NEXT: %_RANDOM = sv.logic : !hw.inout<uarray<1xi32>>
|
||||
// CHECK: sv.for %i = %{{false.*}} to %{{true.*}} step %{{true.*}} : i1 {
|
||||
// CHECK-NEXT: %RANDOM = sv.macro.ref.se< "RANDOM"> : i32
|
||||
// CHECK-NEXT: %6 = comb.extract %i from 0 : (i1) -> i0
|
||||
// CHECK-NEXT: %7 = sv.array_index_inout %_RANDOM[%6] : !hw.inout<uarray<1xi32>>, i0
|
||||
// CHECK-NEXT: sv.bpassign %7, %RANDOM : i32
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: %3 = sv.array_index_inout %_RANDOM[%c0_i0] : !hw.inout<uarray<1xi32>>, i0
|
||||
// CHECK-NEXT: %4 = sv.read_inout %3 : !hw.inout<i32>
|
||||
// CHECK-NEXT: %5 = comb.extract %4 from 0 : (i32) -> i2
|
||||
// CHECK-NEXT: sv.bpassign %count, %5 : i2
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: sv.ifdef "FIRRTL_AFTER_INITIAL" {
|
||||
// CHECK-NEXT: sv.verbatim "`FIRRTL_AFTER_INITIAL"
|
||||
|
@ -267,21 +263,21 @@ hw.module private @InitReg1(%clock: i1, %reset: i1, %io_d: i32, %io_en: i1) -> (
|
|||
// CHECK-NEXT: sv.verbatim "`INIT_RANDOM_PROLOG_"
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: sv.ifdef.procedural "RANDOMIZE_REG_INIT" {
|
||||
// CHECK-NEXT: %_RANDOM_0 = sv.logic : !hw.inout<i32>
|
||||
// CHECK-NEXT: %RANDOM = sv.macro.ref.se< "RANDOM"> : i32
|
||||
// CHECK-NEXT: sv.bpassign %_RANDOM_0, %RANDOM : i32
|
||||
// CHECK-NEXT: %_RANDOM_1 = sv.logic : !hw.inout<i32>
|
||||
// CHECK-NEXT: %RANDOM_0 = sv.macro.ref.se< "RANDOM"> : i32
|
||||
// CHECK-NEXT: sv.bpassign %_RANDOM_1, %RANDOM_0 : i32
|
||||
// CHECK-NEXT: %_RANDOM_2 = sv.logic : !hw.inout<i32>
|
||||
// CHECK-NEXT: %RANDOM_1 = sv.macro.ref.se< "RANDOM"> : i32
|
||||
// CHECK-NEXT: sv.bpassign %_RANDOM_2, %RANDOM_1 : i32
|
||||
// CHECK-NEXT: %8 = sv.read_inout %_RANDOM_0 : !hw.inout<i32>
|
||||
// CHECK-NEXT: sv.bpassign %reg, %8 : i32
|
||||
// CHECK-NEXT: %9 = sv.read_inout %_RANDOM_1 : !hw.inout<i32>
|
||||
// CHECK-NEXT: sv.bpassign %reg2, %9 : i32
|
||||
// CHECK-NEXT: %10 = sv.read_inout %_RANDOM_2 : !hw.inout<i32>
|
||||
// CHECK-NEXT: sv.bpassign %reg3, %10 : i32
|
||||
// CHECK-NEXT: %_RANDOM = sv.logic : !hw.inout<uarray<3xi32>>
|
||||
// CHECK-NEXT: sv.for %i = %c0_i2 to %c-1_i2 step %c1_i2 : i2 {
|
||||
// CHECK-NEXT: %RANDOM = sv.macro.ref.se< "RANDOM"> : i32
|
||||
// CHECK-NEXT: %14 = sv.array_index_inout %_RANDOM[%i] : !hw.inout<uarray<3xi32>>, i2
|
||||
// CHECK-NEXT: sv.bpassign %14, %RANDOM : i32
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: %8 = sv.array_index_inout %_RANDOM[%c0_i2] : !hw.inout<uarray<3xi32>>, i2
|
||||
// CHECK-NEXT: %9 = sv.array_index_inout %_RANDOM[%c1_i2] : !hw.inout<uarray<3xi32>>, i2
|
||||
// CHECK-NEXT: %10 = sv.array_index_inout %_RANDOM[%c-2_i2] : !hw.inout<uarray<3xi32>>, i2
|
||||
// CHECK-NEXT: %11 = sv.read_inout %8 : !hw.inout<i32>
|
||||
// CHECK-NEXT: sv.bpassign %reg, %11 : i32
|
||||
// CHECK-NEXT: %12 = sv.read_inout %9 : !hw.inout<i32>
|
||||
// CHECK-NEXT: sv.bpassign %reg2, %12 : i32
|
||||
// CHECK-NEXT: %13 = sv.read_inout %10 : !hw.inout<i32>
|
||||
// CHECK-NEXT: sv.bpassign %reg3, %13 : i32
|
||||
// CHECK-NEXT: }
|
||||
// COMMON-NEXT: sv.if %reset {
|
||||
// COMMON-NEXT: sv.bpassign %reg, %c0_i32 : i32
|
||||
|
@ -315,18 +311,21 @@ hw.module private @UninitReg42(%clock: i1, %reset: i1, %cond: i1, %value: i42) {
|
|||
// CHECK-NEXT: sv.ifdef.procedural "INIT_RANDOM_PROLOG_" {
|
||||
// CHECK-NEXT: sv.verbatim "`INIT_RANDOM_PROLOG_"
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: sv.ifdef.procedural "RANDOMIZE_REG_INIT" {
|
||||
// CHECK-NEXT: %_RANDOM_0 = sv.logic : !hw.inout<i32>
|
||||
// CHECK-NEXT: %RANDOM = sv.macro.ref.se< "RANDOM"> : i32
|
||||
// CHECK-NEXT: sv.bpassign %_RANDOM_0, %RANDOM : i32
|
||||
// CHECK-NEXT: %_RANDOM_1 = sv.logic : !hw.inout<i32>
|
||||
// CHECK-NEXT: %RANDOM_0 = sv.macro.ref.se< "RANDOM"> : i32
|
||||
// CHECK-NEXT: sv.bpassign %_RANDOM_1, %RANDOM_0 : i32
|
||||
// CHECK-NEXT: %3 = sv.read_inout %_RANDOM_0 : !hw.inout<i32>
|
||||
// CHECK-NEXT: %4 = sv.read_inout %_RANDOM_1 : !hw.inout<i32>
|
||||
// CHECK-NEXT: %5 = comb.extract %4 from 0 : (i32) -> i10
|
||||
// CHECK-NEXT: %6 = comb.concat %3, %5 : i32, i10
|
||||
// CHECK-NEXT: sv.bpassign %count, %6 : i42
|
||||
// CHECK-NEXT: sv.ifdef.procedural "RANDOMIZE_REG_INIT" {
|
||||
// CHECK-NEXT: %_RANDOM = sv.logic : !hw.inout<uarray<2xi32>>
|
||||
// CHECK-NEXT: sv.for %i = %c0_i2 to %c-2_i2 step %c1_i2 : i2 {
|
||||
// CHECK-NEXT: %RANDOM = sv.macro.ref.se< "RANDOM"> : i32
|
||||
// CHECK-NEXT: %9 = comb.extract %i from 0 : (i2) -> i1
|
||||
// CHECK-NEXT: %10 = sv.array_index_inout %_RANDOM[%9] : !hw.inout<uarray<2xi32>>, i1
|
||||
// CHECK-NEXT: sv.bpassign %10, %RANDOM : i32
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: %3 = sv.array_index_inout %_RANDOM[%false] : !hw.inout<uarray<2xi32>>, i1
|
||||
// CHECK-NEXT: %4 = sv.array_index_inout %_RANDOM[%true] : !hw.inout<uarray<2xi32>>, i1
|
||||
// CHECK-NEXT: %5 = sv.read_inout %3 : !hw.inout<i32>
|
||||
// CHECK-NEXT: %6 = sv.read_inout %4 : !hw.inout<i32>
|
||||
// CHECK-NEXT: %7 = comb.extract %6 from 0 : (i32) -> i10
|
||||
// CHECK-NEXT: %8 = comb.concat %5, %7 : i32, i10
|
||||
// CHECK-NEXT: sv.bpassign %count, %8 : i42
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: sv.ifdef "FIRRTL_AFTER_INITIAL" {
|
||||
|
@ -338,53 +337,6 @@ hw.module private @UninitReg42(%clock: i1, %reset: i1, %cond: i1, %value: i42) {
|
|||
hw.output
|
||||
}
|
||||
|
||||
// COMMON-LABEL: hw.module private @regInitRandomReuse
|
||||
hw.module private @regInitRandomReuse(%clock: i1, %a: i1) -> (o1: i2, o2: i4, o3: i32, o4: i100) {
|
||||
%c0_i99 = hw.constant 0 : i99
|
||||
%c0_i31 = hw.constant 0 : i31
|
||||
%c0_i3 = hw.constant 0 : i3
|
||||
%false = hw.constant false
|
||||
%r1 = seq.firreg %0 clock %clock sym @__r1__ : i2
|
||||
%r2 = seq.firreg %1 clock %clock sym @__r2__ : i4
|
||||
%r3 = seq.firreg %2 clock %clock sym @__r3__ : i32
|
||||
%r4 = seq.firreg %3 clock %clock sym @__r4__ : i100
|
||||
%0 = comb.concat %false, %a : i1, i1
|
||||
%1 = comb.concat %c0_i3, %a : i3, i1
|
||||
%2 = comb.concat %c0_i31, %a : i31, i1
|
||||
%3 = comb.concat %c0_i99, %a : i99, i1
|
||||
// CHECK: %r1 = sv.reg sym @[[r1_sym:[_A-Za-z0-9]+]]
|
||||
// CHECK: %r2 = sv.reg sym @[[r2_sym:[_A-Za-z0-9]+]]
|
||||
// CHECK: %r3 = sv.reg sym @[[r3_sym:[_A-Za-z0-9]+]]
|
||||
// CHECK: %r4 = sv.reg sym @[[r4_sym:[_A-Za-z0-9]+]]
|
||||
// CHECK: sv.ifdef "SYNTHESIS" {
|
||||
// CHECK-NEXT: } else {
|
||||
// CHECK-NEXT: sv.ordered {
|
||||
// CHECK-NEXT: sv.ifdef "FIRRTL_BEFORE_INITIAL" {
|
||||
// CHECK-NEXT: sv.verbatim "`FIRRTL_BEFORE_INITIAL"
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: sv.initial {
|
||||
// CHECK-NEXT: sv.ifdef.procedural "INIT_RANDOM_PROLOG_" {
|
||||
// CHECK-NEXT: sv.verbatim "`INIT_RANDOM_PROLOG_"
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: sv.ifdef.procedural "RANDOMIZE_REG_INIT" {
|
||||
// CHECK: %9 = comb.extract %8 from 0 : (i32) -> i2
|
||||
// CHECK: %11 = comb.extract %10 from 2 : (i32) -> i4
|
||||
// CHECK: %13 = comb.extract %12 from 6 : (i32) -> i26
|
||||
// CHECK: %15 = comb.extract %14 from 0 : (i32) -> i6
|
||||
// CHECK: %16 = comb.concat %13, %15 : i26, i6
|
||||
// CHECK: %18 = comb.extract %17 from 6 : (i32) -> i26
|
||||
// CHECK: %22 = comb.extract %21 from 0 : (i32) -> i10
|
||||
// CHECK: %23 = comb.concat %18, %19, %20, %22 : i26, i32, i32, i10
|
||||
// CHECK: }
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: sv.ifdef "FIRRTL_AFTER_INITIAL" {
|
||||
// CHECK-NEXT: sv.verbatim "`FIRRTL_AFTER_INITIAL"
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: }
|
||||
hw.output %r1, %r2, %r3, %r4 : i2, i4, i32, i100
|
||||
}
|
||||
|
||||
// COMMON-LABEL: hw.module private @init1DVector
|
||||
hw.module private @init1DVector(%clock: i1, %a: !hw.array<2xi1>) -> (b: !hw.array<2xi1>) {
|
||||
%r = seq.firreg %a clock %clock sym @__r__ : !hw.array<2xi1>
|
||||
|
@ -407,14 +359,23 @@ hw.module private @init1DVector(%clock: i1, %a: !hw.array<2xi1>) -> (b: !hw.arra
|
|||
// CHECK-NEXT: sv.verbatim "`INIT_RANDOM_PROLOG_"
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: sv.ifdef.procedural "RANDOMIZE_REG_INIT" {
|
||||
// CHECK: %1 = sv.read_inout %_RANDOM_0 : !hw.inout<i32>
|
||||
// CHECK-NEXT: %2 = comb.extract %1 from 0 : (i32) -> i2
|
||||
// CHECK-NEXT: %3 = sv.array_index_inout %r[%false] : !hw.inout<array<2xi1>>, i1
|
||||
// CHECK-NEXT: %4 = comb.extract %2 from 1 : (i2) -> i1
|
||||
// CHECK-NEXT: sv.bpassign %3, %4 : i1
|
||||
// CHECK-NEXT: %5 = sv.array_index_inout %r[%true] : !hw.inout<array<2xi1>>, i1
|
||||
// CHECK-NEXT: %6 = comb.extract %2 from 0 : (i2) -> i1
|
||||
// CHECK-NEXT: sv.bpassign %5, %6 : i1
|
||||
// CHECK-NEXT: %_RANDOM = sv.logic : !hw.inout<uarray<1xi32>>
|
||||
// CHECK-NEXT: sv.for %i = %false to %true step %true : i1 {
|
||||
// CHECK-NEXT: %RANDOM = sv.macro.ref.se< "RANDOM"> : i32
|
||||
// CHECK-NEXT: %8 = comb.extract %i from 0 : (i1) -> i0
|
||||
// CHECK-NEXT: %9 = sv.array_index_inout %_RANDOM[%8] : !hw.inout<uarray<1xi32>>, i0
|
||||
// CHECK-NEXT: sv.bpassign %9, %RANDOM : i32
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: %1 = sv.array_index_inout %_RANDOM[%c0_i0] : !hw.inout<uarray<1xi32>>, i0
|
||||
// CHECK-NEXT: %2 = sv.read_inout %1 : !hw.inout<i32>
|
||||
// CHECK-NEXT: %3 = comb.extract %2 from 0 : (i32) -> i2
|
||||
// CHECK-NEXT: %4 = sv.array_index_inout %r[%false] : !hw.inout<array<2xi1>>, i1
|
||||
// CHECK-NEXT: %5 = comb.extract %3 from 1 : (i2) -> i1
|
||||
// CHECK-NEXT: sv.bpassign %4, %5 : i1
|
||||
// CHECK-NEXT: %6 = sv.array_index_inout %r[%true] : !hw.inout<array<2xi1>>, i1
|
||||
// CHECK-NEXT: %7 = comb.extract %3 from 0 : (i2) -> i1
|
||||
// CHECK-NEXT: sv.bpassign %6, %7 : i1
|
||||
|
||||
// CHECK: }
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: sv.ifdef "FIRRTL_AFTER_INITIAL" {
|
||||
|
@ -445,10 +406,19 @@ hw.module private @init2DVector(%clock: i1, %a: !hw.array<1xarray<1xi1>>) -> (b:
|
|||
// CHECK-NEXT: sv.verbatim "`INIT_RANDOM_PROLOG_"
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: sv.ifdef.procedural "RANDOMIZE_REG_INIT" {
|
||||
// CHECK: %2 = comb.extract %1 from 0 : (i32) -> i1
|
||||
// CHECK-NEXT: %3 = sv.array_index_inout %r[%c0_i0] : !hw.inout<array<1xarray<1xi1>>>, i0
|
||||
// CHECK-NEXT: %4 = sv.array_index_inout %3[%c0_i0] : !hw.inout<array<1xi1>>, i0
|
||||
// CHECK-NEXT: sv.bpassign %4, %2 : i1
|
||||
// CHECK-NEXT: %_RANDOM = sv.logic : !hw.inout<uarray<1xi32>>
|
||||
// CHECK-NEXT: sv.for %i = %false to %true step %true : i1 {
|
||||
// CHECK-NEXT: %RANDOM = sv.macro.ref.se< "RANDOM"> : i32
|
||||
// CHECK-NEXT: %6 = comb.extract %i from 0 : (i1) -> i0
|
||||
// CHECK-NEXT: %7 = sv.array_index_inout %_RANDOM[%6] : !hw.inout<uarray<1xi32>>, i0
|
||||
// CHECK-NEXT: sv.bpassign %7, %RANDOM : i32
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: %1 = sv.array_index_inout %_RANDOM[%c0_i0] : !hw.inout<uarray<1xi32>>, i0
|
||||
// CHECK-NEXT: %2 = sv.read_inout %1 : !hw.inout<i32>
|
||||
// CHECK-NEXT: %3 = comb.extract %2 from 0 : (i32) -> i1
|
||||
// CHECK-NEXT: %4 = sv.array_index_inout %r[%c0_i0] : !hw.inout<array<1xarray<1xi1>>>, i0
|
||||
// CHECK-NEXT: %5 = sv.array_index_inout %4[%c0_i0] : !hw.inout<array<1xi1>>, i0
|
||||
// CHECK-NEXT: sv.bpassign %5, %3 : i1
|
||||
// CHECK: }
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: sv.ifdef "FIRRTL_AFTER_INITIAL" {
|
||||
|
@ -477,9 +447,9 @@ hw.module private @initStruct(%clock: i1) {
|
|||
// CHECK-NEXT: sv.verbatim "`INIT_RANDOM_PROLOG_"
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: sv.ifdef.procedural "RANDOMIZE_REG_INIT" {
|
||||
// CHECK: %2 = comb.extract %1 from 0 : (i32) -> i1
|
||||
// CHECK-NEXT: %3 = sv.struct_field_inout %r["a"] : !hw.inout<struct<a: i1>>
|
||||
// CHECK-NEXT: sv.bpassign %3, %2 : i1
|
||||
// CHECK: %[[EXTRACT:.*]] = comb.extract %{{.*}} from 0 : (i32) -> i1
|
||||
// CHECK-NEXT: %[[INOUT:.*]] = sv.struct_field_inout %r["a"] : !hw.inout<struct<a: i1>>
|
||||
// CHECK-NEXT: sv.bpassign %[[INOUT]], %[[EXTRACT]] : i1
|
||||
// CHECK: }
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: sv.ifdef "FIRRTL_AFTER_INITIAL" {
|
||||
|
|
|
@ -26,39 +26,26 @@ circuit Foo:
|
|||
|
||||
q <= r
|
||||
|
||||
; ALL: automatic logic [31:0] _RANDOM_0;
|
||||
; ALL-NEXT: automatic logic [31:0] _RANDOM_1;
|
||||
; ALL-NEXT: automatic logic [31:0] _RANDOM_2;
|
||||
; ALL-NEXT: automatic logic [31:0] _RANDOM_3;
|
||||
; ALL: _RANDOM_0 = `RANDOM;
|
||||
; ALL-NEXT: _RANDOM_1 = `RANDOM;
|
||||
; ALL-NEXT: _RANDOM_2 = `RANDOM;
|
||||
; ALL-NEXT: _RANDOM_3 = `RANDOM;
|
||||
; ALL: automatic logic [31:0] _RANDOM[0:3];
|
||||
; ALL: for (logic [2:0] i = 3'h0; i < 3'h4; i += 3'h1) begin
|
||||
; ALL-NEXT: _RANDOM[i[1:0]] = `RANDOM;
|
||||
|
||||
; NAMED: automatic logic [31:0] _RANDOM_0;
|
||||
; NAMED-NEXT: automatic logic [31:0] _RANDOM_1;
|
||||
; NAMED-NEXT: automatic logic [31:0] _RANDOM_2;
|
||||
; NAMED-NEXT: automatic logic [31:0] _RANDOM_3;
|
||||
; NAMED: _RANDOM_0 = `RANDOM;
|
||||
; NAMED-NEXT: _RANDOM_1 = `RANDOM;
|
||||
; NAMED-NEXT: _RANDOM_2 = `RANDOM;
|
||||
; NAMED-NEXT: _RANDOM_3 = `RANDOM;
|
||||
; NAMED: automatic logic [31:0] _RANDOM[0:3];
|
||||
; NAMED: for (logic [2:0] i = 3'h0; i < 3'h4; i += 3'h1) begin
|
||||
; NAMED-NEXT: _RANDOM[i[1:0]] = `RANDOM;
|
||||
|
||||
; NONE: automatic logic [31:0] _RANDOM_0;
|
||||
; NONE-NEXT: automatic logic [31:0] _RANDOM_1;
|
||||
; NONE-NEXT: automatic logic [31:0] _RANDOM_2;
|
||||
; NONE: _RANDOM_0 = `RANDOM;
|
||||
; NONE-NEXT: _RANDOM_1 = `RANDOM;
|
||||
; NONE-NEXT: _RANDOM_2 = `RANDOM;
|
||||
; NONE: automatic logic [31:0] _RANDOM[0:2];
|
||||
; NONE: for (logic [1:0] i = 2'h0; i < 2'h3; i += 2'h1) begin
|
||||
; NONE-NEXT: _RANDOM[i] = `RANDOM;
|
||||
|
||||
; ALL: _r = {_RANDOM_0, _RANDOM_1[0]};
|
||||
; ALL: _r = {_RANDOM[2'h0], _RANDOM[2'h1][0]};
|
||||
; NAMED-NOT: _r =
|
||||
; NONE-NOT: _r =
|
||||
|
||||
; ALL: r = {_RANDOM_1[31:1], _RANDOM_2[1:0]};
|
||||
; NAMED: r = {_RANDOM_1[31:1], _RANDOM_2[1:0]};
|
||||
; NONE: r = {_RANDOM_1[31:1], _RANDOM_2[1:0]};
|
||||
; ALL: r = {_RANDOM[2'h1][31:1], _RANDOM[2'h2][1:0]};
|
||||
; NAMED: r = {_RANDOM[2'h1][31:1], _RANDOM[2'h2][1:0]};
|
||||
; NONE: r = {_RANDOM[2'h1][31:1], _RANDOM[2'h2][1:0]};
|
||||
|
||||
; ALL: s = {_RANDOM_2[31:2], _RANDOM_3[2:0]};
|
||||
; NAMED: s = {_RANDOM_2[31:2], _RANDOM_3[2:0]};
|
||||
; ALL: s = {_RANDOM[2'h2][31:2], _RANDOM[2'h3][2:0]};
|
||||
; NAMED: s = {_RANDOM[2'h2][31:2], _RANDOM[2'h3][2:0]};
|
||||
; NONE-NOT: s = {{.*}};
|
||||
|
|
Loading…
Reference in New Issue