3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2025-06-22 05:43:40 +00:00

neater errors, lost in the sauce of source

This commit is contained in:
Emil J. Tywoniak 2025-06-18 18:05:48 +02:00
parent 242853f1f2
commit 6ac9f79de6
13 changed files with 196 additions and 245 deletions

View file

@ -48,7 +48,7 @@ The lexer does little more than identifying all keywords and literals recognised
by the Yosys Verilog frontend. by the Yosys Verilog frontend.
The lexer keeps track of the current location in the Verilog source code using The lexer keeps track of the current location in the Verilog source code using
some global variables. These variables are used by the constructor of AST nodes some VerilogLexer member variables. These variables are used by the constructor of AST nodes
to annotate each node with the source code location it originated from. to annotate each node with the source code location it originated from.
Finally the lexer identifies and handles special comments such as "``// synopsys Finally the lexer identifies and handles special comments such as "``// synopsys
@ -189,10 +189,11 @@ the bison code for parsing multiplications:
.. code:: none .. code:: none
:number-lines: :number-lines:
basic_expr '*' attr basic_expr { basic_expr TOK_ASTER attr basic_expr {
$$ = new AstNode(AST_MUL, $1, $4); $$ = std::make_unique<AstNode>(AST_MUL, std::move($1), std::move($4));
append_attr($$, $3); SET_AST_NODE_LOC($$.get(), @1, @4);
} | append_attr($$.get(), $3);
} |
The generated AST data structure is then passed directly to the AST frontend The generated AST data structure is then passed directly to the AST frontend
that performs the actual conversion to RTLIL. that performs the actual conversion to RTLIL.

View file

@ -38,8 +38,7 @@ using namespace AST_INTERNAL;
// instantiate global variables (public API) // instantiate global variables (public API)
namespace AST { namespace AST {
std::string current_filename; bool sv_mode_but_global_and_used_for_literally_one_condition;
bool sv_mode;
unsigned long long astnodes = 0; unsigned long long astnodes = 0;
unsigned long long astnode_count() { return astnodes; } unsigned long long astnode_count() { return astnodes; }
} }
@ -200,7 +199,7 @@ bool AstNode::get_bool_attribute(RTLIL::IdString id)
// create new node (AstNode constructor) // create new node (AstNode constructor)
// (the optional child arguments make it easier to create AST trees) // (the optional child arguments make it easier to create AST trees)
AstNode::AstNode(AstNodeType type, std::unique_ptr<AstNode> child1, std::unique_ptr<AstNode> child2, std::unique_ptr<AstNode> child3, std::unique_ptr<AstNode> child4) AstNode::AstNode(AstSrcLocType loc, AstNodeType type, std::unique_ptr<AstNode> child1, std::unique_ptr<AstNode> child2, std::unique_ptr<AstNode> child3, std::unique_ptr<AstNode> child4)
{ {
static unsigned int hashidx_count = 123456789; static unsigned int hashidx_count = 123456789;
hashidx_count = mkhash_xorshift(hashidx_count); hashidx_count = mkhash_xorshift(hashidx_count);
@ -208,7 +207,7 @@ AstNode::AstNode(AstNodeType type, std::unique_ptr<AstNode> child1, std::unique_
astnodes++; astnodes++;
this->type = type; this->type = type;
filename = current_filename; loc = loc;
is_input = false; is_input = false;
is_output = false; is_output = false;
is_reg = false; is_reg = false;
@ -252,7 +251,7 @@ AstNode::AstNode(AstNodeType type, std::unique_ptr<AstNode> child1, std::unique_
// create a (deep recursive) copy of a node // create a (deep recursive) copy of a node
std::unique_ptr<AstNode> AstNode::clone() const std::unique_ptr<AstNode> AstNode::clone() const
{ {
auto that = std::make_unique<AstNode>(this->type); auto that = std::make_unique<AstNode>(this->location, this->type);
cloneInto(*that.get()); cloneInto(*that.get());
return that; return that;
} }
@ -287,7 +286,6 @@ void AstNode::cloneInto(AstNode &other) const
other.id2ast = id2ast; other.id2ast = id2ast;
other.basic_prep = basic_prep; other.basic_prep = basic_prep;
other.lookahead = lookahead; other.lookahead = lookahead;
other.filename = filename;
other.location = location; other.location = location;
other.in_lvalue = in_lvalue; other.in_lvalue = in_lvalue;
other.in_param = in_param; other.in_param = in_param;
@ -842,9 +840,9 @@ bool AstNode::contains(const AstNode *other) const
} }
// create an AST node for a constant (using a 32 bit int as value) // create an AST node for a constant (using a 32 bit int as value)
std::unique_ptr<AstNode> AstNode::mkconst_int(uint32_t v, bool is_signed, int width) std::unique_ptr<AstNode> AstNode::mkconst_int(AstSrcLocType loc, uint32_t v, bool is_signed, int width)
{ {
auto node = std::make_unique<AstNode>(AST_CONSTANT); auto node = std::make_unique<AstNode>(loc, AST_CONSTANT);
node->integer = v; node->integer = v;
node->is_signed = is_signed; node->is_signed = is_signed;
for (int i = 0; i < width; i++) { for (int i = 0; i < width; i++) {
@ -858,9 +856,9 @@ std::unique_ptr<AstNode> AstNode::mkconst_int(uint32_t v, bool is_signed, int wi
} }
// create an AST node for a constant (using a bit vector as value) // create an AST node for a constant (using a bit vector as value)
std::unique_ptr<AstNode> AstNode::mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed, bool is_unsized) std::unique_ptr<AstNode> AstNode::mkconst_bits(AstSrcLocType loc, const std::vector<RTLIL::State> &v, bool is_signed, bool is_unsized)
{ {
auto node = std::make_unique<AstNode>(AST_CONSTANT); auto node = std::make_unique<AstNode>(loc, AST_CONSTANT);
node->is_signed = is_signed; node->is_signed = is_signed;
node->bits = v; node->bits = v;
for (size_t i = 0; i < 32; i++) { for (size_t i = 0; i < 32; i++) {
@ -876,15 +874,15 @@ std::unique_ptr<AstNode> AstNode::mkconst_bits(const std::vector<RTLIL::State> &
return node; return node;
} }
std::unique_ptr<AstNode> AstNode::mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed) std::unique_ptr<AstNode> AstNode::mkconst_bits(AstSrcLocType loc, const std::vector<RTLIL::State> &v, bool is_signed)
{ {
return mkconst_bits(v, is_signed, false); return mkconst_bits(loc, v, is_signed, false);
} }
// create an AST node for a constant (using a string in bit vector form as value) // create an AST node for a constant (using a string in bit vector form as value)
std::unique_ptr<AstNode> AstNode::mkconst_str(const std::vector<RTLIL::State> &v) std::unique_ptr<AstNode> AstNode::mkconst_str(AstSrcLocType loc, const std::vector<RTLIL::State> &v)
{ {
auto node = mkconst_str(RTLIL::Const(v).decode_string()); auto node = mkconst_str(loc, RTLIL::Const(v).decode_string());
while (GetSize(node->bits) < GetSize(v)) while (GetSize(node->bits) < GetSize(v))
node->bits.push_back(RTLIL::State::S0); node->bits.push_back(RTLIL::State::S0);
log_assert(node->bits == v); log_assert(node->bits == v);
@ -892,14 +890,14 @@ std::unique_ptr<AstNode> AstNode::mkconst_str(const std::vector<RTLIL::State> &v
} }
// create an AST node for a constant (using a string as value) // create an AST node for a constant (using a string as value)
std::unique_ptr<AstNode> AstNode::mkconst_str(const std::string &str) std::unique_ptr<AstNode> AstNode::mkconst_str(AstSrcLocType loc, const std::string &str)
{ {
std::unique_ptr<AstNode> node; std::unique_ptr<AstNode> node;
// LRM 1364-2005 5.2.3.3 The empty string literal ("") shall be considered // LRM 1364-2005 5.2.3.3 The empty string literal ("") shall be considered
// equivalent to the ASCII NUL ("\0") // equivalent to the ASCII NUL ("\0")
if (str.empty()) { if (str.empty()) {
node = AstNode::mkconst_int(0, false, 8); node = AstNode::mkconst_int(loc, 0, false, 8);
} else { } else {
std::vector<RTLIL::State> data; std::vector<RTLIL::State> data;
data.reserve(str.size() * 8); data.reserve(str.size() * 8);
@ -910,7 +908,7 @@ std::unique_ptr<AstNode> AstNode::mkconst_str(const std::string &str)
ch = ch >> 1; ch = ch >> 1;
} }
} }
node = AstNode::mkconst_bits(data, false); node = AstNode::mkconst_bits(loc, data, false);
} }
node->is_string = true; node->is_string = true;
@ -919,19 +917,19 @@ std::unique_ptr<AstNode> AstNode::mkconst_str(const std::string &str)
} }
// create a temporary register // create a temporary register
std::unique_ptr<AstNode> AstNode::mktemp_logic(const std::string &name, AstNode *mod, bool nosync, int range_left, int range_right, bool is_signed) std::unique_ptr<AstNode> AstNode::mktemp_logic(AstSrcLocType loc, const std::string &name, AstNode *mod, bool nosync, int range_left, int range_right, bool is_signed)
{ {
auto wire_owned = std::make_unique<AstNode>(AST_WIRE, std::make_unique<AstNode>(AST_RANGE, mkconst_int(range_left, true), mkconst_int(range_right, true))); auto wire_owned = std::make_unique<AstNode>(loc, AST_WIRE, std::make_unique<AstNode>(loc, AST_RANGE, mkconst_int(loc, range_left, true), mkconst_int(loc, range_right, true)));
auto* wire = wire_owned.get(); auto* wire = wire_owned.get();
wire->str = stringf("%s%s:%d$%d", name.c_str(), RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++); wire->str = stringf("%s%s:%d$%d", name.c_str(), RTLIL::encode_filename(location.filename).c_str(), location.first_line, autoidx++);
if (nosync) if (nosync)
wire->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); wire->set_attribute(ID::nosync, AstNode::mkconst_int(loc, 1, false));
wire->is_signed = is_signed; wire->is_signed = is_signed;
wire->is_logic = true; wire->is_logic = true;
mod->children.push_back(std::move(wire_owned)); mod->children.push_back(std::move(wire_owned));
while (wire->simplify(true, 1, -1, false)) { } while (wire->simplify(true, 1, -1, false)) { }
auto ident = std::make_unique<AstNode>(AST_IDENTIFIER); auto ident = std::make_unique<AstNode>(loc, AST_IDENTIFIER);
ident->str = wire->str; ident->str = wire->str;
ident->id2ast = wire; ident->id2ast = wire;
@ -985,7 +983,7 @@ RTLIL::Const AstNode::asParaConst() const
{ {
if (type == AST_REALVALUE) if (type == AST_REALVALUE)
{ {
auto strnode = AstNode::mkconst_str(stringf("%f", realvalue)); auto strnode = AstNode::mkconst_str(location, stringf("%f", realvalue));
RTLIL::Const val = strnode->asAttrConst(); RTLIL::Const val = strnode->asAttrConst();
val.flags |= RTLIL::CONST_FLAG_REAL; val.flags |= RTLIL::CONST_FLAG_REAL;
return val; return val;
@ -1087,7 +1085,7 @@ RTLIL::Const AstNode::realAsConst(int width)
std::string AstNode::loc_string() const std::string AstNode::loc_string() const
{ {
return stringf("%s:%d.%d-%d.%d", filename.c_str(), location.first_line, location.first_column, location.last_line, location.last_column); return stringf("%s:%d.%d-%d.%d", location.filename.c_str(), location.first_line, location.first_column, location.last_line, location.last_column);
} }
void AST::set_src_attr(RTLIL::AttrObject *obj, const AstNode *ast) void AST::set_src_attr(RTLIL::AttrObject *obj, const AstNode *ast)
@ -1445,7 +1443,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool nodisplay, bool dump
if (design->has(child->str)) { if (design->has(child->str)) {
RTLIL::Module *existing_mod = design->module(child->str); RTLIL::Module *existing_mod = design->module(child->str);
if (!nooverwrite && !overwrite && !existing_mod->get_blackbox_attribute()) { if (!nooverwrite && !overwrite && !existing_mod->get_blackbox_attribute()) {
log_file_error(child->filename, child->location.first_line, "Re-definition of module `%s'!\n", child->str.c_str()); log_file_error(child->location.filename, child->location.first_line, "Re-definition of module `%s'!\n", child->str.c_str());
} else if (nooverwrite) { } else if (nooverwrite) {
log("Ignoring re-definition of module `%s' at %s.\n", log("Ignoring re-definition of module `%s' at %s.\n",
child->str.c_str(), child->loc_string().c_str()); child->str.c_str(), child->loc_string().c_str());
@ -1924,7 +1922,7 @@ void AstNode::input_error(const char *format, ...) const
{ {
va_list ap; va_list ap;
va_start(ap, format); va_start(ap, format);
logv_file_error(filename, location.first_line, format, ap); logv_file_error(location.filename, location.first_line, format, ap);
} }
YOSYS_NAMESPACE_END YOSYS_NAMESPACE_END

View file

@ -163,10 +163,11 @@ namespace AST
}; };
struct AstSrcLocType { struct AstSrcLocType {
std::string filename;
unsigned int first_line, last_line; unsigned int first_line, last_line;
unsigned int first_column, last_column; unsigned int first_column, last_column;
AstSrcLocType() : first_line(0), last_line(0), first_column(0), last_column(0) {} AstSrcLocType() : filename(""), first_line(0), last_line(0), first_column(0), last_column(0) {}
AstSrcLocType(int _first_line, int _first_column, int _last_line, int _last_column) : first_line(_first_line), last_line(_last_line), first_column(_first_column), last_column(_last_column) {} AstSrcLocType(std::string _filename, int _first_line, int _first_column, int _last_line, int _last_column) : filename(_filename), first_line(_first_line), last_line(_last_line), first_column(_first_column), last_column(_last_column) {}
}; };
// convert an node type to a string (e.g. for debug output) // convert an node type to a string (e.g. for debug output)
@ -223,7 +224,6 @@ namespace AST
// this is the original sourcecode location that resulted in this AST node // this is the original sourcecode location that resulted in this AST node
// it is automatically set by the constructor using AST::current_filename and // it is automatically set by the constructor using AST::current_filename and
// the AST::get_line_num() callback function. // the AST::get_line_num() callback function.
std::string filename;
AstSrcLocType location; AstSrcLocType location;
// are we embedded in an lvalue, param? // are we embedded in an lvalue, param?
@ -234,7 +234,7 @@ namespace AST
bool in_param_from_above; bool in_param_from_above;
// creating and deleting nodes // creating and deleting nodes
AstNode(AstNodeType type = AST_NONE, std::unique_ptr<AstNode> child1 = nullptr, std::unique_ptr<AstNode> child2 = nullptr, std::unique_ptr<AstNode> child3 = nullptr, std::unique_ptr<AstNode> child4 = nullptr); AstNode(AstSrcLocType loc, AstNodeType type = AST_NONE, std::unique_ptr<AstNode> child1 = nullptr, std::unique_ptr<AstNode> child2 = nullptr, std::unique_ptr<AstNode> child3 = nullptr, std::unique_ptr<AstNode> child4 = nullptr);
std::unique_ptr<AstNode> clone() const; std::unique_ptr<AstNode> clone() const;
void cloneInto(AstNode &other) const; void cloneInto(AstNode &other) const;
void delete_children(); void delete_children();
@ -322,14 +322,14 @@ namespace AST
AstNode operator=(AstNode) = delete; AstNode operator=(AstNode) = delete;
// helper functions for creating AST nodes for constants // helper functions for creating AST nodes for constants
static std::unique_ptr<AstNode> mkconst_int(uint32_t v, bool is_signed, int width = 32); static std::unique_ptr<AstNode> mkconst_int(AstSrcLocType loc, uint32_t v, bool is_signed, int width = 32);
static std::unique_ptr<AstNode> mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed, bool is_unsized); static std::unique_ptr<AstNode> mkconst_bits(AstSrcLocType loc, const std::vector<RTLIL::State> &v, bool is_signed, bool is_unsized);
static std::unique_ptr<AstNode> mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed); static std::unique_ptr<AstNode> mkconst_bits(AstSrcLocType loc, const std::vector<RTLIL::State> &v, bool is_signed);
static std::unique_ptr<AstNode> mkconst_str(const std::vector<RTLIL::State> &v); static std::unique_ptr<AstNode> mkconst_str(AstSrcLocType loc, const std::vector<RTLIL::State> &v);
static std::unique_ptr<AstNode> mkconst_str(const std::string &str); static std::unique_ptr<AstNode> mkconst_str(AstSrcLocType loc, const std::string &str);
// helper function to create an AST node for a temporary register // helper function to create an AST node for a temporary register
std::unique_ptr<AstNode> mktemp_logic(const std::string &name, AstNode *mod, bool nosync, int range_left, int range_right, bool is_signed); std::unique_ptr<AstNode> mktemp_logic(AstSrcLocType loc, const std::string &name, AstNode *mod, bool nosync, int range_left, int range_right, bool is_signed);
// helper function for creating sign-extended const objects // helper function for creating sign-extended const objects
RTLIL::Const bitsAsConst(int width, bool is_signed); RTLIL::Const bitsAsConst(int width, bool is_signed);
@ -409,7 +409,7 @@ namespace AST
// to initialize the filename and linenum properties of new nodes // to initialize the filename and linenum properties of new nodes
extern std::string current_filename; extern std::string current_filename;
// also set by the language frontend to control some AST processing // also set by the language frontend to control some AST processing
extern bool sv_mode; extern bool sv_mode_but_global_and_used_for_literally_one_condition;
// for stats // for stats
unsigned long long astnode_count(); unsigned long long astnode_count();
@ -419,7 +419,7 @@ namespace AST
void use_internal_line_num(); void use_internal_line_num();
// call a DPI function // call a DPI function
std::unique_ptr<AstNode> dpi_call(const std::string &rtype, const std::string &fname, const std::vector<std::string> &argtypes, const std::vector<std::unique_ptr<AstNode>> &args); std::unique_ptr<AstNode> dpi_call(AstSrcLocType loc, const std::string &rtype, const std::string &fname, const std::vector<std::string> &argtypes, const std::vector<std::unique_ptr<AstNode>> &args);
// Helper functions related to handling SystemVerilog interfaces // Helper functions related to handling SystemVerilog interfaces
std::pair<std::string,std::string> split_modport_from_type(std::string name_type); std::pair<std::string,std::string> split_modport_from_type(std::string name_type);

View file

@ -64,7 +64,7 @@ static ffi_fptr resolve_fn (std::string symbol_name)
log_error("unable to resolve '%s'.\n", symbol_name.c_str()); log_error("unable to resolve '%s'.\n", symbol_name.c_str());
} }
std::unique_ptr<AST::AstNode> AST::dpi_call(const std::string &rtype, const std::string &fname, const std::vector<std::string> &argtypes, const std::vector<std::unique_ptr<AST::AstNode>> &args) std::unique_ptr<AST::AstNode> AST::dpi_call(AstSrcLocType loc, const std::string &rtype, const std::string &fname, const std::vector<std::string> &argtypes, const std::vector<std::unique_ptr<AST::AstNode>> &args)
{ {
std::unique_ptr<AST::AstNode> newNode = nullptr; std::unique_ptr<AST::AstNode> newNode = nullptr;
union value { double f64; float f32; int32_t i32; void *ptr; }; union value { double f64; float f32; int32_t i32; void *ptr; };
@ -125,11 +125,11 @@ std::unique_ptr<AST::AstNode> AST::dpi_call(const std::string &rtype, const std:
ffi_call(&cif, resolve_fn(fname.c_str()), values[args.size()], values.data()); ffi_call(&cif, resolve_fn(fname.c_str()), values[args.size()], values.data());
if (rtype == "real") { if (rtype == "real") {
newNode = std::make_unique<AstNode>(AST_REALVALUE); newNode = std::make_unique<AstNode>(loc, AST_REALVALUE);
newNode->realvalue = value_store[args.size()].f64; newNode->realvalue = value_store[args.size()].f64;
log(" return realvalue: %g\n", newNode->asReal(true)); log(" return realvalue: %g\n", newNode->asReal(true));
} else if (rtype == "shortreal") { } else if (rtype == "shortreal") {
newNode = std::make_unique<AstNode>(AST_REALVALUE); newNode = std::make_unique<AstNode>(loc, AST_REALVALUE);
newNode->realvalue = value_store[args.size()].f32; newNode->realvalue = value_store[args.size()].f32;
log(" return realvalue: %g\n", newNode->asReal(true)); log(" return realvalue: %g\n", newNode->asReal(true));
} else if (rtype == "chandle") { } else if (rtype == "chandle") {
@ -137,10 +137,10 @@ std::unique_ptr<AST::AstNode> AST::dpi_call(const std::string &rtype, const std:
std::vector<RTLIL::State> bits(64); std::vector<RTLIL::State> bits(64);
for (int i = 0; i < 64; i++) for (int i = 0; i < 64; i++)
bits.at(i) = (rawval & (1ULL << i)) ? RTLIL::State::S1 : RTLIL::State::S0; bits.at(i) = (rawval & (1ULL << i)) ? RTLIL::State::S1 : RTLIL::State::S0;
newNode = AstNode::mkconst_bits(bits, false); newNode = AstNode::mkconst_bits(loc, bits, false);
log(" return chandle: %llx\n", (unsigned long long)newNode->asInt(false)); log(" return chandle: %llx\n", (unsigned long long)newNode->asInt(false));
} else { } else {
newNode = AstNode::mkconst_int(value_store[args.size()].i32, false); newNode = AstNode::mkconst_int(loc, value_store[args.size()].i32, false);
log(" return integer: %lld\n", (long long)newNode->asInt(true)); log(" return integer: %lld\n", (long long)newNode->asInt(true));
} }
@ -153,7 +153,7 @@ YOSYS_NAMESPACE_END
YOSYS_NAMESPACE_BEGIN YOSYS_NAMESPACE_BEGIN
AST::AstNode *AST::dpi_call(const std::string&, const std::string &fname, const std::vector<std::string>&, const std::vector<AstNode*>&) AST::AstNode *AST::dpi_call(AstSrcLocType loc, const std::string&, const std::string &fname, const std::vector<std::string>&, const std::vector<AstNode*>&)
{ {
log_error("Can't call DPI function `%s': this version of yosys is built without plugin support\n", fname.c_str()); log_error("Can't call DPI function `%s': this version of yosys is built without plugin support\n", fname.c_str());
} }

View file

@ -45,7 +45,7 @@ using namespace AST_INTERNAL;
// helper function for creating RTLIL code for unary operations // helper function for creating RTLIL code for unary operations
static RTLIL::SigSpec uniop2rtlil(AstNode *that, IdString type, int result_width, const RTLIL::SigSpec &arg, bool gen_attributes = true) static RTLIL::SigSpec uniop2rtlil(AstNode *that, IdString type, int result_width, const RTLIL::SigSpec &arg, bool gen_attributes = true)
{ {
IdString name = stringf("%s$%s:%d$%d", type.c_str(), RTLIL::encode_filename(that->filename).c_str(), that->location.first_line, autoidx++); IdString name = stringf("%s$%s:%d$%d", type.c_str(), RTLIL::encode_filename(that->location.filename).c_str(), that->location.first_line, autoidx++);
RTLIL::Cell *cell = current_module->addCell(name, type); RTLIL::Cell *cell = current_module->addCell(name, type);
set_src_attr(cell, that); set_src_attr(cell, that);
@ -77,7 +77,7 @@ static void widthExtend(AstNode *that, RTLIL::SigSpec &sig, int width, bool is_s
return; return;
} }
IdString name = stringf("$extend$%s:%d$%d", RTLIL::encode_filename(that->filename).c_str(), that->location.first_line, autoidx++); IdString name = stringf("$extend$%s:%d$%d", RTLIL::encode_filename(that->location.filename).c_str(), that->location.first_line, autoidx++);
RTLIL::Cell *cell = current_module->addCell(name, ID($pos)); RTLIL::Cell *cell = current_module->addCell(name, ID($pos));
set_src_attr(cell, that); set_src_attr(cell, that);
@ -104,7 +104,7 @@ static void widthExtend(AstNode *that, RTLIL::SigSpec &sig, int width, bool is_s
// helper function for creating RTLIL code for binary operations // helper function for creating RTLIL code for binary operations
static RTLIL::SigSpec binop2rtlil(AstNode *that, IdString type, int result_width, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right) static RTLIL::SigSpec binop2rtlil(AstNode *that, IdString type, int result_width, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right)
{ {
IdString name = stringf("%s$%s:%d$%d", type.c_str(), RTLIL::encode_filename(that->filename).c_str(), that->location.first_line, autoidx++); IdString name = stringf("%s$%s:%d$%d", type.c_str(), RTLIL::encode_filename(that->location.filename).c_str(), that->location.first_line, autoidx++);
RTLIL::Cell *cell = current_module->addCell(name, type); RTLIL::Cell *cell = current_module->addCell(name, type);
set_src_attr(cell, that); set_src_attr(cell, that);
@ -138,7 +138,7 @@ static RTLIL::SigSpec mux2rtlil(AstNode *that, const RTLIL::SigSpec &cond, const
log_assert(cond.size() == 1); log_assert(cond.size() == 1);
std::stringstream sstr; std::stringstream sstr;
sstr << "$ternary$" << RTLIL::encode_filename(that->filename) << ":" << that->location.first_line << "$" << (autoidx++); sstr << "$ternary$" << RTLIL::encode_filename(that->location.filename) << ":" << that->location.first_line << "$" << (autoidx++);
RTLIL::Cell *cell = current_module->addCell(sstr.str(), ID($mux)); RTLIL::Cell *cell = current_module->addCell(sstr.str(), ID($mux));
set_src_attr(cell, that); set_src_attr(cell, that);
@ -347,7 +347,7 @@ struct AST_INTERNAL::ProcessGenerator
LookaheadRewriter la_rewriter(always.get()); LookaheadRewriter la_rewriter(always.get());
// generate process and simple root case // generate process and simple root case
proc = current_module->addProcess(stringf("$proc$%s:%d$%d", RTLIL::encode_filename(always->filename).c_str(), always->location.first_line, autoidx++)); proc = current_module->addProcess(stringf("$proc$%s:%d$%d", RTLIL::encode_filename(always->location.filename).c_str(), always->location.first_line, autoidx++));
set_src_attr(proc, always.get()); set_src_attr(proc, always.get());
for (auto &attr : always->attributes) { for (auto &attr : always->attributes) {
if (attr.second->type != AST_CONSTANT) if (attr.second->type != AST_CONSTANT)
@ -723,7 +723,7 @@ struct AST_INTERNAL::ProcessGenerator
if (ast->str == "$display" || ast->str == "$displayb" || ast->str == "$displayh" || ast->str == "$displayo" || if (ast->str == "$display" || ast->str == "$displayb" || ast->str == "$displayh" || ast->str == "$displayo" ||
ast->str == "$write" || ast->str == "$writeb" || ast->str == "$writeh" || ast->str == "$writeo") { ast->str == "$write" || ast->str == "$writeb" || ast->str == "$writeh" || ast->str == "$writeo") {
std::stringstream sstr; std::stringstream sstr;
sstr << ast->str << "$" << ast->filename << ":" << ast->location.first_line << "$" << (autoidx++); sstr << ast->str << "$" << ast->location.filename << ":" << ast->location.first_line << "$" << (autoidx++);
Wire *en = current_module->addWire(sstr.str() + "_EN", 1); Wire *en = current_module->addWire(sstr.str() + "_EN", 1);
set_src_attr(en, ast); set_src_attr(en, ast);
@ -766,7 +766,7 @@ struct AST_INTERNAL::ProcessGenerator
node->detectSignWidth(width, is_signed, nullptr); node->detectSignWidth(width, is_signed, nullptr);
VerilogFmtArg arg = {}; VerilogFmtArg arg = {};
arg.filename = node->filename; arg.filename = node->location.filename;
arg.first_line = node->location.first_line; arg.first_line = node->location.first_line;
if (node->type == AST_CONSTANT && node->is_string) { if (node->type == AST_CONSTANT && node->is_string) {
arg.type = VerilogFmtArg::STRING; arg.type = VerilogFmtArg::STRING;
@ -793,7 +793,7 @@ struct AST_INTERNAL::ProcessGenerator
fmt.append_literal("\n"); fmt.append_literal("\n");
fmt.emit_rtlil(cell); fmt.emit_rtlil(cell);
} else if (!ast->str.empty()) { } else if (!ast->str.empty()) {
log_file_error(ast->filename, ast->location.first_line, "Found unsupported invocation of system task `%s'!\n", ast->str.c_str()); log_file_error(ast->location.filename, ast->location.first_line, "Found unsupported invocation of system task `%s'!\n", ast->str.c_str());
} }
break; break;
@ -813,7 +813,7 @@ struct AST_INTERNAL::ProcessGenerator
IdString cellname; IdString cellname;
if (ast->str.empty()) if (ast->str.empty())
cellname = stringf("$%s$%s:%d$%d", flavor.c_str(), RTLIL::encode_filename(ast->filename).c_str(), ast->location.first_line, autoidx++); cellname = stringf("$%s$%s:%d$%d", flavor.c_str(), RTLIL::encode_filename(ast->location.filename).c_str(), ast->location.first_line, autoidx++);
else else
cellname = ast->str; cellname = ast->str;
check_unique_id(current_module, cellname, ast, "procedural assertion"); check_unique_id(current_module, cellname, ast, "procedural assertion");
@ -843,7 +843,7 @@ struct AST_INTERNAL::ProcessGenerator
set_src_attr(cell, ast); set_src_attr(cell, ast);
for (auto &attr : ast->attributes) { for (auto &attr : ast->attributes) {
if (attr.second->type != AST_CONSTANT) if (attr.second->type != AST_CONSTANT)
log_file_error(ast->filename, ast->location.first_line, "Attribute `%s' with non-constant value!\n", attr.first.c_str()); log_file_error(ast->location.filename, ast->location.first_line, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
cell->attributes[attr.first] = attr.second->asAttrConst(); cell->attributes[attr.first] = attr.second->asAttrConst();
} }
cell->setParam(ID::FLAVOR, flavor); cell->setParam(ID::FLAVOR, flavor);
@ -1503,7 +1503,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
} }
RTLIL::SigSpec sig = realAsConst(width_hint); RTLIL::SigSpec sig = realAsConst(width_hint);
log_file_warning(filename, location.first_line, "converting real value %e to binary %s.\n", realvalue, log_signal(sig)); log_file_warning(location.filename, location.first_line, "converting real value %e to binary %s.\n", realvalue, log_signal(sig));
return sig; return sig;
} }
@ -1535,7 +1535,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
if (dynamic_cast<RTLIL::Binding*>(current_module)) { if (dynamic_cast<RTLIL::Binding*>(current_module)) {
/* nothing to do here */ /* nothing to do here */
} else if (flag_autowire) } else if (flag_autowire)
log_file_warning(filename, location.first_line, "Identifier `%s' is implicitly declared.\n", str.c_str()); log_file_warning(location.filename, location.first_line, "Identifier `%s' is implicitly declared.\n", str.c_str());
else else
input_error("Identifier `%s' is implicitly declared and `default_nettype is set to none.\n", str.c_str()); input_error("Identifier `%s' is implicitly declared and `default_nettype is set to none.\n", str.c_str());
} }
@ -1640,10 +1640,10 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
chunk.offset = source_width - (chunk.offset + chunk.width); chunk.offset = source_width - (chunk.offset + chunk.width);
if (chunk.offset > chunk_left || chunk.offset + chunk.width < chunk_right) { if (chunk.offset > chunk_left || chunk.offset + chunk.width < chunk_right) {
if (chunk.width == 1) if (chunk.width == 1)
log_file_warning(filename, location.first_line, "Range select out of bounds on signal `%s': Setting result bit to undef.\n", log_file_warning(location.filename, location.first_line, "Range select out of bounds on signal `%s': Setting result bit to undef.\n",
str.c_str()); str.c_str());
else else
log_file_warning(filename, location.first_line, "Range select [%d:%d] out of bounds on signal `%s': Setting all %d result bits to undef.\n", log_file_warning(location.filename, location.first_line, "Range select [%d:%d] out of bounds on signal `%s': Setting all %d result bits to undef.\n",
children[0]->range_left, children[0]->range_right, str.c_str(), chunk.width); children[0]->range_left, children[0]->range_right, str.c_str(), chunk.width);
chunk = RTLIL::SigChunk(RTLIL::State::Sx, chunk.width); chunk = RTLIL::SigChunk(RTLIL::State::Sx, chunk.width);
} else { } else {
@ -1657,10 +1657,10 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
chunk.offset += add_undef_bits_lsb; chunk.offset += add_undef_bits_lsb;
} }
if (add_undef_bits_lsb) if (add_undef_bits_lsb)
log_file_warning(filename, location.first_line, "Range [%d:%d] select out of bounds on signal `%s': Setting %d LSB bits to undef.\n", log_file_warning(location.filename, location.first_line, "Range [%d:%d] select out of bounds on signal `%s': Setting %d LSB bits to undef.\n",
children[0]->range_left, children[0]->range_right, str.c_str(), add_undef_bits_lsb); children[0]->range_left, children[0]->range_right, str.c_str(), add_undef_bits_lsb);
if (add_undef_bits_msb) if (add_undef_bits_msb)
log_file_warning(filename, location.first_line, "Range [%d:%d] select out of bounds on signal `%s': Setting %d MSB bits to undef.\n", log_file_warning(location.filename, location.first_line, "Range [%d:%d] select out of bounds on signal `%s': Setting %d MSB bits to undef.\n",
children[0]->range_left, children[0]->range_right, str.c_str(), add_undef_bits_msb); children[0]->range_left, children[0]->range_right, str.c_str(), add_undef_bits_msb);
} }
} }
@ -1934,7 +1934,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
case AST_MEMRD: case AST_MEMRD:
{ {
std::stringstream sstr; std::stringstream sstr;
sstr << "$memrd$" << str << "$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++); sstr << "$memrd$" << str << "$" << RTLIL::encode_filename(location.filename) << ":" << location.first_line << "$" << (autoidx++);
RTLIL::Cell *cell = current_module->addCell(sstr.str(), ID($memrd)); RTLIL::Cell *cell = current_module->addCell(sstr.str(), ID($memrd));
set_src_attr(cell, this); set_src_attr(cell, this);
@ -1972,7 +1972,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
case AST_MEMINIT: case AST_MEMINIT:
{ {
std::stringstream sstr; std::stringstream sstr;
sstr << "$meminit$" << str << "$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++); sstr << "$meminit$" << str << "$" << RTLIL::encode_filename(location.filename) << ":" << location.first_line << "$" << (autoidx++);
SigSpec en_sig = children[2]->genRTLIL(); SigSpec en_sig = children[2]->genRTLIL();
@ -2017,7 +2017,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
IdString cellname; IdString cellname;
if (str.empty()) if (str.empty())
cellname = stringf("$%s$%s:%d$%d", flavor.c_str(), RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++); cellname = stringf("$%s$%s:%d$%d", flavor.c_str(), RTLIL::encode_filename(location.filename).c_str(), location.first_line, autoidx++);
else else
cellname = str; cellname = str;
check_unique_id(current_module, cellname, this, "procedural assertion"); check_unique_id(current_module, cellname, this, "procedural assertion");
@ -2060,7 +2060,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
new_left.append(left[i]); new_left.append(left[i]);
new_right.append(right[i]); new_right.append(right[i]);
} }
log_file_warning(filename, location.first_line, "Ignoring assignment to constant bits:\n" log_file_warning(location.filename, location.first_line, "Ignoring assignment to constant bits:\n"
" old assignment: %s = %s\n new assignment: %s = %s.\n", " old assignment: %s = %s\n new assignment: %s = %s.\n",
log_signal(left), log_signal(right), log_signal(left), log_signal(right),
log_signal(new_left), log_signal(new_right)); log_signal(new_left), log_signal(new_right));
@ -2095,7 +2095,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
IdString paraname = child->str.empty() ? stringf("$%d", ++para_counter) : child->str; IdString paraname = child->str.empty() ? stringf("$%d", ++para_counter) : child->str;
const AstNode *value = child->children[0].get(); const AstNode *value = child->children[0].get();
if (value->type == AST_REALVALUE) if (value->type == AST_REALVALUE)
log_file_warning(filename, location.first_line, "Replacing floating point parameter %s.%s = %f with string.\n", log_file_warning(location.filename, location.first_line, "Replacing floating point parameter %s.%s = %f with string.\n",
log_id(cell), log_id(paraname), value->realvalue); log_id(cell), log_id(paraname), value->realvalue);
else if (value->type != AST_CONSTANT) else if (value->type != AST_CONSTANT)
input_error("Parameter %s.%s with non-constant value!\n", input_error("Parameter %s.%s with non-constant value!\n",
@ -2192,14 +2192,14 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
int sz = children.size(); int sz = children.size();
if (str == "$info") { if (str == "$info") {
if (sz > 0) if (sz > 0)
log_file_info(filename, location.first_line, "%s.\n", children[0]->str.c_str()); log_file_info(location.filename, location.first_line, "%s.\n", children[0]->str.c_str());
else else
log_file_info(filename, location.first_line, "\n"); log_file_info(location.filename, location.first_line, "\n");
} else if (str == "$warning") { } else if (str == "$warning") {
if (sz > 0) if (sz > 0)
log_file_warning(filename, location.first_line, "%s.\n", children[0]->str.c_str()); log_file_warning(location.filename, location.first_line, "%s.\n", children[0]->str.c_str());
else else
log_file_warning(filename, location.first_line, "\n"); log_file_warning(location.filename, location.first_line, "\n");
} else if (str == "$error") { } else if (str == "$error") {
if (sz > 0) if (sz > 0)
input_error("%s.\n", children[0]->str.c_str()); input_error("%s.\n", children[0]->str.c_str());

View file

@ -155,7 +155,7 @@ Fmt AstNode::processFormat(int stage, bool sformat_like, int default_base, size_
while (node_arg->simplify(true, stage, -1, false)) { } while (node_arg->simplify(true, stage, -1, false)) { }
VerilogFmtArg arg = {}; VerilogFmtArg arg = {};
arg.filename = filename; arg.filename = location.filename;
arg.first_line = location.first_line; arg.first_line = location.first_line;
if (node_arg->type == AST_CONSTANT && node_arg->is_string) { if (node_arg->type == AST_CONSTANT && node_arg->is_string) {
arg.type = VerilogFmtArg::STRING; arg.type = VerilogFmtArg::STRING;
@ -173,10 +173,10 @@ Fmt AstNode::processFormat(int stage, bool sformat_like, int default_base, size_
arg.sig = node_arg->bitsAsConst(); arg.sig = node_arg->bitsAsConst();
arg.signed_ = node_arg->is_signed; arg.signed_ = node_arg->is_signed;
} else if (may_fail) { } else if (may_fail) {
log_file_info(filename, location.first_line, "Skipping system task `%s' with non-constant argument at position %zu.\n", str.c_str(), index + 1); log_file_info(location.filename, location.first_line, "Skipping system task `%s' with non-constant argument at position %zu.\n", str.c_str(), index + 1);
return Fmt(); return Fmt();
} else { } else {
log_file_error(filename, location.first_line, "Failed to evaluate system task `%s' with non-constant argument at position %zu.\n", str.c_str(), index + 1); log_file_error(location.filename, location.first_line, "Failed to evaluate system task `%s' with non-constant argument at position %zu.\n", str.c_str(), index + 1);
} }
args.push_back(arg); args.push_back(arg);
} }
@ -240,20 +240,20 @@ void AstNode::annotateTypedEnums(AstNode *template_node)
RTLIL::Const val = enum_item->children[0]->bitsAsConst(width, is_signed); RTLIL::Const val = enum_item->children[0]->bitsAsConst(width, is_signed);
enum_item_str.append(val.as_string()); enum_item_str.append(val.as_string());
//set attribute for available val to enum item name mappings //set attribute for available val to enum item name mappings
set_attribute(enum_item_str.c_str(), mkconst_str(enum_item->str)); set_attribute(enum_item_str.c_str(), mkconst_str(location, enum_item->str));
} }
} }
} }
static std::unique_ptr<AstNode> make_range(int left, int right, bool is_signed = false) static std::unique_ptr<AstNode> make_range(AstSrcLocType loc, int left, int right, bool is_signed = false)
{ {
// generate a pre-validated range node for a fixed signal range. // generate a pre-validated range node for a fixed signal range.
auto range = std::make_unique<AstNode>(AST_RANGE); auto range = std::make_unique<AstNode>(loc, AST_RANGE);
range->range_left = left; range->range_left = left;
range->range_right = right; range->range_right = right;
range->range_valid = true; range->range_valid = true;
range->children.push_back(AstNode::mkconst_int(left, true)); range->children.push_back(AstNode::mkconst_int(loc, left, true));
range->children.push_back(AstNode::mkconst_int(right, true)); range->children.push_back(AstNode::mkconst_int(loc, right, true));
range->is_signed = is_signed; range->is_signed = is_signed;
return range; return range;
} }
@ -388,30 +388,32 @@ static int size_packed_struct(AstNode *snode, int base_offset)
return width; return width;
} }
static std::unique_ptr<AstNode> node_int(int ival) static std::unique_ptr<AstNode> node_int(AstSrcLocType loc, int ival)
{ {
return AstNode::mkconst_int(ival, true); return AstNode::mkconst_int(loc, ival, true);
} }
static std::unique_ptr<AstNode> multiply_by_const(std::unique_ptr<AstNode> expr_node, int stride) static std::unique_ptr<AstNode> multiply_by_const(std::unique_ptr<AstNode> expr_node, int stride)
{ {
return std::make_unique<AstNode>(AST_MUL, std::move(expr_node), node_int(stride)); auto loc = expr_node->location;
return std::make_unique<AstNode>(loc, AST_MUL, std::move(expr_node), node_int(loc, stride));
} }
static std::unique_ptr<AstNode> normalize_index(AstNode *expr, AstNode *decl_node, int dimension) static std::unique_ptr<AstNode> normalize_index(AstNode *expr, AstNode *decl_node, int dimension)
{ {
auto new_expr = expr->clone(); auto new_expr = expr->clone();
auto loc = expr->location;
int offset = decl_node->dimensions[dimension].range_right; int offset = decl_node->dimensions[dimension].range_right;
if (offset) { if (offset) {
new_expr = std::make_unique<AstNode>(AST_SUB, std::move(new_expr), node_int(offset)); new_expr = std::make_unique<AstNode>(loc, AST_SUB, std::move(new_expr), node_int(loc, offset));
} }
// Packed dimensions are normally indexed by lsb, while unpacked dimensions are normally indexed by msb. // Packed dimensions are normally indexed by lsb, while unpacked dimensions are normally indexed by msb.
if ((dimension < decl_node->unpacked_dimensions) ^ decl_node->dimensions[dimension].range_swapped) { if ((dimension < decl_node->unpacked_dimensions) ^ decl_node->dimensions[dimension].range_swapped) {
// Swap the index if the dimension is declared the "wrong" way. // Swap the index if the dimension is declared the "wrong" way.
int left = decl_node->dimensions[dimension].range_width - 1; int left = decl_node->dimensions[dimension].range_width - 1;
new_expr = std::make_unique<AstNode>(AST_SUB, node_int(left), std::move(new_expr)); new_expr = std::make_unique<AstNode>(loc, AST_SUB, node_int(loc, left), std::move(new_expr));
} }
return new_expr; return new_expr;
@ -433,7 +435,7 @@ static std::unique_ptr<AstNode> index_msb_offset(std::unique_ptr<AstNode> lsb_of
std::unique_ptr<AstNode> add_offset; std::unique_ptr<AstNode> add_offset;
if (rnode->children.size() == 1) { if (rnode->children.size() == 1) {
// Index, e.g. s.a[i] // Index, e.g. s.a[i]
add_offset = node_int(stride - 1); add_offset = node_int(rnode->location, stride - 1);
} }
else { else {
// rnode->children.size() == 2 // rnode->children.size() == 2
@ -620,7 +622,7 @@ const RTLIL::Module* AstNode::lookup_cell_module()
auto reprocess_after = [this] (const std::string &modname) { auto reprocess_after = [this] (const std::string &modname) {
if (!attributes.count(ID::reprocess_after)) if (!attributes.count(ID::reprocess_after))
set_attribute(ID::reprocess_after, AstNode::mkconst_str(modname)); set_attribute(ID::reprocess_after, AstNode::mkconst_str(location, modname));
}; };
const AstNode *celltype = nullptr; const AstNode *celltype = nullptr;
@ -929,7 +931,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin
#if 0 #if 0
log("-------------\n"); log("-------------\n");
log("AST simplify[%d] depth %d at %s:%d on %s %p:\n", stage, recursion_counter, filename.c_str(), location.first_line, type2str(type).c_str(), this); log("AST simplify[%d] depth %d at %s:%d on %s %p:\n", stage, recursion_counter, location.filename.c_str(), location.first_line, type2str(type).c_str(), this);
log("const_fold=%d, stage=%d, width_hint=%d, sign_hint=%d\n", log("const_fold=%d, stage=%d, width_hint=%d, sign_hint=%d\n",
int(const_fold), int(stage), int(width_hint), int(sign_hint)); int(const_fold), int(stage), int(width_hint), int(sign_hint));
// dumpAst(nullptr, "> "); // dumpAst(nullptr, "> ");
@ -1020,7 +1022,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin
for (auto &it : node->attributes) for (auto &it : node->attributes)
if (it.first != ID::mem2reg) if (it.first != ID::mem2reg)
reg->set_attribute(it.first, it.second->clone()); reg->set_attribute(it.first, it.second->clone());
reg->filename = node->filename; reg->location.filename = node->location.filename;
reg->location = node->location; reg->location = node->location;
while (reg->simplify(true, 1, -1, false)) { } while (reg->simplify(true, 1, -1, false)) { }
children.push_back(std::move(reg)); children.push_back(std::move(reg));
@ -1049,7 +1051,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin
// note that $display, $finish, and $stop are used for synthesis-time DRC so they're not in this list // note that $display, $finish, and $stop are used for synthesis-time DRC so they're not in this list
if ((type == AST_FCALL || type == AST_TCALL) && (str == "$strobe" || str == "$monitor" || str == "$time" || if ((type == AST_FCALL || type == AST_TCALL) && (str == "$strobe" || str == "$monitor" || str == "$time" ||
str == "$dumpfile" || str == "$dumpvars" || str == "$dumpon" || str == "$dumpoff" || str == "$dumpall")) { str == "$dumpfile" || str == "$dumpvars" || str == "$dumpon" || str == "$dumpoff" || str == "$dumpall")) {
log_file_warning(filename, location.first_line, "Ignoring call to system %s %s.\n", type == AST_FCALL ? "function" : "task", str.c_str()); log_file_warning(location.filename, location.first_line, "Ignoring call to system %s %s.\n", type == AST_FCALL ? "function" : "task", str.c_str());
delete_children(); delete_children();
str = std::string(); str = std::string();
} }
@ -1059,7 +1061,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin
str == "$write" || str == "$writeb" || str == "$writeh" || str == "$writeo")) str == "$write" || str == "$writeb" || str == "$writeh" || str == "$writeo"))
{ {
if (!current_always) { if (!current_always) {
log_file_warning(filename, location.first_line, "System task `%s' outside initial or always block is unsupported.\n", str.c_str()); log_file_warning(location.filename, location.first_line, "System task `%s' outside initial or always block is unsupported.\n", str.c_str());
delete_children(); delete_children();
str = std::string(); str = std::string();
} else { } else {
@ -1336,7 +1338,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin
// create the indirection wire // create the indirection wire
std::stringstream sstr; std::stringstream sstr;
sstr << "$indirect$" << ref->name.c_str() << "$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++); sstr << "$indirect$" << ref->name.c_str() << "$" << RTLIL::encode_filename(location.filename) << ":" << location.first_line << "$" << (autoidx++);
std::string tmp_str = sstr.str(); std::string tmp_str = sstr.str();
add_wire_for_ref(ref, tmp_str); add_wire_for_ref(ref, tmp_str);
@ -2174,7 +2176,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin
int width = std::abs(children[1]->range_left - children[1]->range_right) + 1; int width = std::abs(children[1]->range_left - children[1]->range_right) + 1;
if (children[0]->type == AST_REALVALUE) { if (children[0]->type == AST_REALVALUE) {
RTLIL::Const constvalue = children[0]->realAsConst(width); RTLIL::Const constvalue = children[0]->realAsConst(width);
log_file_warning(filename, location.first_line, "converting real value %e to binary %s.\n", log_file_warning(location.filename, location.first_line, "converting real value %e to binary %s.\n",
children[0]->realvalue, log_signal(constvalue)); children[0]->realvalue, log_signal(constvalue));
children[0] = mkconst_bits(constvalue.to_bits(), sign_hint); children[0] = mkconst_bits(constvalue.to_bits(), sign_hint);
fixup_hierarchy_flags(); fixup_hierarchy_flags();
@ -2316,7 +2318,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin
std::swap(data_range_left, data_range_right); std::swap(data_range_left, data_range_right);
std::stringstream sstr; std::stringstream sstr;
sstr << "$mem2bits$" << str << "$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++); sstr << "$mem2bits$" << str << "$" << RTLIL::encode_filename(location.filename) << ":" << location.first_line << "$" << (autoidx++);
std::string wire_id = sstr.str(); std::string wire_id = sstr.str();
auto wire_owned = std::make_unique<AstNode>(AST_WIRE, std::make_unique<AstNode>(AST_RANGE, mkconst_int(data_range_left, true), mkconst_int(data_range_right, true))); auto wire_owned = std::make_unique<AstNode>(AST_WIRE, std::make_unique<AstNode>(AST_RANGE, mkconst_int(data_range_left, true), mkconst_int(data_range_right, true)));
@ -2536,7 +2538,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin
for (size_t i = 0; i < children.size(); i++) for (size_t i = 0; i < children.size(); i++)
if (children[i]->type == AST_WIRE || children[i]->type == AST_MEMORY || children[i]->type == AST_PARAMETER || children[i]->type == AST_LOCALPARAM || children[i]->type == AST_TYPEDEF) if (children[i]->type == AST_WIRE || children[i]->type == AST_MEMORY || children[i]->type == AST_PARAMETER || children[i]->type == AST_LOCALPARAM || children[i]->type == AST_TYPEDEF)
{ {
log_assert(!sv_mode); log_assert(!sv_mode_but_global_and_used_for_literally_one_condition);
children[i]->input_error("Local declaration in unnamed block is only supported in SystemVerilog mode!\n"); children[i]->input_error("Local declaration in unnamed block is only supported in SystemVerilog mode!\n");
} }
} }
@ -3072,7 +3074,7 @@ skip_dynamic_range_lvalue_expansion:;
auto wire_tmp_owned = std::make_unique<AstNode>(AST_WIRE, std::make_unique<AstNode>(AST_RANGE, mkconst_int(width_hint-1, true), mkconst_int(0, true))); auto wire_tmp_owned = std::make_unique<AstNode>(AST_WIRE, std::make_unique<AstNode>(AST_RANGE, mkconst_int(width_hint-1, true), mkconst_int(0, true)));
auto wire_tmp = wire_tmp_owned.get(); auto wire_tmp = wire_tmp_owned.get();
wire_tmp->str = stringf("$splitcmplxassign$%s:%d$%d", RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++); wire_tmp->str = stringf("$splitcmplxassign$%s:%d$%d", RTLIL::encode_filename(location.filename).c_str(), location.first_line, autoidx++);
current_scope[wire_tmp->str] = wire_tmp; current_scope[wire_tmp->str] = wire_tmp;
current_ast_mod->children.push_back(std::move(wire_tmp_owned)); current_ast_mod->children.push_back(std::move(wire_tmp_owned));
wire_tmp->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); wire_tmp->set_attribute(ID::nosync, AstNode::mkconst_int(1, false));
@ -3114,7 +3116,7 @@ skip_dynamic_range_lvalue_expansion:;
input_error("Insufficient number of array indices for %s.\n", log_id(str)); input_error("Insufficient number of array indices for %s.\n", log_id(str));
std::stringstream sstr; std::stringstream sstr;
sstr << "$memwr$" << children[0]->str << "$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++); sstr << "$memwr$" << children[0]->str << "$" << RTLIL::encode_filename(location.filename) << ":" << location.first_line << "$" << (autoidx++);
std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA", id_en = sstr.str() + "_EN"; std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA", id_en = sstr.str() + "_EN";
int mem_width, mem_size, addr_bits; int mem_width, mem_size, addr_bits;
@ -3385,7 +3387,7 @@ skip_dynamic_range_lvalue_expansion:;
auto* reg = reg_owned.get(); auto* reg = reg_owned.get();
current_ast_mod->children.push_back(std::move(reg_owned)); current_ast_mod->children.push_back(std::move(reg_owned));
reg->str = stringf("$past$%s:%d$%d$%d", RTLIL::encode_filename(filename).c_str(), location.first_line, myidx, i); reg->str = stringf("$past$%s:%d$%d$%d", RTLIL::encode_filename(location.filename).c_str(), location.first_line, myidx, i);
reg->is_reg = true; reg->is_reg = true;
reg->is_signed = sign_hint; reg->is_signed = sign_hint;
@ -3761,7 +3763,7 @@ skip_dynamic_range_lvalue_expansion:;
input_error("Failed to evaluate DPI function with non-constant argument.\n"); input_error("Failed to evaluate DPI function with non-constant argument.\n");
} }
newNode = dpi_call(rtype, fname, argtypes, args); newNode = dpi_call(dpi_decl->location, rtype, fname, argtypes, args);
goto apply_newNode; goto apply_newNode;
} }
@ -3845,7 +3847,7 @@ skip_dynamic_range_lvalue_expansion:;
std::stringstream sstr; std::stringstream sstr;
sstr << str << "$func$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++) << '.'; sstr << str << "$func$" << RTLIL::encode_filename(location.filename) << ":" << location.first_line << "$" << (autoidx++) << '.';
std::string prefix = sstr.str(); std::string prefix = sstr.str();
auto* decl = current_scope[str]; auto* decl = current_scope[str];
@ -4375,7 +4377,7 @@ apply_newNode:
// newNode->dumpAst(stderr, "+ "); // newNode->dumpAst(stderr, "+ ");
log_assert(newNode != nullptr); log_assert(newNode != nullptr);
// newNode->null_check(); // newNode->null_check();
newNode->filename = filename; newNode->location.filename = location.filename;
newNode->location = location; newNode->location = location;
newNode->cloneInto(*this); newNode->cloneInto(*this);
fixup_hierarchy_flags(); fixup_hierarchy_flags();
@ -4422,7 +4424,7 @@ std::unique_ptr<AstNode> AstNode::readmem(bool is_readmemh, std::string mem_file
#else #else
char slash = '/'; char slash = '/';
#endif #endif
std::string path = filename.substr(0, filename.find_last_of(slash)+1); std::string path = location.filename.substr(0, location.filename.find_last_of(slash)+1);
f.open(path + mem_filename.c_str()); f.open(path + mem_filename.c_str());
yosys_input_files.insert(path + mem_filename); yosys_input_files.insert(path + mem_filename);
} else { } else {
@ -4479,7 +4481,7 @@ std::unique_ptr<AstNode> AstNode::readmem(bool is_readmemh, std::string mem_file
continue; continue;
} }
VERILOG_FRONTEND::ConstParser p{mem_filename, std::nullopt}; VERILOG_FRONTEND::ConstParser p{memory->location};
auto value = p.const2ast(stringf("%d'%c", mem_width, is_readmemh ? 'h' : 'b') + token); auto value = p.const2ast(stringf("%d'%c", mem_width, is_readmemh ? 'h' : 'b') + token);
if (unconditional_init) if (unconditional_init)
@ -4701,7 +4703,7 @@ static void mark_memories_assign_lhs_complex(dict<AstNode*, pool<std::string>> &
if (that->type == AST_IDENTIFIER && that->id2ast && that->id2ast->type == AST_MEMORY) { if (that->type == AST_IDENTIFIER && that->id2ast && that->id2ast->type == AST_MEMORY) {
AstNode *mem = that->id2ast; AstNode *mem = that->id2ast;
if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_CMPLX_LHS)) if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_CMPLX_LHS))
mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(that->filename).c_str(), that->location.first_line)); mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(that->location.filename).c_str(), that->location.first_line));
mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_CMPLX_LHS; mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_CMPLX_LHS;
} }
} }
@ -4729,14 +4731,14 @@ void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg
// activate mem2reg if this is assigned in an async proc // activate mem2reg if this is assigned in an async proc
if (flags & AstNode::MEM2REG_FL_ASYNC) { if (flags & AstNode::MEM2REG_FL_ASYNC) {
if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_SET_ASYNC)) if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_SET_ASYNC))
mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(filename).c_str(), location.first_line)); mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(location.filename).c_str(), location.first_line));
mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_SET_ASYNC; mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_SET_ASYNC;
} }
// remember if this is assigned blocking (=) // remember if this is assigned blocking (=)
if (type == AST_ASSIGN_EQ) { if (type == AST_ASSIGN_EQ) {
if (!(proc_flags[mem] & AstNode::MEM2REG_FL_EQ1)) if (!(proc_flags[mem] & AstNode::MEM2REG_FL_EQ1))
mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(filename).c_str(), location.first_line)); mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(location.filename).c_str(), location.first_line));
proc_flags[mem] |= AstNode::MEM2REG_FL_EQ1; proc_flags[mem] |= AstNode::MEM2REG_FL_EQ1;
} }
@ -4753,11 +4755,11 @@ void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg
// remember where this is // remember where this is
if (flags & MEM2REG_FL_INIT) { if (flags & MEM2REG_FL_INIT) {
if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_SET_INIT)) if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_SET_INIT))
mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(filename).c_str(), location.first_line)); mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(location.filename).c_str(), location.first_line));
mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_SET_INIT; mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_SET_INIT;
} else { } else {
if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_SET_ELSE)) if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_SET_ELSE))
mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(filename).c_str(), location.first_line)); mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(location.filename).c_str(), location.first_line));
mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_SET_ELSE; mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_SET_ELSE;
} }
} }
@ -4774,7 +4776,7 @@ void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg
// flag if used after blocking assignment (in same proc) // flag if used after blocking assignment (in same proc)
if ((proc_flags[mem] & AstNode::MEM2REG_FL_EQ1) && !(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_EQ2)) { if ((proc_flags[mem] & AstNode::MEM2REG_FL_EQ1) && !(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_EQ2)) {
mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(filename).c_str(), location.first_line)); mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(location.filename).c_str(), location.first_line));
mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_EQ2; mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_EQ2;
} }
} }
@ -4960,7 +4962,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,
children[0]->children[0]->children[0]->type != AST_CONSTANT) children[0]->children[0]->children[0]->type != AST_CONSTANT)
{ {
std::stringstream sstr; std::stringstream sstr;
sstr << "$mem2reg_wr$" << children[0]->str << "$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++); sstr << "$mem2reg_wr$" << children[0]->str << "$" << RTLIL::encode_filename(location.filename) << ":" << location.first_line << "$" << (autoidx++);
std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA"; std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA";
int mem_width, mem_size, addr_bits; int mem_width, mem_size, addr_bits;
@ -5079,7 +5081,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,
else else
{ {
std::stringstream sstr; std::stringstream sstr;
sstr << "$mem2reg_rd$" << str << "$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++); sstr << "$mem2reg_rd$" << str << "$" << RTLIL::encode_filename(location.filename) << ":" << location.first_line << "$" << (autoidx++);
std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA"; std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA";
int mem_width, mem_size, addr_bits; int mem_width, mem_size, addr_bits;

View file

@ -13,6 +13,7 @@ frontends/verilog/verilog_parser.tab.cc: frontends/verilog/verilog_parser.y
frontends/verilog/verilog_parser.tab.hh: frontends/verilog/verilog_parser.tab.cc frontends/verilog/verilog_parser.tab.hh: frontends/verilog/verilog_parser.tab.cc
frontends/verilog/verilog_frontend.h: frontends/verilog/verilog_parser.tab.hh frontends/verilog/verilog_frontend.h: frontends/verilog/verilog_parser.tab.hh
frontends/verilog/verilog_error.h: frontends/verilog/verilog_parser.tab.hh
frontends/verilog/verilog_lexer.cc: frontends/verilog/verilog_lexer.l frontends/verilog/verilog_parser.tab.cc frontends/verilog/verilog_lexer.cc: frontends/verilog/verilog_lexer.l frontends/verilog/verilog_parser.tab.cc
$(Q) mkdir -p $(dir $@) $(Q) mkdir -p $(dir $@)
@ -24,5 +25,6 @@ OBJS += frontends/verilog/verilog_parser.tab.o
OBJS += frontends/verilog/verilog_lexer.o OBJS += frontends/verilog/verilog_lexer.o
OBJS += frontends/verilog/preproc.o OBJS += frontends/verilog/preproc.o
OBJS += frontends/verilog/verilog_frontend.o OBJS += frontends/verilog/verilog_frontend.o
OBJS += frontends/verilog/verilog_error.o
OBJS += frontends/verilog/const2ast.o OBJS += frontends/verilog/const2ast.o

View file

@ -46,11 +46,8 @@ using namespace VERILOG_FRONTEND;
std::string ConstParser::fmt_maybe_loc(std::string msg) { std::string ConstParser::fmt_maybe_loc(std::string msg) {
std::string s; std::string s;
s += filename.value_or("INTERNAL");
if (loc) s += stringf("%s:%d:", loc.filename, loc.first_line);
s += stringf("%d", loc->first_line);
s += ": ";
s += msg; s += msg;
return s; return s;
@ -191,7 +188,7 @@ std::unique_ptr<AstNode> ConstParser::const2ast(std::string code, char case_type
ch = ch >> 1; ch = ch >> 1;
} }
} }
auto ast = AstNode::mkconst_bits(data, false); auto ast = AstNode::mkconst_bits(loc, data, false);
ast->str = code; ast->str = code;
return ast; return ast;
} }
@ -210,7 +207,7 @@ std::unique_ptr<AstNode> ConstParser::const2ast(std::string code, char case_type
my_strtobin(data, str, -1, 10, case_type, false); my_strtobin(data, str, -1, 10, case_type, false);
if (data.back() == State::S1) if (data.back() == State::S1)
data.push_back(State::S0); data.push_back(State::S0);
return AstNode::mkconst_bits(data, true); return AstNode::mkconst_bits(loc, data, true);
} }
// unsized constant // unsized constant
@ -258,7 +255,7 @@ std::unique_ptr<AstNode> ConstParser::const2ast(std::string code, char case_type
if (is_signed && data.back() == State::S1) if (is_signed && data.back() == State::S1)
data.push_back(State::S0); data.push_back(State::S0);
} }
return AstNode::mkconst_bits(data, is_signed, is_unsized); return AstNode::mkconst_bits(loc, data, is_signed, is_unsized);
} }
return NULL; return NULL;

View file

@ -32,10 +32,12 @@
#include "verilog_frontend.h" #include "verilog_frontend.h"
#include "verilog_lexer.h" #include "verilog_lexer.h"
#include "verilog_error.h"
#include "preproc.h" #include "preproc.h"
#include "kernel/yosys.h" #include "kernel/yosys.h"
#include "libs/sha1/sha1.h" #include "libs/sha1/sha1.h"
#include <stdarg.h> #include <stdarg.h>
#include <list>
YOSYS_NAMESPACE_BEGIN YOSYS_NAMESPACE_BEGIN
using namespace VERILOG_FRONTEND; using namespace VERILOG_FRONTEND;
@ -47,10 +49,10 @@ static std::list<std::vector<std::string>> verilog_defaults_stack;
static void error_on_dpi_function(AST::AstNode *node) static void error_on_dpi_function(AST::AstNode *node)
{ {
if (node->type == AST::AST_DPI_FUNCTION) if (node->type == AST::AST_DPI_FUNCTION)
log_file_error(node->filename, node->location.first_line, "Found DPI function %s.\n", node->str.c_str()); err_at_ast(node->location, "Found DPI function %s.\n", node->str.c_str());
for (auto& child : node->children) for (auto& child : node->children)
error_on_dpi_function(child.get()); error_on_dpi_function(child.get());
} }
static void add_package_types(dict<std::string, AST::AstNode *> &user_types, std::vector<std::unique_ptr<AST::AstNode>> &package_list) static void add_package_types(dict<std::string, AST::AstNode *> &user_types, std::vector<std::unique_ptr<AST::AstNode>> &package_list)
@ -69,15 +71,7 @@ static void add_package_types(dict<std::string, AST::AstNode *> &user_types, std
} }
struct VerilogFrontend : public Frontend { struct VerilogFrontend : public Frontend {
ParseMode parse_mode; VerilogFrontend() : Frontend("verilog", "read modules from Verilog file") { }
ParseState parse_state;
VerilogLexer lexer;
frontend_verilog_yy::parser parser;
VerilogFrontend() : Frontend("verilog", "read modules from Verilog file"),
parse_mode(),
parse_state(),
lexer(&parse_state, &parse_mode),
parser(&lexer, &parse_state, &parse_mode) { }
void help() override void help() override
{ {
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
@ -259,6 +253,8 @@ struct VerilogFrontend : public Frontend {
bool flag_dump_vlog1 = false; bool flag_dump_vlog1 = false;
bool flag_dump_vlog2 = false; bool flag_dump_vlog2 = false;
bool flag_dump_rtlil = false; bool flag_dump_rtlil = false;
bool flag_debug_lexer = false;
bool flag_debug_parser = false;
bool flag_nolatches = false; bool flag_nolatches = false;
bool flag_nomeminit = false; bool flag_nomeminit = false;
bool flag_nomem2reg = false; bool flag_nomem2reg = false;
@ -281,8 +277,8 @@ struct VerilogFrontend : public Frontend {
std::list<std::string> include_dirs; std::list<std::string> include_dirs;
std::list<std::string> attributes; std::list<std::string> attributes;
lexer.set_debug(false); ParseMode parse_mode;
parser.set_debug_level(0); ParseState parse_state;
parse_mode.sv = false; parse_mode.sv = false;
parse_mode.formal = false; parse_mode.formal = false;
parse_mode.noassert = false; parse_mode.noassert = false;
@ -340,8 +336,8 @@ struct VerilogFrontend : public Frontend {
flag_dump_ast2 = true; flag_dump_ast2 = true;
flag_dump_vlog1 = true; flag_dump_vlog1 = true;
flag_dump_vlog2 = true; flag_dump_vlog2 = true;
lexer.set_debug(true); flag_debug_lexer = true;
parser.set_debug_level(1); flag_debug_parser = true;
continue; continue;
} }
if (arg == "-dump_ast1") { if (arg == "-dump_ast1") {
@ -370,6 +366,8 @@ struct VerilogFrontend : public Frontend {
} }
if (arg == "-yydebug") { if (arg == "-yydebug") {
flag_yydebug = true; flag_yydebug = true;
flag_debug_lexer = true;
flag_debug_parser = true;
continue; continue;
} }
if (arg == "-nolatches") { if (arg == "-nolatches") {
@ -481,6 +479,11 @@ struct VerilogFrontend : public Frontend {
break; break;
} }
VerilogLexer lexer(&parse_state, &parse_mode, &filename);
frontend_verilog_yy::parser parser(&lexer, &parse_state, &parse_mode);
lexer.set_debug(flag_debug_lexer);
parser.set_debug_level(flag_debug_parser ? 1 : 0);
if (parse_mode.formal || !flag_nosynthesis) if (parse_mode.formal || !flag_nosynthesis)
defines_map.add(parse_mode.formal ? "FORMAL" : "SYNTHESIS", "1"); defines_map.add(parse_mode.formal ? "FORMAL" : "SYNTHESIS", "1");
@ -491,10 +494,10 @@ struct VerilogFrontend : public Frontend {
log("Parsing %s%s input from `%s' to AST representation.\n", log("Parsing %s%s input from `%s' to AST representation.\n",
parse_mode.formal ? "formal " : "", parse_mode.sv ? "SystemVerilog" : "Verilog", filename.c_str()); parse_mode.formal ? "formal " : "", parse_mode.sv ? "SystemVerilog" : "Verilog", filename.c_str());
AST::current_filename = filename; AST::sv_mode_but_global_and_used_for_literally_one_condition = parse_mode.sv;
AST::sv_mode = parse_mode.sv;
parse_state.current_ast = new AST::AstNode(AST::AST_DESIGN); AstSrcLocType top_loc = AstSrcLocType ( "read_verilog", 0, 0, 0, 0);
parse_state.current_ast = new AST::AstNode(top_loc, AST::AST_DESIGN);
parse_state.lexin = f; parse_state.lexin = f;
std::string code_after_preproc; std::string code_after_preproc;
@ -522,10 +525,6 @@ struct VerilogFrontend : public Frontend {
// add a new empty type map to allow overriding existing global definitions // add a new empty type map to allow overriding existing global definitions
parse_state.user_type_stack.push_back(UserTypeMap()); parse_state.user_type_stack.push_back(UserTypeMap());
parser.~parser();
lexer.~VerilogLexer();
new (&lexer) VerilogLexer(&parse_state, &parse_mode);
new (&parser) frontend_verilog_yy::parser(&lexer, &parse_state, &parse_mode);
if (flag_yydebug) { if (flag_yydebug) {
lexer.set_debug(true); lexer.set_debug(true);
parser.set_debug_level(1); parser.set_debug_level(1);
@ -537,7 +536,7 @@ struct VerilogFrontend : public Frontend {
if (child->type == AST::AST_MODULE) if (child->type == AST::AST_MODULE)
for (auto &attr : attributes) for (auto &attr : attributes)
if (child->attributes.count(attr) == 0) if (child->attributes.count(attr) == 0)
child->attributes[attr] = AST::AstNode::mkconst_int(1, false); child->attributes[attr] = AST::AstNode::mkconst_int(top_loc, 1, false);
} }
if (flag_nodpi) if (flag_nodpi)
@ -776,24 +775,4 @@ struct VerilogFileList : public Pass {
#endif #endif
[[noreturn]]
void VERILOG_FRONTEND::verr_at(std::string filename, int begin_line, char const *fmt, va_list ap)
{
char buffer[1024];
char *p = buffer;
p += vsnprintf(p, buffer + sizeof(buffer) - p, fmt, ap);
p += snprintf(p, buffer + sizeof(buffer) - p, "\n");
YOSYS_NAMESPACE_PREFIX log_file_error(filename, begin_line, "%s", buffer);
exit(1);
}
[[noreturn]]
void VERILOG_FRONTEND::err_at_ast(AstSrcLocType loc, char const *fmt, ...)
{
va_list args;
va_start(args, fmt);
verr_at(AST::current_filename, loc.first_line, fmt, args);
va_end(args);
}
YOSYS_NAMESPACE_END YOSYS_NAMESPACE_END

View file

@ -39,7 +39,6 @@
#include <stdio.h> #include <stdio.h>
#include <stdint.h> #include <stdint.h>
#include <list>
YOSYS_NAMESPACE_BEGIN YOSYS_NAMESPACE_BEGIN
@ -47,8 +46,7 @@ namespace VERILOG_FRONTEND
{ {
/* Ephemeral context class */ /* Ephemeral context class */
struct ConstParser { struct ConstParser {
std::optional<std::string> filename; AST::AstSrcLocType loc;
std::optional<AST::AstSrcLocType> loc;
private: private:
std::string fmt_maybe_loc(std::string msg); std::string fmt_maybe_loc(std::string msg);
void log_maybe_loc_error(std::string msg); void log_maybe_loc_error(std::string msg);
@ -64,8 +62,6 @@ namespace VERILOG_FRONTEND
std::unique_ptr<AST::AstNode> const2ast(std::string code, char case_type = 0, bool warn_z = false); std::unique_ptr<AST::AstNode> const2ast(std::string code, char case_type = 0, bool warn_z = false);
}; };
[[noreturn]]
extern void err_at_ast(AST::AstSrcLocType loc, char const *fmt, ...);
}; };
YOSYS_NAMESPACE_END YOSYS_NAMESPACE_END

View file

@ -4,18 +4,20 @@
#include "kernel/yosys.h" #include "kernel/yosys.h"
#include "frontends/ast/ast.h" #include "frontends/ast/ast.h"
#include "frontends/verilog/verilog_parser.tab.hh" #include "frontends/verilog/verilog_parser.tab.hh"
#include <string>
YOSYS_NAMESPACE_BEGIN YOSYS_NAMESPACE_BEGIN
namespace VERILOG_FRONTEND { namespace VERILOG_FRONTEND {
[[noreturn]]
extern void verr_at(std::string filename, int begin_line, char const *fmt, va_list ap);
using parser = frontend_verilog_yy::parser; using parser = frontend_verilog_yy::parser;
class VerilogLexer : public frontend_verilog_yyFlexLexer { class VerilogLexer : public frontend_verilog_yyFlexLexer {
ParseState* extra; ParseState* extra;
ParseMode* mode; ParseMode* mode;
public: public:
VerilogLexer(ParseState* e, ParseMode* m) : frontend_verilog_yyFlexLexer(e->lexin), extra(e), mode(m) {} parser::location_type out_loc; // TODO private?
VerilogLexer(ParseState* e, ParseMode* m, std::string* filename) : frontend_verilog_yyFlexLexer(e->lexin), extra(e), mode(m) {
out_loc.begin.filename = filename;
}
~VerilogLexer() override {} ~VerilogLexer() override {}
// autogenerated body due to YY_DECL // autogenerated body due to YY_DECL
parser::symbol_type nextToken(); parser::symbol_type nextToken();
@ -24,19 +26,9 @@ namespace VERILOG_FRONTEND {
parser::symbol_type terminate() { parser::symbol_type terminate() {
return parser::make_FRONTEND_VERILOG_YYEOF(out_loc); return parser::make_FRONTEND_VERILOG_YYEOF(out_loc);
} }
parser::location_type out_loc;
[[noreturn]]
void err(char const *fmt, ...)
{
va_list args;
va_start(args, fmt);
verr_at(AST::current_filename, yylineno, fmt, args);
}
private: private:
std::vector<std::string> fn_stack; std::vector<std::string> fn_stack;
std::vector<int> ln_stack; std::vector<int> ln_stack;
parser::location_type real_loc;
parser::location_type old_loc;
int LexerInput(char* buf, int max_size) override { int LexerInput(char* buf, int max_size) override {
return readsome(*extra->lexin, buf, max_size); return readsome(*extra->lexin, buf, max_size);
} }

View file

@ -85,17 +85,16 @@ YOSYS_NAMESPACE_END
// result = readsome(*extra->lexin, buf, max_size) // result = readsome(*extra->lexin, buf, max_size)
#define YY_USER_ACTION \ #define YY_USER_ACTION \
real_loc.begin = real_loc.end; \ out_loc.begin = out_loc.end; \
for(int i = 0; YYText()[i] != '\0'; ++i){ \ for(int i = 0; YYText()[i] != '\0'; ++i){ \
if(YYText()[i] == '\n') { \ if(YYText()[i] == '\n') { \
real_loc.end.line++; \ out_loc.end.line++; \
real_loc.end.column = 1; \ out_loc.end.column = 1; \
} \ } \
else { \ else { \
real_loc.end.column++; \ out_loc.end.column++; \
} \ } \
} \ }
out_loc = real_loc;
#define YY_BREAK \ #define YY_BREAK \
break; break;
@ -183,7 +182,6 @@ TIME_SCALE_SUFFIX [munpf]?s
current_filename = current_filename.substr(0, current_filename.size()-1); current_filename = current_filename.substr(0, current_filename.size()-1);
yylineno = (0); yylineno = (0);
out_loc.begin.line = out_loc.end.line = 0; out_loc.begin.line = out_loc.end.line = 0;
real_loc.begin.line = real_loc.end.line = 0;
} }
<INITIAL,SYNOPSYS_TRANSLATE_OFF>"`file_pop"[^\n]*\n { <INITIAL,SYNOPSYS_TRANSLATE_OFF>"`file_pop"[^\n]*\n {
@ -191,7 +189,6 @@ TIME_SCALE_SUFFIX [munpf]?s
fn_stack.pop_back(); fn_stack.pop_back();
yylineno = (ln_stack.back()); yylineno = (ln_stack.back());
out_loc.begin.line = out_loc.end.line = ln_stack.back(); out_loc.begin.line = out_loc.end.line = ln_stack.back();
real_loc.begin.line = real_loc.end.line = ln_stack.back();
ln_stack.pop_back(); ln_stack.pop_back();
} }
@ -200,7 +197,6 @@ TIME_SCALE_SUFFIX [munpf]?s
while (*p == ' ' || *p == '\t') p++; while (*p == ' ' || *p == '\t') p++;
yylineno = (atoi(p)); yylineno = (atoi(p));
out_loc.begin.line = out_loc.end.line = atoi(p); out_loc.begin.line = out_loc.end.line = atoi(p);
real_loc.begin.line = real_loc.end.line = atoi(p);
while (*p && *p != ' ' && *p != '\t') p++; while (*p && *p != ' ' && *p != '\t') p++;
while (*p == ' ' || *p == '\t') p++; while (*p == ' ' || *p == '\t') p++;
const char *q = *p ? p + 1 : p; const char *q = *p ? p + 1 : p;
@ -226,14 +222,14 @@ TIME_SCALE_SUFFIX [munpf]?s
else if (!strcmp(p, "wire")) else if (!strcmp(p, "wire"))
extra->default_nettype_wire = true; extra->default_nettype_wire = true;
else else
err("Unsupported default nettype: %s", p); err_at_loc(out_loc, "Unsupported default nettype: %s", p);
} }
"`protect"[^\n]* /* ignore `protect*/ "`protect"[^\n]* /* ignore `protect*/
"`endprotect"[^\n]* /* ignore `endprotect*/ "`endprotect"[^\n]* /* ignore `endprotect*/
"`"[a-zA-Z_$][a-zA-Z0-9_$]* { "`"[a-zA-Z_$][a-zA-Z0-9_$]* {
err("Unimplemented compiler directive or undefined macro %s.", YYText()); err_at_loc(out_loc, "Unimplemented compiler directive or undefined macro %s.", YYText());
} }
"module" { return parser::make_TOK_MODULE(out_loc); } "module" { return parser::make_TOK_MODULE(out_loc); }

View file

@ -45,7 +45,7 @@
%code requires { %code requires {
#include "kernel/yosys_common.h" #include "kernel/yosys_common.h"
// #include "frontends/verilog/verilog_lexer.h" #include "frontends/verilog/verilog_error.h"
// start requires // start requires
YOSYS_NAMESPACE_BEGIN YOSYS_NAMESPACE_BEGIN
namespace VERILOG_FRONTEND { namespace VERILOG_FRONTEND {
@ -157,8 +157,7 @@
static ConstParser make_ConstParser_here(parser::location_type flex_loc) { static ConstParser make_ConstParser_here(parser::location_type flex_loc) {
AstSrcLocType loc; AstSrcLocType loc;
SET_LOC(loc, flex_loc, flex_loc); SET_LOC(loc, flex_loc, flex_loc);
std::optional<std::string> filename = flex_loc.begin.filename ? std::make_optional(*(flex_loc.begin.filename)) : std::nullopt; ConstParser p{loc};
ConstParser p{filename, loc};
return p; return p;
} }
static void append_attr(AstNode *ast, dict<IdString, std::unique_ptr<AstNode>> *al) static void append_attr(AstNode *ast, dict<IdString, std::unique_ptr<AstNode>> *al)
@ -244,17 +243,6 @@
node->children.push_back(std::move(rangeNode)); node->children.push_back(std::move(rangeNode));
} }
[[noreturn]]
extern void verr_at(std::string filename, int begin_line, char const *fmt, va_list ap);
[[noreturn]]
static void err_at_loc(frontend_verilog_yy::parser::location_type loc, char const *fmt, ...)
{
va_list args;
va_start(args, fmt);
verr_at(AST::current_filename, loc.begin.line, fmt, args);
va_end(args);
}
static void checkLabelsMatch(const frontend_verilog_yy::parser::location_type& loc, const char *element, const std::string* before, const std::string *after) static void checkLabelsMatch(const frontend_verilog_yy::parser::location_type& loc, const char *element, const std::string* before, const std::string *after)
{ {
if (!before && after) if (!before && after)
@ -731,7 +719,7 @@ module:
append_attr(mod, $1); append_attr(mod, $1);
} module_para_opt module_args_opt TOK_SEMICOL module_body TOK_ENDMODULE opt_label { } module_para_opt module_args_opt TOK_SEMICOL module_body TOK_ENDMODULE opt_label {
if (extra->port_stubs.size() != 0) if (extra->port_stubs.size() != 0)
lexer->err("Missing details for module port `%s'.", err_at_loc(@7, "Missing details for module port `%s'.",
extra->port_stubs.begin()->first.c_str()); extra->port_stubs.begin()->first.c_str());
SET_AST_NODE_LOC(extra->ast_stack.back(), @2, @$); SET_AST_NODE_LOC(extra->ast_stack.back(), @2, @$);
extra->ast_stack.pop_back(); extra->ast_stack.pop_back();
@ -785,7 +773,7 @@ module_arg_opt_assignment:
extra->ast_stack.back()->children.push_back(std::make_unique<AstNode>(AST_ASSIGN, std::move(wire), std::move($2))); extra->ast_stack.back()->children.push_back(std::make_unique<AstNode>(AST_ASSIGN, std::move(wire), std::move($2)));
} }
} else } else
lexer->err("SystemVerilog interface in module port list cannot have a default value."); err_at_loc(@2, "SystemVerilog interface in module port list cannot have a default value.");
} | } |
%empty; %empty;
@ -799,7 +787,7 @@ module_arg:
extra->ast_stack.back()->children.push_back(std::move(node)); extra->ast_stack.back()->children.push_back(std::move(node));
} else { } else {
if (extra->port_stubs.count(*$1) != 0) if (extra->port_stubs.count(*$1) != 0)
lexer->err("Duplicate module port `%s'.", $1->c_str()); err_at_loc(@1, "Duplicate module port `%s'.", $1->c_str());
extra->port_stubs[*$1] = ++extra->port_counter; extra->port_stubs[*$1] = ++extra->port_counter;
} }
} module_arg_opt_assignment | } module_arg_opt_assignment |
@ -809,7 +797,7 @@ module_arg:
extra->astbuf1->children[0]->str = *$1; extra->astbuf1->children[0]->str = *$1;
} TOK_ID { /* SV interfaces */ } TOK_ID { /* SV interfaces */
if (!mode->sv) if (!mode->sv)
lexer->err("Interface found in port list (%s). This is not supported unless read_verilog is called with -sv!", $3->c_str()); err_at_loc(@3, "Interface found in port list (%s). This is not supported unless read_verilog is called with -sv!", $3->c_str());
extra->astbuf2 = extra->astbuf1->clone(); // really only needed if multiple instances of same type. extra->astbuf2 = extra->astbuf1->clone(); // really only needed if multiple instances of same type.
extra->astbuf2->str = *$3; extra->astbuf2->str = *$3;
extra->astbuf2->port_id = ++extra->port_counter; extra->astbuf2->port_id = ++extra->port_counter;
@ -824,9 +812,9 @@ module_arg:
if (range != nullptr) if (range != nullptr)
node->children.push_back(std::move(range)); node->children.push_back(std::move(range));
if (!node->is_input && !node->is_output) if (!node->is_input && !node->is_output)
lexer->err("Module port `%s' is neither input nor output.", $4->c_str()); err_at_loc(@4, "Module port `%s' is neither input nor output.", $4->c_str());
if (node->is_reg && node->is_input && !node->is_output && !mode->sv) if (node->is_reg && node->is_input && !node->is_output && !mode->sv)
lexer->err("Input port `%s' is declared as register.", $4->c_str()); err_at_loc(@4, "Input port `%s' is declared as register.", $4->c_str());
append_attr(node.get(), $1); append_attr(node.get(), $1);
extra->ast_stack.back()->children.push_back(std::move(node)); extra->ast_stack.back()->children.push_back(std::move(node));
} module_arg_opt_assignment | } module_arg_opt_assignment |
@ -867,7 +855,7 @@ interface:
intf->str = *$3; intf->str = *$3;
} module_para_opt module_args_opt TOK_SEMICOL interface_body TOK_ENDINTERFACE { } module_para_opt module_args_opt TOK_SEMICOL interface_body TOK_ENDINTERFACE {
if (extra->port_stubs.size() != 0) if (extra->port_stubs.size() != 0)
lexer->err("Missing details for module port `%s'.", err_at_loc(@6, "Missing details for module port `%s'.",
extra->port_stubs.begin()->first.c_str()); extra->port_stubs.begin()->first.c_str());
extra->ast_stack.pop_back(); extra->ast_stack.pop_back();
log_assert(extra->ast_stack.size() == 1); log_assert(extra->ast_stack.size() == 1);
@ -1284,7 +1272,7 @@ task_func_port:
extra->astbuf2 = checkRange(extra->astbuf1.get(), std::move($3)); extra->astbuf2 = checkRange(extra->astbuf1.get(), std::move($3));
if (!extra->astbuf1->is_input && !extra->astbuf1->is_output) { if (!extra->astbuf1->is_input && !extra->astbuf1->is_output) {
if (!mode->sv) if (!mode->sv)
lexer->err("task/function argument direction missing"); err_at_loc(@2, "task/function argument direction missing");
extra->astbuf1->is_input = prev_was_input; extra->astbuf1->is_input = prev_was_input;
extra->astbuf1->is_output = prev_was_output; extra->astbuf1->is_output = prev_was_output;
} }
@ -1292,7 +1280,7 @@ task_func_port:
{ {
if (!extra->astbuf1) { if (!extra->astbuf1) {
if (!mode->sv) if (!mode->sv)
lexer->err("task/function argument direction missing"); err_at_loc(@$, "task/function argument direction missing");
extra->albuf = new dict<IdString, std::unique_ptr<AstNode>>; extra->albuf = new dict<IdString, std::unique_ptr<AstNode>>;
extra->astbuf1 = std::make_unique<AstNode>(AST_WIRE); extra->astbuf1 = std::make_unique<AstNode>(AST_WIRE);
extra->current_wire_rand = false; extra->current_wire_rand = false;
@ -1325,7 +1313,7 @@ specify_item:
specify_rise_fall_ptr_t timing = std::move($9); specify_rise_fall_ptr_t timing = std::move($9);
if (specify_edge != 0 && target->dat == nullptr) if (specify_edge != 0 && target->dat == nullptr)
lexer->err("Found specify edge but no data spec.\n"); err_at_loc(@3, "Found specify edge but no data spec.\n");
auto cell_owned = std::make_unique<AstNode>(AST_CELL); auto cell_owned = std::make_unique<AstNode>(AST_CELL);
auto cell = cell_owned.get(); auto cell = cell_owned.get();
@ -1400,7 +1388,7 @@ specify_item:
TOK_ID TOK_LPAREN specify_edge expr specify_condition TOK_COMMA specify_edge expr specify_condition TOK_COMMA specify_triple specify_opt_triple TOK_RPAREN TOK_SEMICOL { TOK_ID TOK_LPAREN specify_edge expr specify_condition TOK_COMMA specify_edge expr specify_condition TOK_COMMA specify_triple specify_opt_triple TOK_RPAREN TOK_SEMICOL {
if (*$1 != "$setup" && *$1 != "$hold" && *$1 != "$setuphold" && *$1 != "$removal" && *$1 != "$recovery" && if (*$1 != "$setup" && *$1 != "$hold" && *$1 != "$setuphold" && *$1 != "$removal" && *$1 != "$recovery" &&
*$1 != "$recrem" && *$1 != "$skew" && *$1 != "$timeskew" && *$1 != "$fullskew" && *$1 != "$nochange") *$1 != "$recrem" && *$1 != "$skew" && *$1 != "$timeskew" && *$1 != "$fullskew" && *$1 != "$nochange")
lexer->err("Unsupported specify rule type: %s\n", $1->c_str()); err_at_loc(@1, "Unsupported specify rule type: %s\n", $1->c_str());
auto src_pen = AstNode::mkconst_int($3 != 0, false, 1); auto src_pen = AstNode::mkconst_int($3 != 0, false, 1);
auto src_pol = AstNode::mkconst_int($3 == 'p', false, 1); auto src_pol = AstNode::mkconst_int($3 == 'p', false, 1);
@ -1766,10 +1754,10 @@ single_param_decl:
AstNode *decl = extra->ast_stack.back()->children.back().get(); AstNode *decl = extra->ast_stack.back()->children.back().get();
if (decl->type != AST_PARAMETER) { if (decl->type != AST_PARAMETER) {
log_assert(decl->type == AST_LOCALPARAM); log_assert(decl->type == AST_LOCALPARAM);
lexer->err("localparam initialization is missing!"); err_at_loc(@1, "localparam initialization is missing!");
} }
if (!mode->sv) if (!mode->sv)
lexer->err("Parameter defaults can only be omitted in SystemVerilog mode!"); err_at_loc(@1, "Parameter defaults can only be omitted in SystemVerilog mode!");
decl->children.erase(decl->children.begin()); decl->children.erase(decl->children.begin());
}; };
@ -1778,7 +1766,7 @@ single_param_decl_ident:
std::unique_ptr<AstNode> node_owned; std::unique_ptr<AstNode> node_owned;
if (extra->astbuf1 == nullptr) { if (extra->astbuf1 == nullptr) {
if (!mode->sv) if (!mode->sv)
lexer->err("In pure Verilog (not SystemVerilog), parameter/localparam with an initializer must use the parameter/localparam keyword"); err_at_loc(@1, "In pure Verilog (not SystemVerilog), parameter/localparam with an initializer must use the parameter/localparam keyword");
node_owned = std::make_unique<AstNode>(AST_PARAMETER); node_owned = std::make_unique<AstNode>(AST_PARAMETER);
node_owned->children.push_back(AstNode::mkconst_int(0, true)); node_owned->children.push_back(AstNode::mkconst_int(0, true));
} else { } else {
@ -1929,7 +1917,7 @@ struct_body: opt_packed TOK_LCURL struct_member_list TOK_RCURL
opt_packed: opt_packed:
TOK_PACKED opt_signed_struct | TOK_PACKED opt_signed_struct |
%empty { lexer->err("Only PACKED supported at this time"); }; %empty { err_at_loc(@$, "Only PACKED supported at this time"); };
opt_signed_struct: opt_signed_struct:
TOK_SIGNED { extra->astbuf2->is_signed = true; } TOK_SIGNED { extra->astbuf2->is_signed = true; }
@ -2114,7 +2102,7 @@ wire_name_and_opt_assign:
wire_name: wire_name:
TOK_ID range_or_multirange { TOK_ID range_or_multirange {
if (extra->astbuf1 == nullptr) if (extra->astbuf1 == nullptr)
lexer->err("Internal error - should not happen - no AST_WIRE node."); err_at_loc(@1, "Internal error - should not happen - no AST_WIRE node.");
auto node = extra->astbuf1->clone(); auto node = extra->astbuf1->clone();
node->str = *$1; node->str = *$1;
append_attr_clone(node.get(), extra->albuf); append_attr_clone(node.get(), extra->albuf);
@ -2122,7 +2110,7 @@ wire_name:
node->children.push_back(extra->astbuf2->clone()); node->children.push_back(extra->astbuf2->clone());
if ($2 != nullptr) { if ($2 != nullptr) {
if (node->is_input || node->is_output) if (node->is_input || node->is_output)
lexer->err("input/output/inout ports cannot have unpacked dimensions."); err_at_loc(@2, "input/output/inout ports cannot have unpacked dimensions.");
if (!extra->astbuf2 && !node->is_custom_type) { if (!extra->astbuf2 && !node->is_custom_type) {
addRange(node.get(), 0, 0, false); addRange(node.get(), 0, 0, false);
} }
@ -2133,21 +2121,21 @@ wire_name:
node->port_id = extra->current_function_or_task_port_id++; node->port_id = extra->current_function_or_task_port_id++;
} else if (extra->ast_stack.back()->type == AST_GENBLOCK) { } else if (extra->ast_stack.back()->type == AST_GENBLOCK) {
if (node->is_input || node->is_output) if (node->is_input || node->is_output)
lexer->err("Cannot declare module port `%s' within a generate block.", $1->c_str()); err_at_loc(@1, "Cannot declare module port `%s' within a generate block.", $1->c_str());
} else { } else {
if (extra->do_not_require_port_stubs && (node->is_input || node->is_output) && extra->port_stubs.count(*$1) == 0) { if (extra->do_not_require_port_stubs && (node->is_input || node->is_output) && extra->port_stubs.count(*$1) == 0) {
extra->port_stubs[*$1] = ++extra->port_counter; extra->port_stubs[*$1] = ++extra->port_counter;
} }
if (extra->port_stubs.count(*$1) != 0) { if (extra->port_stubs.count(*$1) != 0) {
if (!node->is_input && !node->is_output) if (!node->is_input && !node->is_output)
lexer->err("Module port `%s' is neither input nor output.", $1->c_str()); err_at_loc(@1, "Module port `%s' is neither input nor output.", $1->c_str());
if (node->is_reg && node->is_input && !node->is_output && !mode->sv) if (node->is_reg && node->is_input && !node->is_output && !mode->sv)
lexer->err("Input port `%s' is declared as register.", $1->c_str()); err_at_loc(@1, "Input port `%s' is declared as register.", $1->c_str());
node->port_id = extra->port_stubs[*$1]; node->port_id = extra->port_stubs[*$1];
extra->port_stubs.erase(*$1); extra->port_stubs.erase(*$1);
} else { } else {
if (node->is_input || node->is_output) if (node->is_input || node->is_output)
lexer->err("Module port `%s' is not declared in module header.", $1->c_str()); err_at_loc(@1, "Module port `%s' is not declared in module header.", $1->c_str());
} }
} }
//FIXME: for some reason, TOK_ID has a location which always points to one column *after* the real last column... //FIXME: for some reason, TOK_ID has a location which always points to one column *after* the real last column...
@ -2169,7 +2157,7 @@ assign_expr:
}; };
type_name: TOK_ID { $$ = std::move($1); } // first time seen type_name: TOK_ID { $$ = std::move($1); } // first time seen
| TOK_USER_TYPE { if (extra->isInLocalScope($1.get())) lexer->err("Duplicate declaration of TYPEDEF '%s'", $1->c_str()+1); $$ = std::move($1); } | TOK_USER_TYPE { if (extra->isInLocalScope($1.get())) err_at_loc(@1, "Duplicate declaration of TYPEDEF '%s'", $1->c_str()+1); $$ = std::move($1); }
; ;
typedef_decl: typedef_decl:
@ -2347,7 +2335,7 @@ cell_port_list:
} }
if (has_positional_args && has_named_args) if (has_positional_args && has_named_args)
lexer->err("Mix of positional and named cell ports."); err_at_loc(@1, "Mix of positional and named cell ports.");
}; };
cell_port_list_rules: cell_port_list_rules:
@ -2388,7 +2376,7 @@ cell_port:
} | } |
attr TOK_WILDCARD_CONNECT { attr TOK_WILDCARD_CONNECT {
if (!mode->sv) if (!mode->sv)
lexer->err("Wildcard port connections are only supported in SystemVerilog mode."); err_at_loc(@2, "Wildcard port connections are only supported in SystemVerilog mode.");
extra->cell_hack->attributes[ID::wildcard_port_conns] = AstNode::mkconst_int(1, false); extra->cell_hack->attributes[ID::wildcard_port_conns] = AstNode::mkconst_int(1, false);
free_attr($1); free_attr($1);
}; };
@ -2727,11 +2715,11 @@ for_initialization:
extra->ast_stack.back()->children.push_back(std::move(node)); extra->ast_stack.back()->children.push_back(std::move(node));
} | } |
non_io_wire_type range TOK_ID { non_io_wire_type range TOK_ID {
lexer->err("For loop variable declaration is missing initialization!"); err_at_loc(@3, "For loop variable declaration is missing initialization!");
} | } |
non_io_wire_type range TOK_ID TOK_EQ expr { non_io_wire_type range TOK_ID TOK_EQ expr {
if (!mode->sv) if (!mode->sv)
lexer->err("For loop inline variable declaration is only supported in SystemVerilog mode!"); err_at_loc(@4, "For loop inline variable declaration is only supported in SystemVerilog mode!");
// loop variable declaration // loop variable declaration
auto wire = std::move($1); auto wire = std::move($1);
@ -2915,21 +2903,21 @@ if_attr:
attr TOK_UNIQUE0 { attr TOK_UNIQUE0 {
AstNode *context = extra->ast_stack.back(); AstNode *context = extra->ast_stack.back();
if (context && context->type == AST_BLOCK && context->get_bool_attribute(ID::promoted_if)) if (context && context->type == AST_BLOCK && context->get_bool_attribute(ID::promoted_if))
lexer->err("unique0 keyword cannot be used for 'else if' branch."); err_at_loc(@2, "unique0 keyword cannot be used for 'else if' branch.");
(*$1)[ID::parallel_case] = AstNode::mkconst_int(1, false); (*$1)[ID::parallel_case] = AstNode::mkconst_int(1, false);
$$ = $1; $$ = $1;
} | } |
attr TOK_PRIORITY { attr TOK_PRIORITY {
AstNode *context = extra->ast_stack.back(); AstNode *context = extra->ast_stack.back();
if (context && context->type == AST_BLOCK && context->get_bool_attribute(ID::promoted_if)) if (context && context->type == AST_BLOCK && context->get_bool_attribute(ID::promoted_if))
lexer->err("priority keyword cannot be used for 'else if' branch."); err_at_loc(@2, "priority keyword cannot be used for 'else if' branch.");
(*$1)[ID::full_case] = AstNode::mkconst_int(1, false); (*$1)[ID::full_case] = AstNode::mkconst_int(1, false);
$$ = $1; $$ = $1;
} | } |
attr TOK_UNIQUE { attr TOK_UNIQUE {
AstNode *context = extra->ast_stack.back(); AstNode *context = extra->ast_stack.back();
if (context && context->type == AST_BLOCK && context->get_bool_attribute(ID::promoted_if)) if (context && context->type == AST_BLOCK && context->get_bool_attribute(ID::promoted_if))
lexer->err("unique keyword cannot be used for 'else if' branch."); err_at_loc(@2, "unique keyword cannot be used for 'else if' branch.");
(*$1)[ID::full_case] = AstNode::mkconst_int(1, false); (*$1)[ID::full_case] = AstNode::mkconst_int(1, false);
(*$1)[ID::parallel_case] = AstNode::mkconst_int(1, false); (*$1)[ID::parallel_case] = AstNode::mkconst_int(1, false);
$$ = $1; $$ = $1;
@ -3127,11 +3115,11 @@ genvar_identifier:
genvar_initialization: genvar_initialization:
TOK_GENVAR genvar_identifier { TOK_GENVAR genvar_identifier {
lexer->err("Generate for loop variable declaration is missing initialization!"); err_at_loc(@2, "Generate for loop variable declaration is missing initialization!");
} | } |
TOK_GENVAR genvar_identifier TOK_EQ expr { TOK_GENVAR genvar_identifier TOK_EQ expr {
if (!mode->sv) if (!mode->sv)
lexer->err("Generate for loop inline variable declaration is only supported in SystemVerilog mode!"); err_at_loc(@3, "Generate for loop inline variable declaration is only supported in SystemVerilog mode!");
AstNode* node = extra->saveChild(std::make_unique<AstNode>(AST_GENVAR)); AstNode* node = extra->saveChild(std::make_unique<AstNode>(AST_GENVAR));
node->is_reg = true; node->is_reg = true;
node->is_signed = true; node->is_signed = true;
@ -3233,7 +3221,7 @@ basic_expr:
} | } |
TOK_LPAREN expr TOK_RPAREN integral_number { TOK_LPAREN expr TOK_RPAREN integral_number {
if ($4->compare(0, 1, "'") != 0) if ($4->compare(0, 1, "'") != 0)
lexer->err("Cast operation must be applied on sized constants e.g. (<expr>)<constval> , while %s is not a sized constant.", $4->c_str()); err_at_loc(@4, "Cast operation must be applied on sized constants e.g. (<expr>)<constval> , while %s is not a sized constant.", $4->c_str());
auto p = make_ConstParser_here(@4); auto p = make_ConstParser_here(@4);
auto val = p.const2ast(*$4, extra->case_type_stack.size() == 0 ? 0 : extra->case_type_stack.back(), !mode->lib); auto val = p.const2ast(*$4, extra->case_type_stack.size() == 0 ? 0 : extra->case_type_stack.back(), !mode->lib);
if (val == nullptr) if (val == nullptr)
@ -3242,7 +3230,7 @@ basic_expr:
} | } |
hierarchical_id integral_number { hierarchical_id integral_number {
if ($2->compare(0, 1, "'") != 0) if ($2->compare(0, 1, "'") != 0)
lexer->err("Cast operation must be applied on sized constants, e.g. <ID>\'d0, while %s is not a sized constant.", $2->c_str()); err_at_loc(@2, "Cast operation must be applied on sized constants, e.g. <ID>\'d0, while %s is not a sized constant.", $2->c_str());
auto bits = std::make_unique<AstNode>(AST_IDENTIFIER); auto bits = std::make_unique<AstNode>(AST_IDENTIFIER);
bits->str = *$1; bits->str = *$1;
SET_AST_NODE_LOC(bits.get(), @1, @1); SET_AST_NODE_LOC(bits.get(), @1, @1);
@ -3491,25 +3479,25 @@ basic_expr:
} | } |
TOK_SIGNED OP_CAST TOK_LPAREN expr TOK_RPAREN { TOK_SIGNED OP_CAST TOK_LPAREN expr TOK_RPAREN {
if (!mode->sv) if (!mode->sv)
lexer->err("Static cast is only supported in SystemVerilog mode."); err_at_loc(@2, "Static cast is only supported in SystemVerilog mode.");
$$ = std::make_unique<AstNode>(AST_TO_SIGNED, std::move($4)); $$ = std::make_unique<AstNode>(AST_TO_SIGNED, std::move($4));
SET_AST_NODE_LOC($$.get(), @1, @4); SET_AST_NODE_LOC($$.get(), @1, @4);
} | } |
TOK_UNSIGNED OP_CAST TOK_LPAREN expr TOK_RPAREN { TOK_UNSIGNED OP_CAST TOK_LPAREN expr TOK_RPAREN {
if (!mode->sv) if (!mode->sv)
lexer->err("Static cast is only supported in SystemVerilog mode."); err_at_loc(@2, "Static cast is only supported in SystemVerilog mode.");
$$ = std::make_unique<AstNode>(AST_TO_UNSIGNED, std::move($4)); $$ = std::make_unique<AstNode>(AST_TO_UNSIGNED, std::move($4));
SET_AST_NODE_LOC($$.get(), @1, @4); SET_AST_NODE_LOC($$.get(), @1, @4);
} | } |
basic_expr OP_CAST TOK_LPAREN expr TOK_RPAREN { basic_expr OP_CAST TOK_LPAREN expr TOK_RPAREN {
if (!mode->sv) if (!mode->sv)
lexer->err("Static cast is only supported in SystemVerilog mode."); err_at_loc(@2, "Static cast is only supported in SystemVerilog mode.");
$$ = std::make_unique<AstNode>(AST_CAST_SIZE, std::move($1), std::move($4)); $$ = std::make_unique<AstNode>(AST_CAST_SIZE, std::move($1), std::move($4));
SET_AST_NODE_LOC($$.get(), @1, @4); SET_AST_NODE_LOC($$.get(), @1, @4);
} | } |
typedef_base_type OP_CAST TOK_LPAREN expr TOK_RPAREN { typedef_base_type OP_CAST TOK_LPAREN expr TOK_RPAREN {
if (!mode->sv) if (!mode->sv)
lexer->err("Static cast is only supported in SystemVerilog mode."); err_at_loc(@2, "Static cast is only supported in SystemVerilog mode.");
$$ = std::make_unique<AstNode>(AST_CAST_SIZE, std::move($1), std::move($4)); $$ = std::make_unique<AstNode>(AST_CAST_SIZE, std::move($1), std::move($4));
SET_AST_NODE_LOC($$.get(), @1, @4); SET_AST_NODE_LOC($$.get(), @1, @4);
} | } |