1998-11-04 00:28:49 +01:00
|
|
|
/*
|
2021-01-02 23:04:06 +01:00
|
|
|
* Copyright (c) 1998-2021 Stephen Williams (steve@icarus.com)
|
2013-04-09 03:35:37 +02:00
|
|
|
* Copyright CERN 2013 / Stephen Williams (steve@icarus.com)
|
1998-11-04 00:28:49 +01:00
|
|
|
*
|
|
|
|
|
* This source code is free software; you can redistribute it
|
|
|
|
|
* and/or modify it in source code form under the terms of the GNU
|
|
|
|
|
* General Public License as published by the Free Software
|
|
|
|
|
* Foundation; either version 2 of the License, or (at your option)
|
|
|
|
|
* any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program; if not, write to the Free Software
|
2012-08-29 03:41:23 +02:00
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
1998-11-04 00:28:49 +01:00
|
|
|
*/
|
|
|
|
|
|
2001-07-25 05:10:48 +02:00
|
|
|
# include "config.h"
|
|
|
|
|
|
2022-10-12 04:31:35 +02:00
|
|
|
# include <cstdarg>
|
1999-06-06 22:45:38 +02:00
|
|
|
# include "compiler.h"
|
1998-11-04 00:28:49 +01:00
|
|
|
# include "pform.h"
|
|
|
|
|
# include "parse_misc.h"
|
2001-10-21 01:02:39 +02:00
|
|
|
# include "parse_api.h"
|
2012-03-11 21:18:24 +01:00
|
|
|
# include "PClass.h"
|
2000-04-01 21:31:57 +02:00
|
|
|
# include "PEvent.h"
|
2012-10-21 20:42:19 +02:00
|
|
|
# include "PPackage.h"
|
1998-11-25 03:35:53 +01:00
|
|
|
# include "PUdp.h"
|
2006-04-10 02:37:42 +02:00
|
|
|
# include "PGenerate.h"
|
2015-01-10 12:09:42 +01:00
|
|
|
# include "PModport.h"
|
2006-09-23 06:57:19 +02:00
|
|
|
# include "PSpec.h"
|
2008-05-11 21:00:11 +02:00
|
|
|
# include "discipline.h"
|
1998-11-04 00:28:49 +01:00
|
|
|
# include <list>
|
1998-11-25 03:35:53 +01:00
|
|
|
# include <map>
|
2010-05-31 22:12:06 +02:00
|
|
|
# include <cassert>
|
2007-05-24 06:07:11 +02:00
|
|
|
# include <stack>
|
1998-11-04 00:28:49 +01:00
|
|
|
# include <typeinfo>
|
2003-01-14 22:16:18 +01:00
|
|
|
# include <sstream>
|
2008-01-05 00:23:47 +01:00
|
|
|
# include <cstring>
|
|
|
|
|
# include <cstdlib>
|
2017-01-29 21:13:01 +01:00
|
|
|
# include <cctype>
|
1998-11-04 00:28:49 +01:00
|
|
|
|
2008-01-04 05:13:56 +01:00
|
|
|
# include "ivl_assert.h"
|
2010-10-24 00:52:56 +02:00
|
|
|
# include "ivl_alloc.h"
|
2008-01-04 05:13:56 +01:00
|
|
|
|
2021-11-04 17:12:04 +01:00
|
|
|
using namespace std;
|
|
|
|
|
|
2014-07-16 03:03:40 +02:00
|
|
|
/*
|
|
|
|
|
* The "// synthesis translate_on/off" meta-comments cause this flag
|
|
|
|
|
* to be turned off or on. The pform_make_behavior and similar
|
|
|
|
|
* functions look at this flag and may choose to add implicit ivl
|
|
|
|
|
* synthesis flags.
|
|
|
|
|
*/
|
|
|
|
|
static bool pform_mc_translate_flag = true;
|
|
|
|
|
void pform_mc_translate_on(bool flag) { pform_mc_translate_flag = flag; }
|
|
|
|
|
|
2012-05-10 04:35:11 +02:00
|
|
|
/*
|
|
|
|
|
* The pform_modules is a map of the modules that have been defined in
|
|
|
|
|
* the top level. This should not contain nested modules/programs.
|
2013-12-15 05:07:31 +01:00
|
|
|
* pform_primitives is similar, but for UDP primitives.
|
2012-05-10 04:35:11 +02:00
|
|
|
*/
|
2004-02-18 18:11:54 +01:00
|
|
|
map<perm_string,Module*> pform_modules;
|
|
|
|
|
map<perm_string,PUdp*> pform_primitives;
|
2001-10-21 01:02:39 +02:00
|
|
|
|
2013-12-15 05:07:31 +01:00
|
|
|
/*
|
2017-10-21 16:04:25 +02:00
|
|
|
* The pform_units is a list of the SystemVerilog compilation unit scopes.
|
|
|
|
|
* The current compilation unit is the last element in the list. All items
|
|
|
|
|
* declared or defined at the top level (outside any design element) are
|
|
|
|
|
* added to the current compilation unit scope.
|
2013-12-15 05:07:31 +01:00
|
|
|
*/
|
2017-10-21 16:04:25 +02:00
|
|
|
vector<PPackage*> pform_units;
|
2009-08-06 23:42:13 +02:00
|
|
|
|
2017-10-21 16:04:25 +02:00
|
|
|
static bool is_compilation_unit(LexicalScope*scope)
|
|
|
|
|
{
|
|
|
|
|
// A compilation unit is the only scope that doesn't have a parent.
|
2017-11-05 18:50:05 +01:00
|
|
|
assert(scope);
|
2017-10-21 16:04:25 +02:00
|
|
|
return scope->parent_scope() == 0;
|
|
|
|
|
}
|
2014-10-01 01:06:32 +02:00
|
|
|
|
2012-04-13 05:20:37 +02:00
|
|
|
std::string vlltype::get_fileline() const
|
|
|
|
|
{
|
|
|
|
|
ostringstream buf;
|
|
|
|
|
buf << (text? text : "") << ":" << first_line;
|
|
|
|
|
string res = buf.str();
|
|
|
|
|
return res;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-29 21:13:01 +01:00
|
|
|
static bool is_hex_digit_str(const char *str)
|
|
|
|
|
{
|
|
|
|
|
while (*str) {
|
|
|
|
|
if (!isxdigit(*str)) return false;
|
|
|
|
|
str++;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool is_dec_digit_str(const char *str)
|
|
|
|
|
{
|
|
|
|
|
while (*str) {
|
|
|
|
|
if (!isdigit(*str)) return false;
|
|
|
|
|
str++;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool is_oct_digit_str(const char *str)
|
|
|
|
|
{
|
|
|
|
|
while (*str) {
|
|
|
|
|
if (*str < '0' || *str > '7') return false;
|
|
|
|
|
str++;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool is_bin_digit_str(const char *str)
|
|
|
|
|
{
|
|
|
|
|
while (*str) {
|
|
|
|
|
if (*str != '0' && *str != '1') return false;
|
|
|
|
|
str++;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2009-08-06 23:42:13 +02:00
|
|
|
/*
|
|
|
|
|
* Parse configuration file with format <key>=<value>, where key
|
|
|
|
|
* is the hierarchical name of a valid parameter name, and value
|
|
|
|
|
* is the value user wants to assign to. The value should be constant.
|
|
|
|
|
*/
|
|
|
|
|
void parm_to_defparam_list(const string¶m)
|
|
|
|
|
{
|
2009-08-22 04:28:19 +02:00
|
|
|
char* key;
|
|
|
|
|
char* value;
|
2009-08-06 23:42:13 +02:00
|
|
|
unsigned off = param.find('=');
|
|
|
|
|
if (off > param.size()) {
|
|
|
|
|
key = strdup(param.c_str());
|
2009-08-22 04:28:19 +02:00
|
|
|
value = (char*)malloc(1);
|
|
|
|
|
*value = '\0';
|
2009-08-06 23:42:13 +02:00
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
key = strdup(param.substr(0, off).c_str());
|
2009-08-22 04:28:19 +02:00
|
|
|
value = strdup(param.substr(off+1).c_str());
|
2009-08-06 23:42:13 +02:00
|
|
|
}
|
2010-10-02 20:02:27 +02:00
|
|
|
|
2009-08-06 23:42:13 +02:00
|
|
|
// Resolve hierarchical name for defparam. Remember
|
|
|
|
|
// to deal with bit select for generate scopes. Bit
|
2010-10-02 20:02:27 +02:00
|
|
|
// select expression should be constant integer.
|
2009-08-06 23:42:13 +02:00
|
|
|
pform_name_t name;
|
2009-08-22 04:28:19 +02:00
|
|
|
char *nkey = key;
|
2009-08-06 23:42:13 +02:00
|
|
|
char *ptr = strchr(key, '.');
|
|
|
|
|
while (ptr != 0) {
|
|
|
|
|
*ptr++ = '\0';
|
|
|
|
|
// Find if bit select is applied, this would be something
|
|
|
|
|
// like - scope[2].param = 10
|
|
|
|
|
char *bit_l = strchr(nkey, '[');
|
|
|
|
|
if (bit_l !=0) {
|
|
|
|
|
*bit_l++ = '\0';
|
|
|
|
|
char *bit_r = strchr(bit_l, ']');
|
|
|
|
|
if (bit_r == 0) {
|
|
|
|
|
cerr << "<command line>: error: missing ']' for defparam: " << nkey << endl;
|
2009-08-22 04:28:19 +02:00
|
|
|
free(key);
|
|
|
|
|
free(value);
|
2009-08-06 23:42:13 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
*bit_r = '\0';
|
|
|
|
|
int i = 0;
|
|
|
|
|
while (*(bit_l+i) != '\0')
|
|
|
|
|
if (!isdigit(*(bit_l+i++))) {
|
|
|
|
|
cerr << "<command line>: error: scope index expression is not constant: " << nkey << endl;
|
2009-08-22 04:28:19 +02:00
|
|
|
free(key);
|
|
|
|
|
free(value);
|
2009-08-06 23:42:13 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
name_component_t tmp(lex_strings.make(nkey));
|
|
|
|
|
index_component_t index;
|
|
|
|
|
index.sel = index_component_t::SEL_BIT;
|
|
|
|
|
verinum *seln = new verinum(atoi(bit_l));
|
|
|
|
|
PENumber *sel = new PENumber(seln);
|
|
|
|
|
index.msb = sel;
|
|
|
|
|
index.lsb = sel;
|
|
|
|
|
tmp.index.push_back(index);
|
|
|
|
|
name.push_back(tmp);
|
|
|
|
|
}
|
|
|
|
|
else // no bit select
|
|
|
|
|
name.push_back(name_component_t(lex_strings.make(nkey)));
|
|
|
|
|
|
|
|
|
|
nkey = ptr;
|
|
|
|
|
ptr = strchr(nkey, '.');
|
|
|
|
|
}
|
|
|
|
|
name.push_back(name_component_t(lex_strings.make(nkey)));
|
2017-01-29 21:13:01 +01:00
|
|
|
free(key);
|
2010-10-02 20:02:27 +02:00
|
|
|
|
2009-08-06 23:42:13 +02:00
|
|
|
// Resolve value to PExpr class. Should support all kind of constant
|
|
|
|
|
// format including based number, dec number, real number and string.
|
2010-10-02 20:02:27 +02:00
|
|
|
|
2017-01-29 21:13:01 +01:00
|
|
|
// Is it a string?
|
|
|
|
|
if (*value == '"') {
|
|
|
|
|
char *buf = strdup (value);
|
|
|
|
|
char *buf_ptr = buf+1;
|
|
|
|
|
// Parse until another '"' or '\0'
|
|
|
|
|
while (*buf_ptr != '"' && *buf_ptr != '\0') {
|
|
|
|
|
buf_ptr++;
|
|
|
|
|
// Check for escape, especially '\"', which does not mean the
|
|
|
|
|
// end of string.
|
|
|
|
|
if (*buf_ptr == '\\' && *(buf_ptr+1) != '\0')
|
|
|
|
|
buf_ptr += 2;
|
|
|
|
|
}
|
|
|
|
|
if (*buf_ptr == '\0') // String end without '"'
|
|
|
|
|
cerr << "<command line>: error: missing close quote of string for defparam: " << name << endl;
|
|
|
|
|
else if (*(buf_ptr+1) != 0) { // '"' appears within string with no escape
|
|
|
|
|
cerr << buf_ptr << endl;
|
|
|
|
|
cerr << "<command line>: error: \'\"\' appears within string value for defparam: " << name
|
|
|
|
|
<< ". Ignore characters after \'\"\'" << endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*buf_ptr = '\0';
|
|
|
|
|
buf_ptr = buf+1;
|
|
|
|
|
// Remember to use 'new' to allocate string for PEString
|
|
|
|
|
// because 'delete' is used by its destructor.
|
|
|
|
|
char *nchar = strcpy(new char [strlen(buf_ptr)+1], buf_ptr);
|
|
|
|
|
PExpr* ndec = new PEString(nchar);
|
2009-08-06 23:42:13 +02:00
|
|
|
Module::user_defparms.push_back( make_pair(name, ndec) );
|
2017-01-29 21:13:01 +01:00
|
|
|
free(buf);
|
|
|
|
|
free(value);
|
|
|
|
|
return;
|
2009-08-06 23:42:13 +02:00
|
|
|
}
|
2010-10-02 20:02:27 +02:00
|
|
|
|
2017-01-29 21:13:01 +01:00
|
|
|
// Is it a based number?
|
|
|
|
|
char *num = strchr(value, '\'');
|
|
|
|
|
if (num != 0) {
|
|
|
|
|
verinum *val;
|
|
|
|
|
const char *base = num + 1;
|
|
|
|
|
if (*base == 's' || *base == 'S')
|
|
|
|
|
base++;
|
|
|
|
|
switch (*base) {
|
|
|
|
|
case 'h':
|
|
|
|
|
case 'H':
|
|
|
|
|
if (is_hex_digit_str(base+1)) {
|
|
|
|
|
val = make_unsized_hex(num);
|
|
|
|
|
} else {
|
|
|
|
|
cerr << "<command line>: error: invalid digit in hex value specified for defparam: " << name << endl;
|
|
|
|
|
free(value);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 'd':
|
|
|
|
|
case 'D':
|
|
|
|
|
if (is_dec_digit_str(base+1)) {
|
|
|
|
|
val = make_unsized_dec(num);
|
|
|
|
|
} else {
|
|
|
|
|
cerr << "<command line>: error: invalid digit in decimal value specified for defparam: " << name << endl;
|
|
|
|
|
free(value);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 'o':
|
|
|
|
|
case 'O':
|
|
|
|
|
if (is_oct_digit_str(base+1)) {
|
|
|
|
|
val = make_unsized_octal(num);
|
|
|
|
|
} else {
|
|
|
|
|
cerr << "<command line>: error: invalid digit in octal value specified for defparam: " << name << endl;
|
|
|
|
|
free(value);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 'b':
|
|
|
|
|
case 'B':
|
|
|
|
|
if (is_bin_digit_str(base+1)) {
|
|
|
|
|
val = make_unsized_binary(num);
|
|
|
|
|
} else {
|
|
|
|
|
cerr << "<command line>: error: invalid digit in binary value specified for defparam: " << name << endl;
|
|
|
|
|
free(value);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
cerr << "<command line>: error: invalid numeric base specified for defparam: " << name << endl;
|
|
|
|
|
free(value);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (num != value) { // based number with size
|
|
|
|
|
*num = 0;
|
|
|
|
|
if (is_dec_digit_str(value)) {
|
|
|
|
|
verinum *siz = make_unsized_dec(value);
|
|
|
|
|
val = pform_verinum_with_size(siz, val, "<command line>", 0);
|
|
|
|
|
} else {
|
|
|
|
|
cerr << "<command line>: error: invalid size for value specified for defparam: " << name << endl;
|
|
|
|
|
free(value);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
PExpr* ndec = new PENumber(val);
|
|
|
|
|
Module::user_defparms.push_back( make_pair(name, ndec) );
|
|
|
|
|
free(value);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2010-10-02 20:02:27 +02:00
|
|
|
|
2017-01-29 21:13:01 +01:00
|
|
|
// Is it a decimal number?
|
|
|
|
|
num = (value[0] == '-') ? value + 1 : value;
|
2020-10-24 23:48:00 +02:00
|
|
|
if (num[0] != '\0' && is_dec_digit_str(num)) {
|
2017-01-29 21:13:01 +01:00
|
|
|
verinum *val = make_unsized_dec(num);
|
|
|
|
|
if (value[0] == '-') *val = -(*val);
|
|
|
|
|
PExpr* ndec = new PENumber(val);
|
|
|
|
|
Module::user_defparms.push_back( make_pair(name, ndec) );
|
|
|
|
|
free(value);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2010-10-02 20:02:27 +02:00
|
|
|
|
2017-01-29 21:13:01 +01:00
|
|
|
// Is it a real number?
|
|
|
|
|
char *end = 0;
|
|
|
|
|
double rval = strtod(value, &end);
|
|
|
|
|
if (end != value && *end == 0) {
|
|
|
|
|
verireal *val = new verireal(rval);
|
|
|
|
|
PExpr* nreal = new PEFNumber(val);
|
|
|
|
|
Module::user_defparms.push_back( make_pair(name, nreal) );
|
|
|
|
|
free(value);
|
|
|
|
|
return;
|
2009-08-06 23:42:13 +02:00
|
|
|
}
|
2017-01-29 21:13:01 +01:00
|
|
|
|
|
|
|
|
// None of the above.
|
|
|
|
|
cerr << "<command line>: error: invalid value specified for defparam: " << name << endl;
|
2009-08-22 04:28:19 +02:00
|
|
|
free(value);
|
2009-08-06 23:42:13 +02:00
|
|
|
}
|
|
|
|
|
|
1998-12-09 05:02:47 +01:00
|
|
|
/*
|
|
|
|
|
* The lexor accesses the vl_* variables.
|
|
|
|
|
*/
|
|
|
|
|
string vl_file = "";
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
extern int VLparse();
|
|
|
|
|
|
2006-04-10 02:37:42 +02:00
|
|
|
/* This tracks the current module being processed. There can only be
|
2008-01-29 21:19:59 +01:00
|
|
|
exactly one module currently being parsed, since Verilog does not
|
2006-04-10 02:37:42 +02:00
|
|
|
allow nested module definitions. */
|
2012-05-10 04:35:11 +02:00
|
|
|
static list<Module*>pform_cur_module;
|
2007-04-19 04:52:53 +02:00
|
|
|
|
|
|
|
|
bool pform_library_flag = false;
|
|
|
|
|
|
2014-07-23 03:55:24 +02:00
|
|
|
/*
|
|
|
|
|
* Give each unnamed block that has a variable declaration a unique name.
|
|
|
|
|
*/
|
|
|
|
|
static unsigned scope_unnamed_block_with_decl = 1;
|
|
|
|
|
|
2006-04-10 02:37:42 +02:00
|
|
|
/* This tracks the current generate scheme being processed. This is
|
|
|
|
|
always within a module. */
|
|
|
|
|
static PGenerate*pform_cur_generate = 0;
|
2002-04-15 02:04:22 +02:00
|
|
|
|
2021-08-03 22:29:46 +02:00
|
|
|
/* This indicates whether a new generate construct can be directly
|
|
|
|
|
nested in the current generate construct. */
|
|
|
|
|
bool pform_generate_single_item = false;
|
|
|
|
|
|
2019-09-27 00:35:57 +02:00
|
|
|
/* Blocks within the same conditional generate construct may have
|
|
|
|
|
the same name. Here we collect the set of names used in each
|
|
|
|
|
construct, so they can be added to the local scope without
|
|
|
|
|
conflicting with each other. Generate constructs may nest, so
|
|
|
|
|
we need a stack. */
|
2019-10-02 03:56:50 +02:00
|
|
|
static list<set<perm_string> > conditional_block_names;
|
2019-09-27 00:35:57 +02:00
|
|
|
|
2015-01-10 12:09:42 +01:00
|
|
|
/* This tracks the current modport list being processed. This is
|
|
|
|
|
always within an interface. */
|
|
|
|
|
static PModport*pform_cur_modport = 0;
|
|
|
|
|
|
2004-06-13 06:56:53 +02:00
|
|
|
static NetNet::Type pform_default_nettype = NetNet::WIRE;
|
|
|
|
|
|
2002-04-15 02:04:22 +02:00
|
|
|
/*
|
2017-11-05 18:50:05 +01:00
|
|
|
* These variables track the time scale set by the most recent `timescale
|
|
|
|
|
* directive. Time scales set by SystemVerilog timeunit and timeprecision
|
|
|
|
|
* declarations are stored directly in the current lexical scope.
|
2002-04-15 02:04:22 +02:00
|
|
|
*/
|
2009-05-22 20:03:36 +02:00
|
|
|
static int pform_time_unit;
|
|
|
|
|
static int pform_time_prec;
|
1998-11-04 00:28:49 +01:00
|
|
|
|
2009-06-20 05:58:46 +02:00
|
|
|
/*
|
2017-11-05 18:50:05 +01:00
|
|
|
* These variables track where the most recent `timescale directive
|
|
|
|
|
* occurred. This allows us to warn about time scales that are inherited
|
|
|
|
|
* from another file.
|
2009-06-20 05:58:46 +02:00
|
|
|
*/
|
2002-04-15 02:04:22 +02:00
|
|
|
static char*pform_timescale_file = 0;
|
2009-05-22 20:03:36 +02:00
|
|
|
static unsigned pform_timescale_line;
|
2002-04-15 02:04:22 +02:00
|
|
|
|
2017-11-05 18:50:05 +01:00
|
|
|
/*
|
|
|
|
|
* These variables track whether we can accept new timeunits declarations.
|
|
|
|
|
*/
|
|
|
|
|
bool allow_timeunit_decl = true;
|
|
|
|
|
bool allow_timeprec_decl = true;
|
|
|
|
|
|
2022-02-10 14:03:46 +01:00
|
|
|
// Track whether the current parameter declaration is in a parameter port list
|
|
|
|
|
static bool pform_in_parameter_port_list = false;
|
|
|
|
|
|
1999-06-24 06:24:18 +02:00
|
|
|
/*
|
2008-02-25 04:40:54 +01:00
|
|
|
* The lexical_scope keeps track of the current lexical scope that is
|
|
|
|
|
* being parsed. The lexical scope may stack, so the current scope may
|
|
|
|
|
* have a parent, that is restored when the current scope ends.
|
2006-04-10 02:37:42 +02:00
|
|
|
*
|
2008-02-25 04:40:54 +01:00
|
|
|
* Items that have scoped names are put in the lexical_scope object.
|
1999-06-24 06:24:18 +02:00
|
|
|
*/
|
2010-01-08 23:49:48 +01:00
|
|
|
static LexicalScope* lexical_scope = 0;
|
2000-07-23 00:09:03 +02:00
|
|
|
|
2016-03-19 18:27:27 +01:00
|
|
|
LexicalScope* pform_peek_scope(void)
|
|
|
|
|
{
|
|
|
|
|
assert(lexical_scope);
|
|
|
|
|
return lexical_scope;
|
|
|
|
|
}
|
|
|
|
|
|
1999-06-24 06:24:18 +02:00
|
|
|
void pform_pop_scope()
|
|
|
|
|
{
|
2019-09-30 22:01:30 +02:00
|
|
|
LexicalScope*scope = lexical_scope;
|
|
|
|
|
assert(scope);
|
|
|
|
|
|
|
|
|
|
map<perm_string,PPackage*>::const_iterator cur;
|
|
|
|
|
for (cur = scope->possible_imports.begin(); cur != scope->possible_imports.end(); ++cur) {
|
|
|
|
|
if (scope->local_symbols.find(cur->first) == scope->local_symbols.end())
|
|
|
|
|
scope->explicit_imports[cur->first] = cur->second;
|
|
|
|
|
}
|
|
|
|
|
scope->possible_imports.clear();
|
|
|
|
|
|
|
|
|
|
lexical_scope = scope->parent_scope();
|
2017-10-21 16:04:25 +02:00
|
|
|
assert(lexical_scope);
|
1999-06-24 06:24:18 +02:00
|
|
|
}
|
|
|
|
|
|
2016-03-19 18:27:27 +01:00
|
|
|
static LexicalScope::lifetime_t find_lifetime(LexicalScope::lifetime_t lifetime)
|
|
|
|
|
{
|
|
|
|
|
if (lifetime != LexicalScope::INHERITED)
|
|
|
|
|
return lifetime;
|
|
|
|
|
|
2017-10-21 16:04:25 +02:00
|
|
|
return lexical_scope->default_lifetime;
|
2016-03-19 18:27:27 +01:00
|
|
|
}
|
|
|
|
|
|
2012-11-12 02:42:31 +01:00
|
|
|
static PScopeExtra* find_nearest_scopex(LexicalScope*scope)
|
|
|
|
|
{
|
|
|
|
|
PScopeExtra*scopex = dynamic_cast<PScopeExtra*> (scope);
|
|
|
|
|
while (scope && !scopex) {
|
|
|
|
|
scope = scope->parent_scope();
|
|
|
|
|
scopex = dynamic_cast<PScopeExtra*> (scope);
|
|
|
|
|
}
|
|
|
|
|
return scopex;
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-27 00:35:57 +02:00
|
|
|
static void add_local_symbol(LexicalScope*scope, perm_string name, PNamedItem*item)
|
|
|
|
|
{
|
|
|
|
|
assert(scope);
|
|
|
|
|
|
|
|
|
|
// Check for conflict with another local symbol.
|
|
|
|
|
map<perm_string,PNamedItem*>::const_iterator cur_sym
|
|
|
|
|
= scope->local_symbols.find(name);
|
|
|
|
|
if (cur_sym != scope->local_symbols.end()) {
|
|
|
|
|
cerr << item->get_fileline() << ": error: "
|
|
|
|
|
"'" << name << "' has already been declared "
|
|
|
|
|
"in this scope." << endl;
|
|
|
|
|
cerr << cur_sym->second->get_fileline() << ": : "
|
|
|
|
|
"It was declared here as "
|
|
|
|
|
<< cur_sym->second->symbol_type() << "." << endl;
|
|
|
|
|
error_count += 1;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check for conflict with an explicit import.
|
|
|
|
|
map<perm_string,PPackage*>::const_iterator cur_pkg
|
|
|
|
|
= scope->explicit_imports.find(name);
|
|
|
|
|
if (cur_pkg != scope->explicit_imports.end()) {
|
|
|
|
|
cerr << item->get_fileline() << ": error: "
|
|
|
|
|
"'" << name << "' has already been "
|
|
|
|
|
"imported into this scope from package '"
|
|
|
|
|
<< cur_pkg->second->pscope_name() << "'." << endl;
|
|
|
|
|
error_count += 1;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
scope->local_symbols[name] = item;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static PPackage*find_potential_import(const struct vlltype&loc, LexicalScope*scope,
|
2019-09-30 22:01:30 +02:00
|
|
|
perm_string name, bool tf_call, bool make_explicit)
|
2019-09-27 00:35:57 +02:00
|
|
|
{
|
|
|
|
|
assert(scope);
|
|
|
|
|
|
|
|
|
|
PPackage*found_pkg = 0;
|
2021-07-31 19:36:18 +02:00
|
|
|
for (list<PPackage*>::const_iterator cur_pkg = scope->potential_imports.begin();
|
2019-09-27 00:35:57 +02:00
|
|
|
cur_pkg != scope->potential_imports.end(); ++cur_pkg) {
|
|
|
|
|
PPackage*search_pkg = *cur_pkg;
|
|
|
|
|
map<perm_string,PNamedItem*>::const_iterator cur_sym
|
|
|
|
|
= search_pkg->local_symbols.find(name);
|
|
|
|
|
if (cur_sym != search_pkg->local_symbols.end()) {
|
2019-09-29 20:16:35 +02:00
|
|
|
if (found_pkg && make_explicit) {
|
2019-09-27 00:35:57 +02:00
|
|
|
cerr << loc.get_fileline() << ": error: "
|
|
|
|
|
"Ambiguous use of '" << name << "'. "
|
|
|
|
|
"It is exported by both '"
|
|
|
|
|
<< found_pkg->pscope_name()
|
|
|
|
|
<< "' and by '"
|
|
|
|
|
<< search_pkg->pscope_name()
|
|
|
|
|
<< "'." << endl;
|
|
|
|
|
error_count += 1;
|
|
|
|
|
} else {
|
|
|
|
|
found_pkg = search_pkg;
|
2019-09-30 22:01:30 +02:00
|
|
|
if (make_explicit) {
|
|
|
|
|
if (tf_call)
|
|
|
|
|
scope->possible_imports[name] = found_pkg;
|
|
|
|
|
else
|
|
|
|
|
scope->explicit_imports[name] = found_pkg;
|
|
|
|
|
}
|
2019-09-27 00:35:57 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return found_pkg;
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-30 22:01:30 +02:00
|
|
|
static void check_potential_imports(const struct vlltype&loc, perm_string name, bool tf_call)
|
2019-09-27 00:35:57 +02:00
|
|
|
{
|
|
|
|
|
LexicalScope*scope = lexical_scope;
|
|
|
|
|
while (scope) {
|
|
|
|
|
if (scope->local_symbols.find(name) != scope->local_symbols.end())
|
|
|
|
|
return;
|
|
|
|
|
if (scope->explicit_imports.find(name) != scope->explicit_imports.end())
|
|
|
|
|
return;
|
2019-09-30 22:01:30 +02:00
|
|
|
if (find_potential_import(loc, scope, name, tf_call, true))
|
2019-09-27 00:35:57 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
scope = scope->parent_scope();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-22 23:48:20 +02:00
|
|
|
/*
|
2017-11-05 18:50:05 +01:00
|
|
|
* Set the local time unit/precision. This version is used for setting
|
|
|
|
|
* the time scale for design elements (modules, packages, etc.) and is
|
|
|
|
|
* called after any initial timeunit and timeprecision declarations
|
|
|
|
|
* have been parsed.
|
2016-07-22 23:48:20 +02:00
|
|
|
*/
|
2017-11-05 18:50:05 +01:00
|
|
|
void pform_set_scope_timescale(const struct vlltype&loc)
|
|
|
|
|
{
|
|
|
|
|
PScopeExtra*scope = dynamic_cast<PScopeExtra*>(lexical_scope);
|
|
|
|
|
assert(scope);
|
|
|
|
|
|
|
|
|
|
PScopeExtra*parent = find_nearest_scopex(scope->parent_scope());
|
|
|
|
|
|
|
|
|
|
bool used_global_timescale = false;
|
|
|
|
|
if (scope->time_unit_is_default) {
|
|
|
|
|
if (is_compilation_unit(scope)) {
|
|
|
|
|
scope->time_unit = def_ts_units;
|
|
|
|
|
} else if (!is_compilation_unit(parent)) {
|
|
|
|
|
scope->time_unit = parent->time_unit;
|
|
|
|
|
scope->time_unit_is_default = parent->time_unit_is_default;
|
|
|
|
|
} else if (pform_timescale_file != 0) {
|
|
|
|
|
scope->time_unit = pform_time_unit;
|
|
|
|
|
scope->time_unit_is_default = false;
|
|
|
|
|
used_global_timescale = true;
|
|
|
|
|
} else /* parent is compilation unit */ {
|
|
|
|
|
scope->time_unit = parent->time_unit;
|
|
|
|
|
scope->time_unit_is_default = parent->time_unit_is_default;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (scope->time_prec_is_default) {
|
|
|
|
|
if (is_compilation_unit(scope)) {
|
|
|
|
|
scope->time_precision = def_ts_prec;
|
|
|
|
|
} else if (!is_compilation_unit(parent)) {
|
|
|
|
|
scope->time_precision = parent->time_precision;
|
|
|
|
|
scope->time_prec_is_default = parent->time_prec_is_default;
|
|
|
|
|
} else if (pform_timescale_file != 0) {
|
|
|
|
|
scope->time_precision = pform_time_prec;
|
|
|
|
|
scope->time_prec_is_default = false;
|
|
|
|
|
used_global_timescale = true;
|
|
|
|
|
} else {
|
|
|
|
|
scope->time_precision = parent->time_precision;
|
|
|
|
|
scope->time_prec_is_default = parent->time_prec_is_default;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (gn_system_verilog() && (scope->time_unit < scope->time_precision)) {
|
2017-11-06 01:37:56 +01:00
|
|
|
if (scope->time_unit_is_local || scope->time_prec_is_local) {
|
|
|
|
|
VLerror("error: a timeprecision is missing or is too large!");
|
|
|
|
|
}
|
2017-11-05 18:50:05 +01:00
|
|
|
} else {
|
|
|
|
|
assert(scope->time_unit >= scope->time_precision);
|
|
|
|
|
}
|
2016-07-22 23:48:20 +02:00
|
|
|
|
2017-11-05 18:50:05 +01:00
|
|
|
if (warn_timescale && used_global_timescale
|
2016-07-22 23:48:20 +02:00
|
|
|
&& (strcmp(pform_timescale_file, loc.text) != 0)) {
|
|
|
|
|
|
|
|
|
|
cerr << loc.get_fileline() << ": warning: "
|
|
|
|
|
<< "timescale for " << scope->pscope_name()
|
|
|
|
|
<< " inherited from another file." << endl;
|
|
|
|
|
cerr << pform_timescale_file << ":" << pform_timescale_line
|
|
|
|
|
<< ": ...: The inherited timescale is here." << endl;
|
|
|
|
|
}
|
2017-11-05 18:50:05 +01:00
|
|
|
|
|
|
|
|
allow_timeunit_decl = false;
|
|
|
|
|
allow_timeprec_decl = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Set the local time unit/precision. This version is used for setting
|
|
|
|
|
* the time scale for subsidiary items (classes, subroutines, etc.),
|
|
|
|
|
* which simply inherit their time scale from their parent scope.
|
|
|
|
|
*/
|
|
|
|
|
static void pform_set_scope_timescale(PScope*scope, const PScope*parent)
|
|
|
|
|
{
|
|
|
|
|
scope->time_unit = parent->time_unit;
|
|
|
|
|
scope->time_precision = parent->time_precision;
|
|
|
|
|
scope->time_unit_is_default = parent->time_unit_is_default;
|
|
|
|
|
scope->time_prec_is_default = parent->time_prec_is_default;
|
2016-07-22 23:48:20 +02:00
|
|
|
}
|
|
|
|
|
|
2016-03-19 18:27:27 +01:00
|
|
|
PClass* pform_push_class_scope(const struct vlltype&loc, perm_string name,
|
|
|
|
|
LexicalScope::lifetime_t lifetime)
|
2012-03-11 21:18:24 +01:00
|
|
|
{
|
|
|
|
|
PClass*class_scope = new PClass(name, lexical_scope);
|
2016-03-19 18:27:27 +01:00
|
|
|
class_scope->default_lifetime = find_lifetime(lifetime);
|
2012-03-11 21:18:24 +01:00
|
|
|
FILE_NAME(class_scope, loc);
|
|
|
|
|
|
2012-11-12 02:42:31 +01:00
|
|
|
PScopeExtra*scopex = find_nearest_scopex(lexical_scope);
|
2017-10-21 16:04:25 +02:00
|
|
|
assert(scopex);
|
2012-11-12 02:42:31 +01:00
|
|
|
assert(!pform_cur_generate);
|
|
|
|
|
|
2017-11-05 18:50:05 +01:00
|
|
|
pform_set_scope_timescale(class_scope, scopex);
|
|
|
|
|
|
2012-11-12 02:42:31 +01:00
|
|
|
scopex->classes[name] = class_scope;
|
2013-04-29 01:28:24 +02:00
|
|
|
scopex->classes_lexical .push_back(class_scope);
|
2012-11-12 02:42:31 +01:00
|
|
|
|
2012-03-11 21:18:24 +01:00
|
|
|
lexical_scope = class_scope;
|
|
|
|
|
return class_scope;
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-19 18:27:27 +01:00
|
|
|
PPackage* pform_push_package_scope(const struct vlltype&loc, perm_string name,
|
|
|
|
|
LexicalScope::lifetime_t lifetime)
|
2012-10-21 20:42:19 +02:00
|
|
|
{
|
|
|
|
|
PPackage*pkg_scope = new PPackage(name, lexical_scope);
|
2016-03-19 18:27:27 +01:00
|
|
|
pkg_scope->default_lifetime = find_lifetime(lifetime);
|
2012-10-21 20:42:19 +02:00
|
|
|
FILE_NAME(pkg_scope, loc);
|
|
|
|
|
|
2017-11-05 18:50:05 +01:00
|
|
|
allow_timeunit_decl = true;
|
|
|
|
|
allow_timeprec_decl = true;
|
2016-07-22 23:48:20 +02:00
|
|
|
|
2012-10-21 20:42:19 +02:00
|
|
|
lexical_scope = pkg_scope;
|
|
|
|
|
return pkg_scope;
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-19 18:27:27 +01:00
|
|
|
PTask* pform_push_task_scope(const struct vlltype&loc, char*name,
|
|
|
|
|
LexicalScope::lifetime_t lifetime)
|
2008-02-16 06:20:24 +01:00
|
|
|
{
|
|
|
|
|
perm_string task_name = lex_strings.make(name);
|
|
|
|
|
|
2016-03-19 18:27:27 +01:00
|
|
|
LexicalScope::lifetime_t default_lifetime = find_lifetime(lifetime);
|
|
|
|
|
bool is_auto = default_lifetime == LexicalScope::AUTOMATIC;
|
|
|
|
|
|
2010-01-08 23:49:48 +01:00
|
|
|
PTask*task = new PTask(task_name, lexical_scope, is_auto);
|
2016-03-19 18:27:27 +01:00
|
|
|
task->default_lifetime = default_lifetime;
|
2010-01-08 23:49:48 +01:00
|
|
|
FILE_NAME(task, loc);
|
2012-03-11 21:18:24 +01:00
|
|
|
|
2012-11-12 02:42:31 +01:00
|
|
|
PScopeExtra*scopex = find_nearest_scopex(lexical_scope);
|
2017-10-21 16:04:25 +02:00
|
|
|
assert(scopex);
|
|
|
|
|
if (is_compilation_unit(scopex) && !gn_system_verilog()) {
|
2014-05-23 22:55:46 +02:00
|
|
|
cerr << task->get_fileline() << ": error: task declarations "
|
|
|
|
|
"must be contained within a module." << endl;
|
|
|
|
|
error_count += 1;
|
|
|
|
|
}
|
2012-03-11 21:18:24 +01:00
|
|
|
|
2017-11-05 18:50:05 +01:00
|
|
|
pform_set_scope_timescale(task, scopex);
|
|
|
|
|
|
2008-06-20 06:31:53 +02:00
|
|
|
if (pform_cur_generate) {
|
2019-09-27 00:35:57 +02:00
|
|
|
add_local_symbol(pform_cur_generate, task_name, task);
|
|
|
|
|
pform_cur_generate->tasks[task_name] = task;
|
2017-10-21 16:04:25 +02:00
|
|
|
} else {
|
2019-09-27 00:35:57 +02:00
|
|
|
add_local_symbol(scopex, task_name, task);
|
|
|
|
|
scopex->tasks[task_name] = task;
|
2008-06-20 06:31:53 +02:00
|
|
|
}
|
2012-03-11 21:18:24 +01:00
|
|
|
|
2010-01-08 23:49:48 +01:00
|
|
|
lexical_scope = task;
|
2008-06-19 06:54:58 +02:00
|
|
|
|
2008-02-16 06:20:24 +01:00
|
|
|
return task;
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-15 03:03:21 +02:00
|
|
|
PFunction* pform_push_function_scope(const struct vlltype&loc, const char*name,
|
2016-03-19 18:27:27 +01:00
|
|
|
LexicalScope::lifetime_t lifetime)
|
2008-02-16 06:20:24 +01:00
|
|
|
{
|
|
|
|
|
perm_string func_name = lex_strings.make(name);
|
|
|
|
|
|
2016-03-19 18:27:27 +01:00
|
|
|
LexicalScope::lifetime_t default_lifetime = find_lifetime(lifetime);
|
|
|
|
|
bool is_auto = default_lifetime == LexicalScope::AUTOMATIC;
|
|
|
|
|
|
2010-01-08 23:49:48 +01:00
|
|
|
PFunction*func = new PFunction(func_name, lexical_scope, is_auto);
|
2016-03-19 18:27:27 +01:00
|
|
|
func->default_lifetime = default_lifetime;
|
2010-01-08 23:49:48 +01:00
|
|
|
FILE_NAME(func, loc);
|
2012-03-11 21:18:24 +01:00
|
|
|
|
2014-05-23 22:55:46 +02:00
|
|
|
PScopeExtra*scopex = find_nearest_scopex(lexical_scope);
|
2017-10-21 16:04:25 +02:00
|
|
|
assert(scopex);
|
|
|
|
|
if (is_compilation_unit(scopex) && !gn_system_verilog()) {
|
2014-05-23 22:55:46 +02:00
|
|
|
cerr << func->get_fileline() << ": error: function declarations "
|
|
|
|
|
"must be contained within a module." << endl;
|
|
|
|
|
error_count += 1;
|
|
|
|
|
}
|
2012-03-11 21:18:24 +01:00
|
|
|
|
2017-11-05 18:50:05 +01:00
|
|
|
pform_set_scope_timescale(func, scopex);
|
|
|
|
|
|
2008-06-20 06:31:53 +02:00
|
|
|
if (pform_cur_generate) {
|
2019-09-27 00:35:57 +02:00
|
|
|
add_local_symbol(pform_cur_generate, func_name, func);
|
|
|
|
|
pform_cur_generate->funcs[func_name] = func;
|
2014-10-03 00:04:14 +02:00
|
|
|
|
2017-10-21 16:04:25 +02:00
|
|
|
} else {
|
2019-09-27 00:35:57 +02:00
|
|
|
add_local_symbol(scopex, func_name, func);
|
|
|
|
|
scopex->funcs[func_name] = func;
|
2008-06-20 06:31:53 +02:00
|
|
|
}
|
2014-10-03 00:04:14 +02:00
|
|
|
|
2010-01-08 23:49:48 +01:00
|
|
|
lexical_scope = func;
|
2008-06-19 06:54:58 +02:00
|
|
|
|
2008-02-16 06:20:24 +01:00
|
|
|
return func;
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-27 01:46:39 +02:00
|
|
|
PBlock* pform_push_block_scope(const struct vlltype&loc, char*name,
|
|
|
|
|
PBlock::BL_TYPE bt)
|
2008-02-16 06:20:24 +01:00
|
|
|
{
|
2014-07-23 03:55:24 +02:00
|
|
|
perm_string block_name;
|
|
|
|
|
if (name) block_name = lex_strings.make(name);
|
|
|
|
|
else {
|
|
|
|
|
// Create a unique name for this unnamed block.
|
|
|
|
|
char tmp[32];
|
|
|
|
|
snprintf(tmp, sizeof tmp, "$unm_blk_%u",
|
|
|
|
|
scope_unnamed_block_with_decl);
|
|
|
|
|
block_name = lex_strings.make(tmp);
|
|
|
|
|
scope_unnamed_block_with_decl += 1;
|
|
|
|
|
}
|
2008-02-16 06:20:24 +01:00
|
|
|
|
2010-01-08 23:49:48 +01:00
|
|
|
PBlock*block = new PBlock(block_name, lexical_scope, bt);
|
2019-09-27 01:46:39 +02:00
|
|
|
FILE_NAME(block, loc);
|
2016-03-19 21:39:54 +01:00
|
|
|
block->default_lifetime = find_lifetime(LexicalScope::INHERITED);
|
2019-09-27 00:35:57 +02:00
|
|
|
if (name) add_local_symbol(lexical_scope, block_name, block);
|
2010-01-08 23:49:48 +01:00
|
|
|
lexical_scope = block;
|
2008-02-25 04:40:54 +01:00
|
|
|
|
2008-02-16 06:20:24 +01:00
|
|
|
return block;
|
|
|
|
|
}
|
|
|
|
|
|
2013-02-18 01:22:24 +01:00
|
|
|
/*
|
2019-09-22 10:16:10 +02:00
|
|
|
* Create a new identifier.
|
2013-02-18 01:22:24 +01:00
|
|
|
*/
|
2019-09-27 00:35:57 +02:00
|
|
|
PEIdent* pform_new_ident(const struct vlltype&loc, const pform_name_t&name)
|
2013-02-18 01:22:24 +01:00
|
|
|
{
|
2019-10-01 09:46:11 +02:00
|
|
|
if (gn_system_verilog())
|
|
|
|
|
check_potential_imports(loc, name.front().name, false);
|
2019-09-27 00:35:57 +02:00
|
|
|
|
2019-09-22 10:16:10 +02:00
|
|
|
return new PEIdent(name);
|
2013-02-18 01:22:24 +01:00
|
|
|
}
|
|
|
|
|
|
2019-09-29 22:11:01 +02:00
|
|
|
PTrigger* pform_new_trigger(const struct vlltype&loc, PPackage*pkg,
|
|
|
|
|
const pform_name_t&name)
|
2019-09-28 22:00:17 +02:00
|
|
|
{
|
2019-10-01 09:46:11 +02:00
|
|
|
if (gn_system_verilog())
|
|
|
|
|
check_potential_imports(loc, name.front().name, false);
|
2019-09-28 22:00:17 +02:00
|
|
|
|
2019-09-29 22:11:01 +02:00
|
|
|
PTrigger*tmp = new PTrigger(pkg, name);
|
|
|
|
|
FILE_NAME(tmp, loc);
|
|
|
|
|
return tmp;
|
2019-09-28 22:00:17 +02:00
|
|
|
}
|
|
|
|
|
|
2021-02-20 08:21:12 +01:00
|
|
|
PNBTrigger* pform_new_nb_trigger(const struct vlltype&loc,
|
|
|
|
|
const list<PExpr*>*dly,
|
|
|
|
|
const pform_name_t&name)
|
|
|
|
|
{
|
|
|
|
|
if (gn_system_verilog())
|
|
|
|
|
check_potential_imports(loc, name.front().name, false);
|
|
|
|
|
|
|
|
|
|
PExpr*tmp_dly = 0;
|
|
|
|
|
if (dly) {
|
|
|
|
|
assert(dly->size() == 1);
|
|
|
|
|
tmp_dly = dly->front();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PNBTrigger*tmp = new PNBTrigger(name, tmp_dly);
|
|
|
|
|
FILE_NAME(tmp, loc);
|
|
|
|
|
return tmp;
|
|
|
|
|
}
|
|
|
|
|
|
2010-03-12 01:06:02 +01:00
|
|
|
PGenerate* pform_parent_generate(void)
|
|
|
|
|
{
|
|
|
|
|
return pform_cur_generate;
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-03 10:48:42 +01:00
|
|
|
bool pform_error_in_generate(const vlltype&loc, const char *type)
|
|
|
|
|
{
|
|
|
|
|
if (!pform_parent_generate())
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
VLerror(loc, "error: %s is not allowed in generate block.", type);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2008-09-05 06:27:21 +02:00
|
|
|
void pform_bind_attributes(map<perm_string,PExpr*>&attributes,
|
2010-11-13 03:47:06 +01:00
|
|
|
list<named_pexpr_t>*attr, bool keep_attrs)
|
2008-09-05 06:27:21 +02:00
|
|
|
{
|
|
|
|
|
if (attr == 0)
|
|
|
|
|
return;
|
|
|
|
|
|
2011-04-19 03:17:16 +02:00
|
|
|
while (! attr->empty()) {
|
2010-11-13 03:47:06 +01:00
|
|
|
named_pexpr_t tmp = attr->front();
|
|
|
|
|
attr->pop_front();
|
|
|
|
|
attributes[tmp.name] = tmp.parm;
|
2008-09-05 06:27:21 +02:00
|
|
|
}
|
2010-11-13 03:47:06 +01:00
|
|
|
if (!keep_attrs)
|
|
|
|
|
delete attr;
|
2008-09-05 06:27:21 +02:00
|
|
|
}
|
|
|
|
|
|
2012-05-06 19:21:51 +02:00
|
|
|
bool pform_in_program_block()
|
|
|
|
|
{
|
2012-08-08 20:26:46 +02:00
|
|
|
if (pform_cur_module.empty())
|
2012-05-06 19:21:51 +02:00
|
|
|
return false;
|
2012-05-10 04:35:11 +02:00
|
|
|
if (pform_cur_module.front()->program_block)
|
2012-05-06 19:21:51 +02:00
|
|
|
return true;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-20 00:10:14 +01:00
|
|
|
bool pform_in_interface()
|
|
|
|
|
{
|
|
|
|
|
if (pform_cur_module.empty())
|
|
|
|
|
return false;
|
|
|
|
|
if (pform_cur_module.front()->is_interface)
|
|
|
|
|
return true;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2008-10-28 18:52:39 +01:00
|
|
|
static bool pform_at_module_level()
|
|
|
|
|
{
|
2012-05-10 04:35:11 +02:00
|
|
|
return (lexical_scope == pform_cur_module.front())
|
2010-01-08 23:49:48 +01:00
|
|
|
|| (lexical_scope == pform_cur_generate);
|
2008-10-28 18:52:39 +01:00
|
|
|
}
|
|
|
|
|
|
2008-05-12 02:30:33 +02:00
|
|
|
PWire*pform_get_wire_in_scope(perm_string name)
|
2006-04-10 02:37:42 +02:00
|
|
|
{
|
2010-01-08 23:49:48 +01:00
|
|
|
return lexical_scope->wires_find(name);
|
2008-06-20 06:31:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void pform_put_wire_in_scope(perm_string name, PWire*net)
|
|
|
|
|
{
|
2019-09-27 00:35:57 +02:00
|
|
|
add_local_symbol(lexical_scope, name, net);
|
2010-01-08 23:49:48 +01:00
|
|
|
lexical_scope->wires[name] = net;
|
2008-06-20 06:31:53 +02:00
|
|
|
}
|
2006-04-10 02:37:42 +02:00
|
|
|
|
2022-01-15 13:08:32 +01:00
|
|
|
void pform_put_enum_type_in_scope(enum_type_t*enum_set)
|
2010-10-31 19:26:09 +01:00
|
|
|
{
|
2022-01-22 11:30:48 +01:00
|
|
|
if (std::find(lexical_scope->enum_sets.begin(),
|
|
|
|
|
lexical_scope->enum_sets.end(), enum_set) !=
|
|
|
|
|
lexical_scope->enum_sets.end())
|
|
|
|
|
return;
|
2019-09-27 22:29:50 +02:00
|
|
|
|
|
|
|
|
set<perm_string> enum_names;
|
|
|
|
|
list<named_pexpr_t>::const_iterator cur;
|
|
|
|
|
for (cur = enum_set->names->begin(); cur != enum_set->names->end(); ++cur) {
|
|
|
|
|
if (enum_names.count(cur->name)) {
|
|
|
|
|
cerr << enum_set->get_fileline() << ": error: "
|
|
|
|
|
"Duplicate enumeration name '"
|
|
|
|
|
<< cur->name << "'." << endl;
|
|
|
|
|
error_count += 1;
|
|
|
|
|
} else {
|
|
|
|
|
add_local_symbol(lexical_scope, cur->name, enum_set);
|
|
|
|
|
enum_names.insert(cur->name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-22 11:30:48 +01:00
|
|
|
lexical_scope->enum_sets.push_back(enum_set);
|
2010-10-31 19:26:09 +01:00
|
|
|
}
|
|
|
|
|
|
2022-04-23 15:05:53 +02:00
|
|
|
void pform_set_typedef(const struct vlltype&loc, perm_string name,
|
|
|
|
|
data_type_t*data_type,
|
|
|
|
|
std::list<pform_range_t>*unp_ranges)
|
2012-01-09 02:51:18 +01:00
|
|
|
{
|
2014-12-15 11:25:35 +01:00
|
|
|
if(unp_ranges)
|
|
|
|
|
data_type = new uarray_type_t(data_type, unp_ranges);
|
|
|
|
|
|
2022-04-23 15:05:53 +02:00
|
|
|
typedef_t *&td = lexical_scope->typedefs[name];
|
|
|
|
|
if (!td) {
|
|
|
|
|
td = new typedef_t(name);
|
|
|
|
|
FILE_NAME(td, loc);
|
|
|
|
|
add_local_symbol(lexical_scope, name, td);
|
|
|
|
|
}
|
2013-12-15 05:07:31 +01:00
|
|
|
|
2022-04-23 15:05:53 +02:00
|
|
|
if (!td->set_data_type(data_type)) {
|
|
|
|
|
cerr << loc << " error: Type identifier `" << name
|
|
|
|
|
<< "` has already been declared in this scope at "
|
|
|
|
|
<< td->get_data_type()->get_fileline() << "."
|
|
|
|
|
<< endl;
|
|
|
|
|
error_count++;
|
|
|
|
|
delete data_type;
|
|
|
|
|
}
|
2012-01-09 02:51:18 +01:00
|
|
|
}
|
|
|
|
|
|
2019-09-29 20:16:35 +02:00
|
|
|
void pform_set_type_referenced(const struct vlltype&loc, const char*name)
|
|
|
|
|
{
|
|
|
|
|
perm_string lex_name = lex_strings.make(name);
|
2019-09-30 22:01:30 +02:00
|
|
|
check_potential_imports(loc, lex_name, false);
|
2019-09-29 20:16:35 +02:00
|
|
|
}
|
|
|
|
|
|
2022-04-23 15:05:53 +02:00
|
|
|
typedef_t* pform_test_type_identifier(const struct vlltype&loc, const char*txt)
|
2013-12-15 05:07:31 +01:00
|
|
|
{
|
2012-01-09 02:51:18 +01:00
|
|
|
perm_string name = lex_strings.make(txt);
|
2013-04-01 00:46:36 +02:00
|
|
|
|
2012-03-05 04:33:16 +01:00
|
|
|
LexicalScope*cur_scope = lexical_scope;
|
|
|
|
|
do {
|
2022-04-23 15:05:53 +02:00
|
|
|
LexicalScope::typedef_map_t::iterator cur;
|
2013-04-01 00:46:36 +02:00
|
|
|
|
|
|
|
|
// First look to see if this identifier is imported from
|
|
|
|
|
// a package. If it is, see if it is a type in that
|
|
|
|
|
// package. If it is, then great. If imported as
|
2014-01-29 00:50:27 +01:00
|
|
|
// something other than a type, then give up now because
|
2013-04-01 00:46:36 +02:00
|
|
|
// the name has at least shadowed any other possible
|
|
|
|
|
// meaning for this name.
|
|
|
|
|
map<perm_string,PPackage*>::iterator cur_pkg;
|
2019-09-27 00:35:57 +02:00
|
|
|
cur_pkg = cur_scope->explicit_imports.find(name);
|
|
|
|
|
if (cur_pkg != cur_scope->explicit_imports.end()) {
|
2013-04-01 00:46:36 +02:00
|
|
|
PPackage*pkg = cur_pkg->second;
|
|
|
|
|
cur = pkg->typedefs.find(name);
|
|
|
|
|
if (cur != pkg->typedefs.end())
|
|
|
|
|
return cur->second;
|
|
|
|
|
|
|
|
|
|
// Not a type. Give up.
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-05 04:33:16 +01:00
|
|
|
cur = cur_scope->typedefs.find(name);
|
|
|
|
|
if (cur != cur_scope->typedefs.end())
|
|
|
|
|
return cur->second;
|
2012-08-16 20:06:20 +02:00
|
|
|
|
2019-09-30 22:01:30 +02:00
|
|
|
PPackage*pkg = find_potential_import(loc, cur_scope, name, false, false);
|
2019-09-27 00:35:57 +02:00
|
|
|
if (pkg) {
|
|
|
|
|
cur = pkg->typedefs.find(name);
|
2019-10-03 01:28:36 +02:00
|
|
|
if (cur != pkg->typedefs.end())
|
2019-09-27 00:35:57 +02:00
|
|
|
return cur->second;
|
2019-09-29 20:16:35 +02:00
|
|
|
|
|
|
|
|
// Not a type. Give up.
|
|
|
|
|
return 0;
|
2019-09-27 00:35:57 +02:00
|
|
|
}
|
|
|
|
|
|
2012-03-05 04:33:16 +01:00
|
|
|
cur_scope = cur_scope->parent_scope();
|
|
|
|
|
} while (cur_scope);
|
2013-04-01 00:46:36 +02:00
|
|
|
|
2012-03-05 04:33:16 +01:00
|
|
|
return 0;
|
2012-01-09 02:51:18 +01:00
|
|
|
}
|
|
|
|
|
|
2013-04-01 00:46:36 +02:00
|
|
|
PECallFunction* pform_make_call_function(const struct vlltype&loc,
|
|
|
|
|
const pform_name_t&name,
|
|
|
|
|
const list<PExpr*>&parms)
|
|
|
|
|
{
|
2019-10-01 09:46:11 +02:00
|
|
|
if (gn_system_verilog())
|
|
|
|
|
check_potential_imports(loc, name.front().name, true);
|
2019-09-27 00:35:57 +02:00
|
|
|
|
2019-09-22 10:16:10 +02:00
|
|
|
PECallFunction*tmp = new PECallFunction(name, parms);
|
2013-04-01 00:46:36 +02:00
|
|
|
FILE_NAME(tmp, loc);
|
|
|
|
|
return tmp;
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-09 03:12:54 +02:00
|
|
|
PCallTask* pform_make_call_task(const struct vlltype&loc,
|
|
|
|
|
const pform_name_t&name,
|
|
|
|
|
const list<PExpr*>&parms)
|
|
|
|
|
{
|
2019-10-01 09:46:11 +02:00
|
|
|
if (gn_system_verilog())
|
|
|
|
|
check_potential_imports(loc, name.front().name, true);
|
2019-09-27 00:35:57 +02:00
|
|
|
|
2019-09-22 10:16:10 +02:00
|
|
|
PCallTask*tmp = new PCallTask(name, parms);
|
2013-04-09 03:12:54 +02:00
|
|
|
FILE_NAME(tmp, loc);
|
|
|
|
|
return tmp;
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-22 17:22:18 +01:00
|
|
|
void pform_make_var(const struct vlltype&loc,
|
|
|
|
|
std::list<decl_assignment_t*>*assign_list,
|
|
|
|
|
data_type_t*data_type, std::list<named_pexpr_t>*attr)
|
2014-08-22 00:47:46 +02:00
|
|
|
{
|
|
|
|
|
static const struct str_pair_t str = { IVL_DR_STRONG, IVL_DR_STRONG };
|
|
|
|
|
|
2022-01-22 17:22:18 +01:00
|
|
|
pform_makewire(loc, 0, str, assign_list, NetNet::REG, data_type, attr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void pform_make_foreach_declarations(const struct vlltype&loc,
|
|
|
|
|
std::list<perm_string>*loop_vars)
|
|
|
|
|
{
|
2014-08-22 00:47:46 +02:00
|
|
|
list<decl_assignment_t*>assign_list;
|
|
|
|
|
for (list<perm_string>::const_iterator cur = loop_vars->begin()
|
|
|
|
|
; cur != loop_vars->end() ; ++ cur) {
|
|
|
|
|
decl_assignment_t*tmp_assign = new decl_assignment_t;
|
|
|
|
|
tmp_assign->name = lex_strings.make(*cur);
|
|
|
|
|
assign_list.push_back(tmp_assign);
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-22 17:22:18 +01:00
|
|
|
pform_make_var(loc, &assign_list, &size_type);
|
2014-08-22 00:47:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PForeach* pform_make_foreach(const struct vlltype&loc,
|
|
|
|
|
char*name,
|
|
|
|
|
list<perm_string>*loop_vars,
|
|
|
|
|
Statement*stmt)
|
|
|
|
|
{
|
|
|
|
|
perm_string use_name = lex_strings.make(name);
|
|
|
|
|
delete[]name;
|
|
|
|
|
|
2014-08-25 23:58:57 +02:00
|
|
|
if (loop_vars==0 || loop_vars->empty()) {
|
|
|
|
|
cerr << loc.get_fileline() << ": error: "
|
|
|
|
|
<< "No loop variables at all in foreach index." << endl;
|
2014-08-22 05:34:55 +02:00
|
|
|
error_count += 1;
|
|
|
|
|
}
|
2014-08-22 00:47:46 +02:00
|
|
|
|
2014-08-25 23:58:57 +02:00
|
|
|
ivl_assert(loc, loop_vars);
|
|
|
|
|
PForeach*fe = new PForeach(use_name, *loop_vars, stmt);
|
2014-08-22 00:47:46 +02:00
|
|
|
FILE_NAME(fe, loc);
|
|
|
|
|
|
2014-08-25 23:58:57 +02:00
|
|
|
delete loop_vars;
|
|
|
|
|
|
2014-08-22 00:47:46 +02:00
|
|
|
return fe;
|
|
|
|
|
}
|
|
|
|
|
|
2008-06-20 06:31:53 +02:00
|
|
|
static void pform_put_behavior_in_scope(PProcess*pp)
|
|
|
|
|
{
|
2010-01-08 23:49:48 +01:00
|
|
|
lexical_scope->behaviors.push_back(pp);
|
2006-04-10 02:37:42 +02:00
|
|
|
}
|
|
|
|
|
|
2008-07-27 21:02:09 +02:00
|
|
|
void pform_put_behavior_in_scope(AProcess*pp)
|
|
|
|
|
{
|
2010-01-08 23:49:48 +01:00
|
|
|
lexical_scope->analog_behaviors.push_back(pp);
|
2008-07-27 21:02:09 +02:00
|
|
|
}
|
|
|
|
|
|
2004-06-13 06:56:53 +02:00
|
|
|
void pform_set_default_nettype(NetNet::Type type,
|
|
|
|
|
const char*file, unsigned lineno)
|
|
|
|
|
{
|
|
|
|
|
pform_default_nettype = type;
|
|
|
|
|
|
2012-08-08 20:26:46 +02:00
|
|
|
if (! pform_cur_module.empty()) {
|
2004-06-13 06:56:53 +02:00
|
|
|
cerr << file<<":"<<lineno << ": error: "
|
|
|
|
|
<< "`default_nettype directives must appear" << endl;
|
|
|
|
|
cerr << file<<":"<<lineno << ": : "
|
|
|
|
|
<< "outside module definitions. The containing" << endl;
|
|
|
|
|
cerr << file<<":"<<lineno << ": : "
|
2012-05-10 04:35:11 +02:00
|
|
|
<< "module " << pform_cur_module.back()->mod_name()
|
2004-06-13 06:56:53 +02:00
|
|
|
<< " starts on line "
|
2012-05-10 04:35:11 +02:00
|
|
|
<< pform_cur_module.back()->get_fileline() << "." << endl;
|
2004-06-13 06:56:53 +02:00
|
|
|
error_count += 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-01-12 21:11:01 +01:00
|
|
|
static void pform_declare_implicit_nets(PExpr*expr)
|
|
|
|
|
{
|
|
|
|
|
/* If implicit net creation is turned off, then stop now. */
|
|
|
|
|
if (pform_default_nettype == NetNet::NONE)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (expr)
|
|
|
|
|
expr->declare_implicit_nets(lexical_scope, pform_default_nettype);
|
|
|
|
|
}
|
|
|
|
|
|
2002-04-15 02:04:22 +02:00
|
|
|
/*
|
|
|
|
|
* The lexor calls this function to set the active timescale when it
|
|
|
|
|
* detects a `timescale directive. The function saves the directive
|
2017-11-05 18:50:05 +01:00
|
|
|
* values (for use by subsequent design elements) and if warnings are
|
|
|
|
|
* enabled checks to see if some design elements have no timescale.
|
2002-04-15 02:04:22 +02:00
|
|
|
*/
|
|
|
|
|
void pform_set_timescale(int unit, int prec,
|
|
|
|
|
const char*file, unsigned lineno)
|
2001-12-03 05:47:14 +01:00
|
|
|
{
|
|
|
|
|
assert(unit >= prec);
|
|
|
|
|
pform_time_unit = unit;
|
|
|
|
|
pform_time_prec = prec;
|
2002-04-15 02:04:22 +02:00
|
|
|
|
2002-04-18 20:38:37 +02:00
|
|
|
if (pform_timescale_file) {
|
2002-04-15 02:04:22 +02:00
|
|
|
free(pform_timescale_file);
|
2002-04-18 20:38:37 +02:00
|
|
|
}
|
2002-04-15 02:04:22 +02:00
|
|
|
|
2009-05-22 20:03:36 +02:00
|
|
|
if (file) pform_timescale_file = strdup(file);
|
|
|
|
|
else pform_timescale_file = 0;
|
2002-04-15 02:04:22 +02:00
|
|
|
pform_timescale_line = lineno;
|
2001-12-03 05:47:14 +01:00
|
|
|
}
|
|
|
|
|
|
2011-07-05 19:11:56 +02:00
|
|
|
bool get_time_unit(const char*cp, int &unit)
|
|
|
|
|
{
|
|
|
|
|
const char *c;
|
|
|
|
|
bool rc = true;
|
|
|
|
|
|
|
|
|
|
if (strchr(cp, '_')) {
|
|
|
|
|
VLerror(yylloc, "Invalid timeunit constant ('_' is not "
|
|
|
|
|
"supported).");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
c = strpbrk(cp, "munpfs");
|
|
|
|
|
if (!c)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (*c == 's')
|
|
|
|
|
unit = 0;
|
|
|
|
|
else if (!strncmp(c, "ms", 2))
|
|
|
|
|
unit = -3;
|
|
|
|
|
else if (!strncmp(c, "us", 2))
|
|
|
|
|
unit = -6;
|
|
|
|
|
else if (!strncmp(c, "ns", 2))
|
|
|
|
|
unit = -9;
|
|
|
|
|
else if (!strncmp(c, "ps", 2))
|
|
|
|
|
unit = -12;
|
|
|
|
|
else if (!strncmp(c, "fs", 2))
|
|
|
|
|
unit = -15;
|
|
|
|
|
else {
|
|
|
|
|
rc = false;
|
|
|
|
|
|
|
|
|
|
ostringstream msg;
|
|
|
|
|
msg << "Invalid timeunit scale '" << cp << "'.";
|
|
|
|
|
VLerror(msg.str().c_str());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-11 03:19:59 +02:00
|
|
|
/*
|
|
|
|
|
* Get a timeunit or timeprecision value from a string. This is
|
|
|
|
|
* similar to the code in lexor.lex for the `timescale directive.
|
|
|
|
|
*/
|
|
|
|
|
static bool get_time_unit_prec(const char*cp, int &res, bool is_unit)
|
2009-06-20 05:58:46 +02:00
|
|
|
{
|
2009-07-11 03:19:59 +02:00
|
|
|
/* We do not support a '_' in these time constants. */
|
|
|
|
|
if (strchr(cp, '_')) {
|
|
|
|
|
if (is_unit) {
|
|
|
|
|
VLerror(yylloc, "Invalid timeunit constant ('_' is not "
|
|
|
|
|
"supported).");
|
|
|
|
|
} else {
|
|
|
|
|
VLerror(yylloc, "Invalid timeprecision constant ('_' is not "
|
|
|
|
|
"supported).");
|
|
|
|
|
}
|
|
|
|
|
return true;
|
2009-06-20 05:58:46 +02:00
|
|
|
}
|
|
|
|
|
|
2009-07-11 03:19:59 +02:00
|
|
|
/* Check for the 1 digit. */
|
|
|
|
|
if (*cp != '1') {
|
|
|
|
|
if (is_unit) {
|
|
|
|
|
VLerror(yylloc, "Invalid timeunit constant (1st digit).");
|
|
|
|
|
} else {
|
|
|
|
|
VLerror(yylloc, "Invalid timeprecision constant (1st digit).");
|
|
|
|
|
}
|
|
|
|
|
return true;
|
2009-06-20 05:58:46 +02:00
|
|
|
}
|
2009-07-11 03:19:59 +02:00
|
|
|
cp += 1;
|
|
|
|
|
|
|
|
|
|
/* Check the number of zeros after the 1. */
|
|
|
|
|
res = strspn(cp, "0");
|
|
|
|
|
if (res > 2) {
|
|
|
|
|
if (is_unit) {
|
|
|
|
|
VLerror(yylloc, "Invalid timeunit constant (number of "
|
|
|
|
|
"zeros).");
|
|
|
|
|
} else {
|
|
|
|
|
VLerror(yylloc, "Invalid timeprecision constant (number of "
|
|
|
|
|
"zeros).");
|
|
|
|
|
}
|
|
|
|
|
return true;
|
2009-06-20 05:58:46 +02:00
|
|
|
}
|
2009-07-11 03:19:59 +02:00
|
|
|
cp += res;
|
2009-06-20 05:58:46 +02:00
|
|
|
|
2009-07-11 03:19:59 +02:00
|
|
|
/* Now process the scaling string. */
|
|
|
|
|
if (strncmp("s", cp, 1) == 0) {
|
|
|
|
|
res -= 0;
|
|
|
|
|
return false;
|
2009-06-20 05:58:46 +02:00
|
|
|
|
2009-07-11 03:19:59 +02:00
|
|
|
} else if (strncmp("ms", cp, 2) == 0) {
|
|
|
|
|
res -= 3;
|
|
|
|
|
return false;
|
2009-06-20 05:58:46 +02:00
|
|
|
|
2009-07-11 03:19:59 +02:00
|
|
|
} else if (strncmp("us", cp, 2) == 0) {
|
|
|
|
|
res -= 6;
|
|
|
|
|
return false;
|
2009-06-20 05:58:46 +02:00
|
|
|
|
2009-07-11 03:19:59 +02:00
|
|
|
} else if (strncmp("ns", cp, 2) == 0) {
|
|
|
|
|
res -= 9;
|
|
|
|
|
return false;
|
2009-06-20 05:58:46 +02:00
|
|
|
|
2009-07-11 03:19:59 +02:00
|
|
|
} else if (strncmp("ps", cp, 2) == 0) {
|
|
|
|
|
res -= 12;
|
|
|
|
|
return false;
|
2009-06-20 05:58:46 +02:00
|
|
|
|
2009-07-11 03:19:59 +02:00
|
|
|
} else if (strncmp("fs", cp, 2) == 0) {
|
|
|
|
|
res -= 15;
|
|
|
|
|
return false;
|
2009-06-20 05:58:46 +02:00
|
|
|
|
|
|
|
|
}
|
2009-07-11 03:19:59 +02:00
|
|
|
|
|
|
|
|
ostringstream msg;
|
|
|
|
|
msg << "Invalid ";
|
|
|
|
|
if (is_unit) msg << "timeunit";
|
|
|
|
|
else msg << "timeprecision";
|
|
|
|
|
msg << " scale '" << cp << "'.";
|
|
|
|
|
VLerror(msg.str().c_str());
|
|
|
|
|
return true;
|
2009-06-20 05:58:46 +02:00
|
|
|
}
|
|
|
|
|
|
2017-11-06 01:37:56 +01:00
|
|
|
void pform_set_timeunit(const char*txt, bool initial_decl)
|
2009-06-20 05:58:46 +02:00
|
|
|
{
|
2009-07-11 03:19:59 +02:00
|
|
|
int val;
|
|
|
|
|
|
|
|
|
|
if (get_time_unit_prec(txt, val, true)) return;
|
|
|
|
|
|
2017-11-05 18:50:05 +01:00
|
|
|
PScopeExtra*scope = dynamic_cast<PScopeExtra*>(lexical_scope);
|
2022-02-03 10:48:42 +01:00
|
|
|
if (!scope)
|
|
|
|
|
return;
|
2017-11-05 18:50:05 +01:00
|
|
|
|
2017-11-06 01:37:56 +01:00
|
|
|
if (initial_decl) {
|
2017-11-05 18:50:05 +01:00
|
|
|
scope->time_unit = val;
|
|
|
|
|
scope->time_unit_is_local = true;
|
|
|
|
|
scope->time_unit_is_default = false;
|
|
|
|
|
allow_timeunit_decl = false;
|
|
|
|
|
} else if (!scope->time_unit_is_local) {
|
|
|
|
|
VLerror(yylloc, "error: repeat timeunit found and the initial "
|
|
|
|
|
"timeunit for this scope is missing.");
|
|
|
|
|
} else if (scope->time_unit != val) {
|
|
|
|
|
VLerror(yylloc, "error: repeat timeunit does not match the "
|
|
|
|
|
"initial timeunit for this scope.");
|
2009-06-20 05:58:46 +02:00
|
|
|
}
|
2009-07-11 03:19:59 +02:00
|
|
|
}
|
2009-06-20 05:58:46 +02:00
|
|
|
|
2011-07-05 19:11:56 +02:00
|
|
|
int pform_get_timeunit()
|
|
|
|
|
{
|
2017-11-05 18:50:05 +01:00
|
|
|
PScopeExtra*scopex = find_nearest_scopex(lexical_scope);
|
|
|
|
|
assert(scopex);
|
|
|
|
|
return scopex->time_unit;
|
2011-07-05 19:11:56 +02:00
|
|
|
}
|
|
|
|
|
|
2021-02-13 10:10:38 +01:00
|
|
|
int pform_get_timeprec()
|
|
|
|
|
{
|
|
|
|
|
PScopeExtra*scopex = find_nearest_scopex(lexical_scope);
|
|
|
|
|
assert(scopex);
|
|
|
|
|
return scopex->time_precision;
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-06 01:37:56 +01:00
|
|
|
void pform_set_timeprec(const char*txt, bool initial_decl)
|
2009-07-11 03:19:59 +02:00
|
|
|
{
|
|
|
|
|
int val;
|
|
|
|
|
|
|
|
|
|
if (get_time_unit_prec(txt, val, false)) return;
|
|
|
|
|
|
2017-11-05 18:50:05 +01:00
|
|
|
PScopeExtra*scope = dynamic_cast<PScopeExtra*>(lexical_scope);
|
2022-02-03 10:48:42 +01:00
|
|
|
if (!scope)
|
|
|
|
|
return;
|
2017-11-05 18:50:05 +01:00
|
|
|
|
2017-11-06 01:37:56 +01:00
|
|
|
if (initial_decl) {
|
2017-11-05 18:50:05 +01:00
|
|
|
scope->time_precision = val;
|
|
|
|
|
scope->time_prec_is_local = true;
|
|
|
|
|
scope->time_prec_is_default = false;
|
|
|
|
|
allow_timeprec_decl = false;
|
|
|
|
|
} else if (!scope->time_prec_is_local) {
|
|
|
|
|
VLerror(yylloc, "error: repeat timeprecision found and the initial "
|
|
|
|
|
"timeprecision for this scope is missing.");
|
|
|
|
|
} else if (scope->time_precision != val) {
|
|
|
|
|
VLerror(yylloc, "error: repeat timeprecision does not match the "
|
|
|
|
|
"initial timeprecision for this scope.");
|
2009-06-20 05:58:46 +02:00
|
|
|
}
|
|
|
|
|
}
|
2001-12-03 05:47:14 +01:00
|
|
|
|
2003-04-14 05:37:47 +02:00
|
|
|
verinum* pform_verinum_with_size(verinum*siz, verinum*val,
|
|
|
|
|
const char*file, unsigned lineno)
|
|
|
|
|
{
|
|
|
|
|
assert(siz->is_defined());
|
|
|
|
|
unsigned long size = siz->as_ulong();
|
|
|
|
|
|
2015-04-26 12:04:02 +02:00
|
|
|
if (size == 0) {
|
|
|
|
|
cerr << file << ":" << lineno << ": error: Sized numeric constant "
|
|
|
|
|
"must have a size greater than zero." << endl;
|
|
|
|
|
error_count += 1;
|
|
|
|
|
}
|
|
|
|
|
|
2003-04-14 05:37:47 +02:00
|
|
|
verinum::V pad;
|
|
|
|
|
|
2015-09-23 01:15:41 +02:00
|
|
|
if (val->len() == 0) {
|
2003-04-14 05:37:47 +02:00
|
|
|
pad = verinum::Vx;
|
2015-09-23 01:15:41 +02:00
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
switch (val->get(val->len()-1)) {
|
|
|
|
|
case verinum::Vz:
|
|
|
|
|
pad = verinum::Vz;
|
|
|
|
|
break;
|
|
|
|
|
case verinum::Vx:
|
|
|
|
|
pad = verinum::Vx;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
pad = verinum::V0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2003-04-14 05:37:47 +02:00
|
|
|
}
|
|
|
|
|
|
2007-01-27 06:36:11 +01:00
|
|
|
verinum*res = new verinum(pad, size, true);
|
2003-04-14 05:37:47 +02:00
|
|
|
|
|
|
|
|
unsigned copy = val->len();
|
|
|
|
|
if (res->len() < copy)
|
|
|
|
|
copy = res->len();
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < copy ; idx += 1) {
|
|
|
|
|
res->set(idx, val->get(idx));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
res->has_sign(val->has_sign());
|
|
|
|
|
|
|
|
|
|
bool trunc_flag = false;
|
|
|
|
|
for (unsigned idx = copy ; idx < val->len() ; idx += 1) {
|
|
|
|
|
if (val->get(idx) != pad) {
|
|
|
|
|
trunc_flag = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (trunc_flag) {
|
|
|
|
|
cerr << file << ":" << lineno << ": warning: Numeric constant "
|
|
|
|
|
<< "truncated to " << copy << " bits." << endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
delete siz;
|
|
|
|
|
delete val;
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-01 06:12:59 +02:00
|
|
|
void pform_startmodule(const struct vlltype&loc, const char*name,
|
2014-12-20 00:10:14 +01:00
|
|
|
bool program_block, bool is_interface,
|
2016-03-19 18:27:27 +01:00
|
|
|
LexicalScope::lifetime_t lifetime,
|
2014-12-20 00:10:14 +01:00
|
|
|
list<named_pexpr_t>*attr)
|
1998-11-04 00:28:49 +01:00
|
|
|
{
|
2012-08-08 20:26:46 +02:00
|
|
|
if (! pform_cur_module.empty() && !gn_system_verilog()) {
|
2012-05-10 04:35:11 +02:00
|
|
|
cerr << loc << ": error: Module definition " << name
|
|
|
|
|
<< " cannot nest into module " << pform_cur_module.front()->mod_name() << "." << endl;
|
|
|
|
|
error_count += 1;
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-05 10:49:34 +01:00
|
|
|
|
|
|
|
|
if (lifetime != LexicalScope::INHERITED) {
|
|
|
|
|
pform_requires_sv(loc, "Default subroutine lifetime");
|
2016-03-19 18:27:27 +01:00
|
|
|
}
|
|
|
|
|
|
2014-12-20 00:10:14 +01:00
|
|
|
if (gn_system_verilog() && ! pform_cur_module.empty()) {
|
|
|
|
|
if (pform_cur_module.front()->program_block) {
|
|
|
|
|
cerr << loc << ": error: module, program, or interface "
|
|
|
|
|
"declarations are not allowed in program "
|
|
|
|
|
"blocks." << endl;
|
|
|
|
|
error_count += 1;
|
|
|
|
|
}
|
|
|
|
|
if (pform_cur_module.front()->is_interface
|
|
|
|
|
&& !(program_block || is_interface)) {
|
|
|
|
|
cerr << loc << ": error: module declarations are not "
|
|
|
|
|
"allowed in interfaces." << endl;
|
|
|
|
|
error_count += 1;
|
|
|
|
|
}
|
2012-05-15 04:13:57 +02:00
|
|
|
}
|
1999-09-17 04:06:25 +02:00
|
|
|
|
2004-02-18 18:11:54 +01:00
|
|
|
perm_string lex_name = lex_strings.make(name);
|
2012-05-10 04:35:11 +02:00
|
|
|
Module*cur_module = new Module(lexical_scope, lex_name);
|
|
|
|
|
cur_module->program_block = program_block;
|
2014-12-20 00:10:14 +01:00
|
|
|
cur_module->is_interface = is_interface;
|
2016-03-19 18:27:27 +01:00
|
|
|
cur_module->default_lifetime = find_lifetime(lifetime);
|
|
|
|
|
|
2016-07-22 23:48:20 +02:00
|
|
|
FILE_NAME(cur_module, loc);
|
|
|
|
|
|
2012-05-10 04:35:11 +02:00
|
|
|
cur_module->library_flag = pform_library_flag;
|
2001-10-31 04:11:15 +01:00
|
|
|
|
2012-05-10 04:35:11 +02:00
|
|
|
pform_cur_module.push_front(cur_module);
|
|
|
|
|
|
2017-11-05 18:50:05 +01:00
|
|
|
allow_timeunit_decl = true;
|
|
|
|
|
allow_timeprec_decl = true;
|
|
|
|
|
|
2021-08-03 22:29:46 +02:00
|
|
|
pform_generate_single_item = false;
|
|
|
|
|
|
2019-09-27 00:35:57 +02:00
|
|
|
add_local_symbol(lexical_scope, lex_name, cur_module);
|
|
|
|
|
|
2012-05-10 04:35:11 +02:00
|
|
|
lexical_scope = cur_module;
|
2008-02-25 04:40:54 +01:00
|
|
|
|
2012-05-10 04:35:11 +02:00
|
|
|
pform_bind_attributes(cur_module->attributes, attr);
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-10 14:03:46 +01:00
|
|
|
void pform_start_parameter_port_list()
|
|
|
|
|
{
|
|
|
|
|
pform_in_parameter_port_list = true;
|
2022-02-05 12:04:55 +01:00
|
|
|
pform_peek_scope()->has_parameter_port_list = true;
|
2022-02-10 14:03:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void pform_end_parameter_port_list()
|
|
|
|
|
{
|
|
|
|
|
pform_in_parameter_port_list = false;
|
|
|
|
|
}
|
|
|
|
|
|
2002-05-20 01:37:28 +02:00
|
|
|
/*
|
|
|
|
|
* This function is called by the parser to make a simple port
|
|
|
|
|
* reference. This is a name without a .X(...), so the internal name
|
|
|
|
|
* should be generated to be the same as the X.
|
|
|
|
|
*/
|
2022-01-10 11:21:14 +01:00
|
|
|
Module::port_t* pform_module_port_reference(const struct vlltype&loc,
|
|
|
|
|
perm_string name)
|
2002-05-20 01:37:28 +02:00
|
|
|
{
|
|
|
|
|
Module::port_t*ptmp = new Module::port_t;
|
2008-02-25 04:40:54 +01:00
|
|
|
PEIdent*tmp = new PEIdent(name);
|
2022-01-10 11:21:14 +01:00
|
|
|
FILE_NAME(tmp, loc);
|
2008-02-25 04:40:54 +01:00
|
|
|
ptmp->name = name;
|
2008-11-03 05:08:38 +01:00
|
|
|
ptmp->expr.push_back(tmp);
|
2021-03-10 09:21:42 +01:00
|
|
|
ptmp->default_value = 0;
|
2002-05-20 01:37:28 +02:00
|
|
|
|
|
|
|
|
return ptmp;
|
|
|
|
|
}
|
|
|
|
|
|
2008-11-03 05:08:38 +01:00
|
|
|
void pform_module_set_ports(vector<Module::port_t*>*ports)
|
2002-05-20 01:37:28 +02:00
|
|
|
{
|
2012-08-08 20:26:46 +02:00
|
|
|
assert(! pform_cur_module.empty());
|
2002-05-20 01:37:28 +02:00
|
|
|
|
|
|
|
|
/* The parser parses ``module foo()'' as having one
|
|
|
|
|
unconnected port, but it is really a module with no
|
|
|
|
|
ports. Fix it up here. */
|
2008-11-03 05:08:38 +01:00
|
|
|
if (ports && (ports->size() == 1) && ((*ports)[0] == 0)) {
|
2002-05-20 01:37:28 +02:00
|
|
|
delete ports;
|
|
|
|
|
ports = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ports != 0) {
|
2012-05-10 04:35:11 +02:00
|
|
|
pform_cur_module.front()->ports = *ports;
|
2002-05-20 01:37:28 +02:00
|
|
|
delete ports;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-13 03:53:56 +02:00
|
|
|
void pform_endmodule(const char*name, bool inside_celldefine,
|
|
|
|
|
Module::UCDriveType uc_drive_def)
|
1998-11-04 00:28:49 +01:00
|
|
|
{
|
2019-10-02 00:19:46 +02:00
|
|
|
// The parser will not call pform_endmodule() without first
|
|
|
|
|
// calling pform_startmodule(). Thus, it is impossible for the
|
|
|
|
|
// pform_cur_module stack to be empty at this point.
|
2012-08-08 20:26:46 +02:00
|
|
|
assert(! pform_cur_module.empty());
|
2012-05-10 04:35:11 +02:00
|
|
|
Module*cur_module = pform_cur_module.front();
|
|
|
|
|
pform_cur_module.pop_front();
|
|
|
|
|
perm_string mod_name = cur_module->mod_name();
|
2019-10-02 00:19:46 +02:00
|
|
|
|
|
|
|
|
// Oops, there may be some sort of nesting problem. If
|
|
|
|
|
// SystemVerilog is activated, it is possible for modules to
|
|
|
|
|
// be nested. But if the nested module is broken, the parser
|
|
|
|
|
// will recover and treat is as an invalid module item,
|
|
|
|
|
// leaving the pform_cur_module stack in an inconsistent
|
|
|
|
|
// state. For example, this:
|
|
|
|
|
// module foo;
|
|
|
|
|
// module bar blah blab blah error;
|
|
|
|
|
// endmodule
|
|
|
|
|
// may leave the pform_cur_module stack with the dregs of the
|
|
|
|
|
// bar module. Try to find the foo module in the stack, and
|
|
|
|
|
// print error messages as we go.
|
|
|
|
|
if (strcmp(name, mod_name) != 0) {
|
2021-01-02 23:04:06 +01:00
|
|
|
while (!pform_cur_module.empty()) {
|
2019-10-02 00:19:46 +02:00
|
|
|
Module*tmp_module = pform_cur_module.front();
|
|
|
|
|
perm_string tmp_name = tmp_module->mod_name();
|
|
|
|
|
pform_cur_module.pop_front();
|
|
|
|
|
ostringstream msg;
|
|
|
|
|
msg << "Module " << mod_name
|
|
|
|
|
<< " was nested within " << tmp_name
|
|
|
|
|
<< " but broken.";
|
|
|
|
|
VLerror(msg.str().c_str());
|
|
|
|
|
|
|
|
|
|
ivl_assert(*cur_module, lexical_scope == cur_module);
|
|
|
|
|
pform_pop_scope();
|
|
|
|
|
delete cur_module;
|
|
|
|
|
|
|
|
|
|
cur_module = tmp_module;
|
|
|
|
|
mod_name = tmp_name;
|
|
|
|
|
if (strcmp(name, mod_name) == 0)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2004-02-18 18:11:54 +01:00
|
|
|
assert(strcmp(name, mod_name) == 0);
|
2019-10-02 00:19:46 +02:00
|
|
|
|
2012-05-10 04:35:11 +02:00
|
|
|
cur_module->is_cell = inside_celldefine;
|
|
|
|
|
cur_module->uc_drive = uc_drive_def;
|
|
|
|
|
|
|
|
|
|
// If this is a root module, then there is no parent module
|
|
|
|
|
// and we try to put this newly defined module into the global
|
|
|
|
|
// root list of modules. Otherwise, this is a nested module
|
|
|
|
|
// and we put it into the parent module scope to be elaborated
|
|
|
|
|
// if needed.
|
2012-08-08 20:26:46 +02:00
|
|
|
map<perm_string,Module*>&use_module_map = (pform_cur_module.empty())
|
2012-05-10 04:35:11 +02:00
|
|
|
? pform_modules
|
|
|
|
|
: pform_cur_module.front()->nested_modules;
|
2004-02-18 18:11:54 +01:00
|
|
|
|
2004-10-04 03:10:51 +02:00
|
|
|
map<perm_string,Module*>::const_iterator test =
|
2012-05-10 04:35:11 +02:00
|
|
|
use_module_map.find(mod_name);
|
2003-01-16 22:44:19 +01:00
|
|
|
|
2012-05-10 04:35:11 +02:00
|
|
|
if (test != use_module_map.end()) {
|
2003-01-16 22:44:19 +01:00
|
|
|
ostringstream msg;
|
|
|
|
|
msg << "Module " << name << " was already declared here: "
|
2012-05-10 04:35:11 +02:00
|
|
|
<< test->second->get_fileline() << endl;
|
2003-01-16 22:44:19 +01:00
|
|
|
VLerror(msg.str().c_str());
|
2008-04-10 06:09:55 +02:00
|
|
|
} else {
|
2012-05-10 04:35:11 +02:00
|
|
|
use_module_map[mod_name] = cur_module;
|
2003-01-16 22:44:19 +01:00
|
|
|
}
|
2008-02-25 04:40:54 +01:00
|
|
|
|
2017-10-21 16:04:25 +02:00
|
|
|
// The current lexical scope should be this module by now.
|
2012-05-10 04:35:11 +02:00
|
|
|
ivl_assert(*cur_module, lexical_scope == cur_module);
|
2010-01-08 23:49:48 +01:00
|
|
|
pform_pop_scope();
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
2008-05-06 04:46:30 +02:00
|
|
|
void pform_genvars(const struct vlltype&li, list<perm_string>*names)
|
2006-04-10 02:37:42 +02:00
|
|
|
{
|
|
|
|
|
list<perm_string>::const_iterator cur;
|
|
|
|
|
for (cur = names->begin(); cur != names->end() ; *cur++) {
|
2019-09-27 00:35:57 +02:00
|
|
|
PGenvar*genvar = new PGenvar();
|
|
|
|
|
FILE_NAME(genvar, li);
|
|
|
|
|
|
|
|
|
|
if (pform_cur_generate) {
|
|
|
|
|
add_local_symbol(pform_cur_generate, *cur, genvar);
|
|
|
|
|
pform_cur_generate->genvars[*cur] = genvar;
|
|
|
|
|
} else {
|
|
|
|
|
add_local_symbol(pform_cur_module.front(), *cur, genvar);
|
|
|
|
|
pform_cur_module.front()->genvars[*cur] = genvar;
|
|
|
|
|
}
|
2006-04-10 02:37:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
delete names;
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-04 12:58:18 +02:00
|
|
|
static unsigned detect_directly_nested_generate()
|
2021-08-03 22:29:46 +02:00
|
|
|
{
|
|
|
|
|
if (pform_cur_generate && pform_generate_single_item)
|
|
|
|
|
switch (pform_cur_generate->scheme_type) {
|
|
|
|
|
case PGenerate::GS_CASE_ITEM:
|
|
|
|
|
// fallthrough
|
|
|
|
|
case PGenerate::GS_CONDIT:
|
|
|
|
|
// fallthrough
|
|
|
|
|
case PGenerate::GS_ELSE:
|
|
|
|
|
pform_cur_generate->directly_nested = true;
|
2021-08-04 12:58:18 +02:00
|
|
|
return pform_cur_generate->id_number;
|
2021-08-03 22:29:46 +02:00
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
2021-08-04 12:58:18 +02:00
|
|
|
|
|
|
|
|
return ++lexical_scope->generate_counter;
|
2021-08-03 22:29:46 +02:00
|
|
|
}
|
|
|
|
|
|
2006-04-10 02:37:42 +02:00
|
|
|
void pform_start_generate_for(const struct vlltype&li,
|
2020-01-31 21:29:22 +01:00
|
|
|
bool local_index,
|
2006-04-10 02:37:42 +02:00
|
|
|
char*ident1, PExpr*init,
|
|
|
|
|
PExpr*test,
|
|
|
|
|
char*ident2, PExpr*next)
|
|
|
|
|
{
|
2021-08-04 12:58:18 +02:00
|
|
|
PGenerate*gen = new PGenerate(lexical_scope, ++lexical_scope->generate_counter);
|
2010-01-08 23:49:48 +01:00
|
|
|
lexical_scope = gen;
|
2006-04-10 02:37:42 +02:00
|
|
|
|
2007-12-20 18:31:01 +01:00
|
|
|
FILE_NAME(gen, li);
|
2006-04-10 02:37:42 +02:00
|
|
|
|
|
|
|
|
pform_cur_generate = gen;
|
|
|
|
|
|
|
|
|
|
pform_cur_generate->scheme_type = PGenerate::GS_LOOP;
|
|
|
|
|
|
2020-01-31 21:29:22 +01:00
|
|
|
pform_cur_generate->local_index = local_index;
|
2006-04-10 02:37:42 +02:00
|
|
|
pform_cur_generate->loop_index = lex_strings.make(ident1);
|
|
|
|
|
pform_cur_generate->loop_init = init;
|
|
|
|
|
pform_cur_generate->loop_test = test;
|
|
|
|
|
pform_cur_generate->loop_step = next;
|
|
|
|
|
|
|
|
|
|
delete[]ident1;
|
|
|
|
|
delete[]ident2;
|
|
|
|
|
}
|
|
|
|
|
|
2007-06-22 04:04:48 +02:00
|
|
|
void pform_start_generate_if(const struct vlltype&li, PExpr*test)
|
|
|
|
|
{
|
2021-08-04 12:58:18 +02:00
|
|
|
unsigned id_number = detect_directly_nested_generate();
|
2021-08-03 22:29:46 +02:00
|
|
|
|
2021-08-04 12:58:18 +02:00
|
|
|
PGenerate*gen = new PGenerate(lexical_scope, id_number);
|
2010-01-08 23:49:48 +01:00
|
|
|
lexical_scope = gen;
|
2007-06-22 04:04:48 +02:00
|
|
|
|
2007-12-20 18:31:01 +01:00
|
|
|
FILE_NAME(gen, li);
|
2007-06-22 04:04:48 +02:00
|
|
|
|
|
|
|
|
pform_cur_generate = gen;
|
|
|
|
|
|
|
|
|
|
pform_cur_generate->scheme_type = PGenerate::GS_CONDIT;
|
|
|
|
|
|
|
|
|
|
pform_cur_generate->loop_init = 0;
|
|
|
|
|
pform_cur_generate->loop_test = test;
|
|
|
|
|
pform_cur_generate->loop_step = 0;
|
2019-09-27 00:35:57 +02:00
|
|
|
|
|
|
|
|
conditional_block_names.push_front(set<perm_string>());
|
2007-06-22 04:04:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void pform_start_generate_else(const struct vlltype&li)
|
|
|
|
|
{
|
|
|
|
|
assert(pform_cur_generate);
|
|
|
|
|
assert(pform_cur_generate->scheme_type == PGenerate::GS_CONDIT);
|
|
|
|
|
|
|
|
|
|
PGenerate*cur = pform_cur_generate;
|
2019-09-27 00:35:57 +02:00
|
|
|
pform_endgenerate(false);
|
2007-06-22 04:04:48 +02:00
|
|
|
|
2021-08-04 12:58:18 +02:00
|
|
|
PGenerate*gen = new PGenerate(lexical_scope, cur->id_number);
|
2010-01-08 23:49:48 +01:00
|
|
|
lexical_scope = gen;
|
2007-06-22 04:04:48 +02:00
|
|
|
|
2007-12-20 18:31:01 +01:00
|
|
|
FILE_NAME(gen, li);
|
2007-06-22 04:04:48 +02:00
|
|
|
|
|
|
|
|
pform_cur_generate = gen;
|
|
|
|
|
|
|
|
|
|
pform_cur_generate->scheme_type = PGenerate::GS_ELSE;
|
|
|
|
|
|
|
|
|
|
pform_cur_generate->loop_init = 0;
|
|
|
|
|
pform_cur_generate->loop_test = cur->loop_test;
|
|
|
|
|
pform_cur_generate->loop_step = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2008-02-10 07:19:42 +01:00
|
|
|
/*
|
|
|
|
|
* The GS_CASE version of the PGenerate contains only case items. The
|
|
|
|
|
* items in turn contain the generated items themselves.
|
|
|
|
|
*/
|
|
|
|
|
void pform_start_generate_case(const struct vlltype&li, PExpr*expr)
|
|
|
|
|
{
|
2021-08-04 12:58:18 +02:00
|
|
|
unsigned id_number = detect_directly_nested_generate();
|
2021-08-03 22:29:46 +02:00
|
|
|
|
2021-08-04 12:58:18 +02:00
|
|
|
PGenerate*gen = new PGenerate(lexical_scope, id_number);
|
2010-01-08 23:49:48 +01:00
|
|
|
lexical_scope = gen;
|
2008-02-10 07:19:42 +01:00
|
|
|
|
|
|
|
|
FILE_NAME(gen, li);
|
|
|
|
|
|
|
|
|
|
pform_cur_generate = gen;
|
|
|
|
|
|
|
|
|
|
pform_cur_generate->scheme_type = PGenerate::GS_CASE;
|
|
|
|
|
|
|
|
|
|
pform_cur_generate->loop_init = 0;
|
|
|
|
|
pform_cur_generate->loop_test = expr;
|
|
|
|
|
pform_cur_generate->loop_step = 0;
|
2019-09-27 00:35:57 +02:00
|
|
|
|
|
|
|
|
conditional_block_names.push_front(set<perm_string>());
|
2008-02-10 07:19:42 +01:00
|
|
|
}
|
|
|
|
|
|
2008-11-15 03:35:39 +01:00
|
|
|
/*
|
|
|
|
|
* The named block generate case.
|
|
|
|
|
*/
|
|
|
|
|
void pform_start_generate_nblock(const struct vlltype&li, char*name)
|
|
|
|
|
{
|
2021-08-04 12:58:18 +02:00
|
|
|
PGenerate*gen = new PGenerate(lexical_scope, ++lexical_scope->generate_counter);
|
2010-01-08 23:49:48 +01:00
|
|
|
lexical_scope = gen;
|
2008-11-15 03:35:39 +01:00
|
|
|
|
|
|
|
|
FILE_NAME(gen, li);
|
|
|
|
|
|
|
|
|
|
pform_cur_generate = gen;
|
|
|
|
|
|
|
|
|
|
pform_cur_generate->scheme_type = PGenerate::GS_NBLOCK;
|
|
|
|
|
|
|
|
|
|
pform_cur_generate->loop_init = 0;
|
|
|
|
|
pform_cur_generate->loop_test = 0;
|
|
|
|
|
pform_cur_generate->loop_step = 0;
|
|
|
|
|
|
|
|
|
|
pform_cur_generate->scope_name = lex_strings.make(name);
|
|
|
|
|
delete[]name;
|
2019-09-27 00:35:57 +02:00
|
|
|
|
|
|
|
|
add_local_symbol(pform_cur_generate->parent_scope(),
|
|
|
|
|
pform_cur_generate->scope_name,
|
|
|
|
|
pform_cur_generate);
|
2008-11-15 03:35:39 +01:00
|
|
|
}
|
|
|
|
|
|
2008-02-10 07:19:42 +01:00
|
|
|
/*
|
|
|
|
|
* The generate case item is a special case schema that takes its id
|
|
|
|
|
* from the case schema that it is a part of. The idea is that the
|
|
|
|
|
* case schema can only instantiate exactly one item, so the items
|
|
|
|
|
* need not have a unique number.
|
|
|
|
|
*/
|
2010-10-26 04:36:44 +02:00
|
|
|
void pform_generate_case_item(const struct vlltype&li, list<PExpr*>*expr_list)
|
2008-02-10 07:19:42 +01:00
|
|
|
{
|
|
|
|
|
assert(pform_cur_generate);
|
|
|
|
|
assert(pform_cur_generate->scheme_type == PGenerate::GS_CASE);
|
|
|
|
|
|
2010-01-08 23:49:48 +01:00
|
|
|
PGenerate*gen = new PGenerate(lexical_scope, pform_cur_generate->id_number);
|
|
|
|
|
lexical_scope = gen;
|
2008-02-10 07:19:42 +01:00
|
|
|
|
|
|
|
|
FILE_NAME(gen, li);
|
|
|
|
|
|
2021-08-03 22:29:46 +02:00
|
|
|
gen->directly_nested = pform_cur_generate->directly_nested;
|
|
|
|
|
|
2008-02-10 07:19:42 +01:00
|
|
|
pform_cur_generate = gen;
|
|
|
|
|
|
|
|
|
|
pform_cur_generate->scheme_type = PGenerate::GS_CASE_ITEM;
|
|
|
|
|
|
|
|
|
|
pform_cur_generate->loop_init = 0;
|
2008-11-28 04:45:22 +01:00
|
|
|
pform_cur_generate->loop_test = 0;
|
2008-02-10 07:19:42 +01:00
|
|
|
pform_cur_generate->loop_step = 0;
|
2008-11-28 04:45:22 +01:00
|
|
|
|
|
|
|
|
if (expr_list != 0) {
|
2010-10-26 04:36:44 +02:00
|
|
|
list<PExpr*>::iterator expr_cur = expr_list->begin();
|
|
|
|
|
pform_cur_generate->item_test.resize(expr_list->size());
|
|
|
|
|
for (unsigned idx = 0 ; idx < expr_list->size() ; idx += 1) {
|
|
|
|
|
pform_cur_generate->item_test[idx] = *expr_cur;
|
|
|
|
|
++ expr_cur;
|
|
|
|
|
}
|
|
|
|
|
assert(expr_cur == expr_list->end());
|
2008-11-28 04:45:22 +01:00
|
|
|
}
|
2008-02-10 07:19:42 +01:00
|
|
|
}
|
|
|
|
|
|
2006-04-10 02:37:42 +02:00
|
|
|
void pform_generate_block_name(char*name)
|
|
|
|
|
{
|
|
|
|
|
assert(pform_cur_generate != 0);
|
|
|
|
|
assert(pform_cur_generate->scope_name == 0);
|
2019-09-27 00:35:57 +02:00
|
|
|
perm_string scope_name = lex_strings.make(name);
|
|
|
|
|
pform_cur_generate->scope_name = scope_name;
|
|
|
|
|
|
|
|
|
|
if (pform_cur_generate->scheme_type == PGenerate::GS_CONDIT
|
|
|
|
|
|| pform_cur_generate->scheme_type == PGenerate::GS_ELSE
|
|
|
|
|
|| pform_cur_generate->scheme_type == PGenerate::GS_CASE_ITEM) {
|
|
|
|
|
|
|
|
|
|
if (conditional_block_names.front().count(scope_name))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
conditional_block_names.front().insert(scope_name);
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-27 21:04:09 +02:00
|
|
|
LexicalScope*parent_scope = pform_cur_generate->parent_scope();
|
|
|
|
|
assert(parent_scope);
|
|
|
|
|
if (pform_cur_generate->scheme_type == PGenerate::GS_CASE_ITEM)
|
|
|
|
|
// Skip over the PGenerate::GS_CASE container.
|
|
|
|
|
parent_scope = parent_scope->parent_scope();
|
|
|
|
|
|
|
|
|
|
add_local_symbol(parent_scope, scope_name, pform_cur_generate);
|
2006-04-10 02:37:42 +02:00
|
|
|
}
|
|
|
|
|
|
2019-09-27 00:35:57 +02:00
|
|
|
void pform_endgenerate(bool end_conditional)
|
2006-04-10 02:37:42 +02:00
|
|
|
{
|
|
|
|
|
assert(pform_cur_generate != 0);
|
2012-08-08 20:26:46 +02:00
|
|
|
assert(! pform_cur_module.empty());
|
2006-04-10 02:37:42 +02:00
|
|
|
|
2019-09-27 00:35:57 +02:00
|
|
|
if (end_conditional)
|
|
|
|
|
conditional_block_names.pop_front();
|
|
|
|
|
|
2007-11-17 19:17:23 +01:00
|
|
|
// If there is no explicit block name then generate a temporary
|
|
|
|
|
// name. This will be replaced by the correct name later, once
|
|
|
|
|
// we know all the explicit names in the surrounding scope. If
|
|
|
|
|
// the naming scheme used here is changed, PGenerate::elaborate
|
|
|
|
|
// must be changed to match.
|
2007-06-22 04:04:48 +02:00
|
|
|
if (pform_cur_generate->scope_name == 0) {
|
|
|
|
|
char tmp[16];
|
2013-09-09 22:32:55 +02:00
|
|
|
snprintf(tmp, sizeof tmp, "$gen%u", pform_cur_generate->id_number);
|
2007-06-22 04:04:48 +02:00
|
|
|
pform_cur_generate->scope_name = lex_strings.make(tmp);
|
|
|
|
|
}
|
|
|
|
|
|
2010-01-08 23:49:48 +01:00
|
|
|
// The current lexical scope should be this generate construct by now
|
|
|
|
|
ivl_assert(*pform_cur_generate, lexical_scope == pform_cur_generate);
|
|
|
|
|
pform_pop_scope();
|
2007-06-02 05:42:12 +02:00
|
|
|
|
2010-01-08 23:49:48 +01:00
|
|
|
PGenerate*parent_generate = dynamic_cast<PGenerate*>(lexical_scope);
|
|
|
|
|
if (parent_generate) {
|
|
|
|
|
assert(pform_cur_generate->scheme_type == PGenerate::GS_CASE_ITEM
|
|
|
|
|
|| parent_generate->scheme_type != PGenerate::GS_CASE);
|
|
|
|
|
parent_generate->generate_schemes.push_back(pform_cur_generate);
|
2008-02-10 07:19:42 +01:00
|
|
|
} else {
|
2010-01-08 23:49:48 +01:00
|
|
|
assert(pform_cur_generate->scheme_type != PGenerate::GS_CASE_ITEM);
|
2012-05-10 04:35:11 +02:00
|
|
|
pform_cur_module.front()->generate_schemes.push_back(pform_cur_generate);
|
2008-02-10 07:19:42 +01:00
|
|
|
}
|
2010-01-08 23:49:48 +01:00
|
|
|
pform_cur_generate = parent_generate;
|
2006-04-10 02:37:42 +02:00
|
|
|
}
|
|
|
|
|
|
2021-02-01 09:20:09 +01:00
|
|
|
void pform_make_elab_task(const struct vlltype&li,
|
|
|
|
|
perm_string name,
|
|
|
|
|
const list<PExpr*>¶ms)
|
|
|
|
|
{
|
|
|
|
|
PCallTask*elab_task = new PCallTask(name, params);
|
|
|
|
|
FILE_NAME(elab_task, li);
|
|
|
|
|
|
|
|
|
|
lexical_scope->elab_tasks.push_back(elab_task);
|
|
|
|
|
}
|
|
|
|
|
|
2000-07-29 19:58:20 +02:00
|
|
|
MIN_TYP_MAX min_typ_max_flag = TYP;
|
|
|
|
|
unsigned min_typ_max_warn = 10;
|
|
|
|
|
|
|
|
|
|
PExpr* pform_select_mtm_expr(PExpr*min, PExpr*typ, PExpr*max)
|
|
|
|
|
{
|
|
|
|
|
PExpr*res = 0;
|
|
|
|
|
|
|
|
|
|
switch (min_typ_max_flag) {
|
|
|
|
|
case MIN:
|
|
|
|
|
res = min;
|
|
|
|
|
delete typ;
|
|
|
|
|
delete max;
|
|
|
|
|
break;
|
|
|
|
|
case TYP:
|
|
|
|
|
res = typ;
|
|
|
|
|
delete min;
|
|
|
|
|
delete max;
|
|
|
|
|
break;
|
|
|
|
|
case MAX:
|
|
|
|
|
res = max;
|
|
|
|
|
delete min;
|
2001-05-20 17:03:25 +02:00
|
|
|
delete typ;
|
2000-07-29 19:58:20 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (min_typ_max_warn > 0) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << res->get_fileline() << ": warning: choosing ";
|
2000-07-29 19:58:20 +02:00
|
|
|
switch (min_typ_max_flag) {
|
|
|
|
|
case MIN:
|
|
|
|
|
cerr << "min";
|
|
|
|
|
break;
|
|
|
|
|
case TYP:
|
|
|
|
|
cerr << "typ";
|
|
|
|
|
break;
|
|
|
|
|
case MAX:
|
|
|
|
|
cerr << "max";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cerr << " expression." << endl;
|
|
|
|
|
min_typ_max_warn -= 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
2004-03-08 01:10:29 +01:00
|
|
|
static void process_udp_table(PUdp*udp, list<string>*table,
|
2022-01-10 11:21:14 +01:00
|
|
|
const struct vlltype&loc)
|
2004-03-08 01:10:29 +01:00
|
|
|
{
|
|
|
|
|
const bool synchronous_flag = udp->sequential;
|
|
|
|
|
|
|
|
|
|
/* Interpret and check the table entry strings, to make sure
|
|
|
|
|
they correspond to the inputs, output and output type. Make
|
|
|
|
|
up vectors for the fully interpreted result that can be
|
|
|
|
|
placed in the PUdp object.
|
|
|
|
|
|
|
|
|
|
The table strings are made up by the parser to be two or
|
2008-01-25 22:34:51 +01:00
|
|
|
three substrings separated by ';', i.e.:
|
2004-03-08 01:10:29 +01:00
|
|
|
|
|
|
|
|
0101:1:1 (synchronous device entry)
|
|
|
|
|
0101:0 (combinational device entry)
|
|
|
|
|
|
|
|
|
|
The parser doesn't check that we got the right kind here,
|
|
|
|
|
so this loop must watch out. */
|
2022-02-17 10:48:43 +01:00
|
|
|
std::vector<string> &input = udp->tinput;
|
|
|
|
|
std::vector<char> ¤t = udp->tcurrent;
|
|
|
|
|
std::vector<char> &output = udp->toutput;
|
|
|
|
|
|
|
|
|
|
input.resize(table->size());
|
|
|
|
|
current.resize(table->size());
|
|
|
|
|
output.resize(table->size());
|
|
|
|
|
|
2004-03-08 01:10:29 +01:00
|
|
|
{ unsigned idx = 0;
|
|
|
|
|
for (list<string>::iterator cur = table->begin()
|
2010-10-23 23:57:59 +02:00
|
|
|
; cur != table->end() ; ++ cur , idx += 1) {
|
2004-03-08 01:10:29 +01:00
|
|
|
string tmp = *cur;
|
|
|
|
|
|
|
|
|
|
/* Pull the input values from the string. */
|
2022-02-17 10:48:43 +01:00
|
|
|
assert(tmp.find(':') == (udp->ports.size() - 1));
|
|
|
|
|
input[idx] = tmp.substr(0, udp->ports.size()-1);
|
|
|
|
|
tmp = tmp.substr(udp->ports.size()-1);
|
2004-03-08 01:10:29 +01:00
|
|
|
|
|
|
|
|
assert(tmp[0] == ':');
|
|
|
|
|
|
|
|
|
|
/* If this is a synchronous device, get the current
|
|
|
|
|
output string. */
|
|
|
|
|
if (synchronous_flag) {
|
|
|
|
|
if (tmp.size() != 4) {
|
2022-01-10 11:21:14 +01:00
|
|
|
cerr << loc << ": error: "
|
2004-03-08 01:10:29 +01:00
|
|
|
<< "Invalid table format for"
|
|
|
|
|
<< " sequential primitive." << endl;
|
|
|
|
|
error_count += 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
assert(tmp.size() == 4);
|
|
|
|
|
current[idx] = tmp[1];
|
|
|
|
|
tmp = tmp.substr(2);
|
|
|
|
|
|
|
|
|
|
} else if (tmp.size() != 2) {
|
2022-01-10 11:21:14 +01:00
|
|
|
cerr << loc << ": error: "
|
2004-03-08 01:10:29 +01:00
|
|
|
<< "Invalid table format for"
|
|
|
|
|
<< " combinational primitive." << endl;
|
|
|
|
|
error_count += 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Finally, extract the desired output. */
|
|
|
|
|
assert(tmp.size() == 2);
|
|
|
|
|
output[idx] = tmp[1];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-10 11:21:14 +01:00
|
|
|
void pform_make_udp(const struct vlltype&loc, perm_string name,
|
|
|
|
|
list<perm_string>*parms, vector<PWire*>*decl,
|
|
|
|
|
list<string>*table, Statement*init_expr)
|
1998-11-25 03:35:53 +01:00
|
|
|
{
|
2001-10-21 03:55:24 +02:00
|
|
|
unsigned local_errors = 0;
|
2010-04-14 06:29:15 +02:00
|
|
|
assert(!parms->empty());
|
1998-11-25 03:35:53 +01:00
|
|
|
|
2013-02-25 03:06:12 +01:00
|
|
|
assert(decl);
|
|
|
|
|
|
1998-11-25 03:35:53 +01:00
|
|
|
/* Put the declarations into a map, so that I can check them
|
1999-06-17 07:34:42 +02:00
|
|
|
off with the parameters in the list. If the port is already
|
|
|
|
|
in the map, merge the port type. I will rebuild a list
|
1998-11-25 03:35:53 +01:00
|
|
|
of parameters for the PUdp object. */
|
2008-02-25 04:40:54 +01:00
|
|
|
map<perm_string,PWire*> defs;
|
2013-02-25 03:06:12 +01:00
|
|
|
for (unsigned idx = 0 ; idx < decl->size() ; idx += 1) {
|
1999-06-17 07:34:42 +02:00
|
|
|
|
2008-02-25 04:40:54 +01:00
|
|
|
perm_string port_name = (*decl)[idx]->basename();
|
2001-12-03 05:47:14 +01:00
|
|
|
|
2007-05-24 06:07:11 +02:00
|
|
|
if (PWire*cur = defs[port_name]) {
|
1999-06-21 03:02:16 +02:00
|
|
|
bool rc = true;
|
|
|
|
|
assert((*decl)[idx]);
|
|
|
|
|
if ((*decl)[idx]->get_port_type() != NetNet::PIMPLICIT) {
|
|
|
|
|
rc = cur->set_port_type((*decl)[idx]->get_port_type());
|
|
|
|
|
assert(rc);
|
|
|
|
|
}
|
|
|
|
|
if ((*decl)[idx]->get_wire_type() != NetNet::IMPLICIT) {
|
|
|
|
|
rc = cur->set_wire_type((*decl)[idx]->get_wire_type());
|
|
|
|
|
assert(rc);
|
|
|
|
|
}
|
1999-06-17 07:34:42 +02:00
|
|
|
|
|
|
|
|
} else {
|
2007-05-24 06:07:11 +02:00
|
|
|
defs[port_name] = (*decl)[idx];
|
1998-11-25 03:35:53 +01:00
|
|
|
}
|
1999-06-17 07:34:42 +02:00
|
|
|
}
|
1998-11-25 03:35:53 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Put the parameters into a vector of wire descriptions. Look
|
2001-10-21 03:55:24 +02:00
|
|
|
in the map for the definitions of the name. In this loop,
|
|
|
|
|
the parms list in the list of ports in the port list of the
|
|
|
|
|
UDP declaration, and the defs map maps that name to a
|
|
|
|
|
PWire* created by an input or output declaration. */
|
2022-02-17 10:48:43 +01:00
|
|
|
std::vector<PWire*> pins(parms->size());
|
|
|
|
|
std::vector<perm_string> pin_names(parms->size());
|
2008-02-25 04:40:54 +01:00
|
|
|
{ list<perm_string>::iterator cur;
|
1998-11-25 03:35:53 +01:00
|
|
|
unsigned idx;
|
|
|
|
|
for (cur = parms->begin(), idx = 0
|
|
|
|
|
; cur != parms->end()
|
2014-06-30 05:38:23 +02:00
|
|
|
; ++ idx, ++ cur) {
|
1998-11-25 03:35:53 +01:00
|
|
|
pins[idx] = defs[*cur];
|
2001-10-21 03:55:24 +02:00
|
|
|
pin_names[idx] = *cur;
|
1998-11-25 03:35:53 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Check that the output is an output and the inputs are
|
|
|
|
|
inputs. I can also make sure that only the single output is
|
2001-10-21 03:55:24 +02:00
|
|
|
declared a register, if anything. The possible errors are:
|
|
|
|
|
|
|
|
|
|
-- an input port (not the first) is missing an input
|
|
|
|
|
declaration.
|
|
|
|
|
|
|
|
|
|
-- An input port is declared output.
|
|
|
|
|
|
|
|
|
|
*/
|
2022-02-17 10:48:43 +01:00
|
|
|
assert(pins.size() > 0);
|
2001-10-21 03:55:24 +02:00
|
|
|
do {
|
|
|
|
|
if (pins[0] == 0) {
|
2022-01-10 11:21:14 +01:00
|
|
|
cerr << loc << ": error: "
|
2001-10-21 03:55:24 +02:00
|
|
|
<< "Output port of primitive " << name
|
|
|
|
|
<< " missing output declaration." << endl;
|
2022-01-10 11:21:14 +01:00
|
|
|
cerr << loc << ": : "
|
2001-10-21 03:55:24 +02:00
|
|
|
<< "Try: output " << pin_names[0] << ";"
|
|
|
|
|
<< endl;
|
|
|
|
|
error_count += 1;
|
|
|
|
|
local_errors += 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (pins[0]->get_port_type() != NetNet::POUTPUT) {
|
2022-01-10 11:21:14 +01:00
|
|
|
cerr << loc << ": error: "
|
2001-10-21 03:55:24 +02:00
|
|
|
<< "The first port of a primitive"
|
|
|
|
|
<< " must be an output." << endl;
|
2022-01-10 11:21:14 +01:00
|
|
|
cerr << loc << ": : "
|
2001-10-21 03:55:24 +02:00
|
|
|
<< "Try: output " << pin_names[0] << ";"
|
|
|
|
|
<< endl;
|
|
|
|
|
error_count += 1;
|
|
|
|
|
local_errors += 1;
|
|
|
|
|
break;;
|
|
|
|
|
}
|
|
|
|
|
} while (0);
|
|
|
|
|
|
2022-02-17 10:48:43 +01:00
|
|
|
for (unsigned idx = 1 ; idx < pins.size() ; idx += 1) {
|
2001-10-21 03:55:24 +02:00
|
|
|
if (pins[idx] == 0) {
|
2022-01-10 11:21:14 +01:00
|
|
|
cerr << loc << ": error: "
|
2001-10-21 03:55:24 +02:00
|
|
|
<< "Port " << (idx+1)
|
|
|
|
|
<< " of primitive " << name << " missing"
|
|
|
|
|
<< " input declaration." << endl;
|
2022-01-10 11:21:14 +01:00
|
|
|
cerr << loc << ": : "
|
2001-10-21 03:55:24 +02:00
|
|
|
<< "Try: input " << pin_names[idx] << ";"
|
|
|
|
|
<< endl;
|
|
|
|
|
error_count += 1;
|
|
|
|
|
local_errors += 1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (pins[idx]->get_port_type() != NetNet::PINPUT) {
|
2022-01-10 11:21:14 +01:00
|
|
|
cerr << loc << ": error: "
|
2004-02-15 18:48:28 +01:00
|
|
|
<< "Input port " << (idx+1)
|
|
|
|
|
<< " of primitive " << name
|
|
|
|
|
<< " has an output (or missing) declaration." << endl;
|
2022-01-10 11:21:14 +01:00
|
|
|
cerr << loc << ": : "
|
2004-02-15 18:48:28 +01:00
|
|
|
<< "Note that only the first port can be an output."
|
|
|
|
|
<< endl;
|
2022-01-10 11:21:14 +01:00
|
|
|
cerr << loc << ": : "
|
2004-02-15 18:48:28 +01:00
|
|
|
<< "Try \"input " << name << ";\""
|
|
|
|
|
<< endl;
|
|
|
|
|
error_count += 1;
|
|
|
|
|
local_errors += 1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pins[idx]->get_wire_type() == NetNet::REG) {
|
2022-01-10 11:21:14 +01:00
|
|
|
cerr << loc << ": error: "
|
2001-10-21 03:55:24 +02:00
|
|
|
<< "Port " << (idx+1)
|
2004-02-15 18:48:28 +01:00
|
|
|
<< " of primitive " << name << " is an input port"
|
|
|
|
|
<< " with a reg declaration." << endl;
|
2022-01-10 11:21:14 +01:00
|
|
|
cerr << loc << ": : "
|
2004-02-15 18:48:28 +01:00
|
|
|
<< "primitive inputs cannot be reg."
|
2001-10-21 03:55:24 +02:00
|
|
|
<< endl;
|
|
|
|
|
error_count += 1;
|
|
|
|
|
local_errors += 1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
1998-11-25 03:35:53 +01:00
|
|
|
}
|
2004-02-15 18:48:28 +01:00
|
|
|
|
2001-10-21 03:55:24 +02:00
|
|
|
if (local_errors > 0) {
|
|
|
|
|
delete parms;
|
|
|
|
|
delete decl;
|
|
|
|
|
delete table;
|
|
|
|
|
delete init_expr;
|
|
|
|
|
return;
|
|
|
|
|
}
|
1998-11-25 03:35:53 +01:00
|
|
|
|
2004-02-15 18:48:28 +01:00
|
|
|
|
2004-03-08 01:10:29 +01:00
|
|
|
/* Verify the "initial" statement, if present, to be sure that
|
|
|
|
|
it only assigns to the output and the output is
|
|
|
|
|
registered. Then save the initial value that I get. */
|
|
|
|
|
verinum::V init = verinum::Vx;
|
|
|
|
|
if (init_expr) {
|
|
|
|
|
// XXXX
|
|
|
|
|
assert(pins[0]->get_wire_type() == NetNet::REG);
|
2004-02-15 18:48:28 +01:00
|
|
|
|
2004-03-08 01:10:29 +01:00
|
|
|
PAssign*pa = dynamic_cast<PAssign*>(init_expr);
|
|
|
|
|
assert(pa);
|
2004-02-15 18:48:28 +01:00
|
|
|
|
2004-03-08 01:10:29 +01:00
|
|
|
const PEIdent*id = dynamic_cast<const PEIdent*>(pa->lval());
|
|
|
|
|
assert(id);
|
2004-02-15 18:48:28 +01:00
|
|
|
|
2004-03-08 01:10:29 +01:00
|
|
|
// XXXX
|
|
|
|
|
//assert(id->name() == pins[0]->name());
|
1998-11-25 03:35:53 +01:00
|
|
|
|
2004-03-08 01:10:29 +01:00
|
|
|
const PENumber*np = dynamic_cast<const PENumber*>(pa->rval());
|
|
|
|
|
assert(np);
|
1998-11-25 03:35:53 +01:00
|
|
|
|
2004-03-08 01:10:29 +01:00
|
|
|
init = np->value()[0];
|
|
|
|
|
}
|
2004-02-15 18:48:28 +01:00
|
|
|
|
2004-03-08 01:10:29 +01:00
|
|
|
// Put the primitive into the primitives table
|
|
|
|
|
if (pform_primitives[name]) {
|
2019-05-17 15:20:49 +02:00
|
|
|
VLwarn("UDP primitive already exists.");
|
2004-02-15 18:48:28 +01:00
|
|
|
|
2004-03-08 01:10:29 +01:00
|
|
|
} else {
|
|
|
|
|
PUdp*udp = new PUdp(name, parms->size());
|
2022-01-10 11:21:14 +01:00
|
|
|
FILE_NAME(udp, loc);
|
1998-11-25 03:35:53 +01:00
|
|
|
|
2004-03-08 01:10:29 +01:00
|
|
|
// Detect sequential udp.
|
|
|
|
|
if (pins[0]->get_wire_type() == NetNet::REG)
|
|
|
|
|
udp->sequential = true;
|
|
|
|
|
|
|
|
|
|
// Make the port list for the UDP
|
2022-02-17 10:48:43 +01:00
|
|
|
for (unsigned idx = 0 ; idx < pins.size() ; idx += 1)
|
2008-02-25 04:40:54 +01:00
|
|
|
udp->ports[idx] = pins[idx]->basename();
|
2004-03-08 01:10:29 +01:00
|
|
|
|
2022-01-10 11:21:14 +01:00
|
|
|
process_udp_table(udp, table, loc);
|
2004-03-08 01:10:29 +01:00
|
|
|
udp->initial = init;
|
|
|
|
|
|
|
|
|
|
pform_primitives[name] = udp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Delete the excess tables and lists from the parser. */
|
|
|
|
|
delete parms;
|
|
|
|
|
delete decl;
|
|
|
|
|
delete table;
|
|
|
|
|
delete init_expr;
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-10 11:21:14 +01:00
|
|
|
void pform_make_udp(const struct vlltype&loc, perm_string name,
|
|
|
|
|
bool synchronous_flag, perm_string out_name,
|
|
|
|
|
PExpr*init_expr, list<perm_string>*parms,
|
|
|
|
|
list<string>*table)
|
2004-03-08 01:10:29 +01:00
|
|
|
{
|
|
|
|
|
|
2022-02-17 10:48:43 +01:00
|
|
|
std::vector<PWire*> pins(parms->size() + 1);
|
2004-03-08 01:10:29 +01:00
|
|
|
|
|
|
|
|
/* Make the PWire for the output port. */
|
2008-02-25 04:40:54 +01:00
|
|
|
pins[0] = new PWire(out_name,
|
2004-03-08 01:10:29 +01:00
|
|
|
synchronous_flag? NetNet::REG : NetNet::WIRE,
|
2008-02-25 04:40:54 +01:00
|
|
|
NetNet::POUTPUT, IVL_VT_LOGIC);
|
2022-01-10 11:21:14 +01:00
|
|
|
FILE_NAME(pins[0], loc);
|
2004-03-08 01:10:29 +01:00
|
|
|
|
|
|
|
|
/* Make the PWire objects for the input ports. */
|
|
|
|
|
{ list<perm_string>::iterator cur;
|
|
|
|
|
unsigned idx;
|
|
|
|
|
for (cur = parms->begin(), idx = 1
|
|
|
|
|
; cur != parms->end()
|
2014-06-30 05:38:23 +02:00
|
|
|
; idx += 1, ++ cur) {
|
2022-02-17 10:48:43 +01:00
|
|
|
assert(idx < pins.size());
|
2008-02-25 04:40:54 +01:00
|
|
|
pins[idx] = new PWire(*cur, NetNet::WIRE,
|
|
|
|
|
NetNet::PINPUT, IVL_VT_LOGIC);
|
2022-01-10 11:21:14 +01:00
|
|
|
FILE_NAME(pins[idx], loc);
|
1998-11-25 03:35:53 +01:00
|
|
|
}
|
2022-02-17 10:48:43 +01:00
|
|
|
assert(idx == pins.size());
|
1998-11-25 03:35:53 +01:00
|
|
|
}
|
|
|
|
|
|
2004-03-08 01:10:29 +01:00
|
|
|
/* Verify the initial expression, if present, to be sure that
|
2003-01-10 04:08:13 +01:00
|
|
|
it only assigns to the output and the output is
|
1998-11-25 03:35:53 +01:00
|
|
|
registered. Then save the initial value that I get. */
|
|
|
|
|
verinum::V init = verinum::Vx;
|
|
|
|
|
if (init_expr) {
|
|
|
|
|
// XXXX
|
1999-06-17 07:34:42 +02:00
|
|
|
assert(pins[0]->get_wire_type() == NetNet::REG);
|
1998-11-25 03:35:53 +01:00
|
|
|
|
|
|
|
|
PAssign*pa = dynamic_cast<PAssign*>(init_expr);
|
|
|
|
|
assert(pa);
|
|
|
|
|
|
1999-05-10 02:16:57 +02:00
|
|
|
const PEIdent*id = dynamic_cast<const PEIdent*>(pa->lval());
|
|
|
|
|
assert(id);
|
|
|
|
|
|
1998-11-25 03:35:53 +01:00
|
|
|
// XXXX
|
2001-12-03 05:47:14 +01:00
|
|
|
//assert(id->name() == pins[0]->name());
|
1998-11-25 03:35:53 +01:00
|
|
|
|
1999-06-14 01:51:16 +02:00
|
|
|
const PENumber*np = dynamic_cast<const PENumber*>(pa->rval());
|
1998-11-25 03:35:53 +01:00
|
|
|
assert(np);
|
|
|
|
|
|
|
|
|
|
init = np->value()[0];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Put the primitive into the primitives table
|
2001-10-21 01:02:39 +02:00
|
|
|
if (pform_primitives[name]) {
|
1998-11-25 03:35:53 +01:00
|
|
|
VLerror("UDP primitive already exists.");
|
|
|
|
|
|
|
|
|
|
} else {
|
2022-02-17 10:48:43 +01:00
|
|
|
PUdp*udp = new PUdp(name, pins.size());
|
2022-01-10 11:21:14 +01:00
|
|
|
FILE_NAME(udp, loc);
|
1998-11-25 03:35:53 +01:00
|
|
|
|
|
|
|
|
// Detect sequential udp.
|
2004-03-08 01:10:29 +01:00
|
|
|
udp->sequential = synchronous_flag;
|
1998-11-25 03:35:53 +01:00
|
|
|
|
|
|
|
|
// Make the port list for the UDP
|
2022-02-17 10:48:43 +01:00
|
|
|
for (unsigned idx = 0 ; idx < pins.size() ; idx += 1)
|
2008-02-25 04:40:54 +01:00
|
|
|
udp->ports[idx] = pins[idx]->basename();
|
1998-11-25 03:35:53 +01:00
|
|
|
|
2004-03-08 01:10:29 +01:00
|
|
|
assert(udp);
|
|
|
|
|
assert(table);
|
2022-01-10 11:21:14 +01:00
|
|
|
process_udp_table(udp, table, loc);
|
1998-11-25 03:35:53 +01:00
|
|
|
udp->initial = init;
|
|
|
|
|
|
2001-10-21 01:02:39 +02:00
|
|
|
pform_primitives[name] = udp;
|
1998-11-25 03:35:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
delete parms;
|
|
|
|
|
delete table;
|
|
|
|
|
delete init_expr;
|
|
|
|
|
}
|
|
|
|
|
|
2000-10-31 18:00:04 +01:00
|
|
|
/*
|
|
|
|
|
* This function attaches a range to a given name. The function is
|
|
|
|
|
* only called by the parser within the scope of the net declaration,
|
|
|
|
|
* and the name that I receive only has the tail component.
|
|
|
|
|
*/
|
2022-04-18 11:01:54 +02:00
|
|
|
static void pform_set_net_range(PWire *wire,
|
2022-04-21 10:28:44 +02:00
|
|
|
const vector_type_t *vec_type,
|
2022-04-18 11:01:54 +02:00
|
|
|
PWSRType rt = SR_NET,
|
|
|
|
|
std::list<named_pexpr_t>*attr = 0)
|
2000-10-31 18:00:04 +01:00
|
|
|
{
|
2022-04-21 10:28:44 +02:00
|
|
|
pform_bind_attributes(wire->attributes, attr, true);
|
|
|
|
|
|
|
|
|
|
if (!vec_type)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
list<pform_range_t> *range = vec_type->pdims.get();
|
2022-03-13 09:50:52 +01:00
|
|
|
if (range)
|
2022-04-18 11:01:54 +02:00
|
|
|
wire->set_range(*range, rt);
|
2022-04-21 10:28:44 +02:00
|
|
|
wire->set_signed(vec_type->signed_flag);
|
2022-04-23 12:22:21 +02:00
|
|
|
wire->set_data_type(vec_type->base_type);
|
2000-10-31 18:00:04 +01:00
|
|
|
}
|
|
|
|
|
|
2000-04-01 21:31:57 +02:00
|
|
|
/*
|
|
|
|
|
* This is invoked to make a named event. This is the declaration of
|
|
|
|
|
* the event, and not necessarily the use of it.
|
|
|
|
|
*/
|
2022-01-10 11:21:14 +01:00
|
|
|
static void pform_make_event(const struct vlltype&loc, perm_string name)
|
2000-04-01 21:31:57 +02:00
|
|
|
{
|
2004-05-25 21:21:06 +02:00
|
|
|
PEvent*event = new PEvent(name);
|
2022-01-10 11:21:14 +01:00
|
|
|
FILE_NAME(event, loc);
|
2019-09-27 00:35:57 +02:00
|
|
|
|
|
|
|
|
add_local_symbol(lexical_scope, name, event);
|
2010-01-08 23:49:48 +01:00
|
|
|
lexical_scope->events[name] = event;
|
2000-04-01 21:31:57 +02:00
|
|
|
}
|
|
|
|
|
|
2022-01-10 11:21:14 +01:00
|
|
|
void pform_make_events(const struct vlltype&loc, list<perm_string>*names)
|
2000-04-01 21:31:57 +02:00
|
|
|
{
|
2004-05-25 21:21:06 +02:00
|
|
|
list<perm_string>::iterator cur;
|
2010-10-23 23:57:59 +02:00
|
|
|
for (cur = names->begin() ; cur != names->end() ; ++ cur ) {
|
2004-05-25 21:21:06 +02:00
|
|
|
perm_string txt = *cur;
|
2022-01-10 11:21:14 +01:00
|
|
|
pform_make_event(loc, txt);
|
2000-10-31 18:00:04 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
delete names;
|
2000-04-01 21:31:57 +02:00
|
|
|
}
|
|
|
|
|
|
1999-02-15 03:06:15 +01:00
|
|
|
/*
|
|
|
|
|
* pform_makegates is called when a list of gates (with the same type)
|
|
|
|
|
* are ready to be instantiated. The function runs through the list of
|
1999-05-29 04:36:17 +02:00
|
|
|
* gates and calls the pform_makegate function to make the individual gate.
|
1999-02-15 03:06:15 +01:00
|
|
|
*/
|
2010-11-13 03:47:06 +01:00
|
|
|
static void pform_makegate(PGBuiltin::Type type,
|
|
|
|
|
struct str_pair_t str,
|
|
|
|
|
list<PExpr*>* delay,
|
|
|
|
|
const lgate&info,
|
|
|
|
|
list<named_pexpr_t>*attr)
|
1998-11-04 00:28:49 +01:00
|
|
|
{
|
1999-05-29 04:36:17 +02:00
|
|
|
if (info.parms_by_name) {
|
2022-03-11 09:21:42 +01:00
|
|
|
cerr << info.get_fileline() << ": Gates do not have port names."
|
|
|
|
|
<< endl;
|
1999-05-29 04:36:17 +02:00
|
|
|
error_count += 1;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-21 22:37:17 +02:00
|
|
|
if (info.parms) {
|
|
|
|
|
for (list<PExpr*>::iterator cur = info.parms->begin()
|
|
|
|
|
; cur != info.parms->end() ; ++cur) {
|
|
|
|
|
pform_declare_implicit_nets(*cur);
|
|
|
|
|
}
|
2010-01-12 21:11:01 +01:00
|
|
|
}
|
|
|
|
|
|
2004-02-18 18:11:54 +01:00
|
|
|
perm_string dev_name = lex_strings.make(info.name);
|
|
|
|
|
PGBuiltin*cur = new PGBuiltin(type, dev_name, info.parms, delay);
|
2021-11-06 01:02:38 +01:00
|
|
|
cur->set_ranges(info.ranges);
|
1999-02-15 03:06:15 +01:00
|
|
|
|
2010-11-13 03:47:06 +01:00
|
|
|
// The pform_makegates() that calls me will take care of
|
|
|
|
|
// deleting the attr pointer, so tell the
|
|
|
|
|
// pform_bind_attributes function to keep the attr object.
|
|
|
|
|
pform_bind_attributes(cur->attributes, attr, true);
|
2002-05-23 05:08:50 +02:00
|
|
|
|
2000-05-08 07:30:19 +02:00
|
|
|
cur->strength0(str.str0);
|
|
|
|
|
cur->strength1(str.str1);
|
2022-03-11 09:21:42 +01:00
|
|
|
cur->set_line(info);
|
1999-02-15 03:06:15 +01:00
|
|
|
|
2019-09-27 00:35:57 +02:00
|
|
|
if (pform_cur_generate) {
|
|
|
|
|
if (dev_name != "") add_local_symbol(pform_cur_generate, dev_name, cur);
|
2006-04-10 02:37:42 +02:00
|
|
|
pform_cur_generate->add_gate(cur);
|
2019-09-27 00:35:57 +02:00
|
|
|
} else {
|
|
|
|
|
if (dev_name != "") add_local_symbol(pform_cur_module.front(), dev_name, cur);
|
2012-05-10 04:35:11 +02:00
|
|
|
pform_cur_module.front()->add_gate(cur);
|
2019-09-27 00:35:57 +02:00
|
|
|
}
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
2012-05-15 04:13:57 +02:00
|
|
|
void pform_makegates(const struct vlltype&loc,
|
|
|
|
|
PGBuiltin::Type type,
|
2000-05-08 07:30:19 +02:00
|
|
|
struct str_pair_t str,
|
2010-10-26 04:36:44 +02:00
|
|
|
list<PExpr*>*delay,
|
2022-02-17 10:48:43 +01:00
|
|
|
std::vector<lgate>*gates,
|
2010-11-13 03:47:06 +01:00
|
|
|
list<named_pexpr_t>*attr)
|
1998-11-04 00:28:49 +01:00
|
|
|
{
|
2012-08-08 20:26:46 +02:00
|
|
|
assert(! pform_cur_module.empty());
|
2012-05-15 04:13:57 +02:00
|
|
|
if (pform_cur_module.front()->program_block) {
|
2014-12-20 00:10:14 +01:00
|
|
|
cerr << loc << ": error: Gates and switches may not be instantiated in "
|
|
|
|
|
<< "program blocks." << endl;
|
|
|
|
|
error_count += 1;
|
|
|
|
|
}
|
|
|
|
|
if (pform_cur_module.front()->is_interface) {
|
|
|
|
|
cerr << loc << ": error: Gates and switches may not be instantiated in "
|
|
|
|
|
<< "interfaces." << endl;
|
2012-05-15 04:13:57 +02:00
|
|
|
error_count += 1;
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-17 10:48:43 +01:00
|
|
|
for (unsigned idx = 0 ; idx < gates->size() ; idx += 1) {
|
2002-05-23 05:08:50 +02:00
|
|
|
pform_makegate(type, str, delay, (*gates)[idx], attr);
|
|
|
|
|
}
|
|
|
|
|
|
2010-11-13 03:47:06 +01:00
|
|
|
if (attr) delete attr;
|
1998-11-04 00:28:49 +01:00
|
|
|
delete gates;
|
|
|
|
|
}
|
|
|
|
|
|
1999-05-29 04:36:17 +02:00
|
|
|
/*
|
|
|
|
|
* A module is different from a gate in that there are different
|
2000-02-18 06:15:02 +01:00
|
|
|
* constraints, and sometimes different syntax. The X_modgate
|
2003-01-10 04:08:13 +01:00
|
|
|
* functions handle the instantiations of modules (and UDP objects) by
|
2000-02-18 06:15:02 +01:00
|
|
|
* making PGModule objects.
|
2007-06-12 06:05:45 +02:00
|
|
|
*
|
|
|
|
|
* The first pform_make_modgate handles the case of a module
|
|
|
|
|
* instantiated with ports passed by position. The "wires" is an
|
|
|
|
|
* ordered array of port expressions.
|
|
|
|
|
*
|
|
|
|
|
* The second pform_make_modgate handles the case of a module
|
|
|
|
|
* instantiated with ports passed by name. The "bind" argument is the
|
|
|
|
|
* ports matched with names.
|
1999-05-29 04:36:17 +02:00
|
|
|
*/
|
2004-02-18 18:11:54 +01:00
|
|
|
static void pform_make_modgate(perm_string type,
|
|
|
|
|
perm_string name,
|
2000-01-09 06:50:48 +01:00
|
|
|
struct parmvalue_t*overrides,
|
2010-10-26 04:36:44 +02:00
|
|
|
list<PExpr*>*wires,
|
2021-11-06 01:02:38 +01:00
|
|
|
list<pform_range_t>*ranges,
|
2022-03-11 09:21:42 +01:00
|
|
|
const LineInfo&li,
|
2017-03-16 15:41:10 +01:00
|
|
|
std::list<named_pexpr_t>*attr)
|
1998-11-04 00:28:49 +01:00
|
|
|
{
|
2010-10-26 04:36:44 +02:00
|
|
|
for (list<PExpr*>::iterator idx = wires->begin()
|
|
|
|
|
; idx != wires->end() ; ++idx) {
|
|
|
|
|
pform_declare_implicit_nets(*idx);
|
2010-01-12 21:11:01 +01:00
|
|
|
}
|
|
|
|
|
|
2000-01-09 06:50:48 +01:00
|
|
|
PGModule*cur = new PGModule(type, name, wires);
|
2022-03-11 09:21:42 +01:00
|
|
|
cur->set_line(li);
|
2021-11-06 01:02:38 +01:00
|
|
|
cur->set_ranges(ranges);
|
2000-01-09 06:50:48 +01:00
|
|
|
|
|
|
|
|
if (overrides && overrides->by_name) {
|
2010-11-13 03:47:06 +01:00
|
|
|
unsigned cnt = overrides->by_name->size();
|
2000-01-09 06:50:48 +01:00
|
|
|
named<PExpr*>*byname = new named<PExpr*>[cnt];
|
|
|
|
|
|
2010-11-13 03:47:06 +01:00
|
|
|
list<named_pexpr_t>::iterator by_name_cur = overrides->by_name->begin();
|
|
|
|
|
for (unsigned idx = 0 ; idx < cnt ; idx += 1, ++ by_name_cur) {
|
|
|
|
|
byname[idx].name = by_name_cur->name;
|
|
|
|
|
byname[idx].parm = by_name_cur->parm;
|
2000-01-09 06:50:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cur->set_parameters(byname, cnt);
|
|
|
|
|
|
|
|
|
|
} else if (overrides && overrides->by_order) {
|
|
|
|
|
cur->set_parameters(overrides->by_order);
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-27 00:35:57 +02:00
|
|
|
if (pform_cur_generate) {
|
|
|
|
|
if (name != "") add_local_symbol(pform_cur_generate, name, cur);
|
2006-04-10 02:37:42 +02:00
|
|
|
pform_cur_generate->add_gate(cur);
|
2019-09-27 00:35:57 +02:00
|
|
|
} else {
|
|
|
|
|
if (name != "") add_local_symbol(pform_cur_module.front(), name, cur);
|
2012-05-10 04:35:11 +02:00
|
|
|
pform_cur_module.front()->add_gate(cur);
|
2019-09-27 00:35:57 +02:00
|
|
|
}
|
2017-03-16 15:41:10 +01:00
|
|
|
pform_bind_attributes(cur->attributes, attr);
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
2004-02-18 18:11:54 +01:00
|
|
|
static void pform_make_modgate(perm_string type,
|
|
|
|
|
perm_string name,
|
2000-01-09 06:50:48 +01:00
|
|
|
struct parmvalue_t*overrides,
|
2010-11-13 03:47:06 +01:00
|
|
|
list<named_pexpr_t>*bind,
|
2021-11-06 01:02:38 +01:00
|
|
|
list<pform_range_t>*ranges,
|
2022-03-11 09:21:42 +01:00
|
|
|
const LineInfo&li,
|
2017-03-16 15:41:10 +01:00
|
|
|
std::list<named_pexpr_t>*attr)
|
1999-05-29 04:36:17 +02:00
|
|
|
{
|
2010-11-13 03:47:06 +01:00
|
|
|
unsigned npins = bind->size();
|
2000-01-09 06:50:48 +01:00
|
|
|
named<PExpr*>*pins = new named<PExpr*>[npins];
|
2010-11-13 03:47:06 +01:00
|
|
|
list<named_pexpr_t>::iterator bind_cur = bind->begin();
|
|
|
|
|
for (unsigned idx = 0 ; idx < npins ; idx += 1, ++bind_cur) {
|
|
|
|
|
pins[idx].name = bind_cur->name;
|
|
|
|
|
pins[idx].parm = bind_cur->parm;
|
|
|
|
|
pform_declare_implicit_nets(bind_cur->parm);
|
1999-05-29 04:36:17 +02:00
|
|
|
}
|
|
|
|
|
|
2000-01-09 06:50:48 +01:00
|
|
|
PGModule*cur = new PGModule(type, name, pins, npins);
|
2022-03-11 09:21:42 +01:00
|
|
|
cur->set_line(li);
|
2021-11-06 01:02:38 +01:00
|
|
|
cur->set_ranges(ranges);
|
2000-01-09 06:50:48 +01:00
|
|
|
|
|
|
|
|
if (overrides && overrides->by_name) {
|
2010-11-13 03:47:06 +01:00
|
|
|
unsigned cnt = overrides->by_name->size();
|
2000-01-09 06:50:48 +01:00
|
|
|
named<PExpr*>*byname = new named<PExpr*>[cnt];
|
|
|
|
|
|
2010-11-13 03:47:06 +01:00
|
|
|
list<named_pexpr_t>::iterator by_name_cur = overrides->by_name->begin();
|
|
|
|
|
for (unsigned idx = 0 ; idx < cnt ; idx += 1, ++by_name_cur) {
|
|
|
|
|
byname[idx].name = by_name_cur->name;
|
|
|
|
|
byname[idx].parm = by_name_cur->parm;
|
2000-01-09 06:50:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cur->set_parameters(byname, cnt);
|
|
|
|
|
|
|
|
|
|
} else if (overrides && overrides->by_order) {
|
|
|
|
|
|
|
|
|
|
cur->set_parameters(overrides->by_order);
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-27 00:35:57 +02:00
|
|
|
if (pform_cur_generate) {
|
|
|
|
|
add_local_symbol(pform_cur_generate, name, cur);
|
2007-06-12 06:05:45 +02:00
|
|
|
pform_cur_generate->add_gate(cur);
|
2019-09-27 00:35:57 +02:00
|
|
|
} else {
|
|
|
|
|
add_local_symbol(pform_cur_module.front(), name, cur);
|
2012-05-10 04:35:11 +02:00
|
|
|
pform_cur_module.front()->add_gate(cur);
|
2019-09-27 00:35:57 +02:00
|
|
|
}
|
2017-03-16 15:41:10 +01:00
|
|
|
pform_bind_attributes(cur->attributes, attr);
|
1999-05-29 04:36:17 +02:00
|
|
|
}
|
|
|
|
|
|
2012-05-15 04:13:57 +02:00
|
|
|
void pform_make_modgates(const struct vlltype&loc,
|
|
|
|
|
perm_string type,
|
2000-01-09 06:50:48 +01:00
|
|
|
struct parmvalue_t*overrides,
|
2022-02-17 10:48:43 +01:00
|
|
|
std::vector<lgate>*gates,
|
2017-03-16 15:41:10 +01:00
|
|
|
std::list<named_pexpr_t>*attr)
|
1998-11-04 00:28:49 +01:00
|
|
|
{
|
2019-10-03 17:38:36 +02:00
|
|
|
// The grammer should not allow module gates to happen outside
|
|
|
|
|
// an active module. But if really bad input errors combine in
|
|
|
|
|
// an ugly way with error recovery, then catch this
|
|
|
|
|
// implausible situation and return an error.
|
|
|
|
|
if (pform_cur_module.empty()) {
|
|
|
|
|
cerr << loc << ": internal error: "
|
|
|
|
|
<< "Module instantiations outside module scope are not possible."
|
|
|
|
|
<< endl;
|
|
|
|
|
error_count += 1;
|
|
|
|
|
delete gates;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2012-08-08 20:26:46 +02:00
|
|
|
assert(! pform_cur_module.empty());
|
2019-10-03 17:38:36 +02:00
|
|
|
|
|
|
|
|
// Detect some more realistic errors.
|
|
|
|
|
|
2012-05-15 04:13:57 +02:00
|
|
|
if (pform_cur_module.front()->program_block) {
|
2014-12-20 00:10:14 +01:00
|
|
|
cerr << loc << ": error: Module instantiations are not allowed in "
|
|
|
|
|
<< "program blocks." << endl;
|
|
|
|
|
error_count += 1;
|
|
|
|
|
}
|
|
|
|
|
if (pform_cur_module.front()->is_interface) {
|
|
|
|
|
cerr << loc << ": error: Module instantiations are not allowed in "
|
|
|
|
|
<< "interfaces." << endl;
|
2012-05-15 04:13:57 +02:00
|
|
|
error_count += 1;
|
|
|
|
|
}
|
2001-01-15 01:47:01 +01:00
|
|
|
|
2022-02-17 10:48:43 +01:00
|
|
|
for (unsigned idx = 0 ; idx < gates->size() ; idx += 1) {
|
1999-05-06 06:37:17 +02:00
|
|
|
lgate cur = (*gates)[idx];
|
2004-02-18 18:11:54 +01:00
|
|
|
perm_string cur_name = lex_strings.make(cur.name);
|
1998-11-04 00:28:49 +01:00
|
|
|
|
1999-05-29 04:36:17 +02:00
|
|
|
if (cur.parms_by_name) {
|
2004-02-18 18:11:54 +01:00
|
|
|
pform_make_modgate(type, cur_name, overrides,
|
2021-11-06 01:02:38 +01:00
|
|
|
cur.parms_by_name, cur.ranges,
|
2022-03-11 09:21:42 +01:00
|
|
|
cur, attr);
|
1999-05-29 04:36:17 +02:00
|
|
|
|
|
|
|
|
} else if (cur.parms) {
|
2000-05-23 18:03:13 +02:00
|
|
|
|
|
|
|
|
/* If there are no parameters, the parser will be
|
|
|
|
|
tricked into thinking it is one empty
|
|
|
|
|
parameter. This fixes that. */
|
2010-10-26 04:36:44 +02:00
|
|
|
if ((cur.parms->size() == 1) && (cur.parms->front() == 0)) {
|
2000-05-23 18:03:13 +02:00
|
|
|
delete cur.parms;
|
2010-10-26 04:36:44 +02:00
|
|
|
cur.parms = new list<PExpr*>;
|
2000-05-23 18:03:13 +02:00
|
|
|
}
|
2004-02-18 18:11:54 +01:00
|
|
|
pform_make_modgate(type, cur_name, overrides,
|
2021-11-06 01:02:38 +01:00
|
|
|
cur.parms, cur.ranges,
|
2022-03-11 09:21:42 +01:00
|
|
|
cur, attr);
|
2000-05-23 18:03:13 +02:00
|
|
|
|
1999-05-10 02:16:57 +02:00
|
|
|
} else {
|
2010-10-26 04:36:44 +02:00
|
|
|
list<PExpr*>*wires = new list<PExpr*>;
|
2004-02-18 18:11:54 +01:00
|
|
|
pform_make_modgate(type, cur_name, overrides,
|
2021-11-06 01:02:38 +01:00
|
|
|
wires, cur.ranges,
|
2022-03-11 09:21:42 +01:00
|
|
|
cur, attr);
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
delete gates;
|
|
|
|
|
}
|
|
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
static PGAssign* pform_make_pgassign(PExpr*lval, PExpr*rval,
|
2010-10-26 04:36:44 +02:00
|
|
|
list<PExpr*>*del,
|
2000-05-06 17:41:56 +02:00
|
|
|
struct str_pair_t str)
|
1998-11-04 00:28:49 +01:00
|
|
|
{
|
2010-01-12 21:11:01 +01:00
|
|
|
/* Implicit declaration of nets on the LHS of a continuous
|
|
|
|
|
assignment was introduced in IEEE1364-2001. */
|
|
|
|
|
if (generation_flag != GN_VER1995)
|
|
|
|
|
pform_declare_implicit_nets(lval);
|
|
|
|
|
|
2010-10-26 04:36:44 +02:00
|
|
|
list<PExpr*>*wires = new list<PExpr*>;
|
|
|
|
|
wires->push_back(lval);
|
|
|
|
|
wires->push_back(rval);
|
1999-08-01 18:34:50 +02:00
|
|
|
|
|
|
|
|
PGAssign*cur;
|
|
|
|
|
|
|
|
|
|
if (del == 0)
|
|
|
|
|
cur = new PGAssign(wires);
|
|
|
|
|
else
|
|
|
|
|
cur = new PGAssign(wires, del);
|
|
|
|
|
|
2000-05-06 17:41:56 +02:00
|
|
|
cur->strength0(str.str0);
|
|
|
|
|
cur->strength1(str.str1);
|
|
|
|
|
|
2006-04-10 02:37:42 +02:00
|
|
|
if (pform_cur_generate)
|
|
|
|
|
pform_cur_generate->add_gate(cur);
|
|
|
|
|
else
|
2012-05-10 04:35:11 +02:00
|
|
|
pform_cur_module.front()->add_gate(cur);
|
2006-04-10 02:37:42 +02:00
|
|
|
|
1999-05-20 06:31:45 +02:00
|
|
|
return cur;
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
2022-01-10 11:21:14 +01:00
|
|
|
void pform_make_pgassign_list(const struct vlltype&loc,
|
|
|
|
|
list<PExpr*>*alist,
|
2010-10-26 04:36:44 +02:00
|
|
|
list<PExpr*>*del,
|
2022-01-10 11:21:14 +01:00
|
|
|
struct str_pair_t str)
|
1999-08-27 17:08:37 +02:00
|
|
|
{
|
2010-10-26 04:36:44 +02:00
|
|
|
assert(alist->size() % 2 == 0);
|
|
|
|
|
while (! alist->empty()) {
|
|
|
|
|
PExpr*lval = alist->front(); alist->pop_front();
|
|
|
|
|
PExpr*rval = alist->front(); alist->pop_front();
|
|
|
|
|
PGAssign*tmp = pform_make_pgassign(lval, rval, del, str);
|
2022-01-10 11:21:14 +01:00
|
|
|
FILE_NAME(tmp, loc);
|
2010-10-26 04:36:44 +02:00
|
|
|
}
|
1999-08-27 17:08:37 +02:00
|
|
|
}
|
|
|
|
|
|
1999-12-30 20:06:14 +01:00
|
|
|
/*
|
2016-03-19 14:04:38 +01:00
|
|
|
* This function makes the initial assignment to a variable as given
|
|
|
|
|
* in the source. It handles the case where a variable is assigned
|
|
|
|
|
* where it is declared, e.g.
|
1999-12-30 20:06:14 +01:00
|
|
|
*
|
|
|
|
|
* reg foo = <expr>;
|
|
|
|
|
*
|
2016-03-19 14:04:38 +01:00
|
|
|
* In Verilog-2001 this is only supported at the module level, and is
|
|
|
|
|
* equivalent to the combination of statements:
|
1999-12-30 20:06:14 +01:00
|
|
|
*
|
|
|
|
|
* reg foo;
|
2003-01-10 04:08:13 +01:00
|
|
|
* initial foo = <expr>;
|
1999-12-30 20:06:14 +01:00
|
|
|
*
|
2016-03-19 14:04:38 +01:00
|
|
|
* In SystemVerilog, variable initializations are allowed in any scope.
|
|
|
|
|
* For static variables, initializations are performed before the start
|
|
|
|
|
* of simulation. For automatic variables, initializations are performed
|
|
|
|
|
* each time the enclosing block is entered. Here we store the variable
|
|
|
|
|
* assignments in the current scope, and later elaboration creates an
|
|
|
|
|
* initialization block that will be executed at the appropriate time.
|
|
|
|
|
*
|
|
|
|
|
* This syntax is not part of the IEEE1364-1995 standard, but is
|
|
|
|
|
* approved by OVI as enhancement BTF-B14.
|
1999-12-30 20:06:14 +01:00
|
|
|
*/
|
2016-03-19 14:04:38 +01:00
|
|
|
void pform_make_var_init(const struct vlltype&li,
|
|
|
|
|
perm_string name, PExpr*expr)
|
1999-12-30 20:06:14 +01:00
|
|
|
{
|
2012-03-11 23:08:42 +01:00
|
|
|
if (! pform_at_module_level() && !gn_system_verilog()) {
|
|
|
|
|
VLerror(li, "error: variable declaration assignments are only "
|
2008-10-28 18:52:39 +01:00
|
|
|
"allowed at the module level.");
|
|
|
|
|
delete expr;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2008-02-25 04:40:54 +01:00
|
|
|
PEIdent*lval = new PEIdent(name);
|
2007-12-20 18:31:01 +01:00
|
|
|
FILE_NAME(lval, li);
|
2019-10-05 21:11:38 +02:00
|
|
|
PAssign*ass = new PAssign(lval, expr, !gn_system_verilog());
|
2007-12-20 18:31:01 +01:00
|
|
|
FILE_NAME(ass, li);
|
1999-12-30 20:06:14 +01:00
|
|
|
|
2016-03-19 14:04:38 +01:00
|
|
|
lexical_scope->var_inits.push_back(ass);
|
1999-12-30 20:06:14 +01:00
|
|
|
}
|
|
|
|
|
|
2022-03-13 09:50:52 +01:00
|
|
|
/*
|
|
|
|
|
* This function makes a single signal (a wire, a reg, etc) as
|
|
|
|
|
* requested by the parser. The name is unscoped, so I attach the
|
|
|
|
|
* current scope to it (with the scoped_name function) and I try to
|
|
|
|
|
* resolve it with an existing PWire in the scope.
|
|
|
|
|
*
|
|
|
|
|
* The wire might already exist because of an implicit declaration in
|
|
|
|
|
* a module port, i.e.:
|
|
|
|
|
*
|
|
|
|
|
* module foo (bar...
|
|
|
|
|
*
|
|
|
|
|
* reg bar;
|
|
|
|
|
*
|
|
|
|
|
* The output (or other port direction indicator) may or may not have
|
|
|
|
|
* been seen already, so I do not do any checking with it yet. But I
|
|
|
|
|
* do check to see if the name has already been declared, as this
|
|
|
|
|
* function is called for every declaration.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static PWire* pform_get_or_make_wire(const struct vlltype&li, perm_string name,
|
|
|
|
|
NetNet::Type type, NetNet::PortType ptype,
|
2022-04-23 12:22:21 +02:00
|
|
|
PWSRType rt)
|
2022-03-13 09:50:52 +01:00
|
|
|
{
|
|
|
|
|
PWire *cur = 0;
|
|
|
|
|
|
|
|
|
|
// If this is not a full declaration check if there is already a signal
|
|
|
|
|
// with the same name that can be extended.
|
|
|
|
|
if (rt != SR_BOTH)
|
|
|
|
|
cur = pform_get_wire_in_scope(name);
|
|
|
|
|
|
|
|
|
|
// If the wire already exists but isn't yet fully defined,
|
|
|
|
|
// carry on adding details.
|
|
|
|
|
if (rt == SR_NET && cur && !cur->is_net()) {
|
|
|
|
|
// At the moment there can only be one location for the PWire, if
|
|
|
|
|
// there is both a port and signal declaration use the location of
|
|
|
|
|
// the signal.
|
|
|
|
|
FILE_NAME(cur, li);
|
|
|
|
|
cur->set_net(type);
|
|
|
|
|
return cur;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (rt == SR_PORT && cur && !cur->is_port()) {
|
|
|
|
|
cur->set_port(ptype);
|
|
|
|
|
return cur;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If the wire already exists and is fully defined, this
|
|
|
|
|
// must be a redeclaration. Start again with a new wire.
|
|
|
|
|
// The error will be reported when we add the new wire
|
|
|
|
|
// to the scope. Do not delete the old wire - it will
|
|
|
|
|
// remain in the local symbol map.
|
|
|
|
|
|
2022-04-23 12:22:21 +02:00
|
|
|
cur = new PWire(name, type, ptype, IVL_VT_NO_TYPE, rt);
|
2022-03-13 09:50:52 +01:00
|
|
|
FILE_NAME(cur, li);
|
|
|
|
|
|
|
|
|
|
pform_put_wire_in_scope(name, cur);
|
|
|
|
|
|
|
|
|
|
return cur;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2002-05-20 04:06:01 +02:00
|
|
|
/*
|
|
|
|
|
* This function is used by the parser when I have port definition of
|
|
|
|
|
* the form like this:
|
|
|
|
|
*
|
|
|
|
|
* input wire signed [7:0] nm;
|
|
|
|
|
*
|
|
|
|
|
* The port_type, type, signed_flag and range are known all at once,
|
|
|
|
|
* so we can create the PWire object all at once instead of piecemeal
|
|
|
|
|
* as is done for the old method.
|
|
|
|
|
*/
|
|
|
|
|
void pform_module_define_port(const struct vlltype&li,
|
2008-02-25 04:40:54 +01:00
|
|
|
perm_string name,
|
2014-03-10 03:22:13 +01:00
|
|
|
NetNet::PortType port_kind,
|
2002-05-20 04:06:01 +02:00
|
|
|
NetNet::Type type,
|
2012-04-13 05:20:37 +02:00
|
|
|
data_type_t*vtype,
|
2022-04-11 09:48:29 +02:00
|
|
|
list<pform_range_t>*urange,
|
2016-04-04 21:40:30 +02:00
|
|
|
list<named_pexpr_t>*attr,
|
|
|
|
|
bool keep_attr)
|
2002-05-20 04:06:01 +02:00
|
|
|
{
|
2022-01-20 15:59:28 +01:00
|
|
|
pform_check_net_data_type(li, type, vtype);
|
|
|
|
|
|
2022-04-23 12:22:21 +02:00
|
|
|
PWire *cur = pform_get_or_make_wire(li, name, type, port_kind, SR_BOTH);
|
2002-05-20 04:06:01 +02:00
|
|
|
|
2022-04-23 12:22:21 +02:00
|
|
|
vector_type_t*vec_type = dynamic_cast<vector_type_t*> (vtype);
|
|
|
|
|
if (vec_type)
|
|
|
|
|
pform_set_net_range(cur, vec_type, SR_BOTH);
|
|
|
|
|
else if (vtype)
|
2022-01-09 00:27:56 +01:00
|
|
|
cur->set_data_type(vtype);
|
2021-04-28 21:18:04 +02:00
|
|
|
|
2014-03-17 01:08:38 +01:00
|
|
|
if (urange) {
|
|
|
|
|
cur->set_unpacked_idx(*urange);
|
2022-04-11 09:48:29 +02:00
|
|
|
delete urange;
|
2002-05-20 04:06:01 +02:00
|
|
|
}
|
|
|
|
|
|
2016-04-04 21:40:30 +02:00
|
|
|
pform_bind_attributes(cur->attributes, attr, keep_attr);
|
2002-05-20 04:06:01 +02:00
|
|
|
}
|
|
|
|
|
|
2016-04-04 21:40:30 +02:00
|
|
|
void pform_module_define_port(const struct vlltype&li,
|
|
|
|
|
list<pform_port_t>*ports,
|
|
|
|
|
NetNet::PortType port_kind,
|
|
|
|
|
NetNet::Type type,
|
|
|
|
|
data_type_t*vtype,
|
|
|
|
|
list<named_pexpr_t>*attr)
|
|
|
|
|
{
|
|
|
|
|
for (list<pform_port_t>::iterator cur = ports->begin()
|
|
|
|
|
; cur != ports->end() ; ++ cur ) {
|
|
|
|
|
|
|
|
|
|
data_type_t*use_type = vtype;
|
|
|
|
|
|
|
|
|
|
pform_module_define_port(li, cur->name, port_kind, type, use_type,
|
2022-04-11 09:48:29 +02:00
|
|
|
cur->udims, attr, true);
|
2016-04-04 21:40:30 +02:00
|
|
|
|
|
|
|
|
if (cur->expr)
|
|
|
|
|
pform_make_var_init(li, cur->name, cur->expr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
delete ports;
|
|
|
|
|
delete attr;
|
|
|
|
|
}
|
|
|
|
|
|
2006-04-10 02:37:42 +02:00
|
|
|
/*
|
2008-01-29 21:19:59 +01:00
|
|
|
* this is the basic form of pform_makewire. This takes a single simple
|
2006-04-10 02:37:42 +02:00
|
|
|
* name, port type, net type, data type, and attributes, and creates
|
|
|
|
|
* the variable/net. Other forms of pform_makewire ultimately call
|
|
|
|
|
* this one to create the wire and stash it.
|
|
|
|
|
*/
|
2022-04-17 20:57:03 +02:00
|
|
|
PWire *pform_makewire(const vlltype&li, perm_string name, NetNet::Type type,
|
2022-04-23 12:22:21 +02:00
|
|
|
std::list<pform_range_t> *indices)
|
1998-11-04 00:28:49 +01:00
|
|
|
{
|
2022-03-11 21:39:20 +01:00
|
|
|
PWire*cur = pform_get_or_make_wire(li, name, type, NetNet::NOT_A_PORT,
|
2022-04-23 12:22:21 +02:00
|
|
|
SR_NET);
|
2021-11-07 17:14:30 +01:00
|
|
|
assert(cur);
|
1998-11-04 00:28:49 +01:00
|
|
|
|
2022-03-11 11:06:53 +01:00
|
|
|
if (indices && !indices->empty())
|
|
|
|
|
cur->set_unpacked_idx(*indices);
|
2022-04-17 20:57:03 +02:00
|
|
|
|
|
|
|
|
return cur;
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
2013-04-08 01:38:48 +02:00
|
|
|
void pform_makewire(const struct vlltype&li,
|
2018-02-18 15:09:03 +01:00
|
|
|
std::list<PExpr*>*delay,
|
|
|
|
|
str_pair_t str,
|
2013-04-08 01:38:48 +02:00
|
|
|
std::list<decl_assignment_t*>*assign_list,
|
|
|
|
|
NetNet::Type type,
|
2022-01-22 09:56:07 +01:00
|
|
|
data_type_t*data_type,
|
|
|
|
|
list<named_pexpr_t>*attr)
|
2013-04-08 01:38:48 +02:00
|
|
|
{
|
2017-10-21 16:04:25 +02:00
|
|
|
if (is_compilation_unit(lexical_scope) && !gn_system_verilog()) {
|
2015-08-21 00:55:00 +02:00
|
|
|
VLerror(li, "error: variable declarations must be contained within a module.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-17 20:57:03 +02:00
|
|
|
std::vector<PWire*> *wires = new std::vector<PWire*>;
|
2013-04-08 01:38:48 +02:00
|
|
|
|
|
|
|
|
for (list<decl_assignment_t*>::iterator cur = assign_list->begin()
|
|
|
|
|
; cur != assign_list->end() ; ++ cur) {
|
|
|
|
|
decl_assignment_t* curp = *cur;
|
2022-04-23 12:22:21 +02:00
|
|
|
PWire *wire = pform_makewire(li, curp->name, type, &curp->index);
|
2022-04-17 20:57:03 +02:00
|
|
|
wires->push_back(wire);
|
2013-04-08 01:38:48 +02:00
|
|
|
}
|
|
|
|
|
|
2022-04-17 20:57:03 +02:00
|
|
|
pform_set_data_type(li, data_type, wires, type, attr);
|
2013-04-08 01:38:48 +02:00
|
|
|
|
|
|
|
|
while (! assign_list->empty()) {
|
|
|
|
|
decl_assignment_t*first = assign_list->front();
|
|
|
|
|
assign_list->pop_front();
|
2018-02-18 15:09:03 +01:00
|
|
|
if (PExpr*expr = first->expr.release()) {
|
|
|
|
|
if (type == NetNet::REG || type == NetNet::IMPLICIT_REG) {
|
|
|
|
|
pform_make_var_init(li, first->name, expr);
|
|
|
|
|
} else {
|
|
|
|
|
PEIdent*lval = new PEIdent(first->name);
|
2022-01-10 11:21:14 +01:00
|
|
|
FILE_NAME(lval, li);
|
2018-02-18 15:09:03 +01:00
|
|
|
PGAssign*ass = pform_make_pgassign(lval, expr, delay, str);
|
2022-01-10 11:21:14 +01:00
|
|
|
FILE_NAME(ass, li);
|
2018-02-18 15:09:03 +01:00
|
|
|
}
|
|
|
|
|
}
|
2013-04-08 01:38:48 +02:00
|
|
|
delete first;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1999-07-24 04:11:19 +02:00
|
|
|
/*
|
|
|
|
|
* This function is called by the parser to create task ports. The
|
|
|
|
|
* resulting wire (which should be a register) is put into a list to
|
|
|
|
|
* be packed into the task parameter list.
|
|
|
|
|
*
|
|
|
|
|
* It is possible that the wire (er, register) was already created,
|
|
|
|
|
* but we know that if the name matches it is a part of the current
|
|
|
|
|
* task, so in that case I just assign direction to it.
|
|
|
|
|
*
|
1999-07-31 21:14:47 +02:00
|
|
|
* The following example demonstrates some of the issues:
|
1999-07-24 04:11:19 +02:00
|
|
|
*
|
|
|
|
|
* task foo;
|
|
|
|
|
* input a;
|
|
|
|
|
* reg a, b;
|
|
|
|
|
* input b;
|
|
|
|
|
* [...]
|
|
|
|
|
* endtask
|
|
|
|
|
*
|
|
|
|
|
* This function is called when the parser matches the "input a" and
|
|
|
|
|
* the "input b" statements. For ``a'', this function is called before
|
|
|
|
|
* the wire is declared as a register, so I create the foo.a
|
|
|
|
|
* wire. For ``b'', I will find that there is already a foo.b and I
|
|
|
|
|
* just set the port direction. In either case, the ``reg a, b''
|
1999-07-31 21:14:47 +02:00
|
|
|
* statement is caught by the block_item non-terminal and processed
|
|
|
|
|
* there.
|
|
|
|
|
*
|
|
|
|
|
* Ports are implicitly type reg, because it must be possible for the
|
|
|
|
|
* port to act as an l-value in a procedural assignment. It is obvious
|
|
|
|
|
* for output and inout ports that the type is reg, because the task
|
|
|
|
|
* only contains behavior (no structure) to a procedural assignment is
|
1999-07-31 21:15:21 +02:00
|
|
|
* the *only* way to affect the output. It is less obvious for input
|
1999-07-31 21:14:47 +02:00
|
|
|
* ports, but in practice an input port receives its value as if by a
|
|
|
|
|
* procedural assignment from the calling behavior.
|
|
|
|
|
*
|
|
|
|
|
* This function also handles the input ports of function
|
|
|
|
|
* definitions. Input ports to function definitions have the same
|
|
|
|
|
* constraints as those of tasks, so this works fine. Functions have
|
|
|
|
|
* no output or inout ports.
|
1999-07-24 04:11:19 +02:00
|
|
|
*/
|
2022-04-22 08:45:21 +02:00
|
|
|
static vector<pform_tf_port_t>*pform_make_task_ports_vec(const struct vlltype&loc,
|
|
|
|
|
NetNet::PortType pt,
|
|
|
|
|
vector_type_t *vec_type,
|
|
|
|
|
list<pform_port_t>*ports,
|
|
|
|
|
bool allow_implicit)
|
1999-07-24 04:11:19 +02:00
|
|
|
{
|
2012-03-10 03:54:05 +01:00
|
|
|
assert(pt != NetNet::PIMPLICIT && pt != NetNet::NOT_A_PORT);
|
2022-02-19 22:44:02 +01:00
|
|
|
assert(ports);
|
2013-09-14 02:04:25 +02:00
|
|
|
vector<pform_tf_port_t>*res = new vector<pform_tf_port_t>(0);
|
2022-04-22 08:45:21 +02:00
|
|
|
|
|
|
|
|
PWSRType rt = SR_BOTH;
|
|
|
|
|
|
|
|
|
|
if (allow_implicit && vec_type->implicit_flag)
|
|
|
|
|
rt = SR_PORT;
|
2022-03-13 09:50:52 +01:00
|
|
|
|
2022-02-19 22:44:02 +01:00
|
|
|
for (list<pform_port_t>::iterator cur = ports->begin()
|
|
|
|
|
; cur != ports->end() ; ++ cur ) {
|
|
|
|
|
perm_string &name = cur->name;
|
1999-07-24 04:11:19 +02:00
|
|
|
|
|
|
|
|
/* Look for a preexisting wire. If it exists, set the
|
|
|
|
|
port direction. If not, create it. */
|
2022-03-13 09:50:52 +01:00
|
|
|
PWire*curw = pform_get_or_make_wire(loc, name, NetNet::IMPLICIT_REG,
|
2022-04-23 12:22:21 +02:00
|
|
|
pt, rt);
|
2022-04-22 08:45:21 +02:00
|
|
|
pform_set_net_range(curw, vec_type, rt);
|
1999-07-24 04:11:19 +02:00
|
|
|
|
2022-02-19 22:44:02 +01:00
|
|
|
if (cur->udims) {
|
|
|
|
|
if (pform_requires_sv(loc, "Task/function port with unpacked dimensions"))
|
|
|
|
|
curw->set_unpacked_idx(*cur->udims);
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-14 02:04:25 +02:00
|
|
|
res->push_back(pform_tf_port_t(curw));
|
1999-07-24 04:11:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-14 02:04:25 +02:00
|
|
|
static vector<pform_tf_port_t>*do_make_task_ports(const struct vlltype&loc,
|
2013-03-15 04:08:32 +01:00
|
|
|
NetNet::PortType pt,
|
|
|
|
|
data_type_t*data_type,
|
2022-02-19 22:44:02 +01:00
|
|
|
list<pform_port_t>*ports)
|
2013-03-15 04:08:32 +01:00
|
|
|
{
|
|
|
|
|
assert(pt != NetNet::PIMPLICIT && pt != NetNet::NOT_A_PORT);
|
2022-02-19 22:44:02 +01:00
|
|
|
assert(ports);
|
2013-09-14 02:04:25 +02:00
|
|
|
vector<pform_tf_port_t>*res = new vector<pform_tf_port_t>(0);
|
2022-03-13 09:50:52 +01:00
|
|
|
PWSRType rt = data_type ? SR_BOTH : SR_PORT;
|
2013-03-15 04:08:32 +01:00
|
|
|
|
2022-02-19 22:44:02 +01:00
|
|
|
for (list<pform_port_t>::iterator cur = ports->begin()
|
|
|
|
|
; cur != ports->end() ; ++cur) {
|
|
|
|
|
perm_string &name = cur->name;
|
|
|
|
|
|
2022-03-13 09:50:52 +01:00
|
|
|
PWire*curw = pform_get_or_make_wire(loc, name, NetNet::IMPLICIT_REG,
|
2022-04-23 12:22:21 +02:00
|
|
|
pt, rt);
|
|
|
|
|
|
2022-03-13 09:50:52 +01:00
|
|
|
if (data_type)
|
2013-03-15 04:08:32 +01:00
|
|
|
curw->set_data_type(data_type);
|
|
|
|
|
|
2022-02-19 22:44:02 +01:00
|
|
|
if (cur->udims) {
|
|
|
|
|
if (pform_requires_sv(loc, "Task/function port with unpacked dimensions"))
|
|
|
|
|
curw->set_unpacked_idx(*cur->udims);
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-14 02:04:25 +02:00
|
|
|
res->push_back(pform_tf_port_t(curw));
|
2013-03-15 04:08:32 +01:00
|
|
|
}
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-14 02:04:25 +02:00
|
|
|
vector<pform_tf_port_t>*pform_make_task_ports(const struct vlltype&loc,
|
2012-02-19 19:29:50 +01:00
|
|
|
NetNet::PortType pt,
|
|
|
|
|
data_type_t*vtype,
|
2022-02-19 22:44:02 +01:00
|
|
|
list<pform_port_t>*ports,
|
2022-01-04 16:16:08 +01:00
|
|
|
bool allow_implicit)
|
2012-02-19 19:29:50 +01:00
|
|
|
{
|
2015-01-13 10:07:16 +01:00
|
|
|
vector<pform_tf_port_t>*ret = NULL;
|
|
|
|
|
|
2012-02-26 07:05:00 +01:00
|
|
|
if (vector_type_t*vec_type = dynamic_cast<vector_type_t*> (vtype)) {
|
2022-04-22 08:45:21 +02:00
|
|
|
ret = pform_make_task_ports_vec(loc, pt, vec_type, ports,
|
|
|
|
|
allow_implicit);
|
2022-04-23 12:22:21 +02:00
|
|
|
} else {
|
|
|
|
|
ret = do_make_task_ports(loc, pt, vtype, ports);
|
2015-12-20 21:27:41 +01:00
|
|
|
}
|
2015-01-13 10:07:16 +01:00
|
|
|
|
2022-02-19 22:44:02 +01:00
|
|
|
delete ports;
|
2015-01-13 10:07:16 +01:00
|
|
|
return ret;
|
2012-02-19 19:29:50 +01:00
|
|
|
}
|
|
|
|
|
|
2012-02-20 03:54:58 +01:00
|
|
|
/*
|
|
|
|
|
* The parser calls this in the rule that matches increment/decrement
|
|
|
|
|
* statements. The rule that does the matching creates a PEUnary with
|
|
|
|
|
* all the information we need, but here we convert that expression to
|
|
|
|
|
* a compressed assignment statement.
|
|
|
|
|
*/
|
|
|
|
|
PAssign* pform_compressed_assign_from_inc_dec(const struct vlltype&loc, PExpr*exp)
|
|
|
|
|
{
|
|
|
|
|
PEUnary*expu = dynamic_cast<PEUnary*> (exp);
|
|
|
|
|
ivl_assert(*exp, expu != 0);
|
|
|
|
|
|
|
|
|
|
char use_op = 0;
|
|
|
|
|
switch (expu->get_op()) {
|
|
|
|
|
case 'i':
|
|
|
|
|
case 'I':
|
|
|
|
|
use_op = '+';
|
|
|
|
|
break;
|
|
|
|
|
case 'd':
|
|
|
|
|
case 'D':
|
|
|
|
|
use_op = '-';
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
ivl_assert(*exp, 0);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PExpr*lval = expu->get_expr();
|
|
|
|
|
PExpr*rval = new PENumber(new verinum((uint64_t)1, 1));
|
|
|
|
|
FILE_NAME(rval, loc);
|
|
|
|
|
|
|
|
|
|
PAssign*tmp = new PAssign(lval, use_op, rval);
|
|
|
|
|
FILE_NAME(tmp, loc);
|
|
|
|
|
|
|
|
|
|
delete exp;
|
|
|
|
|
return tmp;
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-30 22:45:04 +01:00
|
|
|
PExpr* pform_genvar_inc_dec(const struct vlltype&loc, const char*name, bool inc_flag)
|
|
|
|
|
{
|
2022-02-05 10:49:34 +01:00
|
|
|
pform_requires_sv(loc, "Increment/decrement operator");
|
2020-01-30 22:45:04 +01:00
|
|
|
|
|
|
|
|
PExpr*lval = new PEIdent(lex_strings.make(name));
|
2021-12-13 21:45:57 +01:00
|
|
|
PExpr*rval = new PENumber(new verinum(1));
|
2020-01-30 22:45:04 +01:00
|
|
|
FILE_NAME(lval, loc);
|
|
|
|
|
FILE_NAME(rval, loc);
|
|
|
|
|
|
|
|
|
|
PEBinary*tmp = new PEBinary(inc_flag ? '+' : '-', lval, rval);
|
|
|
|
|
FILE_NAME(tmp, loc);
|
|
|
|
|
|
|
|
|
|
return tmp;
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-04 00:09:25 +02:00
|
|
|
PExpr* pform_genvar_compressed(const struct vlltype &loc, const char *name,
|
|
|
|
|
char op, PExpr *rval)
|
|
|
|
|
{
|
|
|
|
|
pform_requires_sv(loc, "Compressed assignment operator");
|
|
|
|
|
|
|
|
|
|
PExpr *lval = new PEIdent(lex_strings.make(name));
|
|
|
|
|
FILE_NAME(lval, loc);
|
|
|
|
|
|
|
|
|
|
PExpr *expr;
|
|
|
|
|
switch (op) {
|
|
|
|
|
case 'l':
|
|
|
|
|
case 'r':
|
|
|
|
|
case 'R':
|
|
|
|
|
expr = new PEBShift(op, lval, rval);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
expr = new PEBinary(op, lval, rval);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
FILE_NAME(expr, loc);
|
|
|
|
|
|
|
|
|
|
return expr;
|
|
|
|
|
}
|
|
|
|
|
|
2004-02-20 19:53:33 +01:00
|
|
|
void pform_set_attrib(perm_string name, perm_string key, char*value)
|
1998-11-23 01:20:22 +01:00
|
|
|
{
|
2008-02-25 04:40:54 +01:00
|
|
|
if (PWire*cur = lexical_scope->wires_find(name)) {
|
2002-05-23 05:08:50 +02:00
|
|
|
cur->attributes[key] = new PEString(value);
|
1999-12-11 06:45:41 +01:00
|
|
|
|
2012-05-10 04:35:11 +02:00
|
|
|
} else if (PGate*curg = pform_cur_module.front()->get_gate(name)) {
|
2008-10-13 18:51:05 +02:00
|
|
|
curg->attributes[key] = new PEString(value);
|
1999-12-11 06:45:41 +01:00
|
|
|
|
|
|
|
|
} else {
|
2009-01-09 02:03:33 +01:00
|
|
|
delete[] value;
|
1999-12-11 06:45:41 +01:00
|
|
|
VLerror("Unable to match name for setting attribute.");
|
|
|
|
|
|
|
|
|
|
}
|
1998-11-23 01:20:22 +01:00
|
|
|
}
|
|
|
|
|
|
1998-12-01 01:42:13 +01:00
|
|
|
/*
|
|
|
|
|
* Set the attribute of a TYPE. This is different from an object in
|
|
|
|
|
* that this applies to every instantiation of the given type.
|
|
|
|
|
*/
|
2004-02-18 18:11:54 +01:00
|
|
|
void pform_set_type_attrib(perm_string name, const string&key,
|
2002-05-23 05:08:50 +02:00
|
|
|
char*value)
|
1998-12-01 01:42:13 +01:00
|
|
|
{
|
2004-02-18 18:11:54 +01:00
|
|
|
map<perm_string,PUdp*>::const_iterator udp = pform_primitives.find(name);
|
2001-10-21 01:02:39 +02:00
|
|
|
if (udp == pform_primitives.end()) {
|
1998-12-01 01:42:13 +01:00
|
|
|
VLerror("type name is not (yet) defined.");
|
2009-01-09 02:03:33 +01:00
|
|
|
delete[] value;
|
1998-12-01 01:42:13 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2002-05-23 05:08:50 +02:00
|
|
|
(*udp).second ->attributes[key] = new PEString(value);
|
1998-12-01 01:42:13 +01:00
|
|
|
}
|
|
|
|
|
|
2008-09-17 22:25:59 +02:00
|
|
|
LexicalScope::range_t* pform_parameter_value_range(bool exclude_flag,
|
2008-05-13 06:26:38 +02:00
|
|
|
bool low_open, PExpr*low_expr,
|
|
|
|
|
bool hig_open, PExpr*hig_expr)
|
|
|
|
|
{
|
2008-05-14 06:22:52 +02:00
|
|
|
// Detect +-inf and make the the *_open flags false to force
|
|
|
|
|
// the range interpretation as inf.
|
|
|
|
|
if (low_expr == 0) low_open = false;
|
|
|
|
|
if (hig_expr == 0) hig_open = false;
|
|
|
|
|
|
2008-09-17 22:25:59 +02:00
|
|
|
LexicalScope::range_t*tmp = new LexicalScope::range_t;
|
2008-05-13 06:26:38 +02:00
|
|
|
tmp->exclude_flag = exclude_flag;
|
|
|
|
|
tmp->low_open_flag = low_open;
|
|
|
|
|
tmp->low_expr = low_expr;
|
|
|
|
|
tmp->high_open_flag = hig_open;
|
|
|
|
|
tmp->high_expr = hig_expr;
|
|
|
|
|
tmp->next = 0;
|
|
|
|
|
return tmp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void pform_set_parameter(const struct vlltype&loc,
|
2022-01-23 20:51:51 +01:00
|
|
|
perm_string name, bool is_local, data_type_t*data_type, PExpr*expr,
|
2008-09-17 22:25:59 +02:00
|
|
|
LexicalScope::range_t*value_range)
|
1999-02-21 18:01:57 +01:00
|
|
|
{
|
2010-01-08 23:49:48 +01:00
|
|
|
LexicalScope*scope = lexical_scope;
|
2017-10-21 16:04:25 +02:00
|
|
|
if (is_compilation_unit(scope) && !gn_system_verilog()) {
|
2022-01-23 20:51:51 +01:00
|
|
|
VLerror(loc, "error: %s declarations must be contained within a module.",
|
|
|
|
|
is_local ? "localparam" : "parameter");
|
2015-08-21 00:55:00 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2022-02-10 10:13:22 +01:00
|
|
|
|
2022-02-10 14:03:46 +01:00
|
|
|
if (expr == 0) {
|
|
|
|
|
if (is_local) {
|
|
|
|
|
VLerror(loc, "error: localparam must have a value.");
|
|
|
|
|
} else if (!pform_in_parameter_port_list) {
|
|
|
|
|
VLerror(loc, "error: parameter declared outside parameter "
|
|
|
|
|
"port list must have a default value.");
|
|
|
|
|
} else {
|
|
|
|
|
pform_requires_sv(loc, "parameter without default value");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-10 10:13:22 +01:00
|
|
|
bool overridable = !is_local;
|
|
|
|
|
|
2022-01-23 20:51:51 +01:00
|
|
|
if (scope == pform_cur_generate && !is_local) {
|
2022-01-25 11:24:57 +01:00
|
|
|
if (!gn_system_verilog()) {
|
|
|
|
|
VLerror(loc, "parameter declarations are not permitted in generate blocks");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// SystemVerilog allows `parameter` in generate blocks, but it has
|
|
|
|
|
// the same semantics as `localparam` in that scope.
|
|
|
|
|
overridable = false;
|
2008-09-17 22:25:59 +02:00
|
|
|
}
|
2009-04-25 04:07:48 +02:00
|
|
|
|
2022-02-05 12:04:55 +01:00
|
|
|
bool in_module = dynamic_cast<Module*>(scope) &&
|
|
|
|
|
scope == pform_cur_module.front();
|
|
|
|
|
|
|
|
|
|
if (!pform_in_parameter_port_list && in_module &&
|
|
|
|
|
scope->has_parameter_port_list)
|
|
|
|
|
overridable = false;
|
|
|
|
|
|
2022-02-05 11:29:27 +01:00
|
|
|
if (pform_in_class())
|
|
|
|
|
overridable = false;
|
|
|
|
|
|
2019-09-27 01:29:46 +02:00
|
|
|
Module::param_expr_t*parm = new Module::param_expr_t();
|
|
|
|
|
FILE_NAME(parm, loc);
|
2008-05-13 06:26:38 +02:00
|
|
|
|
2019-09-27 01:29:46 +02:00
|
|
|
add_local_symbol(scope, name, parm);
|
2002-08-19 04:39:16 +02:00
|
|
|
|
2019-09-27 01:29:46 +02:00
|
|
|
parm->expr = expr;
|
2020-12-25 03:12:06 +01:00
|
|
|
parm->data_type = data_type;
|
2019-09-27 01:29:46 +02:00
|
|
|
parm->range = value_range;
|
2022-02-09 22:30:12 +01:00
|
|
|
parm->local_flag = is_local;
|
2022-02-10 10:13:22 +01:00
|
|
|
parm->overridable = overridable;
|
2019-09-27 00:35:57 +02:00
|
|
|
|
2022-02-09 22:30:12 +01:00
|
|
|
scope->parameters[name] = parm;
|
1999-02-21 18:01:57 +01:00
|
|
|
|
2022-02-09 22:30:12 +01:00
|
|
|
// Only a module keeps the position of the parameter.
|
2022-02-05 12:04:55 +01:00
|
|
|
if (overridable && in_module)
|
2022-02-09 22:30:12 +01:00
|
|
|
pform_cur_module.front()->param_names.push_back(name);
|
2000-03-12 18:09:40 +01:00
|
|
|
}
|
|
|
|
|
|
2012-05-07 00:11:26 +02:00
|
|
|
void pform_set_specparam(const struct vlltype&loc, perm_string name,
|
|
|
|
|
list<pform_range_t>*range, PExpr*expr)
|
2003-02-27 07:45:11 +01:00
|
|
|
{
|
2012-08-08 20:26:46 +02:00
|
|
|
assert(! pform_cur_module.empty());
|
2012-05-10 04:35:11 +02:00
|
|
|
Module*scope = pform_cur_module.front();
|
2022-02-03 10:48:42 +01:00
|
|
|
if (scope != lexical_scope) {
|
|
|
|
|
delete range;
|
|
|
|
|
delete expr;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2012-05-07 00:11:26 +02:00
|
|
|
|
2003-02-27 07:45:11 +01:00
|
|
|
assert(expr);
|
2019-09-27 01:29:46 +02:00
|
|
|
Module::param_expr_t*parm = new Module::param_expr_t();
|
|
|
|
|
FILE_NAME(parm, loc);
|
|
|
|
|
|
|
|
|
|
add_local_symbol(scope, name, parm);
|
|
|
|
|
pform_cur_module.front()->specparams[name] = parm;
|
2012-05-07 00:11:26 +02:00
|
|
|
|
2019-09-27 01:29:46 +02:00
|
|
|
parm->expr = expr;
|
2020-12-25 03:12:06 +01:00
|
|
|
parm->range = 0;
|
2012-05-07 00:11:26 +02:00
|
|
|
|
|
|
|
|
if (range) {
|
|
|
|
|
assert(range->size() == 1);
|
2020-12-25 03:12:06 +01:00
|
|
|
parm->data_type = new vector_type_t(IVL_VT_LOGIC, false, range);
|
|
|
|
|
parm->range = 0;
|
2012-05-07 00:11:26 +02:00
|
|
|
}
|
2003-02-27 07:45:11 +01:00
|
|
|
}
|
|
|
|
|
|
2007-05-24 06:07:11 +02:00
|
|
|
void pform_set_defparam(const pform_name_t&name, PExpr*expr)
|
2000-03-08 05:36:53 +01:00
|
|
|
{
|
|
|
|
|
assert(expr);
|
2012-08-16 01:07:50 +02:00
|
|
|
if (pform_cur_generate)
|
|
|
|
|
pform_cur_generate->defparms.push_back(make_pair(name,expr));
|
|
|
|
|
else
|
|
|
|
|
pform_cur_module.front()->defparms.push_back(make_pair(name,expr));
|
2000-03-08 05:36:53 +01:00
|
|
|
}
|
|
|
|
|
|
2021-01-18 22:01:23 +01:00
|
|
|
void pform_make_let(const struct vlltype&loc,
|
|
|
|
|
perm_string name,
|
|
|
|
|
list<PLet::let_port*>*ports,
|
|
|
|
|
PExpr*expr)
|
|
|
|
|
{
|
|
|
|
|
LexicalScope*scope = pform_peek_scope();
|
|
|
|
|
|
|
|
|
|
cerr << loc.get_fileline() << ": sorry: let declarations ("
|
|
|
|
|
<< name << ") are not currently supported." << endl;
|
|
|
|
|
error_count += 1;
|
|
|
|
|
|
|
|
|
|
PLet*res = new PLet(name, scope, ports, expr);
|
|
|
|
|
FILE_NAME(res, loc);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
cerr << "Found: ";
|
|
|
|
|
res->dump(cerr, 0);
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
delete res;
|
|
|
|
|
delete ports;
|
|
|
|
|
delete expr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PLet::let_port_t* pform_make_let_port(data_type_t*data_type,
|
|
|
|
|
perm_string name,
|
|
|
|
|
list<pform_range_t>*range,
|
|
|
|
|
PExpr*def)
|
|
|
|
|
{
|
|
|
|
|
PLet::let_port_t*res = new PLet::let_port_t;
|
|
|
|
|
|
|
|
|
|
res->type_ = data_type;
|
|
|
|
|
res->name_ = name;
|
|
|
|
|
res->range_ = range;
|
|
|
|
|
res->def_ = def;
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
2003-02-27 07:45:11 +01:00
|
|
|
/*
|
2006-09-23 06:57:19 +02:00
|
|
|
* Specify paths.
|
2003-02-27 07:45:11 +01:00
|
|
|
*/
|
2006-09-23 06:57:19 +02:00
|
|
|
extern PSpecPath* pform_make_specify_path(const struct vlltype&li,
|
|
|
|
|
list<perm_string>*src, char pol,
|
|
|
|
|
bool full_flag, list<perm_string>*dst)
|
2003-02-27 07:45:11 +01:00
|
|
|
{
|
2011-11-23 04:38:36 +01:00
|
|
|
PSpecPath*path = new PSpecPath(src->size(), dst->size(), pol, full_flag);
|
2022-01-10 11:21:14 +01:00
|
|
|
FILE_NAME(path, li);
|
2006-09-23 06:57:19 +02:00
|
|
|
|
|
|
|
|
unsigned idx;
|
|
|
|
|
list<perm_string>::const_iterator cur;
|
|
|
|
|
|
|
|
|
|
idx = 0;
|
2014-06-30 05:38:23 +02:00
|
|
|
for (idx = 0, cur = src->begin() ; cur != src->end() ; ++ idx, ++ cur) {
|
2006-09-23 06:57:19 +02:00
|
|
|
path->src[idx] = *cur;
|
|
|
|
|
}
|
|
|
|
|
assert(idx == path->src.size());
|
2003-02-27 07:45:11 +01:00
|
|
|
delete src;
|
2006-09-23 06:57:19 +02:00
|
|
|
|
2014-06-30 05:38:23 +02:00
|
|
|
for (idx = 0, cur = dst->begin() ; cur != dst->end() ; ++ idx, ++ cur) {
|
2006-09-23 06:57:19 +02:00
|
|
|
path->dst[idx] = *cur;
|
|
|
|
|
}
|
|
|
|
|
assert(idx == path->dst.size());
|
2003-02-27 07:45:11 +01:00
|
|
|
delete dst;
|
2006-09-23 06:57:19 +02:00
|
|
|
|
|
|
|
|
return path;
|
|
|
|
|
}
|
|
|
|
|
|
2007-02-12 02:52:21 +01:00
|
|
|
extern PSpecPath*pform_make_specify_edge_path(const struct vlltype&li,
|
2007-04-13 04:34:35 +02:00
|
|
|
int edge_flag, /*posedge==true */
|
2007-02-12 02:52:21 +01:00
|
|
|
list<perm_string>*src, char pol,
|
|
|
|
|
bool full_flag, list<perm_string>*dst,
|
|
|
|
|
PExpr*data_source_expression)
|
|
|
|
|
{
|
|
|
|
|
PSpecPath*tmp = pform_make_specify_path(li, src, pol, full_flag, dst);
|
2007-04-13 04:34:35 +02:00
|
|
|
tmp->edge = edge_flag;
|
2007-02-12 02:52:21 +01:00
|
|
|
tmp->data_source_expression = data_source_expression;
|
|
|
|
|
return tmp;
|
|
|
|
|
}
|
|
|
|
|
|
2010-10-26 04:36:44 +02:00
|
|
|
extern PSpecPath* pform_assign_path_delay(PSpecPath*path, list<PExpr*>*del)
|
2006-09-23 06:57:19 +02:00
|
|
|
{
|
2007-02-12 02:52:21 +01:00
|
|
|
if (path == 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2011-04-19 03:17:16 +02:00
|
|
|
assert(path->delays.empty());
|
2006-09-23 06:57:19 +02:00
|
|
|
|
2010-10-26 04:36:44 +02:00
|
|
|
path->delays.resize(del->size());
|
|
|
|
|
for (unsigned idx = 0 ; idx < path->delays.size() ; idx += 1) {
|
|
|
|
|
path->delays[idx] = del->front();
|
|
|
|
|
del->pop_front();
|
|
|
|
|
}
|
2006-09-23 06:57:19 +02:00
|
|
|
|
|
|
|
|
delete del;
|
|
|
|
|
|
|
|
|
|
return path;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extern void pform_module_specify_path(PSpecPath*obj)
|
|
|
|
|
{
|
2007-02-12 02:52:21 +01:00
|
|
|
if (obj == 0)
|
|
|
|
|
return;
|
2012-05-10 04:35:11 +02:00
|
|
|
pform_cur_module.front()->specify_paths.push_back(obj);
|
2003-02-27 07:45:11 +01:00
|
|
|
}
|
|
|
|
|
|
2012-03-10 03:54:05 +01:00
|
|
|
|
2001-11-10 03:08:49 +01:00
|
|
|
void pform_set_port_type(const struct vlltype&li,
|
2016-04-04 21:40:30 +02:00
|
|
|
list<pform_port_t>*ports,
|
2013-05-19 10:16:24 +02:00
|
|
|
NetNet::PortType pt,
|
2016-04-04 21:40:30 +02:00
|
|
|
data_type_t*dt,
|
2013-05-19 10:16:24 +02:00
|
|
|
list<named_pexpr_t>*attr)
|
1998-11-04 00:28:49 +01:00
|
|
|
{
|
2012-03-10 03:54:05 +01:00
|
|
|
assert(pt != NetNet::PIMPLICIT && pt != NetNet::NOT_A_PORT);
|
|
|
|
|
|
2022-04-21 10:28:44 +02:00
|
|
|
vector_type_t *vt = dynamic_cast<vector_type_t*> (dt);
|
2016-04-04 21:40:30 +02:00
|
|
|
|
|
|
|
|
bool have_init_expr = false;
|
|
|
|
|
for (list<pform_port_t>::iterator cur = ports->begin()
|
|
|
|
|
; cur != ports->end() ; ++ cur ) {
|
|
|
|
|
|
2022-04-23 12:22:21 +02:00
|
|
|
PWire *wire = pform_get_or_make_wire(li, cur->name,
|
|
|
|
|
NetNet::IMPLICIT, pt,
|
|
|
|
|
SR_PORT);
|
2022-04-21 10:28:44 +02:00
|
|
|
pform_set_net_range(wire, vt, SR_PORT, attr);
|
|
|
|
|
|
2016-04-04 21:40:30 +02:00
|
|
|
if (cur->udims) {
|
2022-01-10 11:21:14 +01:00
|
|
|
cerr << li << ": warning: "
|
2016-04-04 21:40:30 +02:00
|
|
|
<< "Array dimensions in incomplete port declarations "
|
|
|
|
|
<< "are currently ignored." << endl;
|
2022-01-10 11:21:14 +01:00
|
|
|
cerr << li << ": : "
|
2016-04-04 21:40:30 +02:00
|
|
|
<< "The dimensions specified in the net or variable "
|
|
|
|
|
<< "declaration will be used." << endl;
|
|
|
|
|
delete cur->udims;
|
|
|
|
|
}
|
|
|
|
|
if (cur->expr) {
|
|
|
|
|
have_init_expr = true;
|
|
|
|
|
delete cur->expr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (have_init_expr) {
|
2022-01-10 11:21:14 +01:00
|
|
|
cerr << li << ": error: "
|
2016-04-04 21:40:30 +02:00
|
|
|
<< "Incomplete port declarations cannot be initialized."
|
|
|
|
|
<< endl;
|
|
|
|
|
error_count += 1;
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
2000-10-31 18:00:04 +01:00
|
|
|
|
2016-04-04 21:40:30 +02:00
|
|
|
delete ports;
|
|
|
|
|
delete dt;
|
2013-05-19 10:16:24 +02:00
|
|
|
delete attr;
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
2012-01-08 00:37:30 +01:00
|
|
|
/*
|
|
|
|
|
* This function detects the derived class for the given type and
|
|
|
|
|
* dispatches the type to the proper subtype function.
|
|
|
|
|
*/
|
2022-04-17 20:57:03 +02:00
|
|
|
void pform_set_data_type(const struct vlltype&li, data_type_t*data_type,
|
|
|
|
|
std::vector<PWire*> *wires, NetNet::Type net_type,
|
|
|
|
|
list<named_pexpr_t>*attr)
|
2012-01-08 00:37:30 +01:00
|
|
|
{
|
2012-09-03 20:20:29 +02:00
|
|
|
if (data_type == 0) {
|
|
|
|
|
VLerror(li, "internal error: data_type==0.");
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-18 11:01:54 +02:00
|
|
|
vector_type_t*vec_type = dynamic_cast<vector_type_t*> (data_type);
|
2012-06-18 03:22:50 +02:00
|
|
|
|
2022-04-17 20:57:03 +02:00
|
|
|
for (std::vector<PWire*>::iterator it= wires->begin();
|
|
|
|
|
it != wires->end() ; ++it) {
|
|
|
|
|
PWire *wire = *it;
|
2022-01-09 19:09:08 +01:00
|
|
|
|
2022-04-21 10:28:44 +02:00
|
|
|
pform_set_net_range(wire, vec_type);
|
2022-04-18 11:01:54 +02:00
|
|
|
|
2022-01-09 19:09:08 +01:00
|
|
|
// If these fail there is a bug somewhere else. pform_set_data_type()
|
|
|
|
|
// is only ever called on a fresh wire that already exists.
|
|
|
|
|
bool rc = wire->set_wire_type(net_type);
|
|
|
|
|
ivl_assert(li, rc);
|
|
|
|
|
|
2019-12-22 12:03:50 +01:00
|
|
|
wire->set_data_type(data_type);
|
2022-01-09 19:09:08 +01:00
|
|
|
|
|
|
|
|
pform_bind_attributes(wire->attributes, attr, true);
|
2014-12-15 11:25:35 +01:00
|
|
|
}
|
|
|
|
|
|
2022-04-17 20:57:03 +02:00
|
|
|
delete wires;
|
2012-01-08 00:37:30 +01:00
|
|
|
}
|
|
|
|
|
|
2013-02-25 03:06:12 +01:00
|
|
|
vector<PWire*>* pform_make_udp_input_ports(list<perm_string>*names)
|
1998-11-25 03:35:53 +01:00
|
|
|
{
|
2013-02-25 03:06:12 +01:00
|
|
|
vector<PWire*>*out = new vector<PWire*>(names->size());
|
1998-11-25 03:35:53 +01:00
|
|
|
|
1999-06-12 22:35:27 +02:00
|
|
|
unsigned idx = 0;
|
2004-05-25 21:21:06 +02:00
|
|
|
for (list<perm_string>::iterator cur = names->begin()
|
2010-10-23 23:57:59 +02:00
|
|
|
; cur != names->end() ; ++ cur ) {
|
2004-05-25 21:21:06 +02:00
|
|
|
perm_string txt = *cur;
|
2008-02-25 04:40:54 +01:00
|
|
|
PWire*pp = new PWire(txt,
|
2004-05-25 21:21:06 +02:00
|
|
|
NetNet::IMPLICIT,
|
2005-07-07 18:22:49 +02:00
|
|
|
NetNet::PINPUT,
|
|
|
|
|
IVL_VT_LOGIC);
|
1999-06-12 22:35:27 +02:00
|
|
|
(*out)[idx] = pp;
|
1999-06-21 03:02:16 +02:00
|
|
|
idx += 1;
|
1998-11-25 03:35:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
delete names;
|
|
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
|
2008-10-22 07:15:49 +02:00
|
|
|
PProcess* pform_make_behavior(ivl_process_type_t type, Statement*st,
|
2010-11-13 03:47:06 +01:00
|
|
|
list<named_pexpr_t>*attr)
|
1998-11-04 00:28:49 +01:00
|
|
|
{
|
2017-11-20 16:48:35 +01:00
|
|
|
// Add an implicit @* around the statement for the always_comb and
|
|
|
|
|
// always_latch statements.
|
|
|
|
|
if ((type == IVL_PR_ALWAYS_COMB) || (type == IVL_PR_ALWAYS_LATCH)) {
|
|
|
|
|
PEventStatement *tmp = new PEventStatement(true);
|
2022-01-10 11:21:14 +01:00
|
|
|
tmp->set_line(*st);
|
2017-11-20 16:48:35 +01:00
|
|
|
tmp->set_statement(st);
|
|
|
|
|
st = tmp;
|
|
|
|
|
}
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
PProcess*pp = new PProcess(type, st);
|
2002-05-26 03:39:02 +02:00
|
|
|
|
2014-07-16 03:03:40 +02:00
|
|
|
// If we are in a part of the code where the meta-comment
|
|
|
|
|
// synthesis translate_off is in effect, then implicitly add
|
|
|
|
|
// the ivl_synthesis_off attribute to any behavioral code that
|
|
|
|
|
// we run into.
|
|
|
|
|
if (pform_mc_translate_flag == false) {
|
|
|
|
|
if (attr == 0) attr = new list<named_pexpr_t>;
|
|
|
|
|
named_pexpr_t tmp;
|
|
|
|
|
tmp.name = perm_string::literal("ivl_synthesis_off");
|
|
|
|
|
tmp.parm = 0;
|
|
|
|
|
attr->push_back(tmp);
|
|
|
|
|
}
|
|
|
|
|
|
2008-09-05 06:27:21 +02:00
|
|
|
pform_bind_attributes(pp->attributes, attr);
|
2002-05-26 03:39:02 +02:00
|
|
|
|
2008-06-20 06:31:53 +02:00
|
|
|
pform_put_behavior_in_scope(pp);
|
2012-05-06 19:21:51 +02:00
|
|
|
|
2012-08-08 20:26:46 +02:00
|
|
|
ivl_assert(*st, ! pform_cur_module.empty());
|
2017-11-20 16:48:35 +01:00
|
|
|
if (pform_cur_module.front()->program_block &&
|
|
|
|
|
((type == IVL_PR_ALWAYS) || (type == IVL_PR_ALWAYS_COMB) ||
|
|
|
|
|
(type == IVL_PR_ALWAYS_FF) || (type == IVL_PR_ALWAYS_LATCH))) {
|
|
|
|
|
cerr << st->get_fileline() << ": error: Always statements are not allowed"
|
2012-05-06 19:21:51 +02:00
|
|
|
<< " in program blocks." << endl;
|
|
|
|
|
error_count += 1;
|
|
|
|
|
}
|
|
|
|
|
|
1999-01-25 06:45:56 +01:00
|
|
|
return pp;
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
2015-01-10 12:09:42 +01:00
|
|
|
void pform_start_modport_item(const struct vlltype&loc, const char*name)
|
|
|
|
|
{
|
|
|
|
|
Module*scope = pform_cur_module.front();
|
|
|
|
|
ivl_assert(loc, scope && scope->is_interface);
|
|
|
|
|
ivl_assert(loc, pform_cur_modport == 0);
|
|
|
|
|
|
|
|
|
|
perm_string use_name = lex_strings.make(name);
|
|
|
|
|
pform_cur_modport = new PModport(use_name);
|
|
|
|
|
FILE_NAME(pform_cur_modport, loc);
|
2019-09-27 00:35:57 +02:00
|
|
|
|
|
|
|
|
add_local_symbol(scope, use_name, pform_cur_modport);
|
2015-01-10 12:09:42 +01:00
|
|
|
scope->modports[use_name] = pform_cur_modport;
|
2019-09-27 00:35:57 +02:00
|
|
|
|
2015-01-10 12:09:42 +01:00
|
|
|
delete[] name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void pform_end_modport_item(const struct vlltype&loc)
|
|
|
|
|
{
|
|
|
|
|
ivl_assert(loc, pform_cur_modport);
|
|
|
|
|
pform_cur_modport = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void pform_add_modport_port(const struct vlltype&loc,
|
|
|
|
|
NetNet::PortType port_type,
|
|
|
|
|
perm_string name, PExpr*expr)
|
|
|
|
|
{
|
|
|
|
|
ivl_assert(loc, pform_cur_modport);
|
|
|
|
|
|
|
|
|
|
if (pform_cur_modport->simple_ports.find(name)
|
|
|
|
|
!= pform_cur_modport->simple_ports.end()) {
|
|
|
|
|
cerr << loc << ": error: duplicate declaration of port '"
|
|
|
|
|
<< name << "' in modport list '"
|
|
|
|
|
<< pform_cur_modport->name() << "'." << endl;
|
|
|
|
|
error_count += 1;
|
|
|
|
|
}
|
|
|
|
|
pform_cur_modport->simple_ports[name] = make_pair(port_type, expr);
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-05 10:49:34 +01:00
|
|
|
bool pform_requires_sv(const struct vlltype&loc, const char *feature)
|
|
|
|
|
{
|
|
|
|
|
if (gn_system_verilog())
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
VLerror(loc, "error: %s requires SystemVerilog.", feature);
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
1998-11-04 00:28:49 +01:00
|
|
|
|
2022-01-20 15:59:28 +01:00
|
|
|
void pform_check_net_data_type(const struct vlltype&loc, NetNet::Type net_type,
|
|
|
|
|
const data_type_t *data_type)
|
|
|
|
|
{
|
|
|
|
|
// For SystemVerilog the type is checked during elaboration since due to
|
|
|
|
|
// forward typedefs and type parameters the actual type might not be known
|
|
|
|
|
// yet.
|
|
|
|
|
if (gn_system_verilog())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
switch (net_type) {
|
|
|
|
|
case NetNet::REG:
|
|
|
|
|
case NetNet::IMPLICIT_REG:
|
|
|
|
|
return;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!data_type)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
const vector_type_t*vec_type = dynamic_cast<const vector_type_t*>(data_type);
|
|
|
|
|
if (vec_type && vec_type->implicit_flag)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
const real_type_t*rtype = dynamic_cast<const real_type_t*>(data_type);
|
|
|
|
|
if (rtype && rtype->type_code() == real_type_t::REAL)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
pform_requires_sv(loc, "Net data type");
|
|
|
|
|
}
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
FILE*vl_input = 0;
|
2001-10-21 01:02:39 +02:00
|
|
|
extern void reset_lexor();
|
|
|
|
|
|
2017-10-15 12:45:35 +02:00
|
|
|
int pform_parse(const char*path)
|
1998-11-04 00:28:49 +01:00
|
|
|
{
|
1998-12-09 05:02:47 +01:00
|
|
|
vl_file = path;
|
2017-10-15 12:45:35 +02:00
|
|
|
if (strcmp(path, "-") == 0) {
|
|
|
|
|
vl_input = stdin;
|
|
|
|
|
} else if (ivlpp_string) {
|
|
|
|
|
char*cmdline = (char*)malloc(strlen(ivlpp_string) +
|
|
|
|
|
strlen(path) + 4);
|
|
|
|
|
strcpy(cmdline, ivlpp_string);
|
|
|
|
|
strcat(cmdline, " \"");
|
|
|
|
|
strcat(cmdline, path);
|
|
|
|
|
strcat(cmdline, "\"");
|
|
|
|
|
|
|
|
|
|
if (verbose_flag)
|
|
|
|
|
cerr << "Executing: " << cmdline << endl<< flush;
|
|
|
|
|
|
|
|
|
|
vl_input = popen(cmdline, "r");
|
2001-10-21 01:02:39 +02:00
|
|
|
if (vl_input == 0) {
|
2017-10-15 12:45:35 +02:00
|
|
|
cerr << "Unable to preprocess " << path << "." << endl;
|
|
|
|
|
return 1;
|
2001-10-21 01:02:39 +02:00
|
|
|
}
|
|
|
|
|
|
2017-10-15 12:45:35 +02:00
|
|
|
if (verbose_flag)
|
|
|
|
|
cerr << "...parsing output from preprocessor..." << endl << flush;
|
|
|
|
|
|
|
|
|
|
free(cmdline);
|
2001-10-21 01:02:39 +02:00
|
|
|
} else {
|
2017-10-15 12:45:35 +02:00
|
|
|
vl_input = fopen(path, "r");
|
|
|
|
|
if (vl_input == 0) {
|
|
|
|
|
cerr << "Unable to open " << path << "." << endl;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
1998-12-09 05:02:47 +01:00
|
|
|
}
|
|
|
|
|
|
2017-10-21 16:04:25 +02:00
|
|
|
if (pform_units.empty() || separate_compilation) {
|
|
|
|
|
char unit_name[20];
|
|
|
|
|
static unsigned nunits = 0;
|
|
|
|
|
if (separate_compilation)
|
|
|
|
|
sprintf(unit_name, "$unit#%u", ++nunits);
|
|
|
|
|
else
|
|
|
|
|
sprintf(unit_name, "$unit");
|
2017-11-05 18:50:05 +01:00
|
|
|
|
2017-10-21 16:04:25 +02:00
|
|
|
PPackage*unit = new PPackage(lex_strings.make(unit_name), 0);
|
|
|
|
|
unit->default_lifetime = LexicalScope::STATIC;
|
2017-11-05 18:50:05 +01:00
|
|
|
unit->set_file(filename_strings.make(path));
|
|
|
|
|
unit->set_lineno(1);
|
2017-10-21 16:04:25 +02:00
|
|
|
pform_units.push_back(unit);
|
2017-11-05 18:50:05 +01:00
|
|
|
|
2019-07-23 23:18:39 +02:00
|
|
|
pform_cur_module.clear();
|
|
|
|
|
pform_cur_generate = 0;
|
|
|
|
|
pform_cur_modport = 0;
|
|
|
|
|
|
2017-11-05 18:50:05 +01:00
|
|
|
pform_set_timescale(def_ts_units, def_ts_prec, 0, 0);
|
|
|
|
|
|
|
|
|
|
allow_timeunit_decl = true;
|
|
|
|
|
allow_timeprec_decl = true;
|
|
|
|
|
|
2017-10-21 16:04:25 +02:00
|
|
|
lexical_scope = unit;
|
|
|
|
|
}
|
2001-10-21 01:02:39 +02:00
|
|
|
reset_lexor();
|
1998-11-07 18:05:05 +01:00
|
|
|
error_count = 0;
|
|
|
|
|
warn_count = 0;
|
1998-11-04 00:28:49 +01:00
|
|
|
int rc = VLparse();
|
2001-10-21 01:02:39 +02:00
|
|
|
|
2017-10-15 12:45:35 +02:00
|
|
|
if (vl_input != stdin) {
|
|
|
|
|
if (ivlpp_string)
|
|
|
|
|
pclose(vl_input);
|
2017-11-05 23:28:21 +01:00
|
|
|
else
|
2017-10-15 12:45:35 +02:00
|
|
|
fclose(vl_input);
|
|
|
|
|
}
|
2001-10-21 01:02:39 +02:00
|
|
|
|
1998-11-07 18:05:05 +01:00
|
|
|
if (rc) {
|
|
|
|
|
cerr << "I give up." << endl;
|
2000-09-13 18:32:26 +02:00
|
|
|
error_count += 1;
|
1998-11-07 18:05:05 +01:00
|
|
|
}
|
1998-11-25 03:35:53 +01:00
|
|
|
|
2009-06-09 22:12:45 +02:00
|
|
|
destroy_lexor();
|
1998-11-07 18:05:05 +01:00
|
|
|
return error_count;
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|