mirror of https://github.com/YosysHQ/yosys.git
Compare commits
19 Commits
2da093f48a
...
b2e936cc15
Author | SHA1 | Date |
---|---|---|
Philippe Sauter | b2e936cc15 | |
Emil J | 5b6baa3ef1 | |
Martin Povišer | 53a4ec375b | |
George Rennie | 9043dc0ad6 | |
Emil J. Tywoniak | 4d96cbec75 | |
Emil J. Tywoniak | 983c54c75f | |
Emil J. Tywoniak | a5bc36f77e | |
Emil J. Tywoniak | e6793da9a0 | |
Emil J. Tywoniak | b08441d95c | |
Emil J. Tywoniak | 1e3f8cc630 | |
Emil J. Tywoniak | c921d85a85 | |
Emil J. Tywoniak | 45880ea7f2 | |
phsauter | 625ff7b9cd | |
Philippe Sauter | 3f2b391036 | |
phsauter | a8bb683914 | |
phsauter | 8231c0b85f | |
phsauter | 81d4405652 | |
phsauter | 28771fcfa8 | |
Philippe Sauter | e076768b67 |
|
@ -48,6 +48,7 @@
|
||||||
#include "kernel/ff.h"
|
#include "kernel/ff.h"
|
||||||
#include "kernel/cost.h"
|
#include "kernel/cost.h"
|
||||||
#include "kernel/log.h"
|
#include "kernel/log.h"
|
||||||
|
#include "frontends/verilog/verilog_frontend.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -56,6 +57,7 @@
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <climits>
|
#include <climits>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
# include <unistd.h>
|
# include <unistd.h>
|
||||||
|
@ -703,11 +705,19 @@ struct abc_output_filter
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file,
|
// substitute every instance of 'placeholder' in 'str' with 'replacement'
|
||||||
std::vector<std::string> &liberty_files, std::vector<std::string> &genlib_files, std::string constr_file,
|
void substitute(std::string &str, const std::string &placeholder, const std::string &replacement) {
|
||||||
bool cleanup, vector<int> lut_costs, bool dff_mode, std::string clk_str, bool keepff, std::string delay_target,
|
for (size_t pos = str.find(placeholder); pos != std::string::npos; pos = str.find(placeholder, pos)) {
|
||||||
|
str = str.substr(0, pos) + replacement + str.substr(pos + placeholder.length());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file, std::string exe_flags,
|
||||||
|
std::string input_file, std::string output_file, std::vector<std::string> &helper_files, std::vector<std::string> &liberty_files, std::vector<std::string> &genlib_files,
|
||||||
|
std::string constr_file, bool cleanup, vector<int> lut_costs, bool dff_mode, std::string clk_str, bool keepff, std::string delay_target,
|
||||||
std::string sop_inputs, std::string sop_products, std::string lutin_shared, bool fast_mode,
|
std::string sop_inputs, std::string sop_products, std::string lutin_shared, bool fast_mode,
|
||||||
const std::vector<RTLIL::Cell*> &cells, bool show_tempdir, bool sop_mode, bool abc_dress, std::vector<std::string> &dont_use_cells)
|
const std::vector<RTLIL::Cell*> &cells, bool show_tempdir, bool sop_mode, bool abc_dress, std::vector<std::string> &dont_use_cells,
|
||||||
|
bool custom_flow)
|
||||||
{
|
{
|
||||||
module = current_module;
|
module = current_module;
|
||||||
map_autoidx = autoidx++;
|
map_autoidx = autoidx++;
|
||||||
|
@ -717,6 +727,156 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
|
||||||
pi_map.clear();
|
pi_map.clear();
|
||||||
po_map.clear();
|
po_map.clear();
|
||||||
|
|
||||||
|
std::string tempdir_name;
|
||||||
|
tempdir_name = get_base_tmpdir() + "/";
|
||||||
|
tempdir_name += proc_program_prefix() + "yosys-abc-XXXXXX";
|
||||||
|
tempdir_name = make_temp_dir(tempdir_name);
|
||||||
|
log_header(design, "Extracting gate netlist of module `%s' to `%s/%s'..\n",
|
||||||
|
module->name.c_str(), replace_tempdir(tempdir_name, tempdir_name, show_tempdir).c_str(), input_file.c_str());
|
||||||
|
|
||||||
|
|
||||||
|
// load in user provided script
|
||||||
|
std::string user_script = "";
|
||||||
|
if (!script_file.empty()) {
|
||||||
|
if (script_file[0] == '+') { // inline user script
|
||||||
|
for (size_t i = 1; i < script_file.size(); i++)
|
||||||
|
if (script_file[i] == '\'')
|
||||||
|
user_script += "'\\''";
|
||||||
|
else if (script_file[i] == ',')
|
||||||
|
user_script += " ";
|
||||||
|
else
|
||||||
|
user_script += script_file[i];
|
||||||
|
} else {
|
||||||
|
// read in user script
|
||||||
|
std::ifstream ifs(script_file.c_str());
|
||||||
|
if(ifs.is_open()) {
|
||||||
|
user_script.assign( (std::istreambuf_iterator<char>(ifs) ),
|
||||||
|
(std::istreambuf_iterator<char>() ) );
|
||||||
|
} else {
|
||||||
|
log_error("Opening %s for reading failed\n", script_file.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string abc_script;
|
||||||
|
// in a custom flow the user-script handles everything itself
|
||||||
|
if(custom_flow == false) {
|
||||||
|
abc_script = stringf("read_blif \"%s/%s\"; ", tempdir_name.c_str(), input_file.c_str()); // read netlist into ABC
|
||||||
|
|
||||||
|
// load libraries and constraints
|
||||||
|
if (!liberty_files.empty() || !genlib_files.empty()) {
|
||||||
|
std::string dont_use_args;
|
||||||
|
for (std::string dont_use_cell : dont_use_cells) {
|
||||||
|
dont_use_args += stringf("-X \"%s\" ", dont_use_cell.c_str());
|
||||||
|
}
|
||||||
|
bool first_lib = true;
|
||||||
|
for (std::string liberty_file : liberty_files) {
|
||||||
|
abc_script += stringf("read_lib %s %s -w \"%s\" ; ", dont_use_args.c_str(), first_lib ? "" : "-m", liberty_file.c_str());
|
||||||
|
first_lib = false;
|
||||||
|
}
|
||||||
|
for (std::string liberty_file : genlib_files)
|
||||||
|
abc_script += stringf("read_library \"%s\"; ", liberty_file.c_str());
|
||||||
|
if (!constr_file.empty())
|
||||||
|
abc_script += stringf("read_constr -v \"%s\"; ", constr_file.c_str());
|
||||||
|
} else if (!lut_costs.empty())
|
||||||
|
abc_script += stringf("read_lut %s/lutdefs.txt; ", tempdir_name.c_str());
|
||||||
|
else
|
||||||
|
abc_script += stringf("read_library %s/stdcells.genlib; ", tempdir_name.c_str());
|
||||||
|
|
||||||
|
// add user script or build optimization script
|
||||||
|
if (user_script.length() > 0) {
|
||||||
|
abc_script += "\n\n" + user_script + "\n\n";
|
||||||
|
} else if (!lut_costs.empty()) {
|
||||||
|
bool all_luts_cost_same = true;
|
||||||
|
for (int this_cost : lut_costs)
|
||||||
|
if (this_cost != lut_costs.front())
|
||||||
|
all_luts_cost_same = false;
|
||||||
|
abc_script += fast_mode ? ABC_FAST_COMMAND_LUT : ABC_COMMAND_LUT;
|
||||||
|
if (all_luts_cost_same && !fast_mode)
|
||||||
|
abc_script += "; lutpack {S}";
|
||||||
|
} else if (!liberty_files.empty() || !genlib_files.empty())
|
||||||
|
abc_script += constr_file.empty() ? (fast_mode ? ABC_FAST_COMMAND_LIB : ABC_COMMAND_LIB) : (fast_mode ? ABC_FAST_COMMAND_CTR : ABC_COMMAND_CTR);
|
||||||
|
else if (sop_mode)
|
||||||
|
abc_script += fast_mode ? ABC_FAST_COMMAND_SOP : ABC_COMMAND_SOP;
|
||||||
|
else
|
||||||
|
abc_script += fast_mode ? ABC_FAST_COMMAND_DFL : ABC_COMMAND_DFL;
|
||||||
|
|
||||||
|
if (script_file.empty() && !delay_target.empty())
|
||||||
|
for (size_t pos = abc_script.find("dretime;"); pos != std::string::npos; pos = abc_script.find("dretime;", pos+1))
|
||||||
|
abc_script = abc_script.substr(0, pos) + "dretime; retime -o {D};" + abc_script.substr(pos+8);
|
||||||
|
|
||||||
|
if (abc_dress)
|
||||||
|
abc_script += stringf("; dress \"%s/%s\"", tempdir_name.c_str(), input_file.c_str());
|
||||||
|
|
||||||
|
// set output location
|
||||||
|
abc_script += stringf("; write_blif %s/%s", tempdir_name.c_str(), output_file.c_str());
|
||||||
|
abc_script = add_echos_to_abc_cmd(abc_script);
|
||||||
|
|
||||||
|
for (size_t i = 0; i+1 < abc_script.size(); i++)
|
||||||
|
if (abc_script[i] == ';' && abc_script[i+1] == ' ')
|
||||||
|
abc_script[i+1] = '\n';
|
||||||
|
} else {
|
||||||
|
// user provides a custom flow script
|
||||||
|
if(user_script.length() > 0) {
|
||||||
|
abc_script = user_script;
|
||||||
|
} else {
|
||||||
|
log_error("Flag -customflow requires -script <user-script>\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// replace placeholders in abc.script
|
||||||
|
substitute(abc_script, "{D}", delay_target);
|
||||||
|
substitute(abc_script, "{I}", sop_inputs);
|
||||||
|
substitute(abc_script, "{P}", sop_products);
|
||||||
|
substitute(abc_script, "{S}", lutin_shared);
|
||||||
|
substitute(abc_script, "{tmpdir}", tempdir_name.c_str());
|
||||||
|
substitute(abc_script, "{input}", input_file.c_str());
|
||||||
|
substitute(abc_script, "{output}", output_file.c_str());
|
||||||
|
|
||||||
|
// write script file
|
||||||
|
std::string buffer = stringf("%s/abc.script", tempdir_name.c_str());
|
||||||
|
FILE *f = fopen(buffer.c_str(), "wt");
|
||||||
|
if (f == nullptr)
|
||||||
|
log_error("Opening %s for writing failed: %s\n", buffer.c_str(), strerror(errno));
|
||||||
|
fprintf(f, "%s\n", abc_script.c_str());
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
for (const std::string &hfile : helper_files) {
|
||||||
|
std::ifstream fstream(hfile);
|
||||||
|
if (!fstream) {
|
||||||
|
std::cerr << "Error: Unable to open file " << hfile << std::endl;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string hscript((std::istreambuf_iterator<char>(fstream)),
|
||||||
|
std::istreambuf_iterator<char>());
|
||||||
|
fstream.close();
|
||||||
|
|
||||||
|
// Substitute placeholders
|
||||||
|
substitute(hscript, "{D}", delay_target);
|
||||||
|
substitute(hscript, "{I}", sop_inputs);
|
||||||
|
substitute(hscript, "{P}", sop_products);
|
||||||
|
substitute(hscript, "{S}", lutin_shared);
|
||||||
|
substitute(hscript, "{tmpdir}", tempdir_name.c_str());
|
||||||
|
substitute(hscript, "{input}", input_file.c_str());
|
||||||
|
substitute(hscript, "{output}", output_file.c_str());
|
||||||
|
|
||||||
|
// Get filename only (strip the directory path)
|
||||||
|
std::string filename = std::filesystem::path(hfile).filename().string();
|
||||||
|
|
||||||
|
// Write to tempdir
|
||||||
|
std::string hpath = tempdir_name + "/" + filename;
|
||||||
|
std::ofstream tmp_hstream(hpath);
|
||||||
|
if (!tmp_hstream) {
|
||||||
|
std::cerr << "Error: Unable to write tmpfile" << hpath << std::endl;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp_hstream << hscript;
|
||||||
|
tmp_hstream.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse clock domain
|
||||||
if (clk_str != "$")
|
if (clk_str != "$")
|
||||||
{
|
{
|
||||||
clk_polarity = true;
|
clk_polarity = true;
|
||||||
|
@ -787,95 +947,6 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
|
||||||
if (dff_mode && clk_sig.empty())
|
if (dff_mode && clk_sig.empty())
|
||||||
log_cmd_error("Clock domain %s not found.\n", clk_str.c_str());
|
log_cmd_error("Clock domain %s not found.\n", clk_str.c_str());
|
||||||
|
|
||||||
std::string tempdir_name;
|
|
||||||
if (cleanup)
|
|
||||||
tempdir_name = get_base_tmpdir() + "/";
|
|
||||||
else
|
|
||||||
tempdir_name = "_tmp_";
|
|
||||||
tempdir_name += proc_program_prefix() + "yosys-abc-XXXXXX";
|
|
||||||
tempdir_name = make_temp_dir(tempdir_name);
|
|
||||||
log_header(design, "Extracting gate netlist of module `%s' to `%s/input.blif'..\n",
|
|
||||||
module->name.c_str(), replace_tempdir(tempdir_name, tempdir_name, show_tempdir).c_str());
|
|
||||||
|
|
||||||
std::string abc_script = stringf("read_blif \"%s/input.blif\"; ", tempdir_name.c_str());
|
|
||||||
|
|
||||||
if (!liberty_files.empty() || !genlib_files.empty()) {
|
|
||||||
std::string dont_use_args;
|
|
||||||
for (std::string dont_use_cell : dont_use_cells) {
|
|
||||||
dont_use_args += stringf("-X \"%s\" ", dont_use_cell.c_str());
|
|
||||||
}
|
|
||||||
bool first_lib = true;
|
|
||||||
for (std::string liberty_file : liberty_files) {
|
|
||||||
abc_script += stringf("read_lib %s %s -w \"%s\" ; ", dont_use_args.c_str(), first_lib ? "" : "-m", liberty_file.c_str());
|
|
||||||
first_lib = false;
|
|
||||||
}
|
|
||||||
for (std::string liberty_file : genlib_files)
|
|
||||||
abc_script += stringf("read_library \"%s\"; ", liberty_file.c_str());
|
|
||||||
if (!constr_file.empty())
|
|
||||||
abc_script += stringf("read_constr -v \"%s\"; ", constr_file.c_str());
|
|
||||||
} else
|
|
||||||
if (!lut_costs.empty())
|
|
||||||
abc_script += stringf("read_lut %s/lutdefs.txt; ", tempdir_name.c_str());
|
|
||||||
else
|
|
||||||
abc_script += stringf("read_library %s/stdcells.genlib; ", tempdir_name.c_str());
|
|
||||||
|
|
||||||
if (!script_file.empty()) {
|
|
||||||
if (script_file[0] == '+') {
|
|
||||||
for (size_t i = 1; i < script_file.size(); i++)
|
|
||||||
if (script_file[i] == '\'')
|
|
||||||
abc_script += "'\\''";
|
|
||||||
else if (script_file[i] == ',')
|
|
||||||
abc_script += " ";
|
|
||||||
else
|
|
||||||
abc_script += script_file[i];
|
|
||||||
} else
|
|
||||||
abc_script += stringf("source %s", script_file.c_str());
|
|
||||||
} else if (!lut_costs.empty()) {
|
|
||||||
bool all_luts_cost_same = true;
|
|
||||||
for (int this_cost : lut_costs)
|
|
||||||
if (this_cost != lut_costs.front())
|
|
||||||
all_luts_cost_same = false;
|
|
||||||
abc_script += fast_mode ? ABC_FAST_COMMAND_LUT : ABC_COMMAND_LUT;
|
|
||||||
if (all_luts_cost_same && !fast_mode)
|
|
||||||
abc_script += "; lutpack {S}";
|
|
||||||
} else if (!liberty_files.empty() || !genlib_files.empty())
|
|
||||||
abc_script += constr_file.empty() ? (fast_mode ? ABC_FAST_COMMAND_LIB : ABC_COMMAND_LIB) : (fast_mode ? ABC_FAST_COMMAND_CTR : ABC_COMMAND_CTR);
|
|
||||||
else if (sop_mode)
|
|
||||||
abc_script += fast_mode ? ABC_FAST_COMMAND_SOP : ABC_COMMAND_SOP;
|
|
||||||
else
|
|
||||||
abc_script += fast_mode ? ABC_FAST_COMMAND_DFL : ABC_COMMAND_DFL;
|
|
||||||
|
|
||||||
if (script_file.empty() && !delay_target.empty())
|
|
||||||
for (size_t pos = abc_script.find("dretime;"); pos != std::string::npos; pos = abc_script.find("dretime;", pos+1))
|
|
||||||
abc_script = abc_script.substr(0, pos) + "dretime; retime -o {D};" + abc_script.substr(pos+8);
|
|
||||||
|
|
||||||
for (size_t pos = abc_script.find("{D}"); pos != std::string::npos; pos = abc_script.find("{D}", pos))
|
|
||||||
abc_script = abc_script.substr(0, pos) + delay_target + abc_script.substr(pos+3);
|
|
||||||
|
|
||||||
for (size_t pos = abc_script.find("{I}"); pos != std::string::npos; pos = abc_script.find("{I}", pos))
|
|
||||||
abc_script = abc_script.substr(0, pos) + sop_inputs + abc_script.substr(pos+3);
|
|
||||||
|
|
||||||
for (size_t pos = abc_script.find("{P}"); pos != std::string::npos; pos = abc_script.find("{P}", pos))
|
|
||||||
abc_script = abc_script.substr(0, pos) + sop_products + abc_script.substr(pos+3);
|
|
||||||
|
|
||||||
for (size_t pos = abc_script.find("{S}"); pos != std::string::npos; pos = abc_script.find("{S}", pos))
|
|
||||||
abc_script = abc_script.substr(0, pos) + lutin_shared + abc_script.substr(pos+3);
|
|
||||||
if (abc_dress)
|
|
||||||
abc_script += stringf("; dress \"%s/input.blif\"", tempdir_name.c_str());
|
|
||||||
abc_script += stringf("; write_blif %s/output.blif", tempdir_name.c_str());
|
|
||||||
abc_script = add_echos_to_abc_cmd(abc_script);
|
|
||||||
|
|
||||||
for (size_t i = 0; i+1 < abc_script.size(); i++)
|
|
||||||
if (abc_script[i] == ';' && abc_script[i+1] == ' ')
|
|
||||||
abc_script[i+1] = '\n';
|
|
||||||
|
|
||||||
std::string buffer = stringf("%s/abc.script", tempdir_name.c_str());
|
|
||||||
FILE *f = fopen(buffer.c_str(), "wt");
|
|
||||||
if (f == nullptr)
|
|
||||||
log_error("Opening %s for writing failed: %s\n", buffer.c_str(), strerror(errno));
|
|
||||||
fprintf(f, "%s\n", abc_script.c_str());
|
|
||||||
fclose(f);
|
|
||||||
|
|
||||||
if (dff_mode || !clk_str.empty())
|
if (dff_mode || !clk_str.empty())
|
||||||
{
|
{
|
||||||
if (clk_sig.size() == 0)
|
if (clk_sig.size() == 0)
|
||||||
|
@ -924,7 +995,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
|
||||||
|
|
||||||
handle_loops();
|
handle_loops();
|
||||||
|
|
||||||
buffer = stringf("%s/input.blif", tempdir_name.c_str());
|
buffer = stringf("%s/%s", tempdir_name.c_str(), input_file.c_str());
|
||||||
f = fopen(buffer.c_str(), "wt");
|
f = fopen(buffer.c_str(), "wt");
|
||||||
if (f == nullptr)
|
if (f == nullptr)
|
||||||
log_error("Opening %s for writing failed: %s\n", buffer.c_str(), strerror(errno));
|
log_error("Opening %s for writing failed: %s\n", buffer.c_str(), strerror(errno));
|
||||||
|
@ -1105,7 +1176,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
|
||||||
fclose(f);
|
fclose(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer = stringf("\"%s\" -s -f %s/abc.script 2>&1", exe_file.c_str(), tempdir_name.c_str());
|
buffer = stringf("\"%s\" %s %s/abc.script 2>&1", exe_file.c_str(), exe_flags.c_str(), tempdir_name.c_str());
|
||||||
log("Running ABC command: %s\n", replace_tempdir(buffer, tempdir_name, show_tempdir).c_str());
|
log("Running ABC command: %s\n", replace_tempdir(buffer, tempdir_name, show_tempdir).c_str());
|
||||||
|
|
||||||
#ifndef YOSYS_LINK_ABC
|
#ifndef YOSYS_LINK_ABC
|
||||||
|
@ -1158,7 +1229,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
log_error("ABC: execution of command \"%s\" failed: return code %d.\n", buffer.c_str(), ret);
|
log_error("ABC: execution of command \"%s\" failed: return code %d.\n", buffer.c_str(), ret);
|
||||||
|
|
||||||
buffer = stringf("%s/%s", tempdir_name.c_str(), "output.blif");
|
buffer = stringf("%s/%s", tempdir_name.c_str(), output_file.c_str());
|
||||||
std::ifstream ifs;
|
std::ifstream ifs;
|
||||||
ifs.open(buffer);
|
ifs.open(buffer);
|
||||||
if (ifs.fail())
|
if (ifs.fail())
|
||||||
|
@ -1166,7 +1237,30 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
|
||||||
|
|
||||||
bool builtin_lib = liberty_files.empty() && genlib_files.empty();
|
bool builtin_lib = liberty_files.empty() && genlib_files.empty();
|
||||||
RTLIL::Design *mapped_design = new RTLIL::Design;
|
RTLIL::Design *mapped_design = new RTLIL::Design;
|
||||||
|
|
||||||
|
// verilog?
|
||||||
|
if (output_file.rfind(".v") == (output_file.length() - 2)) {
|
||||||
|
AST::current_filename = output_file.c_str();
|
||||||
|
AST::set_line_num = &frontend_verilog_yyset_lineno;
|
||||||
|
AST::get_line_num = &frontend_verilog_yyget_lineno;
|
||||||
|
|
||||||
|
VERILOG_FRONTEND::current_ast = new AST::AstNode(AST::AST_DESIGN);
|
||||||
|
VERILOG_FRONTEND::lexin = &ifs;
|
||||||
|
|
||||||
|
frontend_verilog_yyset_lineno(1);
|
||||||
|
frontend_verilog_yyrestart(NULL);
|
||||||
|
frontend_verilog_yyparse();
|
||||||
|
frontend_verilog_yylex_destroy();
|
||||||
|
|
||||||
|
AST::process(mapped_design, VERILOG_FRONTEND::current_ast, true, false, false, false, false, false, true /*dump rtlil*/, true,
|
||||||
|
true, true, false, false, false, false, true, true, false, false, false, false, false);
|
||||||
|
|
||||||
|
VERILOG_FRONTEND::lexin = NULL;
|
||||||
|
VERILOG_FRONTEND::current_ast = NULL;
|
||||||
|
} else {
|
||||||
|
// default to blif
|
||||||
parse_blif(mapped_design, ifs, builtin_lib ? ID(DFF) : ID(_dff_), false, sop_mode);
|
parse_blif(mapped_design, ifs, builtin_lib ? ID(DFF) : ID(_dff_), false, sop_mode);
|
||||||
|
}
|
||||||
|
|
||||||
ifs.close();
|
ifs.close();
|
||||||
|
|
||||||
|
@ -1633,6 +1727,18 @@ struct AbcPass : public Pass {
|
||||||
log(" preserve naming by an equivalence check between the original and\n");
|
log(" preserve naming by an equivalence check between the original and\n");
|
||||||
log(" post-ABC netlists (experimental).\n");
|
log(" post-ABC netlists (experimental).\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
log(" -customflow\n");
|
||||||
|
log(" User script defines the full ABC flow, not just optimization.\n");
|
||||||
|
log(" Yosys will no longer generate a script to read and write snippets.\n");
|
||||||
|
log(" The script is processed and copied to {tmpdir}/abc.script.\n");
|
||||||
|
log(" The following additional placeholder can be used:\n");
|
||||||
|
log(" {tmpdir}: execution directory for ABC call\n");
|
||||||
|
log(" {input}: generated snippet file to be processed in ABC\n");
|
||||||
|
log(" {output}: processed ABC output file\n");
|
||||||
|
log(" in/out can be set via the scratchpad, the defaults are:\n");
|
||||||
|
log(" abc.input = input.blif\n");
|
||||||
|
log(" abc.output = output.blif\n");
|
||||||
|
log("\n");
|
||||||
log("When no target cell library is specified the Yosys standard cell library is\n");
|
log("When no target cell library is specified the Yosys standard cell library is\n");
|
||||||
log("loaded into ABC before the ABC script is executed.\n");
|
log("loaded into ABC before the ABC script is executed.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
@ -1661,10 +1767,15 @@ struct AbcPass : public Pass {
|
||||||
std::string exe_file = yosys_abc_executable;
|
std::string exe_file = yosys_abc_executable;
|
||||||
std::string script_file, default_liberty_file, constr_file, clk_str;
|
std::string script_file, default_liberty_file, constr_file, clk_str;
|
||||||
std::vector<std::string> liberty_files, genlib_files, dont_use_cells;
|
std::vector<std::string> liberty_files, genlib_files, dont_use_cells;
|
||||||
|
std::string input_file = "input.blif";
|
||||||
|
std::string output_file = "output.blif";
|
||||||
|
std::string exe_flags = "-s -f";
|
||||||
|
std::vector<std::string> helper_files;
|
||||||
std::string delay_target, sop_inputs, sop_products, lutin_shared = "-S 1";
|
std::string delay_target, sop_inputs, sop_products, lutin_shared = "-S 1";
|
||||||
bool fast_mode = false, dff_mode = false, keepff = false, cleanup = true;
|
bool fast_mode = false, dff_mode = false, keepff = false, cleanup = true;
|
||||||
bool show_tempdir = false, sop_mode = false;
|
bool show_tempdir = false, sop_mode = false;
|
||||||
bool abc_dress = false;
|
bool abc_dress = false;
|
||||||
|
bool custom_flow = false;
|
||||||
vector<int> lut_costs;
|
vector<int> lut_costs;
|
||||||
markgroups = false;
|
markgroups = false;
|
||||||
|
|
||||||
|
@ -1677,6 +1788,7 @@ struct AbcPass : public Pass {
|
||||||
// get arguments from scratchpad first, then override by command arguments
|
// get arguments from scratchpad first, then override by command arguments
|
||||||
std::string lut_arg, luts_arg, g_arg;
|
std::string lut_arg, luts_arg, g_arg;
|
||||||
exe_file = design->scratchpad_get_string("abc.exe", exe_file /* inherit default value if not set */);
|
exe_file = design->scratchpad_get_string("abc.exe", exe_file /* inherit default value if not set */);
|
||||||
|
exe_flags = design->scratchpad_get_string("abc.exeflags", exe_flags);
|
||||||
script_file = design->scratchpad_get_string("abc.script", script_file);
|
script_file = design->scratchpad_get_string("abc.script", script_file);
|
||||||
default_liberty_file = design->scratchpad_get_string("abc.liberty", default_liberty_file);
|
default_liberty_file = design->scratchpad_get_string("abc.liberty", default_liberty_file);
|
||||||
constr_file = design->scratchpad_get_string("abc.constr", constr_file);
|
constr_file = design->scratchpad_get_string("abc.constr", constr_file);
|
||||||
|
@ -1699,6 +1811,7 @@ struct AbcPass : public Pass {
|
||||||
map_mux8 = design->scratchpad_get_bool("abc.mux8", map_mux8);
|
map_mux8 = design->scratchpad_get_bool("abc.mux8", map_mux8);
|
||||||
map_mux16 = design->scratchpad_get_bool("abc.mux16", map_mux16);
|
map_mux16 = design->scratchpad_get_bool("abc.mux16", map_mux16);
|
||||||
abc_dress = design->scratchpad_get_bool("abc.dress", abc_dress);
|
abc_dress = design->scratchpad_get_bool("abc.dress", abc_dress);
|
||||||
|
custom_flow = design->scratchpad_get_bool("abc.customflow", custom_flow);
|
||||||
g_arg = design->scratchpad_get_string("abc.g", g_arg);
|
g_arg = design->scratchpad_get_string("abc.g", g_arg);
|
||||||
|
|
||||||
fast_mode = design->scratchpad_get_bool("abc.fast", fast_mode);
|
fast_mode = design->scratchpad_get_bool("abc.fast", fast_mode);
|
||||||
|
@ -1743,6 +1856,10 @@ struct AbcPass : public Pass {
|
||||||
liberty_files.push_back(args[++argidx]);
|
liberty_files.push_back(args[++argidx]);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (arg == "-helper" && argidx+1 < args.size()) {
|
||||||
|
helper_files.push_back(args[++argidx]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (arg == "-dont_use" && argidx+1 < args.size()) {
|
if (arg == "-dont_use" && argidx+1 < args.size()) {
|
||||||
dont_use_cells.push_back(args[++argidx]);
|
dont_use_cells.push_back(args[++argidx]);
|
||||||
continue;
|
continue;
|
||||||
|
@ -1799,6 +1916,10 @@ struct AbcPass : public Pass {
|
||||||
abc_dress = true;
|
abc_dress = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (arg == "-customflow") {
|
||||||
|
custom_flow = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (arg == "-g" && argidx+1 < args.size()) {
|
if (arg == "-g" && argidx+1 < args.size()) {
|
||||||
if (g_arg_from_cmd)
|
if (g_arg_from_cmd)
|
||||||
log_cmd_error("Can only use -g once. Please combine.");
|
log_cmd_error("Can only use -g once. Please combine.");
|
||||||
|
@ -1840,6 +1961,11 @@ struct AbcPass : public Pass {
|
||||||
}
|
}
|
||||||
extra_args(args, argidx, design);
|
extra_args(args, argidx, design);
|
||||||
|
|
||||||
|
if(custom_flow) {
|
||||||
|
input_file = design->scratchpad_get_string("abc.input", input_file);
|
||||||
|
output_file = design->scratchpad_get_string("abc.output", output_file);
|
||||||
|
}
|
||||||
|
|
||||||
if (genlib_files.empty() && liberty_files.empty() && !default_liberty_file.empty())
|
if (genlib_files.empty() && liberty_files.empty() && !default_liberty_file.empty())
|
||||||
liberty_files.push_back(default_liberty_file);
|
liberty_files.push_back(default_liberty_file);
|
||||||
|
|
||||||
|
@ -2052,8 +2178,8 @@ struct AbcPass : public Pass {
|
||||||
initvals.set(&assign_map, mod);
|
initvals.set(&assign_map, mod);
|
||||||
|
|
||||||
if (!dff_mode || !clk_str.empty()) {
|
if (!dff_mode || !clk_str.empty()) {
|
||||||
abc_module(design, mod, script_file, exe_file, liberty_files, genlib_files, constr_file, cleanup, lut_costs, dff_mode, clk_str, keepff,
|
abc_module(design, mod, script_file, exe_file, exe_flags, input_file, output_file, helper_files, liberty_files, genlib_files, constr_file, cleanup, lut_costs, dff_mode, clk_str, keepff,
|
||||||
delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, mod->selected_cells(), show_tempdir, sop_mode, abc_dress, dont_use_cells);
|
delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, mod->selected_cells(), show_tempdir, sop_mode, abc_dress, dont_use_cells, custom_flow);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2214,8 +2340,8 @@ struct AbcPass : public Pass {
|
||||||
arst_sig = assign_map(std::get<5>(it.first));
|
arst_sig = assign_map(std::get<5>(it.first));
|
||||||
srst_polarity = std::get<6>(it.first);
|
srst_polarity = std::get<6>(it.first);
|
||||||
srst_sig = assign_map(std::get<7>(it.first));
|
srst_sig = assign_map(std::get<7>(it.first));
|
||||||
abc_module(design, mod, script_file, exe_file, liberty_files, genlib_files, constr_file, cleanup, lut_costs, !clk_sig.empty(), "$",
|
abc_module(design, mod, script_file, exe_file, exe_flags, input_file, output_file, helper_files, liberty_files, genlib_files, constr_file, cleanup, lut_costs, !clk_sig.empty(), "$", keepff,
|
||||||
keepff, delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, it.second, show_tempdir, sop_mode, abc_dress, dont_use_cells);
|
delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, it.second, show_tempdir, sop_mode, abc_dress, dont_use_cells, custom_flow);
|
||||||
assign_map.set(mod);
|
assign_map.set(mod);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "kernel/yosys.h"
|
#include "kernel/yosys.h"
|
||||||
#include "kernel/ff.h"
|
#include "kernel/ff.h"
|
||||||
|
#include "libparse.h"
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
USING_YOSYS_NAMESPACE
|
USING_YOSYS_NAMESPACE
|
||||||
|
@ -10,6 +11,7 @@ struct ClockGateCell {
|
||||||
IdString ce_pin;
|
IdString ce_pin;
|
||||||
IdString clk_in_pin;
|
IdString clk_in_pin;
|
||||||
IdString clk_out_pin;
|
IdString clk_out_pin;
|
||||||
|
std::vector<IdString> tie_lo_pins;
|
||||||
};
|
};
|
||||||
|
|
||||||
ClockGateCell icg_from_arg(std::string& name, std::string& str) {
|
ClockGateCell icg_from_arg(std::string& name, std::string& str) {
|
||||||
|
@ -37,6 +39,166 @@ ClockGateCell icg_from_arg(std::string& name, std::string& str) {
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::pair<std::optional<ClockGateCell>, std::optional<ClockGateCell>>
|
||||||
|
find_icgs(std::string filename, std::vector<std::string> const& dont_use_cells) {
|
||||||
|
std::ifstream f;
|
||||||
|
f.open(filename.c_str());
|
||||||
|
if (f.fail())
|
||||||
|
log_cmd_error("Can't open liberty file `%s': %s\n", filename.c_str(), strerror(errno));
|
||||||
|
LibertyParser libparser(f);
|
||||||
|
f.close();
|
||||||
|
auto ast = libparser.ast;
|
||||||
|
|
||||||
|
// We will pick the most suitable ICG absed on tie_lo count and area
|
||||||
|
struct ICGRankable : public ClockGateCell { double area; };
|
||||||
|
std::optional<ICGRankable> best_pos;
|
||||||
|
std::optional<ICGRankable> best_neg;
|
||||||
|
|
||||||
|
if (ast->id != "library")
|
||||||
|
log_error("Format error in liberty file.\n");
|
||||||
|
|
||||||
|
// This is a lot of boilerplate, isn't it?
|
||||||
|
for (auto cell : ast->children)
|
||||||
|
{
|
||||||
|
if (cell->id != "cell" || cell->args.size() != 1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const LibertyAst *dn = cell->find("dont_use");
|
||||||
|
if (dn != nullptr && dn->value == "true")
|
||||||
|
continue;
|
||||||
|
|
||||||
|
bool dont_use = false;
|
||||||
|
for (auto dont_use_cell : dont_use_cells)
|
||||||
|
{
|
||||||
|
if (patmatch(dont_use_cell.c_str(), cell->args[0].c_str()))
|
||||||
|
{
|
||||||
|
dont_use = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (dont_use)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const LibertyAst *icg_kind_ast = cell->find("clock_gating_integrated_cell");
|
||||||
|
if (icg_kind_ast == nullptr)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto cell_name = cell->args[0];
|
||||||
|
auto icg_kind = icg_kind_ast->value;
|
||||||
|
auto starts_with = [&](std::string prefix) {
|
||||||
|
return icg_kind.compare(0, prefix.size(), prefix) == 0;
|
||||||
|
};
|
||||||
|
bool clk_pol;
|
||||||
|
if (icg_kind == "latch_posedge" || starts_with("latch_posedge_")) {
|
||||||
|
clk_pol = true;
|
||||||
|
} else if (icg_kind == "latch_negedge" || starts_with("latch_negedge_")) {
|
||||||
|
clk_pol = false;
|
||||||
|
} else {
|
||||||
|
log("Ignoring ICG primitive %s of kind '%s'\n", cell_name.c_str(), icg_kind.c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_debug("maybe valid icg: %s\n", cell_name.c_str());
|
||||||
|
ClockGateCell icg_interface;
|
||||||
|
icg_interface.name = RTLIL::escape_id(cell_name);
|
||||||
|
|
||||||
|
for (auto pin : cell->children) {
|
||||||
|
if (pin->id != "pin" || pin->args.size() != 1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (auto clk = pin->find("clock_gate_clock_pin")) {
|
||||||
|
if (!icg_interface.clk_in_pin.empty()) {
|
||||||
|
log_warning("Malformed liberty file - multiple clock_gate_clock_pin in cell %s\n",
|
||||||
|
cell_name.c_str());
|
||||||
|
continue;
|
||||||
|
} else
|
||||||
|
icg_interface.clk_in_pin = RTLIL::escape_id(pin->args[0]);
|
||||||
|
} else if (auto gclk = pin->find("clock_gate_out_pin")) {
|
||||||
|
if (!icg_interface.clk_out_pin.empty()) {
|
||||||
|
log_warning("Malformed liberty file - multiple clock_gate_out_pin in cell %s\n",
|
||||||
|
cell_name.c_str());
|
||||||
|
continue;
|
||||||
|
} else
|
||||||
|
icg_interface.clk_out_pin = RTLIL::escape_id(pin->args[0]);
|
||||||
|
} else if (auto en = pin->find("clock_gate_enable_pin")) {
|
||||||
|
if (!icg_interface.ce_pin.empty()) {
|
||||||
|
log_warning("Malformed liberty file - multiple clock_gate_enable_pin in cell %s\n",
|
||||||
|
cell_name.c_str());
|
||||||
|
continue;
|
||||||
|
} else
|
||||||
|
icg_interface.ce_pin = RTLIL::escape_id(pin->args[0]);
|
||||||
|
} else if (auto se = pin->find("clock_gate_test_pin")) {
|
||||||
|
icg_interface.tie_lo_pins.push_back(RTLIL::escape_id(pin->args[0]));
|
||||||
|
} else {
|
||||||
|
const LibertyAst *dir = pin->find("direction");
|
||||||
|
if (dir->value == "internal")
|
||||||
|
continue;
|
||||||
|
|
||||||
|
log_warning("Malformed liberty file - extra pin %s in cell %s\n",
|
||||||
|
pin->args[0].c_str(), cell_name.c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (icg_interface.clk_in_pin.empty()) {
|
||||||
|
log_warning("Malformed liberty file - missing clock_gate_clock_pin in cell %s",
|
||||||
|
cell_name.c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (icg_interface.clk_out_pin.empty()) {
|
||||||
|
log_warning("Malformed liberty file - missing clock_gate_out_pin in cell %s",
|
||||||
|
cell_name.c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (icg_interface.ce_pin.empty()) {
|
||||||
|
log_warning("Malformed liberty file - missing clock_gate_enable_pin in cell %s",
|
||||||
|
cell_name.c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
double area = 0;
|
||||||
|
const LibertyAst *ar = cell->find("area");
|
||||||
|
if (ar != nullptr && !ar->value.empty())
|
||||||
|
area = atof(ar->value.c_str());
|
||||||
|
|
||||||
|
std::optional<ICGRankable>& icg_to_beat = clk_pol ? best_pos : best_neg;
|
||||||
|
|
||||||
|
bool winning = false;
|
||||||
|
if (icg_to_beat) {
|
||||||
|
log_debug("ties: %zu ? %zu\n", icg_to_beat->tie_lo_pins.size(),
|
||||||
|
icg_interface.tie_lo_pins.size());
|
||||||
|
log_debug("area: %f ? %f\n", icg_to_beat->area, area);
|
||||||
|
|
||||||
|
// Prefer fewer test enables over area reduction (unlikely to matter)
|
||||||
|
auto goal = std::make_pair(icg_to_beat->tie_lo_pins.size(), icg_to_beat->area);
|
||||||
|
auto cost = std::make_pair(icg_interface.tie_lo_pins.size(), area);
|
||||||
|
winning = cost < goal;
|
||||||
|
|
||||||
|
if (winning)
|
||||||
|
log_debug("%s beats %s\n", icg_interface.name.c_str(), icg_to_beat->name.c_str());
|
||||||
|
} else {
|
||||||
|
log_debug("%s is the first of its polarity\n", icg_interface.name.c_str());
|
||||||
|
winning = true;
|
||||||
|
}
|
||||||
|
if (winning) {
|
||||||
|
ICGRankable new_icg {icg_interface, area};
|
||||||
|
icg_to_beat.emplace(new_icg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<ClockGateCell> pos;
|
||||||
|
std::optional<ClockGateCell> neg;
|
||||||
|
if (best_pos) {
|
||||||
|
log("Selected rising edge ICG %s from Liberty file\n", best_pos->name.c_str());
|
||||||
|
pos.emplace(*best_pos);
|
||||||
|
}
|
||||||
|
if (best_neg) {
|
||||||
|
log("Selected falling edge ICG %s from Liberty file\n", best_neg->name.c_str());
|
||||||
|
neg.emplace(*best_neg);
|
||||||
|
}
|
||||||
|
return std::make_pair(pos, neg);
|
||||||
|
}
|
||||||
|
|
||||||
struct ClockgatePass : public Pass {
|
struct ClockgatePass : public Pass {
|
||||||
ClockgatePass() : Pass("clockgate", "extract clock gating out of flip flops") { }
|
ClockgatePass() : Pass("clockgate", "extract clock gating out of flip flops") { }
|
||||||
void help() override {
|
void help() override {
|
||||||
|
@ -60,12 +222,20 @@ struct ClockgatePass : public Pass {
|
||||||
log(" user-specified <celltype> ICG (integrated clock gating)\n");
|
log(" user-specified <celltype> ICG (integrated clock gating)\n");
|
||||||
log(" cell with ports named <ce>, <clk>, <gclk>.\n");
|
log(" cell with ports named <ce>, <clk>, <gclk>.\n");
|
||||||
log(" The ICG's clock enable pin must be active high.\n");
|
log(" The ICG's clock enable pin must be active high.\n");
|
||||||
|
log(" -liberty <filename>\n");
|
||||||
|
log(" If specified, ICGs will be selected from the liberty file\n");
|
||||||
|
log(" if available. Priority is given to cells with fewer tie_lo\n");
|
||||||
|
log(" inputs and smaller size. This removes the need to manually\n");
|
||||||
|
log(" specify -pos or -neg and -tie_lo.\n");
|
||||||
|
log(" -dont_use <celltype>\n");
|
||||||
|
log(" Cells <celltype> won't be considered when searching for ICGs\n");
|
||||||
|
log(" in the liberty file specified by -liberty.\n");
|
||||||
log(" -tie_lo <port_name>\n");
|
log(" -tie_lo <port_name>\n");
|
||||||
log(" Port <port_name> of the ICG will be tied to zero.\n");
|
log(" Port <port_name> of the ICG will be tied to zero.\n");
|
||||||
log(" Intended for DFT scan-enable pins.\n");
|
log(" Intended for DFT scan-enable pins.\n");
|
||||||
log(" -min_net_size <n>\n");
|
log(" -min_net_size <n>\n");
|
||||||
log(" Only transform sets of at least <n> eligible FFs.\n");
|
log(" Only transform sets of at least <n> eligible FFs.\n");
|
||||||
// log(" \n");
|
log(" \n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// One ICG will be generated per ClkNetInfo
|
// One ICG will be generated per ClkNetInfo
|
||||||
|
@ -110,7 +280,9 @@ struct ClockgatePass : public Pass {
|
||||||
|
|
||||||
std::optional<ClockGateCell> pos_icg_desc;
|
std::optional<ClockGateCell> pos_icg_desc;
|
||||||
std::optional<ClockGateCell> neg_icg_desc;
|
std::optional<ClockGateCell> neg_icg_desc;
|
||||||
std::vector<std::string> tie_lo_ports;
|
std::vector<std::string> tie_lo_pins;
|
||||||
|
std::string liberty_file;
|
||||||
|
std::vector<std::string> dont_use_cells;
|
||||||
int min_net_size = 0;
|
int min_net_size = 0;
|
||||||
|
|
||||||
size_t argidx;
|
size_t argidx;
|
||||||
|
@ -126,13 +298,33 @@ struct ClockgatePass : public Pass {
|
||||||
neg_icg_desc = icg_from_arg(name, rest);
|
neg_icg_desc = icg_from_arg(name, rest);
|
||||||
}
|
}
|
||||||
if (args[argidx] == "-tie_lo" && argidx+1 < args.size()) {
|
if (args[argidx] == "-tie_lo" && argidx+1 < args.size()) {
|
||||||
tie_lo_ports.push_back(RTLIL::escape_id(args[++argidx]));
|
tie_lo_pins.push_back(RTLIL::escape_id(args[++argidx]));
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-liberty" && argidx+1 < args.size()) {
|
||||||
|
liberty_file = args[++argidx];
|
||||||
|
rewrite_filename(liberty_file);
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-dont_use" && argidx+1 < args.size()) {
|
||||||
|
dont_use_cells.push_back(args[++argidx]);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
if (args[argidx] == "-min_net_size" && argidx+1 < args.size()) {
|
if (args[argidx] == "-min_net_size" && argidx+1 < args.size()) {
|
||||||
min_net_size = atoi(args[++argidx].c_str());
|
min_net_size = atoi(args[++argidx].c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!liberty_file.empty())
|
||||||
|
std::tie(pos_icg_desc, neg_icg_desc) =
|
||||||
|
find_icgs(liberty_file, dont_use_cells);
|
||||||
|
else {
|
||||||
|
for (auto pin : tie_lo_pins) {
|
||||||
|
if (pos_icg_desc)
|
||||||
|
pos_icg_desc->tie_lo_pins.push_back(pin);
|
||||||
|
if (neg_icg_desc)
|
||||||
|
neg_icg_desc->tie_lo_pins.push_back(pin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
extra_args(args, argidx, design);
|
extra_args(args, argidx, design);
|
||||||
|
|
||||||
pool<Cell*> ce_ffs;
|
pool<Cell*> ce_ffs;
|
||||||
|
@ -185,7 +377,7 @@ struct ClockgatePass : public Pass {
|
||||||
gclk.new_net = module->addWire(NEW_ID);
|
gclk.new_net = module->addWire(NEW_ID);
|
||||||
icg->setPort(matching_icg_desc->clk_out_pin, gclk.new_net);
|
icg->setPort(matching_icg_desc->clk_out_pin, gclk.new_net);
|
||||||
// Tie low DFT ports like scan chain enable
|
// Tie low DFT ports like scan chain enable
|
||||||
for (auto port : tie_lo_ports)
|
for (auto port : matching_icg_desc->tie_lo_pins)
|
||||||
icg->setPort(port, Const(0, 1));
|
icg->setPort(port, Const(0, 1));
|
||||||
// Fix CE polarity if needed
|
// Fix CE polarity if needed
|
||||||
if (!clk.pol_ce) {
|
if (!clk.pol_ce) {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
read_ilang <<EOT
|
read_rtlil <<EOT
|
||||||
autoidx 1
|
autoidx 1
|
||||||
module \top
|
module \top
|
||||||
wire output 1 \Y
|
wire output 1 \Y
|
||||||
|
|
|
@ -0,0 +1,107 @@
|
||||||
|
library(test) {
|
||||||
|
/* Integrated clock gating cells */
|
||||||
|
cell (pos_small_tielo) {
|
||||||
|
area : 1;
|
||||||
|
clock_gating_integrated_cell : latch_posedge_precontrol;
|
||||||
|
pin (GCLK) {
|
||||||
|
clock_gate_out_pin : true;
|
||||||
|
direction : output;
|
||||||
|
}
|
||||||
|
pin (CLK) {
|
||||||
|
clock_gate_clock_pin : true;
|
||||||
|
direction : input;
|
||||||
|
}
|
||||||
|
pin (CE) {
|
||||||
|
clock_gate_enable_pin : true;
|
||||||
|
direction : input;
|
||||||
|
}
|
||||||
|
pin (SE) {
|
||||||
|
clock_gate_test_pin : true;
|
||||||
|
direction : input;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cell (pos_big) {
|
||||||
|
area : 10;
|
||||||
|
clock_gating_integrated_cell : latch_posedge;
|
||||||
|
pin (GCLK) {
|
||||||
|
clock_gate_out_pin : true;
|
||||||
|
direction : output;
|
||||||
|
}
|
||||||
|
pin (CLK) {
|
||||||
|
clock_gate_clock_pin : true;
|
||||||
|
direction : input;
|
||||||
|
}
|
||||||
|
pin (CE) {
|
||||||
|
clock_gate_enable_pin : true;
|
||||||
|
direction : input;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cell (pos_small) {
|
||||||
|
area : 1;
|
||||||
|
clock_gating_integrated_cell : latch_posedge;
|
||||||
|
pin (GCLK) {
|
||||||
|
clock_gate_out_pin : true;
|
||||||
|
direction : output;
|
||||||
|
}
|
||||||
|
pin (CLK) {
|
||||||
|
clock_gate_clock_pin : true;
|
||||||
|
direction : input;
|
||||||
|
}
|
||||||
|
pin (CE) {
|
||||||
|
clock_gate_enable_pin : true;
|
||||||
|
direction : input;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cell (neg_big) {
|
||||||
|
area : 10;
|
||||||
|
clock_gating_integrated_cell : latch_negedge;
|
||||||
|
pin (GCLK) {
|
||||||
|
clock_gate_out_pin : true;
|
||||||
|
direction : output;
|
||||||
|
}
|
||||||
|
pin (CLK) {
|
||||||
|
clock_gate_clock_pin : true;
|
||||||
|
direction : input;
|
||||||
|
}
|
||||||
|
pin (CE) {
|
||||||
|
clock_gate_enable_pin : true;
|
||||||
|
direction : input;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cell (neg_small_tielo) {
|
||||||
|
area : 1;
|
||||||
|
clock_gating_integrated_cell : latch_negedge_precontrol;
|
||||||
|
pin (GCLK) {
|
||||||
|
clock_gate_out_pin : true;
|
||||||
|
direction : output;
|
||||||
|
}
|
||||||
|
pin (CLK) {
|
||||||
|
clock_gate_clock_pin : true;
|
||||||
|
direction : input;
|
||||||
|
}
|
||||||
|
pin (CE) {
|
||||||
|
clock_gate_enable_pin : true;
|
||||||
|
direction : input;
|
||||||
|
}
|
||||||
|
pin (SE) {
|
||||||
|
clock_gate_test_pin : true;
|
||||||
|
direction : input;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cell (neg_small) {
|
||||||
|
area : 1;
|
||||||
|
clock_gating_integrated_cell : latch_negedge;
|
||||||
|
pin (GCLK) {
|
||||||
|
clock_gate_out_pin : true;
|
||||||
|
direction : output;
|
||||||
|
}
|
||||||
|
pin (CLK) {
|
||||||
|
clock_gate_clock_pin : true;
|
||||||
|
direction : input;
|
||||||
|
}
|
||||||
|
pin (CE) {
|
||||||
|
clock_gate_enable_pin : true;
|
||||||
|
direction : input;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -61,7 +61,7 @@ clockgate -pos pdk_icg ce:clkin:clkout -tie_lo scanen
|
||||||
# falling edge clock flops don't get matched on -pos
|
# falling edge clock flops don't get matched on -pos
|
||||||
select -module dffe_00 -assert-count 0 t:\\pdk_icg
|
select -module dffe_00 -assert-count 0 t:\\pdk_icg
|
||||||
select -module dffe_01 -assert-count 0 t:\\pdk_icg
|
select -module dffe_01 -assert-count 0 t:\\pdk_icg
|
||||||
# falling edge clock flops do get matched on -pos
|
# rising edge clock flops do get matched on -pos
|
||||||
select -module dffe_10 -assert-count 1 t:\\pdk_icg
|
select -module dffe_10 -assert-count 1 t:\\pdk_icg
|
||||||
select -module dffe_11 -assert-count 1 t:\\pdk_icg
|
select -module dffe_11 -assert-count 1 t:\\pdk_icg
|
||||||
# if necessary, EN is inverted, since the given ICG
|
# if necessary, EN is inverted, since the given ICG
|
||||||
|
@ -79,10 +79,10 @@ select -module dffe_wide_11 -assert-count 1 t:\\pdk_icg
|
||||||
design -load before
|
design -load before
|
||||||
clockgate -min_net_size 1 -neg pdk_icg ce:clkin:clkout -tie_lo scanen
|
clockgate -min_net_size 1 -neg pdk_icg ce:clkin:clkout -tie_lo scanen
|
||||||
|
|
||||||
# rising edge clock flops don't get matched on -neg
|
# falling edge clock flops do get matched on -neg
|
||||||
select -module dffe_00 -assert-count 1 t:\\pdk_icg
|
select -module dffe_00 -assert-count 1 t:\\pdk_icg
|
||||||
select -module dffe_01 -assert-count 1 t:\\pdk_icg
|
select -module dffe_01 -assert-count 1 t:\\pdk_icg
|
||||||
# rising edge clock flops do get matched on -neg
|
# rising edge clock flops don't get matched on -neg
|
||||||
select -module dffe_10 -assert-count 0 t:\\pdk_icg
|
select -module dffe_10 -assert-count 0 t:\\pdk_icg
|
||||||
select -module dffe_11 -assert-count 0 t:\\pdk_icg
|
select -module dffe_11 -assert-count 0 t:\\pdk_icg
|
||||||
# if necessary, EN is inverted, since the given ICG
|
# if necessary, EN is inverted, since the given ICG
|
||||||
|
@ -193,4 +193,55 @@ select -assert-count 1 t:\\pdk_icg
|
||||||
|
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
# TODO test -tie_lo
|
design -load before
|
||||||
|
clockgate -liberty clockgate.lib
|
||||||
|
|
||||||
|
# rising edge ICGs
|
||||||
|
select -module dffe_00 -assert-count 0 t:\\pos_small
|
||||||
|
select -module dffe_01 -assert-count 0 t:\\pos_small
|
||||||
|
|
||||||
|
select -module dffe_10 -assert-count 1 t:\\pos_small
|
||||||
|
select -module dffe_11 -assert-count 1 t:\\pos_small
|
||||||
|
|
||||||
|
# falling edge ICGs
|
||||||
|
select -module dffe_00 -assert-count 1 t:\\neg_small
|
||||||
|
select -module dffe_01 -assert-count 1 t:\\neg_small
|
||||||
|
|
||||||
|
select -module dffe_10 -assert-count 0 t:\\neg_small
|
||||||
|
select -module dffe_11 -assert-count 0 t:\\neg_small
|
||||||
|
|
||||||
|
# and nothing else
|
||||||
|
select -module dffe_00 -assert-count 0 t:\\pos_big
|
||||||
|
select -module dffe_01 -assert-count 0 t:\\pos_big
|
||||||
|
select -module dffe_10 -assert-count 0 t:\\pos_big
|
||||||
|
select -module dffe_11 -assert-count 0 t:\\pos_big
|
||||||
|
select -module dffe_00 -assert-count 0 t:\\pos_small_tielo
|
||||||
|
select -module dffe_01 -assert-count 0 t:\\pos_small_tielo
|
||||||
|
select -module dffe_10 -assert-count 0 t:\\pos_small_tielo
|
||||||
|
select -module dffe_11 -assert-count 0 t:\\pos_small_tielo
|
||||||
|
select -module dffe_00 -assert-count 0 t:\\neg_big
|
||||||
|
select -module dffe_01 -assert-count 0 t:\\neg_big
|
||||||
|
select -module dffe_10 -assert-count 0 t:\\neg_big
|
||||||
|
select -module dffe_11 -assert-count 0 t:\\neg_big
|
||||||
|
select -module dffe_00 -assert-count 0 t:\\neg_small_tielo
|
||||||
|
select -module dffe_01 -assert-count 0 t:\\neg_small_tielo
|
||||||
|
select -module dffe_10 -assert-count 0 t:\\neg_small_tielo
|
||||||
|
select -module dffe_11 -assert-count 0 t:\\neg_small_tielo
|
||||||
|
|
||||||
|
# if necessary, EN is inverted, since the given ICG
|
||||||
|
# is assumed to have an active-high EN
|
||||||
|
select -module dffe_10 -assert-count 1 t:\$_NOT_
|
||||||
|
select -module dffe_11 -assert-count 0 t:\$_NOT_
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
design -load before
|
||||||
|
clockgate -liberty clockgate.lib -dont_use pos_small -dont_use neg_small
|
||||||
|
|
||||||
|
# rising edge ICGs
|
||||||
|
select -module dffe_10 -assert-count 1 t:\\pos_big
|
||||||
|
select -module dffe_11 -assert-count 1 t:\\pos_big
|
||||||
|
|
||||||
|
# falling edge ICGs
|
||||||
|
select -module dffe_00 -assert-count 1 t:\\neg_big
|
||||||
|
select -module dffe_01 -assert-count 1 t:\\neg_big
|
||||||
|
|
Loading…
Reference in New Issue