This commit is contained in:
parent
f4a01eb452
commit
0507fb4655
|
|
@ -2154,6 +2154,13 @@ The grammar of configuration commands is as follows:
|
|||
:option:`/*verilator&32;public_flat*/`, etc., metacomments. See
|
||||
also :ref:`VPI Example`.
|
||||
|
||||
.. option:: profile_data -hier-dpi "<function_name>" -cost <cost_value>
|
||||
|
||||
Internal profiling data inserted during :vlopt:`--hierarchical`; specifies
|
||||
execution cost of a hierarchical DPI wrappers for modules with
|
||||
:option:`/*verilator&32;hier_block*/` metacomment. See
|
||||
:ref:`Hierarchical Verilation`.
|
||||
|
||||
.. option:: profile_data -mtask "<mtask_hash>" -cost <cost_value>
|
||||
|
||||
Feeds profile-guided optimization data into the Verilator algorithms in
|
||||
|
|
|
|||
|
|
@ -643,6 +643,7 @@ class AstCFunc final : public AstNode {
|
|||
bool m_dpiImportWrapper : 1; // Wrapper for invoking DPI import prototype from generated code
|
||||
bool m_needProcess : 1; // Needs access to VlProcess of the caller
|
||||
bool m_recursive : 1; // Recursive or part of recursion
|
||||
int m_cost; // Function call cost
|
||||
public:
|
||||
AstCFunc(FileLine* fl, const string& name, AstScope* scopep, const string& rtnType = "")
|
||||
: ASTGEN_SUPER_CFunc(fl) {
|
||||
|
|
@ -671,6 +672,7 @@ public:
|
|||
m_dpiImportPrototype = false;
|
||||
m_dpiImportWrapper = false;
|
||||
m_recursive = false;
|
||||
m_cost = v3Global.opt.instrCountDpi(); // As proxy for unknown general DPI cost
|
||||
}
|
||||
ASTGEN_MEMBERS_AstCFunc;
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
|
|
@ -685,9 +687,7 @@ public:
|
|||
}
|
||||
//
|
||||
void name(const string& name) override { m_name = name; }
|
||||
int instrCount() const override {
|
||||
return dpiImportPrototype() ? v3Global.opt.instrCountDpi() : 0;
|
||||
}
|
||||
int instrCount() const override { return m_cost; }
|
||||
VBoolOrUnknown isConst() const { return m_isConst; }
|
||||
void isConst(bool flag) { m_isConst.setTrueOrFalse(flag); }
|
||||
void isConst(VBoolOrUnknown flag) { m_isConst = flag; }
|
||||
|
|
@ -746,6 +746,7 @@ public:
|
|||
bool isCoroutine() const { return m_rtnType == "VlCoroutine"; }
|
||||
void recursive(bool flag) { m_recursive = flag; }
|
||||
bool recursive() const { return m_recursive; }
|
||||
void cost(int cost) { m_cost = cost; }
|
||||
// Special methods
|
||||
bool emptyBody() const {
|
||||
return argsp() == nullptr && initsp() == nullptr && stmtsp() == nullptr
|
||||
|
|
|
|||
|
|
@ -533,11 +533,13 @@ public:
|
|||
// Resolve modules and files in the design
|
||||
|
||||
class V3ConfigResolver final {
|
||||
enum ProfileDataMode : uint8_t { NONE = 0, MTASK = 1, HIER_DPI = 2 };
|
||||
V3ConfigModuleResolver m_modules; // Access to module names (with wildcards)
|
||||
V3ConfigFileResolver m_files; // Access to file names (with wildcards)
|
||||
V3ConfigScopeTraceResolver m_scopeTraces; // Regexp to trace enables
|
||||
std::unordered_map<string, std::unordered_map<string, uint64_t>>
|
||||
m_profileData; // Access to profile_data records
|
||||
uint8_t m_mode = NONE;
|
||||
FileLine* m_profileFileLine = nullptr;
|
||||
|
||||
V3ConfigResolver() = default;
|
||||
|
|
@ -552,10 +554,21 @@ public:
|
|||
V3ConfigFileResolver& files() { return m_files; }
|
||||
V3ConfigScopeTraceResolver& scopeTraces() { return m_scopeTraces; }
|
||||
|
||||
void addProfileData(FileLine* fl, const string& model, const string& key, uint64_t cost) {
|
||||
void addProfileData(FileLine* fl, const string& hierDpi, uint64_t cost) {
|
||||
// Empty key for hierarchical DPI wrapper costs.
|
||||
addProfileData(fl, hierDpi, "", cost, HIER_DPI);
|
||||
}
|
||||
void addProfileData(FileLine* fl, const string& model, const string& key, uint64_t cost,
|
||||
ProfileDataMode mode = MTASK) {
|
||||
if (!m_profileFileLine) m_profileFileLine = fl;
|
||||
if (cost == 0) cost = 1; // Cost 0 means delete (or no data)
|
||||
m_profileData[model][key] += cost;
|
||||
m_mode |= mode;
|
||||
}
|
||||
bool containsMTaskProfileData() const { return m_mode & MTASK; }
|
||||
uint64_t getProfileData(const string& hierDpi) const {
|
||||
// Empty key for hierarchical DPI wrapper costs.
|
||||
return getProfileData(hierDpi, "");
|
||||
}
|
||||
uint64_t getProfileData(const string& model, const string& key) const {
|
||||
const auto mit = m_profileData.find(model);
|
||||
|
|
@ -619,6 +632,10 @@ void V3Config::addModulePragma(const string& module, VPragmaType pragma) {
|
|||
V3ConfigResolver::s().modules().at(module).addModulePragma(pragma);
|
||||
}
|
||||
|
||||
void V3Config::addProfileData(FileLine* fl, const string& hierDpi, uint64_t cost) {
|
||||
V3ConfigResolver::s().addProfileData(fl, hierDpi, cost);
|
||||
}
|
||||
|
||||
void V3Config::addProfileData(FileLine* fl, const string& model, const string& key,
|
||||
uint64_t cost) {
|
||||
V3ConfigResolver::s().addProfileData(fl, model, key, cost);
|
||||
|
|
@ -724,6 +741,9 @@ void V3Config::applyVarAttr(AstNodeModule* modulep, AstNodeFTask* ftaskp, AstVar
|
|||
if (vp) vp->apply(varp);
|
||||
}
|
||||
|
||||
uint64_t V3Config::getProfileData(const string& hierDpi) {
|
||||
return V3ConfigResolver::s().getProfileData(hierDpi);
|
||||
}
|
||||
uint64_t V3Config::getProfileData(const string& model, const string& key) {
|
||||
return V3ConfigResolver::s().getProfileData(model, key);
|
||||
}
|
||||
|
|
@ -736,6 +756,10 @@ bool V3Config::getScopeTraceOn(const string& scope) {
|
|||
|
||||
void V3Config::contentsPushText(const string& text) { return WildcardContents::pushText(text); }
|
||||
|
||||
bool V3Config::containsMTaskProfileData() {
|
||||
return V3ConfigResolver::s().containsMTaskProfileData();
|
||||
}
|
||||
|
||||
bool V3Config::waive(FileLine* filelinep, V3ErrorCode code, const string& message) {
|
||||
V3ConfigFile* filep = V3ConfigResolver::s().files().resolve(filelinep->filename());
|
||||
if (!filep) return false;
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ public:
|
|||
const string& match);
|
||||
static void addInline(FileLine* fl, const string& module, const string& ftask, bool on);
|
||||
static void addModulePragma(const string& module, VPragmaType pragma);
|
||||
static void addProfileData(FileLine* fl, const string& hierDpi, uint64_t cost);
|
||||
static void addProfileData(FileLine* fl, const string& model, const string& key,
|
||||
uint64_t cost);
|
||||
static void addScopeTraceOn(bool on, const string& scope, int levels);
|
||||
|
|
@ -51,12 +52,15 @@ public:
|
|||
static void applyModule(AstNodeModule* modulep);
|
||||
static void applyVarAttr(AstNodeModule* modulep, AstNodeFTask* ftaskp, AstVar* varp);
|
||||
|
||||
static uint64_t getProfileData(const string& hierDpi);
|
||||
static uint64_t getProfileData(const string& model, const string& key);
|
||||
static FileLine* getProfileDataFileLine();
|
||||
static bool getScopeTraceOn(const string& scope);
|
||||
|
||||
static void contentsPushText(const string& text);
|
||||
|
||||
static bool containsMTaskProfileData();
|
||||
|
||||
static bool waive(FileLine* filelinep, V3ErrorCode code, const string& message);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -528,9 +528,11 @@ void fillinCosts(V3Graph* execMTaskGraphp) {
|
|||
|
||||
if (missingProfiles) {
|
||||
if (FileLine* const fl = V3Config::getProfileDataFileLine()) {
|
||||
fl->v3warn(PROFOUTOFDATE, "Profile data for mtasks may be out of date. "
|
||||
<< missingProfiles << " of " << totalEstimates
|
||||
<< " mtasks had no data");
|
||||
if (V3Config::containsMTaskProfileData()) {
|
||||
fl->v3warn(PROFOUTOFDATE, "Profile data for mtasks may be out of date. "
|
||||
<< missingProfiles << " of " << totalEstimates
|
||||
<< " mtasks had no data");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1710,7 +1710,11 @@ class DpiImportCallVisitor final : public VNVisitor {
|
|||
if (nodep->dpiImportWrapper()) {
|
||||
if (nodep->dpiPure() ? !v3Global.opt.threadsDpiPure()
|
||||
: !v3Global.opt.threadsDpiUnpure()) {
|
||||
m_hasDpiHazard = true;
|
||||
// If hierarchical DPI wrapper cost is not found or is of a 0 cost,
|
||||
// we have a normal DPI which induces DPI hazard by default.
|
||||
m_hasDpiHazard = V3Config::getProfileData(nodep->cname()) == 0;
|
||||
UINFO(9, "DPI wrapper '" << nodep->cname()
|
||||
<< "' has dpi hazard = " << m_hasDpiHazard << endl);
|
||||
}
|
||||
}
|
||||
iterateChildren(nodep);
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
#include "V3ProtectLib.h"
|
||||
|
||||
#include "V3Hasher.h"
|
||||
#include "V3InstrCount.h"
|
||||
#include "V3String.h"
|
||||
#include "V3Task.h"
|
||||
|
||||
|
|
@ -98,6 +99,32 @@ class ProtectVisitor final : public VNVisitor {
|
|||
txtp->addNodesp(new AstComment{fl, comment});
|
||||
}
|
||||
|
||||
void configSection(AstNodeModule* modp, AstTextBlock* txtp, FileLine* fl) {
|
||||
txtp->addText(fl, "\n`ifdef VERILATOR\n");
|
||||
txtp->addText(fl, "`verilator_config\n");
|
||||
|
||||
// The `eval` function is called inside both update functions. As those functions
|
||||
// are created by text bashing, we need to find cost of `_eval` which is the first function
|
||||
// with a real cost in AST.
|
||||
uint32_t cost = 0;
|
||||
modp->foreach([&cost](AstCFunc* cfuncp) {
|
||||
if (cfuncp->name() == "_eval") cost = V3InstrCount::count(cfuncp, false);
|
||||
});
|
||||
txtp->addText(fl, "profile_data -hier-dpi \"" + m_libName
|
||||
+ "_protectlib_combo_update\" -cost 64'd" + std::to_string(cost)
|
||||
+ "\n");
|
||||
txtp->addText(fl, "profile_data -hier-dpi \"" + m_libName
|
||||
+ "_protectlib_seq_update\" -cost 64'd" + std::to_string(cost)
|
||||
+ "\n");
|
||||
|
||||
// Mark remaining NDA protectlib wrapper DPIs as non-hazardous by deliberately forwarding
|
||||
// them with non-zero cost.
|
||||
txtp->addText(fl, "profile_data -hier-dpi \"" + m_libName
|
||||
+ "_protectlib_combo_ignore\" -cost 64'd1\n");
|
||||
txtp->addText(fl, "`verilog\n");
|
||||
txtp->addText(fl, "`endif\n");
|
||||
}
|
||||
|
||||
void hashComment(AstTextBlock* txtp, FileLine* fl) {
|
||||
addComment(txtp, fl, "Checks to make sure the .sv wrapper and library agree");
|
||||
}
|
||||
|
|
@ -283,6 +310,9 @@ class ProtectVisitor final : public VNVisitor {
|
|||
txtp->addText(fl, "final " + m_libName + "_protectlib_final(handle__V);\n\n");
|
||||
|
||||
txtp->addText(fl, "endmodule\n");
|
||||
|
||||
configSection(modp, txtp, fl);
|
||||
|
||||
m_vfilep->tblockp(txtp);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
#include "V3Task.h"
|
||||
|
||||
#include "V3Config.h"
|
||||
#include "V3Const.h"
|
||||
#include "V3EmitCBase.h"
|
||||
#include "V3Graph.h"
|
||||
|
|
@ -372,6 +373,7 @@ class TaskVisitor final : public VNVisitor {
|
|||
// STATE - across all visitors
|
||||
DpiCFuncs m_dpiNames; // Map of all created DPI functions
|
||||
VDouble0 m_statInlines; // Statistic tracking
|
||||
VDouble0 m_statHierDpisWithCosts; // Statistic tracking
|
||||
|
||||
// METHODS
|
||||
|
||||
|
|
@ -980,6 +982,11 @@ class TaskVisitor final : public VNVisitor {
|
|||
funcp->isMethod(false);
|
||||
funcp->protect(false);
|
||||
funcp->dpiPure(nodep->dpiPure());
|
||||
|
||||
const int cost = static_cast<int>(V3Config::getProfileData(funcp->name()));
|
||||
m_statHierDpisWithCosts += (cost != 0);
|
||||
funcp->cost(cost);
|
||||
|
||||
// Add DPI Import to top, since it's a global function
|
||||
m_topScopep->scopep()->addBlocksp(funcp);
|
||||
makePortList(nodep, funcp);
|
||||
|
|
@ -1259,6 +1266,8 @@ class TaskVisitor final : public VNVisitor {
|
|||
if (nodep->name() == "new") cfuncp->isConstructor(true);
|
||||
if (cfuncp->dpiExportImpl()) cfuncp->cname(nodep->cname());
|
||||
|
||||
if (cfuncp->dpiImportWrapper()) cfuncp->cname(nodep->cname());
|
||||
|
||||
if (!nodep->dpiImport() && !nodep->taskPublic()) {
|
||||
// Need symbol table
|
||||
cfuncp->argTypes(EmitCBase::symClassVar());
|
||||
|
|
@ -1613,7 +1622,11 @@ public:
|
|||
: m_statep{statep} {
|
||||
iterate(nodep);
|
||||
}
|
||||
~TaskVisitor() { V3Stats::addStat("Optimizations, Functions inlined", m_statInlines); }
|
||||
~TaskVisitor() {
|
||||
V3Stats::addStat("Optimizations, Functions inlined", m_statInlines);
|
||||
V3Stats::addStat("Optimizations, Hierarchical DPI wrappers with costs",
|
||||
m_statHierDpisWithCosts);
|
||||
}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
|
|
|||
|
|
@ -141,6 +141,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
|
|||
-?"-cost" { FL; return yVLT_D_COST; }
|
||||
-?"-file" { FL; return yVLT_D_FILE; }
|
||||
-?"-function" { FL; return yVLT_D_FUNCTION; }
|
||||
-?"-hier-dpi" { FL; return yVLT_D_HIER_DPI; }
|
||||
-?"-levels" { FL; return yVLT_D_LEVELS; }
|
||||
-?"-lines" { FL; return yVLT_D_LINES; }
|
||||
-?"-match" { FL; return yVLT_D_MATCH; }
|
||||
|
|
|
|||
|
|
@ -492,6 +492,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"})
|
|||
%token<fl> yVLT_D_COST "--cost"
|
||||
%token<fl> yVLT_D_FILE "--file"
|
||||
%token<fl> yVLT_D_FUNCTION "--function"
|
||||
%token<fl> yVLT_D_HIER_DPI "--hier-dpi"
|
||||
%token<fl> yVLT_D_LEVELS "--levels"
|
||||
%token<fl> yVLT_D_LINES "--lines"
|
||||
%token<fl> yVLT_D_MATCH "--match"
|
||||
|
|
@ -7655,6 +7656,8 @@ vltItem:
|
|||
{ V3Config::addCaseParallel(*$2, 0); }
|
||||
| yVLT_PARALLEL_CASE vltDFile yVLT_D_LINES yaINTNUM
|
||||
{ V3Config::addCaseParallel(*$2, $4->toUInt()); }
|
||||
| yVLT_PROFILE_DATA vltDHierDpi vltDCost
|
||||
{ V3Config::addProfileData($<fl>1, *$2, $3->toUQuad()); }
|
||||
| yVLT_PROFILE_DATA vltDModel vltDMtask vltDCost
|
||||
{ V3Config::addProfileData($<fl>1, *$2, *$3, $4->toUQuad()); }
|
||||
;
|
||||
|
|
@ -7699,6 +7702,10 @@ vltDFile<strp>: // --file <arg>
|
|||
yVLT_D_FILE str { $$ = $2; }
|
||||
;
|
||||
|
||||
vltDHierDpi<strp>: // --hier-dpi <arg>
|
||||
yVLT_D_HIER_DPI str { $$ = $2; }
|
||||
;
|
||||
|
||||
vltDLevels<nump>: // --levels <arg>
|
||||
yVLT_D_LEVELS yaINTNUM { $$ = $2; }
|
||||
;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,40 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2025 by Wilson Snyder. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt_all')
|
||||
test.init_benchmarksim()
|
||||
test.cycles = (int(test.benchmark) if test.benchmark else 1000000)
|
||||
test.sim_time = test.cycles * 10 + 1000
|
||||
THREADS = int(os.environ["SIM_THREADS"]) if "SIM_THREADS" in os.environ else 2
|
||||
|
||||
test.compile(benchmarksim=1,
|
||||
v_flags2=[
|
||||
"+define+SIM_CYCLES=" + str(test.cycles), "--prof-exec", "--hierarchical",
|
||||
"--stats"
|
||||
],
|
||||
threads=(THREADS if test.vltmt else 1))
|
||||
|
||||
test.file_grep(test.obj_dir + "/V" + test.name + "__hier.dir/V" + test.name + "__stats.txt",
|
||||
r'Optimizations, Hierarchical DPI wrappers with costs\s+(\d+)', 3)
|
||||
|
||||
test.execute(all_run_flags=[
|
||||
"+verilator+prof+exec+start+2",
|
||||
" +verilator+prof+exec+window+2",
|
||||
" +verilator+prof+exec+file+" + test.obj_dir + "/profile_exec.dat",
|
||||
" +verilator+prof+vlt+file+" + test.obj_dir + "/profile.vlt"]) # yapf:disable
|
||||
|
||||
test.run(cmd=[
|
||||
os.environ["VERILATOR_ROOT"] + "/bin/verilator_gantt", test.obj_dir +
|
||||
"/profile_exec.dat", "--vcd " + test.obj_dir + "/profile_exec.vcd", "| tee " + test.obj_dir +
|
||||
"/gantt.log"
|
||||
])
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,314 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2025 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// based on t_gate_ormux
|
||||
|
||||
`ifndef HIER_CORES
|
||||
`define HIER_CORES 3
|
||||
`endif
|
||||
|
||||
`ifndef MAIN_CORES
|
||||
`define MAIN_CORES 1
|
||||
`endif
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
input clk;
|
||||
|
||||
generate
|
||||
for (genvar i = 0; i < `MAIN_CORES; ++i) NonHierCore mainCore(clk);
|
||||
endgenerate
|
||||
|
||||
generate
|
||||
for (genvar i = 0; i < `HIER_CORES; ++i) Core hierCore(clk);
|
||||
endgenerate
|
||||
endmodule
|
||||
|
||||
module Core(input clk); /* verilator hier_block */
|
||||
reg [63:0] crc;
|
||||
logic [31:0] rdata;
|
||||
logic [31:0] rdata2;
|
||||
wire [31:0] wdata = crc[31:0];
|
||||
wire [15:0] sel = {11'h0, crc[36:32]};
|
||||
wire we = crc[48];
|
||||
|
||||
Test test (
|
||||
// Outputs
|
||||
.rdata (rdata[31:0]),
|
||||
.rdata2 (rdata2[31:0]),
|
||||
// Inputs
|
||||
.clk (clk),
|
||||
.we (we),
|
||||
.sel (sel[15:0]),
|
||||
.wdata (wdata[31:0]));
|
||||
wire [63:0] result = {rdata2, rdata};
|
||||
|
||||
Check check(.clk(clk), .crc(crc), .result(result), .rdata(rdata), .rdata2(rdata2));
|
||||
endmodule
|
||||
|
||||
module NonHierCore(input clk);
|
||||
reg [63:0] crc;
|
||||
logic [31:0] rdata;
|
||||
logic [31:0] rdata2;
|
||||
wire [31:0] wdata = crc[31:0];
|
||||
wire [15:0] sel = {11'h0, crc[36:32]};
|
||||
wire we = crc[48];
|
||||
|
||||
Test test (
|
||||
// Outputs
|
||||
.rdata (rdata[31:0]),
|
||||
.rdata2 (rdata2[31:0]),
|
||||
// Inputs
|
||||
.clk (clk),
|
||||
.we (we),
|
||||
.sel (sel[15:0]),
|
||||
.wdata (wdata[31:0]));
|
||||
wire [63:0] result = {rdata2, rdata};
|
||||
|
||||
Check check(.clk(clk), .crc(crc), .result(result), .rdata(rdata), .rdata2(rdata2));
|
||||
endmodule
|
||||
|
||||
module Check(
|
||||
input clk,
|
||||
output reg [63:0] crc,
|
||||
input wire [63:0] result,
|
||||
input logic [31:0] rdata,
|
||||
input logic [31:0] rdata2
|
||||
);
|
||||
integer cyc = 0;
|
||||
reg [63:0] sum;
|
||||
|
||||
always @ (posedge clk) begin
|
||||
`ifdef TEST_VERBOSE
|
||||
$write("[%0t] cyc==%0d crc=%x result=%x\n", $time, cyc, crc, result);
|
||||
`endif
|
||||
cyc <= cyc + 1;
|
||||
crc <= {crc[62:0], crc[63] ^ crc[2] ^ crc[0]};
|
||||
sum <= result ^ {sum[62:0], sum[63] ^ sum[2] ^ sum[0]};
|
||||
if (rdata2 != rdata) $stop;
|
||||
if (cyc==0) begin
|
||||
// Setup
|
||||
crc <= 64'h5aef0c8d_d70a4497;
|
||||
sum <= '0;
|
||||
end
|
||||
else if (cyc<10) begin
|
||||
sum <= '0;
|
||||
end
|
||||
else if (cyc == 99) begin
|
||||
$write("[%0t] cyc==%0d crc=%x sum=%x\n", $time, cyc, crc, sum);
|
||||
if (crc !== 64'hc77bb9b3784ea091) $stop;
|
||||
`define EXPECTED_SUM 64'h8977713eb467bc86
|
||||
if (sum !== `EXPECTED_SUM) $stop;
|
||||
end
|
||||
else if (cyc == `SIM_CYCLES) begin
|
||||
$write("[%0t] cyc==%0d crc=%x sum=%x\n", $time, cyc, crc, sum);
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
|
||||
module Test(/*AUTOARG*/
|
||||
// Outputs
|
||||
rdata, rdata2,
|
||||
// Inputs
|
||||
clk, we, sel, wdata
|
||||
);
|
||||
input clk;
|
||||
input we;
|
||||
input [15:0] sel;
|
||||
input [31:0] wdata;
|
||||
output logic [31:0] rdata;
|
||||
output logic [31:0] rdata2;
|
||||
|
||||
logic we_d1r;
|
||||
logic [15:0] sel_d1r;
|
||||
logic [31:0] wdata_d1r;
|
||||
always_ff @ (posedge clk) begin
|
||||
we_d1r <= we;
|
||||
sel_d1r <= sel;
|
||||
wdata_d1r <= wdata;
|
||||
end
|
||||
|
||||
reg [31:0] csr0000;
|
||||
reg [31:0] csr0001;
|
||||
reg [31:0] csr0002;
|
||||
reg [31:0] csr0003;
|
||||
reg [31:0] csr0004;
|
||||
reg [31:0] csr0005;
|
||||
reg [31:0] csr0006;
|
||||
reg [31:0] csr0007;
|
||||
reg [31:0] csr0008;
|
||||
reg [31:0] csr0009;
|
||||
reg [31:0] csr000a;
|
||||
reg [31:0] csr000b;
|
||||
reg [31:0] csr000c;
|
||||
reg [31:0] csr000d;
|
||||
reg [31:0] csr000e;
|
||||
reg [31:0] csr000f;
|
||||
wire [31:0] csr0010 = 32'h33675230;
|
||||
wire [31:0] csr0011 = 32'h00fa2144;
|
||||
wire [31:0] csr0012 = 32'h6a5e8e10;
|
||||
wire [31:0] csr0013 = 32'h000a5b5e;
|
||||
wire [31:0] csr0014 = 32'h002fe51b;
|
||||
wire [31:0] csr0015 = 32'h00027e00;
|
||||
wire [31:0] csr0016 = 32'h0000e3c0;
|
||||
wire [31:0] csr0017 = 32'h00efcf16;
|
||||
wire [31:0] csr0018 = 32'h007a2600;
|
||||
wire [31:0] csr0019 = 32'h0a4a9f10;
|
||||
wire [31:0] csr001a = 32'h7d789de3;
|
||||
wire [31:0] csr001b = 32'h40f655f9;
|
||||
wire [31:0] csr001c = 32'hadad01f4;
|
||||
wire [31:0] csr001d = 32'h02e7b33c;
|
||||
wire [31:0] csr001e = 32'h12101533;
|
||||
wire [31:0] csr001f = 32'h2cc1cce5;
|
||||
initial begin
|
||||
csr0000 = 32'he172d365;
|
||||
csr0001 = 32'h35cc25e2;
|
||||
csr0002 = 32'haf48436e;
|
||||
csr0003 = 32'h135e55e4;
|
||||
csr0004 = 32'h5fd6e48a;
|
||||
csr0005 = 32'hb07d34ad;
|
||||
csr0006 = 32'h2aa05deb;
|
||||
csr0007 = 32'hfe97b680;
|
||||
csr0008 = 32'h960f20bb;
|
||||
csr0009 = 32'h251129f0;
|
||||
csr000a = 32'hef3d2f93;
|
||||
csr000b = 32'hef4bc127;
|
||||
csr000c = 32'h3dfecb10;
|
||||
csr000d = 32'h1b4690f5;
|
||||
csr000e = 32'ha07822ab;
|
||||
csr000f = 32'hf817cbf6;
|
||||
end
|
||||
|
||||
always_ff @ (posedge clk) begin
|
||||
if (we_d1r && sel_d1r == 16'h0000) csr0000 <= wdata_d1r;
|
||||
if (we_d1r && sel_d1r == 16'h0001) csr0001 <= wdata_d1r;
|
||||
if (we_d1r && sel_d1r == 16'h0002) csr0002 <= wdata_d1r;
|
||||
if (we_d1r && sel_d1r == 16'h0003) csr0003 <= wdata_d1r;
|
||||
if (we_d1r && sel_d1r == 16'h0004) csr0004 <= wdata_d1r;
|
||||
if (we_d1r && sel_d1r == 16'h0005) csr0005 <= wdata_d1r;
|
||||
if (we_d1r && sel_d1r == 16'h0006) csr0006 <= wdata_d1r;
|
||||
if (we_d1r && sel_d1r == 16'h0007) csr0007 <= wdata_d1r;
|
||||
if (we_d1r && sel_d1r == 16'h0008) csr0008 <= wdata_d1r;
|
||||
if (we_d1r && sel_d1r == 16'h0009) csr0009 <= wdata_d1r;
|
||||
if (we_d1r && sel_d1r == 16'h000a) csr000a <= wdata_d1r;
|
||||
if (we_d1r && sel_d1r == 16'h000b) csr000b <= wdata_d1r;
|
||||
if (we_d1r && sel_d1r == 16'h000c) csr000c <= wdata_d1r;
|
||||
if (we_d1r && sel_d1r == 16'h000d) csr000d <= wdata_d1r;
|
||||
if (we_d1r && sel_d1r == 16'h000e) csr000e <= wdata_d1r;
|
||||
if (we_d1r && sel_d1r == 16'h000f) csr000f <= wdata_d1r;
|
||||
end
|
||||
|
||||
wire dec0000 = sel_d1r[15:6] == 0 && !sel_d1r[5] && !sel_d1r[4] && !sel_d1r[3] && !sel_d1r[2] && !sel_d1r[1] && !sel_d1r[0];
|
||||
wire dec0001 = sel_d1r[15:6] == 0 && !sel_d1r[5] && !sel_d1r[4] && !sel_d1r[3] && !sel_d1r[2] && !sel_d1r[1] && sel_d1r[0];
|
||||
wire dec0002 = sel_d1r[15:6] == 0 && !sel_d1r[5] && !sel_d1r[4] && !sel_d1r[3] && !sel_d1r[2] && sel_d1r[1] && !sel_d1r[0];
|
||||
wire dec0003 = sel_d1r[15:6] == 0 && !sel_d1r[5] && !sel_d1r[4] && !sel_d1r[3] && !sel_d1r[2] && sel_d1r[1] && sel_d1r[0];
|
||||
wire dec0004 = sel_d1r[15:6] == 0 && !sel_d1r[5] && !sel_d1r[4] && !sel_d1r[3] && sel_d1r[2] && !sel_d1r[1] && !sel_d1r[0];
|
||||
wire dec0005 = sel_d1r[15:6] == 0 && !sel_d1r[5] && !sel_d1r[4] && !sel_d1r[3] && sel_d1r[2] && !sel_d1r[1] && sel_d1r[0];
|
||||
wire dec0006 = sel_d1r[15:6] == 0 && !sel_d1r[5] && !sel_d1r[4] && !sel_d1r[3] && sel_d1r[2] && sel_d1r[1] && !sel_d1r[0];
|
||||
wire dec0007 = sel_d1r[15:6] == 0 && !sel_d1r[5] && !sel_d1r[4] && !sel_d1r[3] && sel_d1r[2] && sel_d1r[1] && sel_d1r[0];
|
||||
wire dec0008 = sel_d1r[15:6] == 0 && !sel_d1r[5] && !sel_d1r[4] && sel_d1r[3] && !sel_d1r[2] && !sel_d1r[1] && !sel_d1r[0];
|
||||
wire dec0009 = sel_d1r[15:6] == 0 && !sel_d1r[5] && !sel_d1r[4] && sel_d1r[3] && !sel_d1r[2] && !sel_d1r[1] && sel_d1r[0];
|
||||
wire dec000a = sel_d1r[15:6] == 0 && !sel_d1r[5] && !sel_d1r[4] && sel_d1r[3] && !sel_d1r[2] && sel_d1r[1] && !sel_d1r[0];
|
||||
wire dec000b = sel_d1r[15:6] == 0 && !sel_d1r[5] && !sel_d1r[4] && sel_d1r[3] && !sel_d1r[2] && sel_d1r[1] && sel_d1r[0];
|
||||
wire dec000c = sel_d1r[15:6] == 0 && !sel_d1r[5] && !sel_d1r[4] && sel_d1r[3] && sel_d1r[2] && !sel_d1r[1] && !sel_d1r[0];
|
||||
wire dec000d = sel_d1r[15:6] == 0 && !sel_d1r[5] && !sel_d1r[4] && sel_d1r[3] && sel_d1r[2] && !sel_d1r[1] && sel_d1r[0];
|
||||
wire dec000e = sel_d1r[15:6] == 0 && !sel_d1r[5] && !sel_d1r[4] && sel_d1r[3] && sel_d1r[2] && sel_d1r[1] && !sel_d1r[0];
|
||||
wire dec000f = sel_d1r[15:6] == 0 && !sel_d1r[5] && !sel_d1r[4] && sel_d1r[3] && sel_d1r[2] && sel_d1r[1] && sel_d1r[0];
|
||||
wire dec0010 = sel_d1r[15:6] == 0 && !sel_d1r[5] && sel_d1r[4] && !sel_d1r[3] && !sel_d1r[2] && !sel_d1r[1] && !sel_d1r[0];
|
||||
wire dec0011 = sel_d1r[15:6] == 0 && !sel_d1r[5] && sel_d1r[4] && !sel_d1r[3] && !sel_d1r[2] && !sel_d1r[1] && sel_d1r[0];
|
||||
wire dec0012 = sel_d1r[15:6] == 0 && !sel_d1r[5] && sel_d1r[4] && !sel_d1r[3] && !sel_d1r[2] && sel_d1r[1] && !sel_d1r[0];
|
||||
wire dec0013 = sel_d1r[15:6] == 0 && !sel_d1r[5] && sel_d1r[4] && !sel_d1r[3] && !sel_d1r[2] && sel_d1r[1] && sel_d1r[0];
|
||||
wire dec0014 = sel_d1r[15:6] == 0 && !sel_d1r[5] && sel_d1r[4] && !sel_d1r[3] && sel_d1r[2] && !sel_d1r[1] && !sel_d1r[0];
|
||||
wire dec0015 = sel_d1r[15:6] == 0 && !sel_d1r[5] && sel_d1r[4] && !sel_d1r[3] && sel_d1r[2] && !sel_d1r[1] && sel_d1r[0];
|
||||
wire dec0016 = sel_d1r[15:6] == 0 && !sel_d1r[5] && sel_d1r[4] && !sel_d1r[3] && sel_d1r[2] && sel_d1r[1] && !sel_d1r[0];
|
||||
wire dec0017 = sel_d1r[15:6] == 0 && !sel_d1r[5] && sel_d1r[4] && !sel_d1r[3] && sel_d1r[2] && sel_d1r[1] && sel_d1r[0];
|
||||
wire dec0018 = sel_d1r[15:6] == 0 && !sel_d1r[5] && sel_d1r[4] && sel_d1r[3] && !sel_d1r[2] && !sel_d1r[1] && !sel_d1r[0];
|
||||
wire dec0019 = sel_d1r[15:6] == 0 && !sel_d1r[5] && sel_d1r[4] && sel_d1r[3] && !sel_d1r[2] && !sel_d1r[1] && sel_d1r[0];
|
||||
wire dec001a = sel_d1r[15:6] == 0 && !sel_d1r[5] && sel_d1r[4] && sel_d1r[3] && !sel_d1r[2] && sel_d1r[1] && !sel_d1r[0];
|
||||
wire dec001b = sel_d1r[15:6] == 0 && !sel_d1r[5] && sel_d1r[4] && sel_d1r[3] && !sel_d1r[2] && sel_d1r[1] && sel_d1r[0];
|
||||
wire dec001c = sel_d1r[15:6] == 0 && !sel_d1r[5] && sel_d1r[4] && sel_d1r[3] && sel_d1r[2] && !sel_d1r[1] && !sel_d1r[0];
|
||||
wire dec001d = sel_d1r[15:6] == 0 && !sel_d1r[5] && sel_d1r[4] && sel_d1r[3] && sel_d1r[2] && !sel_d1r[1] && sel_d1r[0];
|
||||
wire dec001e = sel_d1r[15:6] == 0 && !sel_d1r[5] && sel_d1r[4] && sel_d1r[3] && sel_d1r[2] && sel_d1r[1] && !sel_d1r[0];
|
||||
wire dec001f = sel_d1r[15:6] == 0 && !sel_d1r[5] && sel_d1r[4] && sel_d1r[3] && sel_d1r[2] && sel_d1r[1] && sel_d1r[0];
|
||||
|
||||
assign rdata = (32'h0
|
||||
| {32{dec0000}} & csr0000
|
||||
| {32{dec0001}} & csr0001
|
||||
| {32{dec0002}} & csr0002
|
||||
| {32{dec0003}} & csr0003
|
||||
| {32{dec0004}} & csr0004
|
||||
| {32{dec0005}} & csr0005
|
||||
| {32{dec0006}} & csr0006
|
||||
| {32{dec0007}} & csr0007
|
||||
| {32{dec0008}} & csr0008
|
||||
| {32{dec0009}} & csr0009
|
||||
| {32{dec000a}} & csr000a
|
||||
| {32{dec000b}} & csr000b
|
||||
| {32{dec000c}} & csr000c
|
||||
| {32{dec000d}} & csr000d
|
||||
| {32{dec000e}} & csr000e
|
||||
| {32{dec000f}} & csr000f
|
||||
| {32{dec0010}} & csr0010
|
||||
| {32{dec0011}} & csr0011
|
||||
| {32{dec0012}} & csr0012
|
||||
| {32{dec0013}} & csr0013
|
||||
| {32{dec0014}} & csr0014
|
||||
| {32{dec0015}} & csr0015
|
||||
| {32{dec0016}} & csr0016
|
||||
| {32{dec0017}} & csr0017
|
||||
| {32{dec0018}} & csr0018
|
||||
| {32{dec0019}} & csr0019
|
||||
| {32{dec001a}} & csr001a
|
||||
| {32{dec001b}} & csr001b
|
||||
| {32{dec001c}} & csr001c
|
||||
| {32{dec001d}} & csr001d
|
||||
| {32{dec001e}} & csr001e
|
||||
| {32{dec001f}} & csr001f
|
||||
);
|
||||
|
||||
always_comb begin
|
||||
case (sel_d1r)
|
||||
16'h0000: rdata2 = csr0000;
|
||||
16'h0001: rdata2 = csr0001;
|
||||
16'h0002: rdata2 = csr0002;
|
||||
16'h0003: rdata2 = csr0003;
|
||||
16'h0004: rdata2 = csr0004;
|
||||
16'h0005: rdata2 = csr0005;
|
||||
16'h0006: rdata2 = csr0006;
|
||||
16'h0007: rdata2 = csr0007;
|
||||
16'h0008: rdata2 = csr0008;
|
||||
16'h0009: rdata2 = csr0009;
|
||||
16'h000a: rdata2 = csr000a;
|
||||
16'h000b: rdata2 = csr000b;
|
||||
16'h000c: rdata2 = csr000c;
|
||||
16'h000d: rdata2 = csr000d;
|
||||
16'h000e: rdata2 = csr000e;
|
||||
16'h000f: rdata2 = csr000f;
|
||||
16'h0010: rdata2 = csr0010;
|
||||
16'h0011: rdata2 = csr0011;
|
||||
16'h0012: rdata2 = csr0012;
|
||||
16'h0013: rdata2 = csr0013;
|
||||
16'h0014: rdata2 = csr0014;
|
||||
16'h0015: rdata2 = csr0015;
|
||||
16'h0016: rdata2 = csr0016;
|
||||
16'h0017: rdata2 = csr0017;
|
||||
16'h0018: rdata2 = csr0018;
|
||||
16'h0019: rdata2 = csr0019;
|
||||
16'h001a: rdata2 = csr001a;
|
||||
16'h001b: rdata2 = csr001b;
|
||||
16'h001c: rdata2 = csr001c;
|
||||
16'h001d: rdata2 = csr001d;
|
||||
16'h001e: rdata2 = csr001e;
|
||||
16'h001f: rdata2 = csr001f;
|
||||
default: rdata2 = 0;
|
||||
endcase
|
||||
end
|
||||
|
||||
endmodule
|
||||
Loading…
Reference in New Issue