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:
commit
6b90d3cf6c
15 changed files with 943 additions and 37 deletions
|
@ -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),
|
||||
|
|
|
@ -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
164
passes/sat/cutpoint.cc
Normal 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
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 ****/
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue