3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2025-04-27 02:45:52 +00:00

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

This commit is contained in:
Eddie Hung 2019-06-12 08:50:39 -07:00
commit f7a9769c14
140 changed files with 4698 additions and 1852 deletions

File diff suppressed because it is too large Load diff

View file

@ -37,16 +37,20 @@ struct AigerReader
unsigned M, I, L, O, A;
unsigned B, C, J, F; // Optional in AIGER 1.9
unsigned line_count;
uint32_t piNum, flopNum;
std::vector<RTLIL::Wire*> inputs;
std::vector<RTLIL::Wire*> latches;
std::vector<RTLIL::Wire*> outputs;
std::vector<RTLIL::Wire*> bad_properties;
std::vector<RTLIL::Cell*> boxes;
AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name, std::string map_filename, bool wideports);
void parse_aiger();
void parse_xaiger();
void parse_aiger_ascii();
void parse_aiger_binary();
void post_process();
};
YOSYS_NAMESPACE_END

View file

@ -154,6 +154,7 @@ std::string AST::type2str(AstNodeType type)
X(AST_GENIF)
X(AST_GENCASE)
X(AST_GENBLOCK)
X(AST_TECALL)
X(AST_POSEDGE)
X(AST_NEGEDGE)
X(AST_EDGE)
@ -194,6 +195,9 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *ch
is_logic = false;
is_signed = false;
is_string = false;
is_wand = false;
is_wor = false;
is_unsized = false;
was_checked = false;
range_valid = false;
range_swapped = false;
@ -722,7 +726,7 @@ AstNode *AstNode::mkconst_int(uint32_t v, bool is_signed, int width)
}
// create an AST node for a constant (using a bit vector as value)
AstNode *AstNode::mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed)
AstNode *AstNode::mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed, bool is_unsized)
{
AstNode *node = new AstNode(AST_CONSTANT);
node->is_signed = is_signed;
@ -736,9 +740,15 @@ AstNode *AstNode::mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signe
node->range_valid = true;
node->range_left = node->bits.size()-1;
node->range_right = 0;
node->is_unsized = is_unsized;
return node;
}
AstNode *AstNode::mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed)
{
return mkconst_bits(v, is_signed, false);
}
// create an AST node for a constant (using a string in bit vector form as value)
AstNode *AstNode::mkconst_str(const std::vector<RTLIL::State> &v)
{
@ -775,6 +785,14 @@ bool AstNode::bits_only_01() const
return true;
}
RTLIL::Const AstNode::bitsAsUnsizedConst(int width)
{
RTLIL::State extbit = bits.back();
while (width > int(bits.size()))
bits.push_back(extbit);
return RTLIL::Const(bits);
}
RTLIL::Const AstNode::bitsAsConst(int width, bool is_signed)
{
std::vector<RTLIL::State> bits = this->bits;
@ -951,6 +969,9 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
continue;
if (child->type == AST_PARAMETER || child->type == AST_LOCALPARAM)
continue;
if (child->type == AST_CELL && child->children.size() > 0 && child->children[0]->type == AST_CELLTYPE &&
(child->children[0]->str == "$specify2" || child->children[0]->str == "$specify3" || child->children[0]->str == "$specrule"))
continue;
blackbox_module = false;
break;
}
@ -1035,6 +1056,9 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
child->delete_children();
child->children.push_back(AstNode::mkconst_int(0, false, 0));
new_children.push_back(child);
} else if (child->type == AST_CELL && child->children.size() > 0 && child->children[0]->type == AST_CELLTYPE &&
(child->children[0]->str == "$specify2" || child->children[0]->str == "$specify3" || child->children[0]->str == "$specrule")) {
new_children.push_back(child);
} else {
delete child;
}

View file

@ -137,7 +137,8 @@ namespace AST
AST_GENIF,
AST_GENCASE,
AST_GENBLOCK,
AST_TECALL,
AST_POSEDGE,
AST_NEGEDGE,
AST_EDGE,
@ -173,7 +174,7 @@ namespace AST
// node content - most of it is unused in most node types
std::string str;
std::vector<RTLIL::State> bits;
bool is_input, is_output, is_reg, is_logic, is_signed, is_string, range_valid, range_swapped, was_checked;
bool is_input, is_output, is_reg, is_logic, is_signed, is_string, is_wand, is_wor, range_valid, range_swapped, was_checked, is_unsized;
int port_id, range_left, range_right;
uint32_t integer;
double realvalue;
@ -262,6 +263,7 @@ namespace AST
// helper functions for creating AST nodes for constants
static AstNode *mkconst_int(uint32_t v, bool is_signed, int width = 32);
static AstNode *mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed, bool is_unsized);
static AstNode *mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed);
static AstNode *mkconst_str(const std::vector<RTLIL::State> &v);
static AstNode *mkconst_str(const std::string &str);
@ -269,6 +271,7 @@ namespace AST
// helper function for creating sign-extended const objects
RTLIL::Const bitsAsConst(int width, bool is_signed);
RTLIL::Const bitsAsConst(int width = -1);
RTLIL::Const bitsAsUnsizedConst(int width);
RTLIL::Const asAttrConst();
RTLIL::Const asParaConst();
uint64_t asInt(bool is_signed);

View file

@ -645,6 +645,8 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
if (!id_ast->children[0]->range_valid)
log_file_error(filename, linenum, "Failed to detect width of memory access `%s'!\n", str.c_str());
this_width = id_ast->children[0]->range_left - id_ast->children[0]->range_right + 1;
if (children.size() > 1)
range = children[1];
} else
log_file_error(filename, linenum, "Failed to detect width for identifier %s!\n", str.c_str());
if (range) {
@ -902,7 +904,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
if (!range_valid)
log_file_error(filename, linenum, "Signal `%s' with non-constant width!\n", str.c_str());
log_assert(range_left >= range_right || (range_left == -1 && range_right == 0));
if (!(range_left >= range_right || (range_left == -1 && range_right == 0)))
log_file_error(filename, linenum, "Signal `%s' with invalid width range %d!\n", str.c_str(), range_left - range_right + 1);
RTLIL::Wire *wire = current_module->addWire(str, range_left - range_right + 1);
wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
@ -917,6 +920,9 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
wire->attributes[attr.first] = attr.second->asAttrConst();
}
if (is_wand) wire->set_bool_attribute("\\wand");
if (is_wor) wire->set_bool_attribute("\\wor");
}
break;
@ -961,8 +967,13 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
detectSignWidth(width_hint, sign_hint);
is_signed = sign_hint;
if (type == AST_CONSTANT)
return RTLIL::SigSpec(bitsAsConst());
if (type == AST_CONSTANT) {
if (is_unsized) {
return RTLIL::SigSpec(bitsAsUnsizedConst(width_hint));
} else {
return RTLIL::SigSpec(bitsAsConst());
}
}
RTLIL::SigSpec sig = realAsConst(width_hint);
log_file_warning(filename, linenum, "converting real value %e to binary %s.\n", realvalue, log_signal(sig));
@ -1490,10 +1501,12 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
continue;
}
if (child->type == AST_PARASET) {
int extra_const_flags = 0;
IdString paraname = child->str.empty() ? stringf("$%d", ++para_counter) : child->str;
if (child->children[0]->type == AST_REALVALUE) {
log_file_warning(filename, linenum, "Replacing floating point parameter %s.%s = %f with string.\n",
log_id(cell), log_id(paraname), child->children[0]->realvalue);
extra_const_flags = RTLIL::CONST_FLAG_REAL;
auto strnode = AstNode::mkconst_str(stringf("%f", child->children[0]->realvalue));
strnode->cloneInto(child->children[0]);
delete strnode;
@ -1502,6 +1515,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
log_file_error(filename, linenum, "Parameter %s.%s with non-constant value!\n",
log_id(cell), log_id(paraname));
cell->parameters[paraname] = child->children[0]->asParaConst();
cell->parameters[paraname].flags |= extra_const_flags;
continue;
}
if (child->type == AST_ARGUMENT) {
@ -1521,9 +1535,29 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
}
for (auto &attr : attributes) {
if (attr.second->type != AST_CONSTANT)
log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
log_file_error(filename, linenum, "Attribute `%s' with non-constant value.\n", attr.first.c_str());
cell->attributes[attr.first] = attr.second->asAttrConst();
}
if (cell->type.in("$specify2", "$specify3")) {
int src_width = GetSize(cell->getPort("\\SRC"));
int dst_width = GetSize(cell->getPort("\\DST"));
bool full = cell->getParam("\\FULL").as_bool();
if (!full && src_width != dst_width)
log_file_error(filename, linenum, "Parallel specify SRC width does not match DST width.\n");
if (cell->type == "$specify3") {
int dat_width = GetSize(cell->getPort("\\DAT"));
if (dat_width != dst_width)
log_file_error(filename, linenum, "Specify DAT width does not match DST width.\n");
}
cell->setParam("\\SRC_WIDTH", Const(src_width));
cell->setParam("\\DST_WIDTH", Const(dst_width));
}
if (cell->type == "$specrule") {
int src_width = GetSize(cell->getPort("\\SRC"));
int dst_width = GetSize(cell->getPort("\\DST"));
cell->setParam("\\SRC_WIDTH", Const(src_width));
cell->setParam("\\DST_WIDTH", Const(dst_width));
}
}
break;
@ -1541,6 +1575,37 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
delete always;
} break;
case AST_TECALL: {
int sz = children.size();
if (str == "$info") {
if (sz > 0)
log_file_info(filename, linenum, "%s.\n", children[0]->str.c_str());
else
log_file_info(filename, linenum, "\n");
} else if (str == "$warning") {
if (sz > 0)
log_file_warning(filename, linenum, "%s.\n", children[0]->str.c_str());
else
log_file_warning(filename, linenum, "\n");
} else if (str == "$error") {
if (sz > 0)
log_file_error(filename, linenum, "%s.\n", children[0]->str.c_str());
else
log_file_error(filename, linenum, "\n");
} else if (str == "$fatal") {
// TODO: 1st parameter, if exists, is 0,1 or 2, and passed to $finish()
// if no parameter is given, default value is 1
// dollar_finish(sz ? children[0] : 1);
// perhaps create & use log_file_fatal()
if (sz > 0)
log_file_error(filename, linenum, "FATAL: %s.\n", children[0]->str.c_str());
else
log_file_error(filename, linenum, "FATAL.\n");
} else {
log_file_error(filename, linenum, "Unknown elabortoon system task '%s'.\n", str.c_str());
}
} break;
case AST_FCALL: {
if (str == "\\$anyconst" || str == "\\$anyseq" || str == "\\$allconst" || str == "\\$allseq")
{

View file

@ -1172,6 +1172,13 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
varbuf->children[0] = buf;
}
if (type == AST_FOR) {
AstNode *buf = next_ast->clone();
delete buf->children[1];
buf->children[1] = varbuf->children[0]->clone();
current_block->children.insert(current_block->children.begin() + current_block_idx++, buf);
}
current_scope[varbuf->str] = backup_scope_varbuf;
delete varbuf;
delete_children();
@ -1598,6 +1605,7 @@ skip_dynamic_range_lvalue_expansion:;
current_scope[wire_tmp->str] = wire_tmp;
wire_tmp->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
while (wire_tmp->simplify(true, false, false, 1, -1, false, false)) { }
wire_tmp->is_logic = true;
AstNode *wire_tmp_id = new AstNode(AST_IDENTIFIER);
wire_tmp_id->str = wire_tmp->str;

View file

@ -53,6 +53,7 @@ USING_YOSYS_NAMESPACE
"attribute" { return TOK_ATTRIBUTE; }
"parameter" { return TOK_PARAMETER; }
"signed" { return TOK_SIGNED; }
"real" { return TOK_REAL; }
"wire" { return TOK_WIRE; }
"memory" { return TOK_MEMORY; }
"width" { return TOK_WIDTH; }

View file

@ -45,7 +45,16 @@ YOSYS_NAMESPACE_END
USING_YOSYS_NAMESPACE
%}
%name-prefix "rtlil_frontend_ilang_yy"
%define api.prefix {rtlil_frontend_ilang_yy}
/* The union is defined in the header, so we need to provide all the
* includes it requires
*/
%code requires {
#include <string>
#include <vector>
#include "frontends/ilang/ilang_frontend.h"
}
%union {
char *string;
@ -61,7 +70,7 @@ USING_YOSYS_NAMESPACE
%token TOK_CELL TOK_CONNECT TOK_SWITCH TOK_CASE TOK_ASSIGN TOK_SYNC
%token TOK_LOW TOK_HIGH TOK_POSEDGE TOK_NEGEDGE TOK_EDGE TOK_ALWAYS TOK_GLOBAL TOK_INIT
%token TOK_UPDATE TOK_PROCESS TOK_END TOK_INVALID TOK_EOL TOK_OFFSET
%token TOK_PARAMETER TOK_ATTRIBUTE TOK_MEMORY TOK_SIZE TOK_SIGNED TOK_UPTO
%token TOK_PARAMETER TOK_ATTRIBUTE TOK_MEMORY TOK_SIZE TOK_SIGNED TOK_REAL TOK_UPTO
%type <rsigspec> sigspec_list_reversed
%type <sigspec> sigspec sigspec_list
@ -241,6 +250,12 @@ cell_body:
free($4);
delete $5;
} |
cell_body TOK_PARAMETER TOK_REAL TOK_ID constant EOL {
current_cell->parameters[$4] = *$5;
current_cell->parameters[$4].flags |= RTLIL::CONST_FLAG_REAL;
free($4);
delete $5;
} |
cell_body TOK_CONNECT TOK_ID sigspec EOL {
if (current_cell->hasPort($3))
rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of cell port %s.", $3).c_str());
@ -445,4 +460,3 @@ conn_stmt:
delete $2;
delete $3;
};

View file

@ -46,7 +46,15 @@ USING_YOSYS_NAMESPACE
#include "VeriModule.h"
#include "VeriWrite.h"
#include "VhdlUnits.h"
#include "Message.h"
#include "VeriLibrary.h"
#ifndef SYMBIOTIC_VERIFIC_API_VERSION
# error "Only Symbiotic EDA flavored Verific is supported. Please contact office@symbioticeda.com for commercial support for Yosys+Verific."
#endif
#if SYMBIOTIC_VERIFIC_API_VERSION < 1
# error "Please update your version of Symbiotic EDA flavored Verific."
#endif
#ifdef __clang__
#pragma clang diagnostic pop
@ -776,13 +784,14 @@ void VerificImporter::merge_past_ffs(pool<RTLIL::Cell*> &candidates)
void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*> &nl_todo)
{
std::string module_name = nl->IsOperator() ? std::string("$verific$") + nl->Owner()->Name() : RTLIL::escape_id(nl->Owner()->Name());
std::string netlist_name = nl->GetAtt(" \\top") ? nl->CellBaseName() : nl->Owner()->Name();
std::string module_name = nl->IsOperator() ? "$verific$" + netlist_name : RTLIL::escape_id(netlist_name);
netlist = nl;
if (design->has(module_name)) {
if (!nl->IsOperator() && !is_blackbox(nl))
log_cmd_error("Re-definition of module `%s'.\n", nl->Owner()->Name());
log_cmd_error("Re-definition of module `%s'.\n", netlist_name.c_str());
return;
}
@ -1752,32 +1761,64 @@ struct VerificExtNets
}
};
void verific_import(Design *design, std::string top)
void verific_import(Design *design, const std::map<std::string,std::string> &parameters, std::string top)
{
verific_sva_fsm_limit = 16;
std::set<Netlist*> nl_todo, nl_done;
{
VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary("work", 1);
VeriLibrary *veri_lib = veri_file::GetLibrary("work", 1);
VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary("work", 1);
VeriLibrary *veri_lib = veri_file::GetLibrary("work", 1);
Array *netlists = NULL;
Array veri_libs, vhdl_libs;
if (vhdl_lib) vhdl_libs.InsertLast(vhdl_lib);
if (veri_lib) veri_libs.InsertLast(veri_lib);
Array veri_libs, vhdl_libs;
if (vhdl_lib) vhdl_libs.InsertLast(vhdl_lib);
if (veri_lib) veri_libs.InsertLast(veri_lib);
Map verific_params(STRING_HASH);
for (const auto &i : parameters)
verific_params.Insert(i.first.c_str(), i.second.c_str());
Array *netlists = hier_tree::ElaborateAll(&veri_libs, &vhdl_libs);
Netlist *nl;
int i;
if (top.empty()) {
netlists = hier_tree::ElaborateAll(&veri_libs, &vhdl_libs, &verific_params);
}
else {
Array veri_modules, vhdl_units;
FOREACH_ARRAY_ITEM(netlists, i, nl) {
if (top.empty() || nl->Owner()->Name() == top)
nl_todo.insert(nl);
if (veri_lib) {
VeriModule *veri_module = veri_lib->GetModule(top.c_str(), 1);
if (veri_module) {
veri_modules.InsertLast(veri_module);
}
// Also elaborate all root modules since they may contain bind statements
MapIter mi;
FOREACH_VERILOG_MODULE_IN_LIBRARY(veri_lib, mi, veri_module) {
if (!veri_module->IsRootModule()) continue;
veri_modules.InsertLast(veri_module);
}
}
delete netlists;
if (vhdl_lib) {
VhdlDesignUnit *vhdl_unit = vhdl_lib->GetPrimUnit(top.c_str());
if (vhdl_unit)
vhdl_units.InsertLast(vhdl_unit);
}
netlists = hier_tree::Elaborate(&veri_modules, &vhdl_units, &verific_params);
}
Netlist *nl;
int i;
FOREACH_ARRAY_ITEM(netlists, i, nl) {
if (top.empty() && nl->CellBaseName() != top)
continue;
nl->AddAtt(new Att(" \\top", NULL));
nl_todo.insert(nl);
}
delete netlists;
if (!verific_error_msg.empty())
log_error("%s\n", verific_error_msg.c_str());
@ -1983,6 +2024,9 @@ struct VerificPass : public Pass {
// WARNING: instantiating unknown module 'XYZ' (VERI-1063)
Message::SetMessageType("VERI-1063", VERIFIC_ERROR);
// https://github.com/YosysHQ/yosys/issues/1055
RuntimeFlags::SetVar("veri_elaborate_top_level_modules_having_interface_ports", 1) ;
#ifndef DB_PRESERVE_INITIAL_VALUE
# warning Verific was built without DB_PRESERVE_INITIAL_VALUE.
#endif
@ -2212,8 +2256,8 @@ struct VerificPass : public Pass {
continue;
}
if (args[argidx] == "-chparam" && argidx+2 < GetSize(args)) {
const std::string &key = args[++argidx];
const std::string &value = args[++argidx];
const std::string &key = args[++argidx];
const std::string &value = args[++argidx];
unsigned new_insertion = parameters.Insert(key.c_str(), value.c_str(),
1 /* force_overwrite */);
if (!new_insertion)
@ -2270,12 +2314,22 @@ struct VerificPass : public Pass {
for (; argidx < GetSize(args); argidx++)
{
const char *name = args[argidx].c_str();
VeriLibrary* veri_lib = veri_file::GetLibrary(work.c_str(), 1);
VeriModule *veri_module = veri_file::GetModule(name);
if (veri_module) {
log("Adding Verilog module '%s' to elaboration queue.\n", name);
veri_modules.InsertLast(veri_module);
continue;
if (veri_lib) {
VeriModule *veri_module = veri_lib->GetModule(name, 1);
if (veri_module) {
log("Adding Verilog module '%s' to elaboration queue.\n", name);
veri_modules.InsertLast(veri_module);
continue;
}
// Also elaborate all root modules since they may contain bind statements
MapIter mi;
FOREACH_VERILOG_MODULE_IN_LIBRARY(veri_lib, mi, veri_module) {
if (!veri_module->IsRootModule()) continue;
veri_modules.InsertLast(veri_module);
}
}
VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary(work.c_str(), 1);
@ -2294,8 +2348,10 @@ struct VerificPass : public Pass {
Netlist *nl;
int i;
FOREACH_ARRAY_ITEM(netlists, i, nl)
FOREACH_ARRAY_ITEM(netlists, i, nl) {
nl->AddAtt(new Att(" \\top", NULL));
nl_todo.insert(nl);
}
delete netlists;
}

View file

@ -26,7 +26,7 @@ YOSYS_NAMESPACE_BEGIN
extern int verific_verbose;
extern bool verific_import_pending;
extern void verific_import(Design *design, std::string top = std::string());
extern void verific_import(Design *design, const std::map<std::string,std::string> &parameters, std::string top = std::string());
extern pool<int> verific_sva_prims;

View file

@ -14,7 +14,7 @@ frontends/verilog/verilog_lexer.cc: frontends/verilog/verilog_lexer.l
$(Q) mkdir -p $(dir $@)
$(P) flex -o frontends/verilog/verilog_lexer.cc $<
frontends/verilog/verilog_parser.tab.o: CXXFLAGS += -DYYMAXDEPTH=100000
frontends/verilog/verilog_parser.tab.o: CXXFLAGS += -DYYMAXDEPTH=10000000
OBJS += frontends/verilog/verilog_parser.tab.o
OBJS += frontends/verilog/verilog_lexer.o

View file

@ -71,7 +71,7 @@ static int my_ilog2(int x)
}
// parse a binary, decimal, hexadecimal or octal number with support for special bits ('x', 'z' and '?')
static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int len_in_bits, int base, char case_type)
static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int len_in_bits, int base, char case_type, bool is_unsized)
{
// all digits in string (MSB at index 0)
std::vector<uint8_t> digits;
@ -129,6 +129,9 @@ static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int le
return;
}
if (is_unsized && (len > len_in_bits))
log_file_error(current_filename, get_line_num(), "Unsized constant must have width of 1 bit, but have %d bits!\n", len);
for (len = len - 1; len >= 0; len--)
if (data[len] == RTLIL::S1)
break;
@ -186,7 +189,7 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn
// Simple base-10 integer
if (*endptr == 0) {
std::vector<RTLIL::State> data;
my_strtobin(data, str, -1, 10, case_type);
my_strtobin(data, str, -1, 10, case_type, false);
if (data.back() == RTLIL::S1)
data.push_back(RTLIL::S0);
return AstNode::mkconst_bits(data, true);
@ -201,6 +204,7 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn
{
std::vector<RTLIL::State> data;
bool is_signed = false;
bool is_unsized = false;
if (*(endptr+1) == 's') {
is_signed = true;
endptr++;
@ -209,28 +213,34 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn
{
case 'b':
case 'B':
my_strtobin(data, endptr+2, len_in_bits, 2, case_type);
my_strtobin(data, endptr+2, len_in_bits, 2, case_type, false);
break;
case 'o':
case 'O':
my_strtobin(data, endptr+2, len_in_bits, 8, case_type);
my_strtobin(data, endptr+2, len_in_bits, 8, case_type, false);
break;
case 'd':
case 'D':
my_strtobin(data, endptr+2, len_in_bits, 10, case_type);
my_strtobin(data, endptr+2, len_in_bits, 10, case_type, false);
break;
case 'h':
case 'H':
my_strtobin(data, endptr+2, len_in_bits, 16, case_type);
my_strtobin(data, endptr+2, len_in_bits, 16, case_type, false);
break;
default:
return NULL;
char next_char = char(tolower(*(endptr+1)));
if (next_char == '0' || next_char == '1' || next_char == 'x' || next_char == 'z') {
my_strtobin(data, endptr+1, 1, 2, case_type, true);
is_unsized = true;
} else {
return NULL;
}
}
if (len_in_bits < 0) {
if (is_signed && data.back() == RTLIL::S1)
data.push_back(RTLIL::S0);
}
return AstNode::mkconst_bits(data, is_signed);
return AstNode::mkconst_bits(data, is_signed, is_unsized);
}
return NULL;

View file

@ -158,6 +158,9 @@ struct VerilogFrontend : public Frontend {
log(" delete (* whitebox *) and (* lib_whitebox *) attributes from\n");
log(" all modules.\n");
log("\n");
log(" -specify\n");
log(" parse and import specify blocks\n");
log("\n");
log(" -noopt\n");
log(" don't perform basic optimizations (such as const folding) in the\n");
log(" high-level front-end.\n");
@ -228,6 +231,8 @@ struct VerilogFrontend : public Frontend {
bool flag_nooverwrite = false;
bool flag_overwrite = false;
bool flag_defer = false;
bool flag_noblackbox = false;
bool flag_nowb = false;
std::map<std::string, std::string> defines_map;
std::list<std::string> include_dirs;
std::list<std::string> attributes;
@ -237,13 +242,10 @@ struct VerilogFrontend : public Frontend {
formal_mode = false;
norestrict_mode = false;
assume_asserts_mode = false;
noblackbox_mode = false;
lib_mode = false;
nowb_mode = false;
specify_mode = false;
default_nettype_wire = true;
log_header(design, "Executing Verilog-2005 frontend.\n");
args.insert(args.begin()+1, verilog_defaults.begin(), verilog_defaults.end());
size_t argidx;
@ -342,7 +344,7 @@ struct VerilogFrontend : public Frontend {
continue;
}
if (arg == "-noblackbox") {
noblackbox_mode = true;
flag_noblackbox = true;
continue;
}
if (arg == "-lib") {
@ -351,7 +353,11 @@ struct VerilogFrontend : public Frontend {
continue;
}
if (arg == "-nowb") {
nowb_mode = true;
flag_nowb = true;
continue;
}
if (arg == "-specify") {
specify_mode = true;
continue;
}
if (arg == "-noopt") {
@ -415,6 +421,8 @@ struct VerilogFrontend : public Frontend {
}
extra_args(f, filename, args, argidx);
log_header(design, "Executing Verilog-2005 frontend: %s\n", filename.c_str());
log("Parsing %s%s input from `%s' to AST representation.\n",
formal_mode ? "formal " : "", sv_mode ? "SystemVerilog" : "Verilog", filename.c_str());
@ -450,7 +458,7 @@ struct VerilogFrontend : public Frontend {
error_on_dpi_function(current_ast);
AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches,
flag_nomeminit, flag_nomem2reg, flag_mem2reg, noblackbox_mode, lib_mode, nowb_mode, flag_noopt, flag_icells, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire);
flag_nomeminit, flag_nomem2reg, flag_mem2reg, flag_noblackbox, lib_mode, flag_nowb, flag_noopt, flag_icells, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire);
if (!flag_nopp)
delete lexin;

View file

@ -69,14 +69,11 @@ namespace VERILOG_FRONTEND
// running in -assert-assumes mode
extern bool assert_assumes_mode;
// running in -noblackbox mode
extern bool noblackbox_mode;
// running in -lib mode
extern bool lib_mode;
// running in -nowb mode
extern bool nowb_mode;
// running in -specify mode
extern bool specify_mode;
// lexer input stream
extern std::istream *lexin;

View file

@ -148,7 +148,7 @@ YOSYS_NAMESPACE_END
"endfunction" { return TOK_ENDFUNCTION; }
"task" { return TOK_TASK; }
"endtask" { return TOK_ENDTASK; }
"specify" { return TOK_SPECIFY; }
"specify" { return specify_mode ? TOK_SPECIFY : TOK_IGNORED_SPECIFY; }
"endspecify" { return TOK_ENDSPECIFY; }
"specparam" { return TOK_SPECPARAM; }
"package" { SV_KEYWORD(TOK_PACKAGE); }
@ -206,7 +206,9 @@ YOSYS_NAMESPACE_END
"const" { if (formal_mode) return TOK_CONST; SV_KEYWORD(TOK_CONST); }
"checker" { if (formal_mode) return TOK_CHECKER; SV_KEYWORD(TOK_CHECKER); }
"endchecker" { if (formal_mode) return TOK_ENDCHECKER; SV_KEYWORD(TOK_ENDCHECKER); }
"final" { SV_KEYWORD(TOK_FINAL); }
"logic" { SV_KEYWORD(TOK_LOGIC); }
"var" { SV_KEYWORD(TOK_VAR); }
"bit" { SV_KEYWORD(TOK_REG); }
"eventually" { if (formal_mode) return TOK_EVENTUALLY; SV_KEYWORD(TOK_EVENTUALLY); }
@ -216,6 +218,8 @@ YOSYS_NAMESPACE_END
"output" { return TOK_OUTPUT; }
"inout" { return TOK_INOUT; }
"wire" { return TOK_WIRE; }
"wor" { return TOK_WOR; }
"wand" { return TOK_WAND; }
"reg" { return TOK_REG; }
"integer" { return TOK_INTEGER; }
"signed" { return TOK_SIGNED; }
@ -230,7 +234,7 @@ YOSYS_NAMESPACE_END
return TOK_CONSTVAL;
}
[0-9]*[ \t]*\'s?[bodhBODH][ \t\r\n]*[0-9a-fA-FzxZX?_]+ {
[0-9]*[ \t]*\'s?[bodhBODH]*[ \t\r\n]*[0-9a-fA-FzxZX?_]+ {
frontend_verilog_yylval.string = new std::string(yytext);
return TOK_CONSTVAL;
}
@ -301,6 +305,17 @@ supply1 { return TOK_SUPPLY1; }
return TOK_ID;
}
"$"(setup|hold|setuphold|removal|recovery|recrem|skew|timeskew|fullskew|nochange) {
if (!specify_mode) REJECT;
frontend_verilog_yylval.string = new std::string(yytext);
return TOK_ID;
}
"$"(info|warning|error|fatal) {
frontend_verilog_yylval.string = new std::string(yytext);
return TOK_ELAB_TASK;
}
"$signed" { return TOK_TO_SIGNED; }
"$unsigned" { return TOK_TO_UNSIGNED; }
@ -411,6 +426,17 @@ import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ {
"+:" { return TOK_POS_INDEXED; }
"-:" { return TOK_NEG_INDEXED; }
[-+]?[=*]> {
if (!specify_mode) REJECT;
frontend_verilog_yylval.string = new std::string(yytext);
return TOK_SPECIFY_OPER;
}
"&&&" {
if (!specify_mode) REJECT;
return TOK_SPECIFY_AND;
}
"/*" { BEGIN(COMMENT); }
<COMMENT>. /* ignore comment body */
<COMMENT>\n /* ignore comment body */

View file

@ -59,7 +59,7 @@ namespace VERILOG_FRONTEND {
std::vector<char> case_type_stack;
bool do_not_require_port_stubs;
bool default_nettype_wire;
bool sv_mode, formal_mode, noblackbox_mode, lib_mode, nowb_mode;
bool sv_mode, formal_mode, lib_mode, specify_mode;
bool noassert_mode, noassume_mode, norestrict_mode;
bool assume_asserts_mode, assert_assumes_mode;
bool current_wire_rand, current_wire_const;
@ -94,29 +94,58 @@ static void free_attr(std::map<std::string, AstNode*> *al)
delete al;
}
struct specify_target {
char polarity_op;
AstNode *dst, *dat;
};
struct specify_triple {
AstNode *t_min, *t_avg, *t_max;
};
struct specify_rise_fall {
specify_triple rise;
specify_triple fall;
};
%}
%name-prefix "frontend_verilog_yy"
%define api.prefix {frontend_verilog_yy}
/* The union is defined in the header, so we need to provide all the
* includes it requires
*/
%code requires {
#include <map>
#include <string>
#include "frontends/verilog/verilog_frontend.h"
}
%union {
std::string *string;
struct YOSYS_NAMESPACE_PREFIX AST::AstNode *ast;
std::map<std::string, YOSYS_NAMESPACE_PREFIX AST::AstNode*> *al;
struct specify_target *specify_target_ptr;
struct specify_triple *specify_triple_ptr;
struct specify_rise_fall *specify_rise_fall_ptr;
bool boolean;
char ch;
}
%token <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE TOK_SVA_LABEL
%token TOK_ASSERT TOK_ASSUME TOK_RESTRICT TOK_COVER
%token <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE
%token <string> TOK_SVA_LABEL TOK_SPECIFY_OPER TOK_ELAB_TASK
%token TOK_ASSERT TOK_ASSUME TOK_RESTRICT TOK_COVER TOK_FINAL
%token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END
%token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM
%token TOK_PACKAGE TOK_ENDPACKAGE TOK_PACKAGESEP
%token TOK_INTERFACE TOK_ENDINTERFACE TOK_MODPORT
%token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_REG TOK_LOGIC
%token TOK_INTERFACE TOK_ENDINTERFACE TOK_MODPORT TOK_VAR
%token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_WAND TOK_WOR TOK_REG TOK_LOGIC
%token TOK_INTEGER TOK_SIGNED TOK_ASSIGN TOK_ALWAYS TOK_INITIAL
%token TOK_BEGIN TOK_END TOK_IF TOK_ELSE TOK_FOR TOK_WHILE TOK_REPEAT
%token TOK_DPI_FUNCTION TOK_POSEDGE TOK_NEGEDGE TOK_OR TOK_AUTOMATIC
%token TOK_CASE TOK_CASEX TOK_CASEZ TOK_ENDCASE TOK_DEFAULT
%token TOK_FUNCTION TOK_ENDFUNCTION TOK_TASK TOK_ENDTASK TOK_SPECIFY TOK_ENDSPECIFY TOK_SPECPARAM
%token TOK_FUNCTION TOK_ENDFUNCTION TOK_TASK TOK_ENDTASK TOK_SPECIFY
%token TOK_IGNORED_SPECIFY TOK_ENDSPECIFY TOK_SPECPARAM TOK_SPECIFY_AND
%token TOK_GENERATE TOK_ENDGENERATE TOK_GENVAR TOK_REAL
%token TOK_SYNOPSYS_FULL_CASE TOK_SYNOPSYS_PARALLEL_CASE
%token TOK_SUPPLY0 TOK_SUPPLY1 TOK_TO_SIGNED TOK_TO_UNSIGNED
@ -130,6 +159,12 @@ static void free_attr(std::map<std::string, AstNode*> *al)
%type <boolean> opt_signed opt_property unique_case_attr
%type <al> attr case_attr
%type <specify_target_ptr> specify_target
%type <specify_triple_ptr> specify_triple
%type <specify_rise_fall_ptr> specify_rise_fall
%type <ast> specify_if specify_condition specify_opt_arg
%type <ch> specify_edge
// operator precedence from low to high
%left OP_LOR
%left OP_LAND
@ -450,12 +485,21 @@ wire_type_token_io:
wire_type_token:
TOK_WIRE {
} |
TOK_WOR {
astbuf3->is_wor = true;
} |
TOK_WAND {
astbuf3->is_wand = true;
} |
TOK_REG {
astbuf3->is_reg = true;
} |
TOK_LOGIC {
astbuf3->is_logic = true;
} |
TOK_VAR {
astbuf3->is_logic = true;
} |
TOK_INTEGER {
astbuf3->is_reg = true;
astbuf3->range_left = 31;
@ -539,7 +583,7 @@ module_body:
module_body_stmt:
task_func_decl | specify_block |param_decl | localparam_decl | defparam_decl | specparam_declaration | wire_decl | assign_stmt | cell_stmt |
always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert_property | checker_decl;
always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert_property | checker_decl | ignored_specify_block;
checker_decl:
TOK_CHECKER TOK_ID ';' {
@ -697,15 +741,254 @@ task_func_body:
task_func_body behavioral_stmt |
/* empty */;
specify_block:
TOK_SPECIFY specify_item_opt TOK_ENDSPECIFY |
TOK_SPECIFY TOK_ENDSPECIFY ;
/*************************** specify parser ***************************/
specify_item_opt:
specify_item_opt specify_item |
specify_item ;
specify_block:
TOK_SPECIFY specify_item_list TOK_ENDSPECIFY;
specify_item_list:
specify_item specify_item_list |
/* empty */;
specify_item:
specify_if '(' specify_edge expr TOK_SPECIFY_OPER specify_target ')' '=' specify_rise_fall ';' {
AstNode *en_expr = $1;
char specify_edge = $3;
AstNode *src_expr = $4;
string *oper = $5;
specify_target *target = $6;
specify_rise_fall *timing = $9;
if (specify_edge != 0 && target->dat == nullptr)
frontend_verilog_yyerror("Found specify edge but no data spec.\n");
AstNode *cell = new AstNode(AST_CELL);
ast_stack.back()->children.push_back(cell);
cell->str = stringf("$specify$%d", autoidx++);
cell->children.push_back(new AstNode(AST_CELLTYPE));
cell->children.back()->str = target->dat ? "$specify3" : "$specify2";
char oper_polarity = 0;
char oper_type = oper->at(0);
if (oper->size() == 3) {
oper_polarity = oper->at(0);
oper_type = oper->at(1);
}
cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(oper_type == '*', false, 1)));
cell->children.back()->str = "\\FULL";
cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(oper_polarity != 0, false, 1)));
cell->children.back()->str = "\\SRC_DST_PEN";
cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(oper_polarity == '+', false, 1)));
cell->children.back()->str = "\\SRC_DST_POL";
cell->children.push_back(new AstNode(AST_PARASET, timing->rise.t_min));
cell->children.back()->str = "\\T_RISE_MIN";
cell->children.push_back(new AstNode(AST_PARASET, timing->rise.t_avg));
cell->children.back()->str = "\\T_RISE_TYP";
cell->children.push_back(new AstNode(AST_PARASET, timing->rise.t_max));
cell->children.back()->str = "\\T_RISE_MAX";
cell->children.push_back(new AstNode(AST_PARASET, timing->fall.t_min));
cell->children.back()->str = "\\T_FALL_MIN";
cell->children.push_back(new AstNode(AST_PARASET, timing->fall.t_avg));
cell->children.back()->str = "\\T_FALL_TYP";
cell->children.push_back(new AstNode(AST_PARASET, timing->fall.t_max));
cell->children.back()->str = "\\T_FALL_MAX";
cell->children.push_back(new AstNode(AST_ARGUMENT, en_expr ? en_expr : AstNode::mkconst_int(1, false, 1)));
cell->children.back()->str = "\\EN";
cell->children.push_back(new AstNode(AST_ARGUMENT, src_expr));
cell->children.back()->str = "\\SRC";
cell->children.push_back(new AstNode(AST_ARGUMENT, target->dst));
cell->children.back()->str = "\\DST";
if (target->dat)
{
cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(specify_edge != 0, false, 1)));
cell->children.back()->str = "\\EDGE_EN";
cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(specify_edge == 'p', false, 1)));
cell->children.back()->str = "\\EDGE_POL";
cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(target->polarity_op != 0, false, 1)));
cell->children.back()->str = "\\DAT_DST_PEN";
cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(target->polarity_op == '+', false, 1)));
cell->children.back()->str = "\\DAT_DST_POL";
cell->children.push_back(new AstNode(AST_ARGUMENT, target->dat));
cell->children.back()->str = "\\DAT";
}
delete oper;
delete target;
delete timing;
} |
TOK_ID '(' specify_edge expr specify_condition ',' specify_edge expr specify_condition ',' expr specify_opt_arg ')' ';' {
if (*$1 != "$setup" && *$1 != "$hold" && *$1 != "$setuphold" && *$1 != "$removal" && *$1 != "$recovery" &&
*$1 != "$recrem" && *$1 != "$skew" && *$1 != "$timeskew" && *$1 != "$fullskew" && *$1 != "$nochange")
frontend_verilog_yyerror("Unsupported specify rule type: %s\n", $1->c_str());
AstNode *src_pen = AstNode::mkconst_int($3 != 0, false, 1);
AstNode *src_pol = AstNode::mkconst_int($3 == 'p', false, 1);
AstNode *src_expr = $4, *src_en = $5 ? $5 : AstNode::mkconst_int(1, false, 1);
AstNode *dst_pen = AstNode::mkconst_int($7 != 0, false, 1);
AstNode *dst_pol = AstNode::mkconst_int($7 == 'p', false, 1);
AstNode *dst_expr = $8, *dst_en = $9 ? $9 : AstNode::mkconst_int(1, false, 1);
AstNode *limit = $11;
AstNode *limit2 = $12;
AstNode *cell = new AstNode(AST_CELL);
ast_stack.back()->children.push_back(cell);
cell->str = stringf("$specify$%d", autoidx++);
cell->children.push_back(new AstNode(AST_CELLTYPE));
cell->children.back()->str = "$specrule";
cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_str(*$1)));
cell->children.back()->str = "\\TYPE";
cell->children.push_back(new AstNode(AST_PARASET, limit));
cell->children.back()->str = "\\T_LIMIT";
cell->children.push_back(new AstNode(AST_PARASET, limit2 ? limit2 : AstNode::mkconst_int(0, true)));
cell->children.back()->str = "\\T_LIMIT2";
cell->children.push_back(new AstNode(AST_PARASET, src_pen));
cell->children.back()->str = "\\SRC_PEN";
cell->children.push_back(new AstNode(AST_PARASET, src_pol));
cell->children.back()->str = "\\SRC_POL";
cell->children.push_back(new AstNode(AST_PARASET, dst_pen));
cell->children.back()->str = "\\DST_PEN";
cell->children.push_back(new AstNode(AST_PARASET, dst_pol));
cell->children.back()->str = "\\DST_POL";
cell->children.push_back(new AstNode(AST_ARGUMENT, src_en));
cell->children.back()->str = "\\SRC_EN";
cell->children.push_back(new AstNode(AST_ARGUMENT, src_expr));
cell->children.back()->str = "\\SRC";
cell->children.push_back(new AstNode(AST_ARGUMENT, dst_en));
cell->children.back()->str = "\\DST_EN";
cell->children.push_back(new AstNode(AST_ARGUMENT, dst_expr));
cell->children.back()->str = "\\DST";
delete $1;
};
specify_opt_arg:
',' expr {
$$ = $2;
} |
/* empty */ {
$$ = nullptr;
};
specify_if:
TOK_IF '(' expr ')' {
$$ = $3;
} |
/* empty */ {
$$ = nullptr;
};
specify_condition:
TOK_SPECIFY_AND expr {
$$ = $2;
} |
/* empty */ {
$$ = nullptr;
};
specify_target:
expr {
$$ = new specify_target;
$$->polarity_op = 0;
$$->dst = $1;
$$->dat = nullptr;
} |
'(' expr ':' expr ')'{
$$ = new specify_target;
$$->polarity_op = 0;
$$->dst = $2;
$$->dat = $4;
} |
'(' expr TOK_NEG_INDEXED expr ')'{
$$ = new specify_target;
$$->polarity_op = '-';
$$->dst = $2;
$$->dat = $4;
} |
'(' expr TOK_POS_INDEXED expr ')'{
$$ = new specify_target;
$$->polarity_op = '+';
$$->dst = $2;
$$->dat = $4;
};
specify_edge:
TOK_POSEDGE { $$ = 'p'; } |
TOK_NEGEDGE { $$ = 'n'; } |
{ $$ = 0; };
specify_rise_fall:
specify_triple {
$$ = new specify_rise_fall;
$$->rise = *$1;
$$->fall.t_min = $1->t_min->clone();
$$->fall.t_avg = $1->t_avg->clone();
$$->fall.t_max = $1->t_max->clone();
delete $1;
} |
'(' specify_triple ',' specify_triple ')' {
$$ = new specify_rise_fall;
$$->rise = *$2;
$$->fall = *$4;
delete $2;
delete $4;
};
specify_triple:
expr {
$$ = new specify_triple;
$$->t_min = $1;
$$->t_avg = $1->clone();
$$->t_max = $1->clone();
} |
expr ':' expr ':' expr {
$$ = new specify_triple;
$$->t_min = $1;
$$->t_avg = $3;
$$->t_max = $5;
};
/******************** ignored specify parser **************************/
ignored_specify_block:
TOK_IGNORED_SPECIFY ignored_specify_item_opt TOK_ENDSPECIFY |
TOK_IGNORED_SPECIFY TOK_ENDSPECIFY ;
ignored_specify_item_opt:
ignored_specify_item_opt ignored_specify_item |
ignored_specify_item ;
ignored_specify_item:
specparam_declaration
// | pulsestyle_declaration
// | showcancelled_declaration
@ -721,13 +1004,13 @@ specparam_declaration:
// and the 'non_opt_range' rule allows index ranges not allowed by 1364-2005
// exxxxtending this for SV specparam would change this anyhow
specparam_range:
'[' constant_expression ':' constant_expression ']' ;
'[' ignspec_constant_expression ':' ignspec_constant_expression ']' ;
list_of_specparam_assignments:
specparam_assignment | list_of_specparam_assignments ',' specparam_assignment;
specparam_assignment:
TOK_ID '=' constant_mintypmax_expression ;
ignspec_id '=' constant_mintypmax_expression ;
/*
pulsestyle_declaration :
@ -802,19 +1085,19 @@ opt_polarity_operator :
// Good enough for the time being
specify_input_terminal_descriptor :
TOK_ID ;
ignspec_id ;
// Good enough for the time being
specify_output_terminal_descriptor :
TOK_ID ;
ignspec_id ;
system_timing_declaration :
TOK_ID '(' system_timing_args ')' ';' ;
ignspec_id '(' system_timing_args ')' ';' ;
system_timing_arg :
TOK_POSEDGE TOK_ID |
TOK_NEGEDGE TOK_ID |
expr ;
TOK_POSEDGE ignspec_id |
TOK_NEGEDGE ignspec_id |
ignspec_expr ;
system_timing_args :
system_timing_arg |
@ -871,19 +1154,27 @@ tzx_path_delay_expression :
*/
path_delay_expression :
constant_expression;
ignspec_constant_expression;
constant_mintypmax_expression :
constant_expression
| constant_expression ':' constant_expression ':' constant_expression
ignspec_constant_expression
| ignspec_constant_expression ':' ignspec_constant_expression ':' ignspec_constant_expression
;
// for the time being this is OK, but we may write our own expr here.
// as I'm not sure it is legal to use a full expr here (probably not)
// On the other hand, other rules requiring constant expressions also use 'expr'
// (such as param assignment), so we may leave this as-is, perhaps adding runtime checks for constant-ness
constant_expression:
expr ;
ignspec_constant_expression:
expr { delete $1; };
ignspec_expr:
expr { delete $1; };
ignspec_id:
TOK_ID { delete $1; };
/**********************************************************************/
param_signed:
TOK_SIGNED {
@ -917,7 +1208,7 @@ param_range:
};
param_decl:
TOK_PARAMETER {
attr TOK_PARAMETER {
astbuf1 = new AstNode(AST_PARAMETER);
astbuf1->children.push_back(AstNode::mkconst_int(0, true));
} param_signed param_integer param_real param_range param_decl_list ';' {
@ -925,7 +1216,7 @@ param_decl:
};
localparam_decl:
TOK_LOCALPARAM {
attr TOK_LOCALPARAM {
astbuf1 = new AstNode(AST_LOCALPARAM);
astbuf1->children.push_back(AstNode::mkconst_int(0, true));
} param_signed param_integer param_real param_range param_decl_list ';' {
@ -1241,27 +1532,40 @@ cell_port_list_rules:
cell_port | cell_port_list_rules ',' cell_port;
cell_port:
/* empty */ {
attr {
AstNode *node = new AstNode(AST_ARGUMENT);
astbuf2->children.push_back(node);
free_attr($1);
} |
expr {
attr expr {
AstNode *node = new AstNode(AST_ARGUMENT);
astbuf2->children.push_back(node);
node->children.push_back($1);
node->children.push_back($2);
free_attr($1);
} |
'.' TOK_ID '(' expr ')' {
attr '.' TOK_ID '(' expr ')' {
AstNode *node = new AstNode(AST_ARGUMENT);
node->str = *$2;
node->str = *$3;
astbuf2->children.push_back(node);
node->children.push_back($4);
delete $2;
node->children.push_back($5);
delete $3;
free_attr($1);
} |
'.' TOK_ID '(' ')' {
attr '.' TOK_ID '(' ')' {
AstNode *node = new AstNode(AST_ARGUMENT);
node->str = *$2;
node->str = *$3;
astbuf2->children.push_back(node);
delete $2;
delete $3;
free_attr($1);
} |
attr '.' TOK_ID {
AstNode *node = new AstNode(AST_ARGUMENT);
node->str = *$3;
astbuf2->children.push_back(node);
node->children.push_back(new AstNode(AST_IDENTIFIER));
node->children.back()->str = *$3;
delete $3;
free_attr($1);
};
always_stmt:
@ -1341,6 +1645,9 @@ opt_property:
TOK_PROPERTY {
$$ = true;
} |
TOK_FINAL {
$$ = false;
} |
/* empty */ {
$$ = false;
};
@ -1869,6 +2176,15 @@ gen_stmt:
if ($6 != NULL)
delete $6;
ast_stack.pop_back();
} |
TOK_ELAB_TASK {
AstNode *node = new AstNode(AST_TECALL);
node->str = *$1;
delete $1;
ast_stack.back()->children.push_back(node);
ast_stack.push_back(node);
} opt_arg_list ';'{
ast_stack.pop_back();
};
gen_stmt_block:
@ -2139,4 +2455,3 @@ concat_list:
$$ = $3;
$$->children.push_back($1);
};