3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2025-08-03 09:50:24 +00:00

test_cell: Test CellTypes::eval() directly

Where possible at least, and disable-able with `-nocteval`.
`$lcu` doesn't work because it uses ports `P, G, CI, CO` instead of the standard `A, B, C, Y`.
`$alu` and `$fa` have more than one output so they don't work either (and in the case of `$alu` it has extra inputs too).
`$macc` is at least supported, but `CellTypes::eval()` doesn't have an implementation so it fails (which would also be true for `$lcu`, `$alu`, and `$fa`; if they weren't being rejected based on ports).

Also add `test_cell -list [all|evaluable|missing]` which prints the list of cell types supported by test_cell, cell types marked evaluable, and cell types marked evaluable but not supported by test_cell respectively.  Potential for listing cell types supported by test_cell but *not* marked evalulable, though that list is currently empty.

Add `tests/various/evaluable.sh` to exercise this.
This commit is contained in:
Krystine Sherwin 2025-03-31 11:46:24 +13:00
parent e7cfb0381c
commit 833721bfc4
No known key found for this signature in database
2 changed files with 144 additions and 7 deletions

View file

@ -24,6 +24,7 @@
#include "kernel/celledges.h" #include "kernel/celledges.h"
#include "kernel/macc.h" #include "kernel/macc.h"
#include "kernel/cost.h" #include "kernel/cost.h"
#include "kernel/celltypes.h"
#include <algorithm> #include <algorithm>
USING_YOSYS_NAMESPACE USING_YOSYS_NAMESPACE
@ -471,7 +472,7 @@ static void run_edges_test(RTLIL::Design *design, bool verbose)
log_error("SAT-based edge table does not match the database!\n"); log_error("SAT-based edge table does not match the database!\n");
} }
static void run_eval_test(RTLIL::Design *design, bool verbose, bool nosat, std::string uut_name, std::ofstream &vlog_file) static void run_eval_test(RTLIL::Design *design, const CellType *ct, bool verbose, bool nosat, std::string uut_name, std::ofstream &vlog_file)
{ {
log("Eval testing:%c", verbose ? '\n' : ' '); log("Eval testing:%c", verbose ? '\n' : ' ');
@ -530,6 +531,8 @@ static void run_eval_test(RTLIL::Design *design, bool verbose, bool nosat, std::
RTLIL::SigSpec out_sig, out_val; RTLIL::SigSpec out_sig, out_val;
std::string vlog_pattern_info; std::string vlog_pattern_info;
std::map<RTLIL::IdString, RTLIL::Const> in_map;
for (auto port : gold_mod->ports) for (auto port : gold_mod->ports)
{ {
RTLIL::Wire *gold_wire = gold_mod->wire(port); RTLIL::Wire *gold_wire = gold_mod->wire(port);
@ -559,6 +562,7 @@ static void run_eval_test(RTLIL::Design *design, bool verbose, bool nosat, std::
in_sig.append(gold_wire); in_sig.append(gold_wire);
in_val.append(in_value); in_val.append(in_value);
in_map[port] = in_value;
gold_ce.set(gold_wire, in_value); gold_ce.set(gold_wire, in_value);
gate_ce.set(gate_wire, in_value); gate_ce.set(gate_wire, in_value);
@ -626,6 +630,49 @@ static void run_eval_test(RTLIL::Design *design, bool verbose, bool nosat, std::
if (verbose) if (verbose)
log("EVAL: %s\n", out_val.as_string().c_str()); log("EVAL: %s\n", out_val.as_string().c_str());
if (ct != nullptr && ct->is_evaluable) {
auto *cell = gold_mod->cell(ID(UUT));
log_assert(cell != nullptr);
bool err = false;
Const result;
// Based on passes/sat/sim.cc
bool has_a, has_b, has_c, has_d, has_s, has_x, has_y;
has_a = cell->hasPort(ID::A);
has_b = cell->hasPort(ID::B);
has_c = cell->hasPort(ID::C);
has_d = cell->hasPort(ID::D);
has_s = cell->hasPort(ID::S);
has_x = cell->hasPort(ID::X);
has_y = cell->hasPort(ID::Y);
// Simple (A -> Y) and (A,B -> Y) cells
if (has_a && !has_c && !has_d && !has_s && !has_x && has_y)
result = CellTypes::eval(cell, in_map[ID::A], in_map[ID::B], &err);
// (A,B,C -> Y) cells
else if (has_a && has_b && has_c && !has_d && !has_s && !has_x && has_y)
result = CellTypes::eval(cell, in_map[ID::A], in_map[ID::B], in_map[ID::B], &err);
// (A,S -> Y) cells
else if (has_a && !has_b && !has_c && !has_d && has_s && !has_x && has_y)
result = CellTypes::eval(cell, in_map[ID::A], in_map[ID::S], &err);
// (A,B,S -> Y) cells
else if (has_a && has_b && !has_c && !has_d && has_s && !has_x && has_y)
result = CellTypes::eval(cell, in_map[ID::A], in_map[ID::B], in_map[ID::S], &err);
// anything else
else
log_error("Unable to handle ports for ID::%s\n", id2cstr(ct->type));
if (err)
log_error("CellTypes::eval(ID::%s) returned error\n", id2cstr(ct->type));
if (result != out_val.as_const())
log_error("CellTypes/ConstEval mismatch for ID::%s, %s != %s\n", id2cstr(ct->type), log_const(result), log_signal(out_val));
if (verbose)
log("eval: %s\n", result.as_string().c_str());
}
if (!nosat) if (!nosat)
{ {
std::vector<int> sat1_in_sig = satgen1.importSigSpec(in_sig); std::vector<int> sat1_in_sig = satgen1.importSigSpec(in_sig);
@ -756,6 +803,9 @@ struct TestCellPass : public Pass {
log(" -noeval\n"); log(" -noeval\n");
log(" do not check const-eval models\n"); log(" do not check const-eval models\n");
log("\n"); log("\n");
log(" -nocteval\n");
log(" do not check celltype-eval models\n");
log("\n");
log(" -noopt\n"); log(" -noopt\n");
log(" do not opt tecchmapped design\n"); log(" do not opt tecchmapped design\n");
log("\n"); log("\n");
@ -773,6 +823,18 @@ struct TestCellPass : public Pass {
log(" check if the estimated cell cost is a valid upper bound for\n"); log(" check if the estimated cell cost is a valid upper bound for\n");
log(" the techmapped cell count \n"); log(" the techmapped cell count \n");
log("\n"); log("\n");
log(" test_cell -list all\n");
log("\n");
log("List all cell types supported by test_cell.\n");
log("\n");
log(" test_cell -list evaluable\n");
log("\n");
log("List all cell types marked evaluable.\n");
log("\n");
log(" test_cell -list missing\n");
log("\n");
log("List all cell types marked evaluable but not supported by test_cell.\n");
log("\n");
} }
void execute(std::vector<std::string> args, RTLIL::Design*) override void execute(std::vector<std::string> args, RTLIL::Design*) override
{ {
@ -786,9 +848,14 @@ struct TestCellPass : public Pass {
bool constmode = false; bool constmode = false;
bool nosat = false; bool nosat = false;
bool noeval = false; bool noeval = false;
bool nocteval = false;
bool noopt = false; bool noopt = false;
bool edges = false; bool edges = false;
bool check_cost = false; bool check_cost = false;
bool list = false;
bool list_all = false;
bool list_evaluable = false;
bool list_missing = false;
int argidx; int argidx;
for (argidx = 1; argidx < GetSize(args); argidx++) for (argidx = 1; argidx < GetSize(args); argidx++)
@ -842,6 +909,10 @@ struct TestCellPass : public Pass {
noeval = true; noeval = true;
continue; continue;
} }
if (args[argidx] == "-nocteval") {
nocteval = true;
continue;
}
if (args[argidx] == "-noopt") { if (args[argidx] == "-noopt") {
noopt = true; noopt = true;
continue; continue;
@ -868,12 +939,20 @@ struct TestCellPass : public Pass {
check_cost = true; check_cost = true;
continue; continue;
} }
break; if (args[argidx] == "-list" && argidx+1 < GetSize(args)) {
list = true;
argidx++;
if (args[argidx].compare("all") == 0)
list_all = true;
else if (args[argidx].compare("evaluable") == 0)
list_evaluable = true;
else if (args[argidx].compare("missing") == 0)
list_missing = true;
else
log_cmd_error("Unknown list type '%s'.\n", args[argidx].c_str());
continue;
} }
break;
if (xorshift32_state == 0) {
xorshift32_state = time(NULL) & 0x7fffffff;
log("Rng seed value: %d\n", int(xorshift32_state));
} }
std::map<IdString, std::string> cell_types; std::map<IdString, std::string> cell_types;
@ -940,6 +1019,33 @@ struct TestCellPass : public Pass {
cell_types[ID($macc)] = "*"; cell_types[ID($macc)] = "*";
cell_types[ID($fa)] = "*"; cell_types[ID($fa)] = "*";
if (list_all) {
log("test_cell supports the following cell types:\n");
for (auto it : cell_types)
log("%s\n", id2cstr(it.first));
}
if (list_evaluable) {
log("cell types marked evaluable:\n");
for (auto it : yosys_celltypes.cell_types)
if (it.second.is_evaluable)
log("%s\n", id2cstr(it.first));
}
if (list_missing) {
log("test_cell missing support for evaluable cell types:\n");
for (auto it : yosys_celltypes.cell_types)
if (it.second.is_evaluable && cell_types.count(it.first) == 0)
log("%s\n", id2cstr(it.first));
}
if (list) return;
if (xorshift32_state == 0) {
xorshift32_state = time(NULL) & 0x7fffffff;
log("Rng seed value: %d\n", int(xorshift32_state));
}
for (; argidx < GetSize(args); argidx++) for (; argidx < GetSize(args); argidx++)
{ {
if (args[argidx].rfind("-", 0) == 0) if (args[argidx].rfind("-", 0) == 0)
@ -998,6 +1104,14 @@ struct TestCellPass : public Pass {
int worst_abs = 0; int worst_abs = 0;
// How many times is it bigger than estimated? // How many times is it bigger than estimated?
float worst_rel = 0.0; float worst_rel = 0.0;
// Get cell type for cell (if possible)
const CellType *ct = nullptr;
if (!nocteval) {
if (yosys_celltypes.cell_known(cell_type))
ct = yosys_celltypes.get_cell(cell_type);
else if (cell_type != ID(rtlil))
log_warning("%s does not have an internal cell type!\n", id2cstr(cell_type));
}
for (int i = 0; i < num_iter; i++) for (int i = 0; i < num_iter; i++)
{ {
Cell* uut = nullptr; Cell* uut = nullptr;
@ -1031,7 +1145,7 @@ struct TestCellPass : public Pass {
uut_names.push_back(uut_name); uut_names.push_back(uut_name);
} }
if (!noeval) if (!noeval)
run_eval_test(design, verbose, nosat, uut_name, vlog_file); run_eval_test(design, ct, verbose, nosat, uut_name, vlog_file);
if (check_cost && uut) { if (check_cost && uut) {
Pass::call(design, "select gate"); Pass::call(design, "select gate");
int num_cells = 0; int num_cells = 0;

23
tests/various/evaluable.sh Executable file
View file

@ -0,0 +1,23 @@
#!/usr/bin/env bash
yosys=../../yosys
log="evalcells.log"
bad=
$yosys -QTL $log -qp 'test_cell -list all'
while read line;
do
if [[ "$line" =~ ^\$.* ]]; then
if ! $yosys -qqp test_cell\ -n\ 1\ -s\ 1\ "$line"; then
bad=1
fi
fi
done <$log
if [ $bad ]; then
echo 'One or more evaluable cells failed testing.'
exit 1
else
echo 'All evaluable cells match behavior.'
fi