3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2025-04-27 10:55:51 +00:00

Merge remote-tracking branch 'origin/master' into xc7srl

This commit is contained in:
Eddie Hung 2019-03-25 13:17:22 -07:00
commit 6b90d3cf6c
15 changed files with 943 additions and 37 deletions

View file

@ -542,7 +542,7 @@ bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram,
}
// assign write ports
pair<SigBit, bool> wr_clkdom;
for (int cell_port_i = 0, bram_port_i = 0; cell_port_i < wr_ports; cell_port_i++)
{
bool clken = wr_clken[cell_port_i] == State::S1;
@ -552,7 +552,7 @@ bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram,
pair<SigBit, bool> clkdom(clksig, clkpol);
if (!clken)
clkdom = pair<SigBit, bool>(State::S1, false);
wr_clkdom = clkdom;
log(" Write port #%d is in clock domain %s%s.\n",
cell_port_i, clkdom.second ? "" : "!",
clken ? log_signal(clkdom.first) : "~async~");
@ -718,7 +718,13 @@ grow_read_ports:;
if (read_transp.count(pi.transp) && read_transp.at(pi.transp) != transp) {
if (match.make_transp && wr_ports <= 1) {
pi.make_transp = true;
enable_make_transp = true;
if (pi.clocks != 0) {
if (wr_ports == 1 && wr_clkdom != clkdom) {
log(" Bram port %c%d.%d cannot have soft transparency logic added as read and write clock domains differ.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
goto skip_bram_rport;
}
enable_make_transp = true;
}
} else {
log(" Bram port %c%d.%d has incompatible read transparency.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
goto skip_bram_rport;
@ -913,17 +919,18 @@ grow_read_ports:;
} else {
SigSpec bram_dout = module->addWire(NEW_ID, bram.dbits);
c->setPort(stringf("\\%sDATA", pf), bram_dout);
if (pi.make_outreg) {
if (pi.make_outreg && pi.make_transp) {
log(" Moving output register to address for transparent port %c%d.%d.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
SigSpec sig_addr_q = module->addWire(NEW_ID, bram.abits);
module->addDff(NEW_ID, pi.sig_clock, sig_addr, sig_addr_q, pi.effective_clkpol);
c->setPort(stringf("\\%sADDR", pf), sig_addr_q);
} else if (pi.make_outreg) {
SigSpec bram_dout_q = module->addWire(NEW_ID, bram.dbits);
if (!pi.sig_en.empty())
bram_dout = module->Mux(NEW_ID, bram_dout_q, bram_dout, pi.sig_en);
module->addDff(NEW_ID, pi.sig_clock, bram_dout, bram_dout_q, pi.effective_clkpol);
bram_dout = bram_dout_q;
}
if (pi.make_transp)
{
} else if (pi.make_transp) {
log(" Adding extra logic for transparent port %c%d.%d.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
SigSpec transp_en_d = module->Mux(NEW_ID, SigSpec(0, make_transp_enbits),

View file

@ -11,4 +11,5 @@ OBJS += passes/sat/async2sync.o
OBJS += passes/sat/supercover.o
OBJS += passes/sat/fmcombine.o
OBJS += passes/sat/mutate.o
OBJS += passes/sat/cutpoint.o

164
passes/sat/cutpoint.cc Normal file
View file

@ -0,0 +1,164 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct CutpointPass : public Pass {
CutpointPass() : Pass("cutpoint", "add hi/lo cover cells for each wire bit") { }
void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" cutpoint [options] [selection]\n");
log("\n");
log("This command adds formal cut points to the design.\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
// bool flag_noinit = false;
log_header(design, "Executing CUTPOINT pass.\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
// if (args[argidx] == "-noinit") {
// flag_noinit = true;
// continue;
// }
break;
}
extra_args(args, argidx, design);
for (auto module : design->selected_modules())
{
if (design->selected_whole_module(module->name)) {
log("Making all outputs of module %s cut points, removing module contents.\n", log_id(module));
module->new_connections(std::vector<RTLIL::SigSig>());
for (auto cell : vector<Cell*>(module->cells()))
module->remove(cell);
vector<Wire*> output_wires;
for (auto wire : module->wires())
if (wire->port_output)
output_wires.push_back(wire);
for (auto wire : output_wires)
module->connect(wire, module->Anyseq(NEW_ID, GetSize(wire)));
continue;
}
SigMap sigmap(module);
pool<SigBit> cutpoint_bits;
for (auto cell : module->selected_cells()) {
if (cell->type == "$anyseq")
continue;
log("Removing cell %s.%s, making all cell outputs cutpoints.\n", log_id(module), log_id(cell));
for (auto &conn : cell->connections()) {
if (cell->output(conn.first))
module->connect(conn.second, module->Anyseq(NEW_ID, GetSize(conn.second)));
}
module->remove(cell);
}
for (auto wire : module->selected_wires()) {
if (wire->port_output) {
log("Making output wire %s.%s a cutpoint.\n", log_id(module), log_id(wire));
Wire *new_wire = module->addWire(NEW_ID, wire);
module->swap_names(wire, new_wire);
module->connect(new_wire, module->Anyseq(NEW_ID, GetSize(new_wire)));
wire->port_id = 0;
wire->port_input = false;
wire->port_output = false;
continue;
}
log("Making wire %s.%s a cutpoint.\n", log_id(module), log_id(wire));
for (auto bit : sigmap(wire))
cutpoint_bits.insert(bit);
}
if (!cutpoint_bits.empty())
{
for (auto cell : module->cells()) {
for (auto &conn : cell->connections()) {
if (!cell->output(conn.first))
continue;
SigSpec sig = sigmap(conn.second);
int bit_count = 0;
for (auto &bit : sig) {
if (cutpoint_bits.count(bit))
bit_count++;
}
if (bit_count == 0)
continue;
SigSpec dummy = module->addWire(NEW_ID, bit_count);
bit_count = 0;
for (auto &bit : sig) {
if (cutpoint_bits.count(bit))
bit = dummy[bit_count++];
}
cell->setPort(conn.first, sig);
}
}
vector<Wire*> rewrite_wires;
for (auto wire : module->wires()) {
if (!wire->port_input)
continue;
int bit_count = 0;
for (auto &bit : sigmap(wire))
if (cutpoint_bits.count(bit))
bit_count++;
if (bit_count)
rewrite_wires.push_back(wire);
}
for (auto wire : rewrite_wires) {
Wire *new_wire = module->addWire(NEW_ID, wire);
SigSpec lhs, rhs, sig = sigmap(wire);
for (int i = 0; i < GetSize(sig); i++)
if (!cutpoint_bits.count(sig[i])) {
lhs.append(SigBit(wire, i));
rhs.append(SigBit(new_wire, i));
}
if (GetSize(lhs))
module->connect(lhs, rhs);
module->swap_names(wire, new_wire);
wire->port_id = 0;
wire->port_input = false;
wire->port_output = false;
}
SigSpec sig(cutpoint_bits);
sig.sort_and_unify();
for (auto chunk : sig.chunks()) {
SigSpec s(chunk);
module->connect(s, module->Anyseq(NEW_ID, GetSize(s)));
}
}
}
}
} CutpointPass;
PRIVATE_NAMESPACE_END

View file

@ -46,6 +46,8 @@ struct mutate_opts_t {
IdString ctrl_name;
int ctrl_width = -1, ctrl_value = -1;
bool none = false;
int pick_cover_prcnt = 80;
int weight_cover = 500;
@ -422,8 +424,9 @@ void database_reduce(std::vector<mutate_t> &database, const mutate_opts_t &opts,
log("Covered %d/%d wire bits (%.2f%%).\n", covered_wirebit_cnt, GetSize(coverdb.wirebit_db), 100.0 * covered_wirebit_cnt / GetSize(coverdb.wirebit_db));
}
void mutate_list(Design *design, const mutate_opts_t &opts, const string &filename, int N)
void mutate_list(Design *design, const mutate_opts_t &opts, const string &filename, const string &srcsfile, int N)
{
pool<string> sources;
std::vector<mutate_t> database;
xs128_t rng(opts.seed);
@ -497,6 +500,9 @@ void mutate_list(Design *design, const mutate_opts_t &opts, const string &filena
entry.wirebit = bit.offset;
}
if (!srcsfile.empty())
sources.insert(entry.src.begin(), entry.src.end());
entry.mode = "inv";
database_add(database, opts, entry);
@ -522,10 +528,20 @@ void mutate_list(Design *design, const mutate_opts_t &opts, const string &filena
log("Raw database size: %d\n", GetSize(database));
if (N != 0) {
database_reduce(database, opts, N, rng);
database_reduce(database, opts, opts.none ? N-1 : N, rng);
log("Reduced database size: %d\n", GetSize(database));
}
if (!srcsfile.empty()) {
std::ofstream sout;
sout.open(srcsfile, std::ios::out | std::ios::trunc);
if (!sout.is_open())
log_error("Could not open file \"%s\" with write access.\n", srcsfile.c_str());
sources.sort();
for (auto &s : sources)
sout << s << std::endl;
}
std::ofstream fout;
if (!filename.empty()) {
@ -536,6 +552,17 @@ void mutate_list(Design *design, const mutate_opts_t &opts, const string &filena
int ctrl_value = opts.ctrl_value;
if (opts.none) {
string str = "mutate";
if (!opts.ctrl_name.empty())
str += stringf(" -ctrl %s %d %d", log_id(opts.ctrl_name), opts.ctrl_width, ctrl_value++);
str += " -mode none";
if (filename.empty())
log("%s\n", str.c_str());
else
fout << str << std::endl;
}
for (auto &entry : database) {
string str = "mutate";
if (!opts.ctrl_name.empty())
@ -710,9 +737,15 @@ struct MutatePass : public Pass {
log(" -o filename\n");
log(" Write list to this file instead of console output\n");
log("\n");
log(" -s filename\n");
log(" Write a list of all src tags found in the design to the specified file\n");
log("\n");
log(" -seed N\n");
log(" RNG seed for selecting mutations\n");
log("\n");
log(" -none\n");
log(" Include a \"none\" mutation in the output\n");
log("\n");
log(" -ctrl name width value\n");
log(" Add -ctrl options to the output. Use 'value' for first mutation, then\n");
log(" simply count up from there.\n");
@ -761,6 +794,7 @@ struct MutatePass : public Pass {
{
mutate_opts_t opts;
string filename;
string srcsfile;
int N = -1;
log_header(design, "Executing MUTATE pass.\n");
@ -776,10 +810,18 @@ struct MutatePass : public Pass {
filename = args[++argidx];
continue;
}
if (args[argidx] == "-s" && argidx+1 < args.size()) {
srcsfile = args[++argidx];
continue;
}
if (args[argidx] == "-seed" && argidx+1 < args.size()) {
opts.seed = atoi(args[++argidx].c_str());
continue;
}
if (args[argidx] == "-none") {
opts.none = true;
continue;
}
if (args[argidx] == "-mode" && argidx+1 < args.size()) {
opts.mode = args[++argidx];
continue;
@ -879,7 +921,16 @@ struct MutatePass : public Pass {
extra_args(args, argidx, design);
if (N >= 0) {
mutate_list(design, opts, filename, N);
mutate_list(design, opts, filename, srcsfile, N);
return;
}
if (opts.mode == "none") {
if (!opts.ctrl_name.empty()) {
Module *topmod = opts.module.empty() ? design->top_module() : design->module(opts.module);
if (topmod)
mutate_ctrl_sig(topmod, opts.ctrl_name, opts.ctrl_width);
}
return;
}

View file

@ -24,6 +24,7 @@
#include <istream>
#include <fstream>
#include <iostream>
#include <sstream>
#ifndef FILTERLIB
#include "kernel/log.h"
@ -86,15 +87,17 @@ int LibertyParser::lexer(std::string &str)
{
int c;
// eat whitespace
do {
c = f.get();
} while (c == ' ' || c == '\t' || c == '\r');
if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.' || c == '[' || c == ']') {
// search for identifiers, numbers, plus or minus.
if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.') {
str = c;
while (1) {
c = f.get();
if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.' || c == '[' || c == ']')
if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.')
str += c;
else
break;
@ -111,6 +114,8 @@ int LibertyParser::lexer(std::string &str)
}
}
// if it wasn't an identifer, number of array range,
// maybe it's a string?
if (c == '"') {
str = "";
while (1) {
@ -125,9 +130,10 @@ int LibertyParser::lexer(std::string &str)
return 'v';
}
// if it wasn't a string, perhaps it's a comment or a forward slash?
if (c == '/') {
c = f.get();
if (c == '*') {
if (c == '*') { // start of '/*' block comment
int last_c = 0;
while (c > 0 && (last_c != '*' || c != '/')) {
last_c = c;
@ -136,7 +142,7 @@ int LibertyParser::lexer(std::string &str)
line++;
}
return lexer(str);
} else if (c == '/') {
} else if (c == '/') { // start of '//' line comment
while (c > 0 && c != '\n')
c = f.get();
line++;
@ -144,9 +150,10 @@ int LibertyParser::lexer(std::string &str)
}
f.unget();
// fprintf(stderr, "LEX: char >>/<<\n");
return '/';
return '/'; // a single '/' charater.
}
// check for a backslash
if (c == '\\') {
c = f.get();
if (c == '\r')
@ -157,11 +164,15 @@ int LibertyParser::lexer(std::string &str)
return '\\';
}
// check for a new line
if (c == '\n') {
line++;
return 'n';
}
// anything else, such as ';' will get passed
// through as literal items.
// if (c >= 32 && c < 255)
// fprintf(stderr, "LEX: char >>%c<<\n", c);
// else
@ -191,12 +202,11 @@ LibertyAst *LibertyParser::parse()
{
tok = lexer(str);
if (tok == ';')
// allow both ';' and new lines to
// terminate a statement.
if ((tok == ';') || (tok == 'n'))
break;
if (tok == 'n')
continue;
if (tok == ':' && ast->value.empty()) {
tok = lexer(ast->value);
if (tok != 'v')
@ -210,7 +220,12 @@ LibertyAst *LibertyParser::parse()
ast->value += str;
tok = lexer(str);
}
if (tok == ';')
// In a liberty file, all key : value pairs should end in ';'
// However, there are some liberty files in the wild that
// just have a newline. We'll be kind and accept a newline
// instead of the ';' too..
if ((tok == ';') || (tok == 'n'))
break;
else
error();
@ -225,6 +240,48 @@ LibertyAst *LibertyParser::parse()
continue;
if (tok == ')')
break;
// FIXME: the AST needs to be extended to store
// these vector ranges.
if (tok == '[')
{
// parse vector range [A] or [A:B]
std::string arg;
tok = lexer(arg);
if (tok != 'v')
{
// expected a vector array index
error("Expected a number.");
}
else
{
// fixme: check for number A
}
tok = lexer(arg);
// optionally check for : in case of [A:B]
// if it isn't we just expect ']'
// as we have [A]
if (tok == ':')
{
tok = lexer(arg);
if (tok != 'v')
{
// expected a vector array index
error("Expected a number.");
}
else
{
// fixme: check for number B
tok = lexer(arg);
}
}
// expect a closing bracket of array range
if (tok != ']')
{
error("Expected ']' on array range.");
}
continue;
}
if (tok != 'v')
error();
ast->args.push_back(arg);
@ -255,6 +312,14 @@ void LibertyParser::error()
log_error("Syntax error in liberty file on line %d.\n", line);
}
void LibertyParser::error(const std::string &str)
{
std::stringstream ss;
ss << "Syntax error in liberty file on line " << line << ".\n";
ss << " " << str << "\n";
log_error("%s", ss.str().c_str());
}
#else
void LibertyParser::error()
@ -263,25 +328,34 @@ void LibertyParser::error()
exit(1);
}
void LibertyParser::error(const std::string &str)
{
std::stringstream ss;
ss << "Syntax error in liberty file on line " << line << ".\n";
ss << " " << str << "\n";
printf("%s", ss.str().c_str());
exit(1);
}
/**** BEGIN: http://svn.clifford.at/tools/trunk/examples/check.h ****/
#define CHECK_NV(result, check) \
do { \
auto _R = (result); \
if (!(_R check)) { \
fprintf(stderr, "Error from '%s' (%ld %s) in %s:%d.\n", \
#result, (long int)_R, #check, __FILE__, __LINE__); \
abort(); \
} \
auto _R = (result); \
if (!(_R check)) { \
fprintf(stderr, "Error from '%s' (%ld %s) in %s:%d.\n", \
#result, (long int)_R, #check, __FILE__, __LINE__); \
abort(); \
} \
} while(0)
#define CHECK_COND(result) \
do { \
if (!(result)) { \
fprintf(stderr, "Error from '%s' in %s:%d.\n", \
#result, __FILE__, __LINE__); \
abort(); \
} \
if (!(result)) { \
fprintf(stderr, "Error from '%s' in %s:%d.\n", \
#result, __FILE__, __LINE__); \
abort(); \
} \
} while(0)
/**** END: http://svn.clifford.at/tools/trunk/examples/check.h ****/

View file

@ -46,9 +46,17 @@ namespace Yosys
LibertyAst *ast;
LibertyParser(std::istream &f) : f(f), line(1), ast(parse()) {}
~LibertyParser() { if (ast) delete ast; }
/* lexer return values:
'v': identifier, string, array range [...] -> str holds the token string
'n': newline
anything else is a single character.
*/
int lexer(std::string &str);
LibertyAst *parse();
LibertyAst *parse();
void error();
void error(const std::string &str);
};
}