mirror of https://github.com/YosysHQ/yosys.git
Merge remote-tracking branch 'origin/eddie/opt_rmdff' into xc7mux
This commit is contained in:
commit
68359bcd6f
|
@ -146,7 +146,7 @@ struct FirrtlWorker
|
||||||
if (!mask.is_fully_def())
|
if (!mask.is_fully_def())
|
||||||
this->ena = SigSpec(RTLIL::Const(1));
|
this->ena = SigSpec(RTLIL::Const(1));
|
||||||
}
|
}
|
||||||
string gen_read(const char * /* indent */) {
|
string gen_read(const char * /* indent */) {
|
||||||
log_error("gen_read called on write_port: %s\n", name.c_str());
|
log_error("gen_read called on write_port: %s\n", name.c_str());
|
||||||
return stringf("gen_read called on write_port: %s\n", name.c_str());
|
return stringf("gen_read called on write_port: %s\n", name.c_str());
|
||||||
}
|
}
|
||||||
|
@ -449,8 +449,10 @@ struct FirrtlWorker
|
||||||
string primop;
|
string primop;
|
||||||
bool always_uint = false;
|
bool always_uint = false;
|
||||||
if (cell->type == "$not") primop = "not";
|
if (cell->type == "$not") primop = "not";
|
||||||
else if (cell->type == "$neg") primop = "neg";
|
else if (cell->type == "$neg") {
|
||||||
else if (cell->type == "$logic_not") {
|
primop = "neg";
|
||||||
|
is_signed = true; // Result of "neg" is signed (an SInt).
|
||||||
|
} else if (cell->type == "$logic_not") {
|
||||||
primop = "eq";
|
primop = "eq";
|
||||||
a_expr = stringf("%s, UInt(0)", a_expr.c_str());
|
a_expr = stringf("%s, UInt(0)", a_expr.c_str());
|
||||||
}
|
}
|
||||||
|
@ -562,6 +564,7 @@ struct FirrtlWorker
|
||||||
auto b_sig = cell->getPort("\\B");
|
auto b_sig = cell->getPort("\\B");
|
||||||
if (b_sig.is_fully_const()) {
|
if (b_sig.is_fully_const()) {
|
||||||
primop = "shl";
|
primop = "shl";
|
||||||
|
b_expr = std::to_string(b_sig.as_int());
|
||||||
} else {
|
} else {
|
||||||
primop = "dshl";
|
primop = "dshl";
|
||||||
// Convert from FIRRTL left shift semantics.
|
// Convert from FIRRTL left shift semantics.
|
||||||
|
@ -575,6 +578,7 @@ struct FirrtlWorker
|
||||||
auto b_sig = cell->getPort("\\B");
|
auto b_sig = cell->getPort("\\B");
|
||||||
if (b_sig.is_fully_const()) {
|
if (b_sig.is_fully_const()) {
|
||||||
primop = "shr";
|
primop = "shr";
|
||||||
|
b_expr = std::to_string(b_sig.as_int());
|
||||||
} else {
|
} else {
|
||||||
primop = "dshr";
|
primop = "dshr";
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,11 +57,15 @@ void AigerReader::parse_aiger()
|
||||||
|
|
||||||
// Optional values
|
// Optional values
|
||||||
B = C = J = F = 0;
|
B = C = J = F = 0;
|
||||||
for (auto &i : std::array<std::reference_wrapper<unsigned>,4>{B, C, J, F}) {
|
if (f.peek() != ' ') goto end_of_header;
|
||||||
if (f.peek() != ' ') break;
|
if (!(f >> B)) log_error("Invalid AIGER header\n");
|
||||||
if (!(f >> i))
|
if (f.peek() != ' ') goto end_of_header;
|
||||||
log_error("Invalid AIGER header\n");
|
if (!(f >> C)) log_error("Invalid AIGER header\n");
|
||||||
}
|
if (f.peek() != ' ') goto end_of_header;
|
||||||
|
if (!(f >> J)) log_error("Invalid AIGER header\n");
|
||||||
|
if (f.peek() != ' ') goto end_of_header;
|
||||||
|
if (!(f >> F)) log_error("Invalid AIGER header\n");
|
||||||
|
end_of_header:
|
||||||
|
|
||||||
std::string line;
|
std::string line;
|
||||||
std::getline(f, line); // Ignore up to start of next line, as standard
|
std::getline(f, line); // Ignore up to start of next line, as standard
|
||||||
|
|
|
@ -320,12 +320,10 @@ class SubCircuit::SolverWorker
|
||||||
|
|
||||||
static int numberOfPermutations(const std::vector<std::string> &list)
|
static int numberOfPermutations(const std::vector<std::string> &list)
|
||||||
{
|
{
|
||||||
int numPermutations = 1;
|
constexpr size_t mappedPermutationsSize = 10;
|
||||||
for (int i = 0; i < int(list.size()); i++) {
|
constexpr int mappedPermutations[mappedPermutationsSize] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880};
|
||||||
assert(numPermutations < maxPermutationsLimit);
|
assert(list.size() < mappedPermutationsSize);
|
||||||
numPermutations *= i+1;
|
return mappedPermutations[list.size()];
|
||||||
}
|
|
||||||
return numPermutations;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void permutateVectorToMap(std::map<std::string, std::string> &map, const std::vector<std::string> &list, int idx)
|
static void permutateVectorToMap(std::map<std::string, std::string> &map, const std::vector<std::string> &list, int idx)
|
||||||
|
|
|
@ -260,8 +260,8 @@ delete_dlatch:
|
||||||
|
|
||||||
bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
|
bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
|
||||||
{
|
{
|
||||||
RTLIL::SigSpec sig_d, sig_q, sig_c, sig_r;
|
RTLIL::SigSpec sig_d, sig_q, sig_c, sig_r, sig_e;
|
||||||
RTLIL::Const val_cp, val_rp, val_rv;
|
RTLIL::Const val_cp, val_rp, val_rv, val_ep;
|
||||||
|
|
||||||
if (dff->type == "$_FF_") {
|
if (dff->type == "$_FF_") {
|
||||||
sig_d = dff->getPort("\\D");
|
sig_d = dff->getPort("\\D");
|
||||||
|
@ -285,6 +285,16 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
|
||||||
val_rp = RTLIL::Const(dff->type[7] == 'P', 1);
|
val_rp = RTLIL::Const(dff->type[7] == 'P', 1);
|
||||||
val_rv = RTLIL::Const(dff->type[8] == '1', 1);
|
val_rv = RTLIL::Const(dff->type[8] == '1', 1);
|
||||||
}
|
}
|
||||||
|
else if (dff->type.substr(0,7) == "$_DFFE_" && dff->type.substr(9) == "_" &&
|
||||||
|
(dff->type[7] == 'N' || dff->type[7] == 'P') &&
|
||||||
|
(dff->type[8] == 'N' || dff->type[8] == 'P')) {
|
||||||
|
sig_d = dff->getPort("\\D");
|
||||||
|
sig_q = dff->getPort("\\Q");
|
||||||
|
sig_c = dff->getPort("\\C");
|
||||||
|
sig_e = dff->getPort("\\E");
|
||||||
|
val_cp = RTLIL::Const(dff->type[6] == 'P', 1);
|
||||||
|
val_ep = RTLIL::Const(dff->type[7] == 'P', 1);
|
||||||
|
}
|
||||||
else if (dff->type == "$ff") {
|
else if (dff->type == "$ff") {
|
||||||
sig_d = dff->getPort("\\D");
|
sig_d = dff->getPort("\\D");
|
||||||
sig_q = dff->getPort("\\Q");
|
sig_q = dff->getPort("\\Q");
|
||||||
|
@ -295,6 +305,14 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
|
||||||
sig_c = dff->getPort("\\CLK");
|
sig_c = dff->getPort("\\CLK");
|
||||||
val_cp = RTLIL::Const(dff->parameters["\\CLK_POLARITY"].as_bool(), 1);
|
val_cp = RTLIL::Const(dff->parameters["\\CLK_POLARITY"].as_bool(), 1);
|
||||||
}
|
}
|
||||||
|
else if (dff->type == "$dffe") {
|
||||||
|
sig_e = dff->getPort("\\EN");
|
||||||
|
sig_d = dff->getPort("\\D");
|
||||||
|
sig_q = dff->getPort("\\Q");
|
||||||
|
sig_c = dff->getPort("\\CLK");
|
||||||
|
val_cp = RTLIL::Const(dff->parameters["\\CLK_POLARITY"].as_bool(), 1);
|
||||||
|
val_ep = RTLIL::Const(dff->parameters["\\EN_POLARITY"].as_bool(), 1);
|
||||||
|
}
|
||||||
else if (dff->type == "$adff") {
|
else if (dff->type == "$adff") {
|
||||||
sig_d = dff->getPort("\\D");
|
sig_d = dff->getPort("\\D");
|
||||||
sig_q = dff->getPort("\\Q");
|
sig_q = dff->getPort("\\Q");
|
||||||
|
@ -320,6 +338,16 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
|
||||||
val_init.bits.push_back(bit.wire == NULL ? bit.data : RTLIL::State::Sx);
|
val_init.bits.push_back(bit.wire == NULL ? bit.data : RTLIL::State::Sx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sig_e.size()) {
|
||||||
|
if (!sig_e.is_fully_const())
|
||||||
|
return false;
|
||||||
|
if (sig_e != val_ep) {
|
||||||
|
if (has_init)
|
||||||
|
mod->connect(sig_q, val_init);
|
||||||
|
goto delete_dff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (dff->type.in("$ff", "$dff") && mux_drivers.has(sig_d)) {
|
if (dff->type.in("$ff", "$dff") && mux_drivers.has(sig_d)) {
|
||||||
std::set<RTLIL::Cell*> muxes;
|
std::set<RTLIL::Cell*> muxes;
|
||||||
mux_drivers.find(sig_d, muxes);
|
mux_drivers.find(sig_d, muxes);
|
||||||
|
@ -489,7 +517,8 @@ struct OptRmdffPass : public Pass {
|
||||||
if (cell->type.in("$_FF_", "$_DFF_N_", "$_DFF_P_",
|
if (cell->type.in("$_FF_", "$_DFF_N_", "$_DFF_P_",
|
||||||
"$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_",
|
"$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_",
|
||||||
"$_DFF_PN0_", "$_DFF_PN1_", "$_DFF_PP0_", "$_DFF_PP1_",
|
"$_DFF_PN0_", "$_DFF_PN1_", "$_DFF_PP0_", "$_DFF_PP1_",
|
||||||
"$ff", "$dff", "$adff"))
|
"$_DFFE_NN_", "$_DFFE_NP_", "$_DFFE_PN_", "$_DFFE_PP_",
|
||||||
|
"$ff", "$dff", "$dffe", "$adff"))
|
||||||
dff_list.push_back(cell->name);
|
dff_list.push_back(cell->name);
|
||||||
|
|
||||||
if (cell->type.in("$dlatch", "$_DLATCH_P_", "$_DLATCH_N_"))
|
if (cell->type.in("$dlatch", "$_DLATCH_P_", "$_DLATCH_N_"))
|
||||||
|
|
|
@ -29,6 +29,7 @@ PRIVATE_NAMESPACE_BEGIN
|
||||||
struct WreduceConfig
|
struct WreduceConfig
|
||||||
{
|
{
|
||||||
pool<IdString> supported_cell_types;
|
pool<IdString> supported_cell_types;
|
||||||
|
bool keepdc = false;
|
||||||
|
|
||||||
WreduceConfig()
|
WreduceConfig()
|
||||||
{
|
{
|
||||||
|
@ -82,7 +83,7 @@ struct WreduceWorker
|
||||||
|
|
||||||
SigBit ref = sig_a[i];
|
SigBit ref = sig_a[i];
|
||||||
for (int k = 0; k < GetSize(sig_s); k++) {
|
for (int k = 0; k < GetSize(sig_s); k++) {
|
||||||
if (ref != Sx && sig_b[k*GetSize(sig_a) + i] != Sx && ref != sig_b[k*GetSize(sig_a) + i])
|
if ((config->keepdc || (ref != Sx && sig_b[k*GetSize(sig_a) + i] != Sx)) && ref != sig_b[k*GetSize(sig_a) + i])
|
||||||
goto no_match_ab;
|
goto no_match_ab;
|
||||||
if (sig_b[k*GetSize(sig_a) + i] != Sx)
|
if (sig_b[k*GetSize(sig_a) + i] != Sx)
|
||||||
ref = sig_b[k*GetSize(sig_a) + i];
|
ref = sig_b[k*GetSize(sig_a) + i];
|
||||||
|
@ -497,6 +498,9 @@ struct WreducePass : public Pass {
|
||||||
log(" Do not change the width of memory address ports. Use this options in\n");
|
log(" Do not change the width of memory address ports. Use this options in\n");
|
||||||
log(" flows that use the 'memory_memx' pass.\n");
|
log(" flows that use the 'memory_memx' pass.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
log(" -keepdc\n");
|
||||||
|
log(" Do not optimize explicit don't-care values.\n");
|
||||||
|
log("\n");
|
||||||
}
|
}
|
||||||
void execute(std::vector<std::string> args, Design *design) YS_OVERRIDE
|
void execute(std::vector<std::string> args, Design *design) YS_OVERRIDE
|
||||||
{
|
{
|
||||||
|
@ -511,6 +515,10 @@ struct WreducePass : public Pass {
|
||||||
opt_memx = true;
|
opt_memx = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (args[argidx] == "-keepdc") {
|
||||||
|
config.keepdc = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
extra_args(args, argidx, design);
|
extra_args(args, argidx, design);
|
||||||
|
|
|
@ -195,9 +195,11 @@ struct PrepPass : public ScriptPass
|
||||||
run(nokeepdc ? "opt" : "opt -keepdc");
|
run(nokeepdc ? "opt" : "opt -keepdc");
|
||||||
if (!ifxmode) {
|
if (!ifxmode) {
|
||||||
if (help_mode)
|
if (help_mode)
|
||||||
run("wreduce [-memx]");
|
run("wreduce -keepdc [-memx]");
|
||||||
else
|
else if (nokeepdc)
|
||||||
run(memxmode ? "wreduce -memx" : "wreduce");
|
run(memxmode ? "wreduce -memx" : "wreduce");
|
||||||
|
else
|
||||||
|
run(memxmode ? "wreduce -keepdc -memx" : "wreduce -keepdc");
|
||||||
}
|
}
|
||||||
if (!nomemmode) {
|
if (!nomemmode) {
|
||||||
run(string("memory_dff") + (help_mode ? " [-nordff]" : nordff ? " -nordff" : ""));
|
run(string("memory_dff") + (help_mode ? " [-nordff]" : nordff ? " -nordff" : ""));
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
module opt_rmdff_test (input C, input D, input E, output reg [16:0] Q);
|
||||||
|
\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) remove0 (.CLK(C), .D(D), .EN(1'b0), .Q(Q[0]));
|
||||||
|
initial Q[1] = 1'b1;
|
||||||
|
\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) remove1 (.CLK(C), .D(D), .EN(1'b0), .Q(Q[1]));
|
||||||
|
\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) remove2 (.CLK(C), .D(D), .EN(1'bx), .Q(Q[2]));
|
||||||
|
\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) keep2 (.CLK(C), .D(D), .EN(1'b1), .Q(Q[2]));
|
||||||
|
initial Q[3] = 1'b0;
|
||||||
|
\$dffe #(.WIDTH(1), .CLK_POLARITY(0), .EN_POLARITY(1)) keep3 (.CLK(C), .D(D), .EN(1'b1), .Q(Q[3]));
|
||||||
|
\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(0)) remove4 (.CLK(C), .D(D), .EN(1'b1), .Q(Q[4]));
|
||||||
|
\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(0)) remove5 (.CLK(C), .D(D), .EN(1'bx), .Q(Q[5]));
|
||||||
|
initial Q[6] = 1'b0;
|
||||||
|
\$dffe #(.WIDTH(1), .CLK_POLARITY(0), .EN_POLARITY(0)) keep6 (.CLK(C), .D(D), .EN(E), .Q(Q[6]));
|
||||||
|
|
||||||
|
\$_DFFE_PP_ remove7 (.C(C), .D(D), .E(1'b0), .Q(Q[7]));
|
||||||
|
initial Q[8] = 1'b1;
|
||||||
|
\$_DFFE_PP_ remove8 (.C(C), .D(D), .E(1'b0), .Q(Q[8]));
|
||||||
|
\$_DFFE_PP_ remove9 (.C(C), .D(D), .E(1'bx), .Q(Q[9]));
|
||||||
|
\$_DFFE_PP_ keep10 (.C(C), .D(D), .E(1'b1), .Q(Q[10]));
|
||||||
|
initial Q[11] = 1'b0;
|
||||||
|
\$_DFFE_PP_ keep11 (.C(C), .D(D), .E(1'b1), .Q(Q[11]));
|
||||||
|
|
||||||
|
\$_DFFE_NN_ remove12 (.C(C), .D(D), .E(1'b1), .Q(Q[12]));
|
||||||
|
initial Q[13] = 1'b1;
|
||||||
|
\$_DFFE_NN_ remove13 (.C(C), .D(D), .E(1'b1), .Q(Q[13]));
|
||||||
|
\$_DFFE_NN_ remove14 (.C(C), .D(D), .E(1'bx), .Q(Q[14]));
|
||||||
|
\$_DFFE_NN_ keep15 (.C(C), .D(D), .E(1'b0), .Q(Q[15]));
|
||||||
|
initial Q[16] = 1'b0;
|
||||||
|
\$_DFFE_NN_ keep16 (.C(C), .D(D), .E(1'b0), .Q(Q[16]));
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,25 @@
|
||||||
|
read_verilog -icells opt_rmdff.v
|
||||||
|
prep
|
||||||
|
design -stash gold
|
||||||
|
read_verilog -icells opt_rmdff.v
|
||||||
|
opt_rmdff
|
||||||
|
|
||||||
|
select -assert-count 0 c:remove*
|
||||||
|
select -assert-min 7 c:keep*
|
||||||
|
|
||||||
|
prep
|
||||||
|
design -stash gate
|
||||||
|
|
||||||
|
design -import gold -as gold
|
||||||
|
design -import gate -as gate
|
||||||
|
|
||||||
|
equiv_make gold gate equiv
|
||||||
|
hierarchy -top equiv
|
||||||
|
equiv_simple -undef
|
||||||
|
equiv_status -assert
|
||||||
|
|
||||||
|
design -load gold
|
||||||
|
stat
|
||||||
|
|
||||||
|
design -load gate
|
||||||
|
stat
|
Loading…
Reference in New Issue