1998-11-04 00:28:49 +01:00
|
|
|
/*
|
2008-05-06 04:46:30 +02:00
|
|
|
* Copyright (c) 1998-2008 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
|
|
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
|
|
|
|
*/
|
|
|
|
|
|
2001-07-25 05:10:48 +02:00
|
|
|
# include "config.h"
|
|
|
|
|
|
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"
|
2000-04-01 21:31:57 +02:00
|
|
|
# include "PEvent.h"
|
1998-11-25 03:35:53 +01:00
|
|
|
# include "PUdp.h"
|
2006-04-10 02:37:42 +02:00
|
|
|
# include "PGenerate.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>
|
1998-11-04 00:28:49 +01:00
|
|
|
# include <assert.h>
|
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>
|
1998-11-04 00:28:49 +01:00
|
|
|
|
2008-01-04 05:13:56 +01:00
|
|
|
# include "ivl_assert.h"
|
|
|
|
|
|
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
|
|
|
|
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. */
|
1999-07-03 04:12:51 +02:00
|
|
|
static Module*pform_cur_module = 0;
|
2007-04-19 04:52:53 +02:00
|
|
|
|
|
|
|
|
bool pform_library_flag = false;
|
|
|
|
|
|
2006-04-10 02:37:42 +02:00
|
|
|
/* increment this for generate schemes within a module, and set it
|
|
|
|
|
to zero when a new module starts. */
|
|
|
|
|
static unsigned scope_generate_counter = 1;
|
|
|
|
|
|
|
|
|
|
/* 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
|
|
|
|
2004-06-13 06:56:53 +02:00
|
|
|
static NetNet::Type pform_default_nettype = NetNet::WIRE;
|
|
|
|
|
|
2002-04-15 02:04:22 +02:00
|
|
|
/*
|
|
|
|
|
* These variables track the current time scale, as well as where the
|
|
|
|
|
* timescale was set. This supports warnings about tangled timescales.
|
|
|
|
|
*/
|
2000-07-23 00:09:03 +02:00
|
|
|
static int pform_time_unit = 0;
|
|
|
|
|
static int pform_time_prec = 0;
|
1998-11-04 00:28:49 +01:00
|
|
|
|
2002-04-15 02:04:22 +02:00
|
|
|
static char*pform_timescale_file = 0;
|
|
|
|
|
static unsigned pform_timescale_line = 0;
|
|
|
|
|
|
2007-12-20 18:31:01 +01:00
|
|
|
static inline void FILE_NAME(LineInfo*obj, const char*file, unsigned lineno)
|
|
|
|
|
{
|
|
|
|
|
obj->set_lineno(lineno);
|
|
|
|
|
obj->set_file(filename_strings.make(file));
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
*/
|
2008-02-16 06:20:24 +01:00
|
|
|
static PScope* lexical_scope = 0;
|
2000-07-23 00:09:03 +02:00
|
|
|
|
1999-06-24 06:24:18 +02:00
|
|
|
void pform_pop_scope()
|
|
|
|
|
{
|
2008-02-16 06:20:24 +01:00
|
|
|
lexical_scope = lexical_scope->pscope_parent();
|
1999-06-24 06:24:18 +02:00
|
|
|
}
|
|
|
|
|
|
2008-02-16 06:20:24 +01:00
|
|
|
PTask* pform_push_task_scope(char*name)
|
|
|
|
|
{
|
|
|
|
|
perm_string task_name = lex_strings.make(name);
|
|
|
|
|
PTask*task = new PTask(task_name, pform_cur_module);
|
|
|
|
|
|
|
|
|
|
// Add the task to the current module
|
|
|
|
|
pform_cur_module->add_task(task->pscope_name(), task);
|
|
|
|
|
// Make this the current lexical scope
|
|
|
|
|
lexical_scope = task;
|
|
|
|
|
return task;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PFunction* pform_push_function_scope(char*name)
|
|
|
|
|
{
|
|
|
|
|
perm_string func_name = lex_strings.make(name);
|
|
|
|
|
PFunction*func = new PFunction(func_name, lexical_scope);
|
|
|
|
|
|
|
|
|
|
// Add the task to the current module
|
|
|
|
|
pform_cur_module->add_function(func->pscope_name(), func);
|
|
|
|
|
// Make this the current lexical scope
|
|
|
|
|
lexical_scope = func;
|
|
|
|
|
return func;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PBlock* pform_push_block_scope(char*name, PBlock::BL_TYPE bt)
|
|
|
|
|
{
|
|
|
|
|
perm_string block_name = lex_strings.make(name);
|
|
|
|
|
PBlock*block = new PBlock(block_name, lexical_scope, bt);
|
|
|
|
|
|
2008-02-25 04:40:54 +01:00
|
|
|
// Make this the current lexical scope
|
|
|
|
|
lexical_scope = block;
|
|
|
|
|
|
2008-02-16 06:20:24 +01:00
|
|
|
return block;
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
{
|
|
|
|
|
/* Note that if we are processing a generate, then the
|
|
|
|
|
scope depth will be empty because generate schemes
|
|
|
|
|
cannot be within sub-scopes. Only directly in
|
|
|
|
|
modules. */
|
|
|
|
|
if (pform_cur_generate)
|
|
|
|
|
return pform_cur_generate->get_wire(name);
|
|
|
|
|
|
2008-02-25 04:40:54 +01:00
|
|
|
return lexical_scope->wires_find(name);
|
2006-04-10 02:37:42 +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;
|
|
|
|
|
|
|
|
|
|
if (pform_cur_module) {
|
|
|
|
|
cerr << file<<":"<<lineno << ": error: "
|
|
|
|
|
<< "`default_nettype directives must appear" << endl;
|
|
|
|
|
cerr << file<<":"<<lineno << ": : "
|
|
|
|
|
<< "outside module definitions. The containing" << endl;
|
|
|
|
|
cerr << file<<":"<<lineno << ": : "
|
|
|
|
|
<< "module " << pform_cur_module->mod_name()
|
|
|
|
|
<< " starts on line "
|
2007-12-20 18:31:01 +01:00
|
|
|
<< pform_cur_module->get_fileline() << "." << endl;
|
2004-06-13 06:56:53 +02:00
|
|
|
error_count += 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
|
|
* values (for use by modules) and if warnings are enabled checks to
|
|
|
|
|
* see if some modules have no timescale.
|
|
|
|
|
*/
|
|
|
|
|
void pform_set_timescale(int unit, int prec,
|
|
|
|
|
const char*file, unsigned lineno)
|
2001-12-03 05:47:14 +01:00
|
|
|
{
|
2002-04-18 20:38:37 +02:00
|
|
|
bool first_flag = true;
|
|
|
|
|
|
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
|
|
|
first_flag = false;
|
|
|
|
|
}
|
2002-04-15 02:04:22 +02:00
|
|
|
|
|
|
|
|
pform_timescale_file = strdup(file);
|
|
|
|
|
pform_timescale_line = lineno;
|
|
|
|
|
|
2002-04-18 20:38:37 +02:00
|
|
|
if (warn_timescale && first_flag && (pform_modules.size() > 0)) {
|
2002-04-15 02:04:22 +02:00
|
|
|
cerr << file << ":" << lineno << ": warning: "
|
|
|
|
|
<< "Some modules have no timescale. This may cause"
|
|
|
|
|
<< endl;
|
|
|
|
|
cerr << file << ":" << lineno << ": : "
|
|
|
|
|
<< "confusing timing results. Affected modules are:"
|
|
|
|
|
<< endl;
|
|
|
|
|
|
2004-02-18 18:11:54 +01:00
|
|
|
map<perm_string,Module*>::iterator mod;
|
2002-04-15 02:04:22 +02:00
|
|
|
for (mod = pform_modules.begin()
|
|
|
|
|
; mod != pform_modules.end() ; mod++) {
|
|
|
|
|
const Module*mp = (*mod).second;
|
|
|
|
|
|
|
|
|
|
cerr << file << ":" << lineno << ": : "
|
|
|
|
|
<< " -- module " << (*mod).first
|
2007-12-20 18:31:01 +01:00
|
|
|
<< " declared here: " << mp->get_fileline() << endl;
|
2002-04-15 02:04:22 +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();
|
|
|
|
|
|
|
|
|
|
verinum::V pad;
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2003-06-20 02:53:19 +02:00
|
|
|
void pform_startmodule(const char*name, const char*file, unsigned lineno,
|
|
|
|
|
svector<named_pexpr_t*>*attr)
|
1998-11-04 00:28:49 +01:00
|
|
|
{
|
1999-07-03 04:12:51 +02:00
|
|
|
assert( pform_cur_module == 0 );
|
1999-09-17 04:06:25 +02:00
|
|
|
|
2004-02-18 18:11:54 +01:00
|
|
|
perm_string lex_name = lex_strings.make(name);
|
2003-03-06 05:37:12 +01:00
|
|
|
pform_cur_module = new Module(lex_name);
|
2000-07-23 00:09:03 +02:00
|
|
|
pform_cur_module->time_unit = pform_time_unit;
|
|
|
|
|
pform_cur_module->time_precision = pform_time_prec;
|
2004-06-13 06:56:53 +02:00
|
|
|
pform_cur_module->default_nettype = pform_default_nettype;
|
2001-10-31 04:11:15 +01:00
|
|
|
|
2007-12-20 18:31:01 +01:00
|
|
|
FILE_NAME(pform_cur_module, file, lineno);
|
2007-04-19 04:52:53 +02:00
|
|
|
pform_cur_module->library_flag = pform_library_flag;
|
2001-10-31 04:11:15 +01:00
|
|
|
|
2008-02-25 04:40:54 +01:00
|
|
|
ivl_assert(*pform_cur_module, lexical_scope == 0);
|
|
|
|
|
lexical_scope = pform_cur_module;
|
|
|
|
|
|
2006-04-10 02:37:42 +02:00
|
|
|
/* The generate scheme numbering starts with *1*, not
|
|
|
|
|
zero. That's just the way it is, thanks to the standard. */
|
|
|
|
|
scope_generate_counter = 1;
|
|
|
|
|
|
2002-04-15 02:04:22 +02:00
|
|
|
if (warn_timescale && pform_timescale_file
|
|
|
|
|
&& (strcmp(pform_timescale_file,file) != 0)) {
|
|
|
|
|
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << pform_cur_module->get_fileline() << ": warning: "
|
2002-04-15 02:04:22 +02:00
|
|
|
<< "timescale for " << name
|
|
|
|
|
<< " inherited from another file." << endl;
|
|
|
|
|
cerr << pform_timescale_file << ":" << pform_timescale_line
|
|
|
|
|
<< ": ...: The inherited timescale is here." << endl;
|
|
|
|
|
}
|
2003-06-20 02:53:19 +02:00
|
|
|
if (attr) {
|
|
|
|
|
for (unsigned idx = 0 ; idx < attr->count() ; idx += 1) {
|
|
|
|
|
named_pexpr_t*tmp = (*attr)[idx];
|
2004-02-20 19:53:33 +01:00
|
|
|
pform_cur_module->attributes[tmp->name] = tmp->parm;
|
2003-06-20 02:53:19 +02:00
|
|
|
}
|
|
|
|
|
}
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
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.
|
|
|
|
|
*/
|
2008-02-25 04:40:54 +01:00
|
|
|
Module::port_t* pform_module_port_reference(perm_string name,
|
2002-05-20 01:37:28 +02:00
|
|
|
const char*file,
|
|
|
|
|
unsigned lineno)
|
|
|
|
|
{
|
|
|
|
|
Module::port_t*ptmp = new Module::port_t;
|
2008-02-25 04:40:54 +01:00
|
|
|
PEIdent*tmp = new PEIdent(name);
|
2007-12-20 18:31:01 +01:00
|
|
|
FILE_NAME(tmp, file, lineno);
|
2008-02-25 04:40:54 +01:00
|
|
|
ptmp->name = name;
|
2002-05-20 01:37:28 +02:00
|
|
|
ptmp->expr = svector<PEIdent*>(1);
|
|
|
|
|
ptmp->expr[0] = tmp;
|
|
|
|
|
|
|
|
|
|
return ptmp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void pform_module_set_ports(svector<Module::port_t*>*ports)
|
|
|
|
|
{
|
|
|
|
|
assert(pform_cur_module);
|
|
|
|
|
|
|
|
|
|
/* The parser parses ``module foo()'' as having one
|
|
|
|
|
unconnected port, but it is really a module with no
|
|
|
|
|
ports. Fix it up here. */
|
|
|
|
|
if (ports && (ports->count() == 1) && ((*ports)[0] == 0)) {
|
|
|
|
|
delete ports;
|
|
|
|
|
ports = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ports != 0) {
|
|
|
|
|
pform_cur_module->ports = *ports;
|
|
|
|
|
delete ports;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2001-10-20 07:21:51 +02:00
|
|
|
void pform_endmodule(const char*name)
|
1998-11-04 00:28:49 +01:00
|
|
|
{
|
1999-07-03 04:12:51 +02:00
|
|
|
assert(pform_cur_module);
|
2004-02-18 18:11:54 +01:00
|
|
|
perm_string mod_name = pform_cur_module->mod_name();
|
|
|
|
|
assert(strcmp(name, mod_name) == 0);
|
|
|
|
|
|
2004-10-04 03:10:51 +02:00
|
|
|
map<perm_string,Module*>::const_iterator test =
|
2004-02-18 18:11:54 +01:00
|
|
|
pform_modules.find(mod_name);
|
2003-01-16 22:44:19 +01:00
|
|
|
|
|
|
|
|
if (test != pform_modules.end()) {
|
|
|
|
|
ostringstream msg;
|
|
|
|
|
msg << "Module " << name << " was already declared here: "
|
2007-12-20 18:31:01 +01: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 {
|
|
|
|
|
pform_modules[mod_name] = pform_cur_module;
|
2003-01-16 22:44:19 +01:00
|
|
|
}
|
2008-02-25 04:40:54 +01:00
|
|
|
|
|
|
|
|
// The current lexical scope should be this module by now, and
|
|
|
|
|
// this module should not have a parent lexical scope.
|
|
|
|
|
ivl_assert(*pform_cur_module, lexical_scope == pform_cur_module);
|
|
|
|
|
lexical_scope = pform_cur_module->pscope_parent();
|
|
|
|
|
ivl_assert(*pform_cur_module, lexical_scope == 0);
|
|
|
|
|
|
1999-07-03 04:12:51 +02:00
|
|
|
pform_cur_module = 0;
|
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++) {
|
2008-05-06 04:46:30 +02:00
|
|
|
LineInfo*lni = new LineInfo();
|
|
|
|
|
FILE_NAME(lni, li);
|
2008-05-06 05:56:50 +02:00
|
|
|
pform_cur_module->genvars[*cur] = lni;
|
2006-04-10 02:37:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
delete names;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void pform_start_generate_for(const struct vlltype&li,
|
|
|
|
|
char*ident1, PExpr*init,
|
|
|
|
|
PExpr*test,
|
|
|
|
|
char*ident2, PExpr*next)
|
|
|
|
|
{
|
|
|
|
|
PGenerate*gen = new PGenerate(scope_generate_counter++);
|
|
|
|
|
|
2007-12-20 18:31:01 +01:00
|
|
|
FILE_NAME(gen, li);
|
2006-04-10 02:37:42 +02:00
|
|
|
|
|
|
|
|
// For now, assume that generates do not nest.
|
2007-06-02 05:42:12 +02:00
|
|
|
gen->parent = pform_cur_generate;
|
2006-04-10 02:37:42 +02:00
|
|
|
pform_cur_generate = gen;
|
|
|
|
|
|
|
|
|
|
pform_cur_generate->scheme_type = PGenerate::GS_LOOP;
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
PGenerate*gen = new PGenerate(scope_generate_counter++);
|
|
|
|
|
|
2007-12-20 18:31:01 +01:00
|
|
|
FILE_NAME(gen, li);
|
2007-06-22 04:04:48 +02:00
|
|
|
|
|
|
|
|
// For now, assume that generates do not nest.
|
|
|
|
|
gen->parent = pform_cur_generate;
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
pform_endgenerate();
|
|
|
|
|
|
|
|
|
|
PGenerate*gen = new PGenerate(scope_generate_counter++);
|
|
|
|
|
|
2007-12-20 18:31:01 +01:00
|
|
|
FILE_NAME(gen, li);
|
2007-06-22 04:04:48 +02:00
|
|
|
|
|
|
|
|
// For now, assume that generates do not nest.
|
|
|
|
|
gen->parent = pform_cur_generate;
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
PGenerate*gen = new PGenerate(scope_generate_counter++);
|
|
|
|
|
|
|
|
|
|
FILE_NAME(gen, li);
|
|
|
|
|
|
|
|
|
|
gen->parent = pform_cur_generate;
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* 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.
|
|
|
|
|
*/
|
|
|
|
|
void pform_generate_case_item(const struct vlltype&li, PExpr*expr)
|
|
|
|
|
{
|
|
|
|
|
assert(pform_cur_generate);
|
|
|
|
|
assert(pform_cur_generate->scheme_type == PGenerate::GS_CASE);
|
|
|
|
|
|
|
|
|
|
PGenerate*gen = new PGenerate(pform_cur_generate->id_number);
|
|
|
|
|
|
|
|
|
|
FILE_NAME(gen, li);
|
|
|
|
|
|
|
|
|
|
gen->parent = pform_cur_generate;
|
|
|
|
|
pform_cur_generate = gen;
|
|
|
|
|
|
|
|
|
|
pform_cur_generate->scheme_type = PGenerate::GS_CASE_ITEM;
|
|
|
|
|
|
|
|
|
|
pform_cur_generate->loop_init = 0;
|
|
|
|
|
pform_cur_generate->loop_test = expr;
|
|
|
|
|
pform_cur_generate->loop_step = 0;
|
|
|
|
|
}
|
|
|
|
|
|
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);
|
|
|
|
|
pform_cur_generate->scope_name = lex_strings.make(name);
|
|
|
|
|
delete[]name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void pform_endgenerate()
|
|
|
|
|
{
|
|
|
|
|
assert(pform_cur_generate != 0);
|
|
|
|
|
assert(pform_cur_module);
|
|
|
|
|
|
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];
|
|
|
|
|
snprintf(tmp, sizeof tmp, "$gen%d", pform_cur_generate->id_number);
|
|
|
|
|
pform_cur_generate->scope_name = lex_strings.make(tmp);
|
|
|
|
|
}
|
|
|
|
|
|
2007-06-02 05:42:12 +02:00
|
|
|
PGenerate*cur = pform_cur_generate;
|
|
|
|
|
pform_cur_generate = cur->parent;
|
|
|
|
|
|
2008-02-10 07:19:42 +01:00
|
|
|
if (pform_cur_generate != 0) {
|
|
|
|
|
assert(cur->scheme_type == PGenerate::GS_CASE_ITEM
|
|
|
|
|
|| pform_cur_generate->scheme_type != PGenerate::GS_CASE);
|
2007-06-02 05:42:12 +02:00
|
|
|
pform_cur_generate->generates.push_back(cur);
|
2008-02-10 07:19:42 +01:00
|
|
|
} else {
|
|
|
|
|
assert(cur->scheme_type != PGenerate::GS_CASE_ITEM);
|
2007-06-02 05:42:12 +02:00
|
|
|
pform_cur_module->generate_schemes.push_back(cur);
|
2008-02-10 07:19:42 +01:00
|
|
|
}
|
2006-04-10 02:37:42 +02:00
|
|
|
}
|
|
|
|
|
|
1999-05-16 07:08:42 +02:00
|
|
|
bool pform_expression_is_constant(const PExpr*ex)
|
|
|
|
|
{
|
1999-07-03 04:12:51 +02:00
|
|
|
return ex->is_constant(pform_cur_module);
|
1999-05-16 07:08:42 +02:00
|
|
|
}
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2008-02-25 04:40:54 +01:00
|
|
|
template <> inline svector<perm_string>::svector(unsigned size)
|
|
|
|
|
: nitems_(size), items_(new perm_string[size])
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2004-03-08 01:10:29 +01:00
|
|
|
static void process_udp_table(PUdp*udp, list<string>*table,
|
|
|
|
|
const char*file, unsigned lineno)
|
|
|
|
|
{
|
|
|
|
|
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. */
|
|
|
|
|
svector<string> input (table->size());
|
|
|
|
|
svector<char> current (table->size());
|
|
|
|
|
svector<char> output (table->size());
|
|
|
|
|
{ unsigned idx = 0;
|
|
|
|
|
for (list<string>::iterator cur = table->begin()
|
|
|
|
|
; cur != table->end()
|
|
|
|
|
; cur ++, idx += 1) {
|
|
|
|
|
string tmp = *cur;
|
|
|
|
|
|
|
|
|
|
/* Pull the input values from the string. */
|
|
|
|
|
assert(tmp.find(':') == (udp->ports.count() - 1));
|
|
|
|
|
input[idx] = tmp.substr(0, udp->ports.count()-1);
|
|
|
|
|
tmp = tmp.substr(udp->ports.count()-1);
|
|
|
|
|
|
|
|
|
|
assert(tmp[0] == ':');
|
|
|
|
|
|
|
|
|
|
/* If this is a synchronous device, get the current
|
|
|
|
|
output string. */
|
|
|
|
|
if (synchronous_flag) {
|
|
|
|
|
if (tmp.size() != 4) {
|
|
|
|
|
cerr << file<<":"<<lineno << ": error: "
|
|
|
|
|
<< "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) {
|
|
|
|
|
cerr << file<<":"<<lineno << ": error: "
|
|
|
|
|
<< "Invalid table format for"
|
|
|
|
|
<< " combinational primitive." << endl;
|
|
|
|
|
error_count += 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Finally, extract the desired output. */
|
|
|
|
|
assert(tmp.size() == 2);
|
|
|
|
|
output[idx] = tmp[1];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
udp->tinput = input;
|
|
|
|
|
udp->tcurrent = current;
|
|
|
|
|
udp->toutput = output;
|
|
|
|
|
}
|
|
|
|
|
|
2008-02-25 04:40:54 +01:00
|
|
|
void pform_make_udp(perm_string name, list<perm_string>*parms,
|
1999-06-12 22:35:27 +02:00
|
|
|
svector<PWire*>*decl, list<string>*table,
|
2001-10-21 03:55:24 +02:00
|
|
|
Statement*init_expr,
|
|
|
|
|
const char*file, unsigned lineno)
|
1998-11-25 03:35:53 +01:00
|
|
|
{
|
2001-10-21 03:55:24 +02:00
|
|
|
unsigned local_errors = 0;
|
1998-11-25 03:35:53 +01:00
|
|
|
assert(parms->size() > 0);
|
|
|
|
|
|
|
|
|
|
/* 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;
|
1999-06-17 07:34:42 +02:00
|
|
|
for (unsigned idx = 0 ; idx < decl->count() ; idx += 1) {
|
|
|
|
|
|
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. */
|
1999-06-15 05:44:53 +02:00
|
|
|
svector<PWire*> pins (parms->size());
|
2008-02-25 04:40:54 +01:00
|
|
|
svector<perm_string> pin_names (parms->size());
|
|
|
|
|
{ list<perm_string>::iterator cur;
|
1998-11-25 03:35:53 +01:00
|
|
|
unsigned idx;
|
|
|
|
|
for (cur = parms->begin(), idx = 0
|
|
|
|
|
; cur != parms->end()
|
|
|
|
|
; idx++, cur++) {
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
|
|
*/
|
1999-06-15 05:44:53 +02:00
|
|
|
assert(pins.count() > 0);
|
2001-10-21 03:55:24 +02:00
|
|
|
do {
|
|
|
|
|
if (pins[0] == 0) {
|
|
|
|
|
cerr << file<<":"<<lineno << ": error: "
|
|
|
|
|
<< "Output port of primitive " << name
|
|
|
|
|
<< " missing output declaration." << endl;
|
|
|
|
|
cerr << file<<":"<<lineno << ": : "
|
|
|
|
|
<< "Try: output " << pin_names[0] << ";"
|
|
|
|
|
<< endl;
|
|
|
|
|
error_count += 1;
|
|
|
|
|
local_errors += 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (pins[0]->get_port_type() != NetNet::POUTPUT) {
|
|
|
|
|
cerr << file<<":"<<lineno << ": error: "
|
|
|
|
|
<< "The first port of a primitive"
|
|
|
|
|
<< " must be an output." << endl;
|
|
|
|
|
cerr << file<<":"<<lineno << ": : "
|
|
|
|
|
<< "Try: output " << pin_names[0] << ";"
|
|
|
|
|
<< endl;
|
|
|
|
|
error_count += 1;
|
|
|
|
|
local_errors += 1;
|
|
|
|
|
break;;
|
|
|
|
|
}
|
|
|
|
|
} while (0);
|
|
|
|
|
|
1999-06-15 05:44:53 +02:00
|
|
|
for (unsigned idx = 1 ; idx < pins.count() ; idx += 1) {
|
2001-10-21 03:55:24 +02:00
|
|
|
if (pins[idx] == 0) {
|
|
|
|
|
cerr << file<<":"<<lineno << ": error: "
|
|
|
|
|
<< "Port " << (idx+1)
|
|
|
|
|
<< " of primitive " << name << " missing"
|
|
|
|
|
<< " input declaration." << endl;
|
|
|
|
|
cerr << file<<":"<<lineno << ": : "
|
|
|
|
|
<< "Try: input " << pin_names[idx] << ";"
|
|
|
|
|
<< endl;
|
|
|
|
|
error_count += 1;
|
|
|
|
|
local_errors += 1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (pins[idx]->get_port_type() != NetNet::PINPUT) {
|
2004-02-15 18:48:28 +01:00
|
|
|
cerr << file<<":"<<lineno << ": error: "
|
|
|
|
|
<< "Input port " << (idx+1)
|
|
|
|
|
<< " of primitive " << name
|
|
|
|
|
<< " has an output (or missing) declaration." << endl;
|
|
|
|
|
cerr << file<<":"<<lineno << ": : "
|
|
|
|
|
<< "Note that only the first port can be an output."
|
|
|
|
|
<< endl;
|
|
|
|
|
cerr << file<<":"<<lineno << ": : "
|
|
|
|
|
<< "Try \"input " << name << ";\""
|
|
|
|
|
<< endl;
|
|
|
|
|
error_count += 1;
|
|
|
|
|
local_errors += 1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pins[idx]->get_wire_type() == NetNet::REG) {
|
2001-10-21 03:55:24 +02:00
|
|
|
cerr << file<<":"<<lineno << ": error: "
|
|
|
|
|
<< "Port " << (idx+1)
|
2004-02-15 18:48:28 +01:00
|
|
|
<< " of primitive " << name << " is an input port"
|
|
|
|
|
<< " with a reg declaration." << endl;
|
2001-10-21 03:55:24 +02:00
|
|
|
cerr << file<<":"<<lineno << ": : "
|
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]) {
|
|
|
|
|
VLerror("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());
|
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
|
|
|
|
|
for (unsigned idx = 0 ; idx < pins.count() ; idx += 1)
|
2008-02-25 04:40:54 +01:00
|
|
|
udp->ports[idx] = pins[idx]->basename();
|
2004-03-08 01:10:29 +01:00
|
|
|
|
|
|
|
|
process_udp_table(udp, table, file, lineno);
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void pform_make_udp(perm_string name, bool synchronous_flag,
|
|
|
|
|
perm_string out_name, PExpr*init_expr,
|
|
|
|
|
list<perm_string>*parms, list<string>*table,
|
|
|
|
|
const char*file, unsigned lineno)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
svector<PWire*> pins(parms->size() + 1);
|
|
|
|
|
|
|
|
|
|
/* 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);
|
2007-12-20 18:31:01 +01:00
|
|
|
FILE_NAME(pins[0], file, lineno);
|
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()
|
|
|
|
|
; idx += 1, cur++) {
|
|
|
|
|
assert(idx < pins.count());
|
2008-02-25 04:40:54 +01:00
|
|
|
pins[idx] = new PWire(*cur, NetNet::WIRE,
|
|
|
|
|
NetNet::PINPUT, IVL_VT_LOGIC);
|
2007-12-20 18:31:01 +01:00
|
|
|
FILE_NAME(pins[idx], file, lineno);
|
1998-11-25 03:35:53 +01:00
|
|
|
}
|
2004-03-08 01:10:29 +01:00
|
|
|
assert(idx == pins.count());
|
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 {
|
2004-03-08 01:10:29 +01:00
|
|
|
PUdp*udp = new PUdp(name, pins.count());
|
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
|
1999-06-15 05:44:53 +02:00
|
|
|
for (unsigned idx = 0 ; idx < pins.count() ; 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);
|
|
|
|
|
process_udp_table(udp, table, file, lineno);
|
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.
|
|
|
|
|
*/
|
2008-02-25 04:40:54 +01:00
|
|
|
static void pform_set_net_range(perm_string name,
|
2000-12-11 01:31:43 +01:00
|
|
|
const svector<PExpr*>*range,
|
2005-07-07 18:22:49 +02:00
|
|
|
bool signed_flag,
|
2007-08-22 04:52:42 +02:00
|
|
|
ivl_variable_type_t dt,
|
|
|
|
|
PWSRType rt)
|
2000-10-31 18:00:04 +01:00
|
|
|
{
|
2008-05-12 02:30:33 +02:00
|
|
|
PWire*cur = pform_get_wire_in_scope(name);
|
2000-10-31 18:00:04 +01:00
|
|
|
if (cur == 0) {
|
2001-01-10 06:32:44 +01:00
|
|
|
VLerror("error: name is not a valid net.");
|
2000-10-31 18:00:04 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2002-01-26 06:28:28 +01:00
|
|
|
if (range == 0) {
|
|
|
|
|
/* This is the special case that we really mean a
|
|
|
|
|
scalar. Set a fake range. */
|
2007-08-22 04:52:42 +02:00
|
|
|
cur->set_range(0, 0, rt);
|
2002-01-26 06:28:28 +01:00
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
assert(range->count() == 2);
|
|
|
|
|
assert((*range)[0]);
|
|
|
|
|
assert((*range)[1]);
|
2007-08-22 04:52:42 +02:00
|
|
|
cur->set_range((*range)[0], (*range)[1], rt);
|
2002-01-26 06:28:28 +01:00
|
|
|
}
|
2000-12-11 01:31:43 +01:00
|
|
|
cur->set_signed(signed_flag);
|
2005-07-07 18:22:49 +02:00
|
|
|
|
|
|
|
|
if (dt != IVL_VT_NO_TYPE)
|
|
|
|
|
cur->set_data_type(dt);
|
2000-10-31 18:00:04 +01:00
|
|
|
}
|
|
|
|
|
|
2004-05-25 21:21:06 +02:00
|
|
|
void pform_set_net_range(list<perm_string>*names,
|
2000-12-11 01:31:43 +01:00
|
|
|
svector<PExpr*>*range,
|
2005-07-07 18:22:49 +02:00
|
|
|
bool signed_flag,
|
2007-08-22 04:52:42 +02:00
|
|
|
ivl_variable_type_t dt,
|
|
|
|
|
PWSRType rt)
|
2000-10-31 18:00:04 +01:00
|
|
|
{
|
2002-04-12 04:57:08 +02:00
|
|
|
assert((range == 0) || (range->count() == 2));
|
2000-10-31 18:00:04 +01:00
|
|
|
|
2004-05-25 21:21:06 +02:00
|
|
|
for (list<perm_string>::iterator cur = names->begin()
|
2000-10-31 18:00:04 +01:00
|
|
|
; cur != names->end()
|
|
|
|
|
; cur ++ ) {
|
2004-05-25 21:21:06 +02:00
|
|
|
perm_string txt = *cur;
|
2007-08-22 04:52:42 +02:00
|
|
|
pform_set_net_range(txt, range, signed_flag, dt, rt);
|
2000-10-31 18:00:04 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
delete names;
|
2002-04-12 04:57:08 +02:00
|
|
|
if (range)
|
|
|
|
|
delete range;
|
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.
|
|
|
|
|
*/
|
2004-05-25 21:21:06 +02:00
|
|
|
static void pform_make_event(perm_string name, const char*fn, unsigned ln)
|
2000-04-01 21:31:57 +02:00
|
|
|
{
|
2004-05-25 21:21:06 +02:00
|
|
|
PEvent*event = new PEvent(name);
|
2007-12-20 18:31:01 +01:00
|
|
|
FILE_NAME(event, fn, ln);
|
2000-04-01 21:31:57 +02:00
|
|
|
pform_cur_module->events[name] = event;
|
|
|
|
|
}
|
|
|
|
|
|
2004-05-25 21:21:06 +02:00
|
|
|
void pform_make_events(list<perm_string>*names, const char*fn, unsigned ln)
|
2000-04-01 21:31:57 +02:00
|
|
|
{
|
2004-05-25 21:21:06 +02:00
|
|
|
list<perm_string>::iterator cur;
|
2000-10-31 18:00:04 +01:00
|
|
|
for (cur = names->begin() ; cur != names->end() ; cur++) {
|
2004-05-25 21:21:06 +02:00
|
|
|
perm_string txt = *cur;
|
2000-10-31 18:00:04 +01:00
|
|
|
pform_make_event(txt, fn, ln);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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
|
|
|
*/
|
1998-11-04 00:28:49 +01:00
|
|
|
void pform_makegate(PGBuiltin::Type type,
|
2000-05-08 07:30:19 +02:00
|
|
|
struct str_pair_t str,
|
1999-08-01 18:34:50 +02:00
|
|
|
svector<PExpr*>* delay,
|
2002-05-23 05:08:50 +02:00
|
|
|
const lgate&info,
|
|
|
|
|
svector<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) {
|
|
|
|
|
cerr << info.file << ":" << info.lineno << ": Gates do not "
|
|
|
|
|
"have port names." << endl;
|
|
|
|
|
error_count += 1;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
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);
|
1999-02-15 03:06:15 +01:00
|
|
|
if (info.range[0])
|
|
|
|
|
cur->set_range(info.range[0], info.range[1]);
|
|
|
|
|
|
2002-05-23 05:08:50 +02:00
|
|
|
if (attr) {
|
|
|
|
|
for (unsigned idx = 0 ; idx < attr->count() ; idx += 1) {
|
|
|
|
|
named_pexpr_t*tmp = (*attr)[idx];
|
2004-02-20 19:53:33 +01:00
|
|
|
cur->attributes[tmp->name] = tmp->parm;
|
2002-05-23 05:08:50 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2000-05-08 07:30:19 +02:00
|
|
|
cur->strength0(str.str0);
|
|
|
|
|
cur->strength1(str.str1);
|
2007-12-20 18:31:01 +01:00
|
|
|
FILE_NAME(cur, info.file, info.lineno);
|
1999-02-15 03:06:15 +01:00
|
|
|
|
2006-04-10 02:37:42 +02:00
|
|
|
if (pform_cur_generate)
|
|
|
|
|
pform_cur_generate->add_gate(cur);
|
|
|
|
|
else
|
|
|
|
|
pform_cur_module->add_gate(cur);
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void pform_makegates(PGBuiltin::Type type,
|
2000-05-08 07:30:19 +02:00
|
|
|
struct str_pair_t str,
|
|
|
|
|
svector<PExpr*>*delay,
|
2002-05-23 05:08:50 +02:00
|
|
|
svector<lgate>*gates,
|
|
|
|
|
svector<named_pexpr_t*>*attr)
|
1998-11-04 00:28:49 +01:00
|
|
|
{
|
1999-05-31 17:45:59 +02:00
|
|
|
for (unsigned idx = 0 ; idx < gates->count() ; idx += 1) {
|
2002-05-23 05:08:50 +02:00
|
|
|
pform_makegate(type, str, delay, (*gates)[idx], attr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (attr) {
|
|
|
|
|
for (unsigned idx = 0 ; idx < attr->count() ; idx += 1) {
|
|
|
|
|
named_pexpr_t*cur = (*attr)[idx];
|
|
|
|
|
delete cur;
|
|
|
|
|
}
|
|
|
|
|
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,
|
1999-05-29 04:36:17 +02:00
|
|
|
svector<PExpr*>*wires,
|
2000-02-18 06:15:02 +01:00
|
|
|
PExpr*msb, PExpr*lsb,
|
2000-11-30 18:31:42 +01:00
|
|
|
const char*fn, unsigned ln)
|
1998-11-04 00:28:49 +01:00
|
|
|
{
|
2000-01-09 06:50:48 +01:00
|
|
|
PGModule*cur = new PGModule(type, name, wires);
|
2007-12-20 18:31:01 +01:00
|
|
|
FILE_NAME(cur, fn, ln);
|
2000-02-18 06:15:02 +01:00
|
|
|
cur->set_range(msb,lsb);
|
2000-01-09 06:50:48 +01:00
|
|
|
|
|
|
|
|
if (overrides && overrides->by_name) {
|
|
|
|
|
unsigned cnt = overrides->by_name->count();
|
|
|
|
|
named<PExpr*>*byname = new named<PExpr*>[cnt];
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < cnt ; idx += 1) {
|
2002-05-23 05:08:50 +02:00
|
|
|
named_pexpr_t*curp = (*overrides->by_name)[idx];
|
2000-01-09 06:50:48 +01:00
|
|
|
byname[idx].name = curp->name;
|
|
|
|
|
byname[idx].parm = curp->parm;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cur->set_parameters(byname, cnt);
|
|
|
|
|
|
|
|
|
|
} else if (overrides && overrides->by_order) {
|
|
|
|
|
cur->set_parameters(overrides->by_order);
|
|
|
|
|
}
|
|
|
|
|
|
2006-04-10 02:37:42 +02:00
|
|
|
if (pform_cur_generate)
|
|
|
|
|
pform_cur_generate->add_gate(cur);
|
|
|
|
|
else
|
|
|
|
|
pform_cur_module->add_gate(cur);
|
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,
|
2002-05-23 05:08:50 +02:00
|
|
|
svector<named_pexpr_t*>*bind,
|
2000-02-18 06:15:02 +01:00
|
|
|
PExpr*msb, PExpr*lsb,
|
2000-11-30 18:31:42 +01:00
|
|
|
const char*fn, unsigned ln)
|
1999-05-29 04:36:17 +02:00
|
|
|
{
|
|
|
|
|
unsigned npins = bind->count();
|
2000-01-09 06:50:48 +01:00
|
|
|
named<PExpr*>*pins = new named<PExpr*>[npins];
|
1999-05-29 04:36:17 +02:00
|
|
|
for (unsigned idx = 0 ; idx < npins ; idx += 1) {
|
2002-05-23 05:08:50 +02:00
|
|
|
named_pexpr_t*curp = (*bind)[idx];
|
1999-05-29 04:36:17 +02:00
|
|
|
pins[idx].name = curp->name;
|
|
|
|
|
pins[idx].parm = curp->parm;
|
|
|
|
|
}
|
|
|
|
|
|
2000-01-09 06:50:48 +01:00
|
|
|
PGModule*cur = new PGModule(type, name, pins, npins);
|
2007-12-20 18:31:01 +01:00
|
|
|
FILE_NAME(cur, fn, ln);
|
2000-02-18 06:15:02 +01:00
|
|
|
cur->set_range(msb,lsb);
|
2000-01-09 06:50:48 +01:00
|
|
|
|
|
|
|
|
if (overrides && overrides->by_name) {
|
|
|
|
|
unsigned cnt = overrides->by_name->count();
|
|
|
|
|
named<PExpr*>*byname = new named<PExpr*>[cnt];
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < cnt ; idx += 1) {
|
2002-05-23 05:08:50 +02:00
|
|
|
named_pexpr_t*curp = (*overrides->by_name)[idx];
|
2000-01-09 06:50:48 +01:00
|
|
|
byname[idx].name = curp->name;
|
|
|
|
|
byname[idx].parm = curp->parm;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cur->set_parameters(byname, cnt);
|
|
|
|
|
|
|
|
|
|
} else if (overrides && overrides->by_order) {
|
|
|
|
|
|
|
|
|
|
cur->set_parameters(overrides->by_order);
|
|
|
|
|
}
|
|
|
|
|
|
2007-06-12 06:05:45 +02:00
|
|
|
|
|
|
|
|
if (pform_cur_generate)
|
|
|
|
|
pform_cur_generate->add_gate(cur);
|
|
|
|
|
else
|
|
|
|
|
pform_cur_module->add_gate(cur);
|
1999-05-29 04:36:17 +02:00
|
|
|
}
|
|
|
|
|
|
2004-02-18 18:11:54 +01:00
|
|
|
void pform_make_modgates(perm_string type,
|
2000-01-09 06:50:48 +01:00
|
|
|
struct parmvalue_t*overrides,
|
1999-08-23 18:48:39 +02:00
|
|
|
svector<lgate>*gates)
|
1998-11-04 00:28:49 +01:00
|
|
|
{
|
2001-01-15 01:47:01 +01:00
|
|
|
|
1999-05-06 06:37:17 +02:00
|
|
|
for (unsigned idx = 0 ; idx < gates->count() ; idx += 1) {
|
|
|
|
|
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,
|
2000-02-18 06:15:02 +01:00
|
|
|
cur.parms_by_name,
|
|
|
|
|
cur.range[0], cur.range[1],
|
1999-05-29 04:36:17 +02:00
|
|
|
cur.file, cur.lineno);
|
|
|
|
|
|
|
|
|
|
} 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. */
|
|
|
|
|
if ((cur.parms->count() == 1) && (cur.parms[0][0] == 0)) {
|
|
|
|
|
delete cur.parms;
|
|
|
|
|
cur.parms = new svector<PExpr*>(0);
|
|
|
|
|
}
|
2004-02-18 18:11:54 +01:00
|
|
|
pform_make_modgate(type, cur_name, overrides,
|
2000-02-18 06:15:02 +01:00
|
|
|
cur.parms,
|
|
|
|
|
cur.range[0], cur.range[1],
|
|
|
|
|
cur.file, cur.lineno);
|
2000-05-23 18:03:13 +02:00
|
|
|
|
1999-05-10 02:16:57 +02:00
|
|
|
} else {
|
1999-05-29 04:36:17 +02:00
|
|
|
svector<PExpr*>*wires = new svector<PExpr*>(0);
|
2004-02-18 18:11:54 +01:00
|
|
|
pform_make_modgate(type, cur_name, overrides,
|
2000-02-18 06:15:02 +01:00
|
|
|
wires,
|
|
|
|
|
cur.range[0], cur.range[1],
|
|
|
|
|
cur.file, cur.lineno);
|
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,
|
2000-05-06 17:41:56 +02:00
|
|
|
svector<PExpr*>*del,
|
|
|
|
|
struct str_pair_t str)
|
1998-11-04 00:28:49 +01:00
|
|
|
{
|
1999-05-29 04:36:17 +02:00
|
|
|
svector<PExpr*>*wires = new svector<PExpr*>(2);
|
|
|
|
|
(*wires)[0] = lval;
|
|
|
|
|
(*wires)[1] = 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
|
|
|
|
|
pform_cur_module->add_gate(cur);
|
|
|
|
|
|
1999-05-20 06:31:45 +02:00
|
|
|
return cur;
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
1999-08-27 17:08:37 +02:00
|
|
|
void pform_make_pgassign_list(svector<PExpr*>*alist,
|
|
|
|
|
svector<PExpr*>*del,
|
2000-05-06 17:41:56 +02:00
|
|
|
struct str_pair_t str,
|
2000-11-30 18:31:42 +01:00
|
|
|
const char* fn,
|
1999-08-27 17:08:37 +02:00
|
|
|
unsigned lineno)
|
|
|
|
|
{
|
|
|
|
|
PGAssign*tmp;
|
|
|
|
|
for (unsigned idx = 0 ; idx < alist->count()/2 ; idx += 1) {
|
|
|
|
|
tmp = pform_make_pgassign((*alist)[2*idx],
|
2000-05-06 17:41:56 +02:00
|
|
|
(*alist)[2*idx+1],
|
|
|
|
|
del, str);
|
2007-12-20 18:31:01 +01:00
|
|
|
FILE_NAME(tmp, fn, lineno);
|
1999-08-27 17:08:37 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1999-12-30 20:06:14 +01:00
|
|
|
/*
|
|
|
|
|
* this function makes the initial assignment to a register as given
|
|
|
|
|
* in the source. It handles the case where a reg variable is assigned
|
|
|
|
|
* where it it declared:
|
|
|
|
|
*
|
|
|
|
|
* reg foo = <expr>;
|
|
|
|
|
*
|
2003-01-10 04:08:13 +01:00
|
|
|
* This 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
|
|
|
*
|
|
|
|
|
* and that is how it is parsed. This syntax is not part of the
|
2003-01-10 04:08:13 +01:00
|
|
|
* IEEE1364-1995 standard, but is approved by OVI as enhancement
|
1999-12-30 20:06:14 +01:00
|
|
|
* BTF-B14.
|
|
|
|
|
*/
|
|
|
|
|
void pform_make_reginit(const struct vlltype&li,
|
2008-02-25 04:40:54 +01:00
|
|
|
perm_string name, PExpr*expr)
|
1999-12-30 20:06:14 +01:00
|
|
|
{
|
2008-02-25 04:40:54 +01:00
|
|
|
PWire*cur = lexical_scope->wires_find(name);
|
1999-12-30 20:06:14 +01:00
|
|
|
if (cur == 0) {
|
|
|
|
|
VLerror(li, "internal error: reginit to non-register?");
|
|
|
|
|
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);
|
1999-12-30 20:06:14 +01:00
|
|
|
PAssign*ass = new PAssign(lval, expr);
|
2007-12-20 18:31:01 +01:00
|
|
|
FILE_NAME(ass, li);
|
1999-12-30 20:06:14 +01:00
|
|
|
PProcess*top = new PProcess(PProcess::PR_INITIAL, ass);
|
2007-12-20 18:31:01 +01:00
|
|
|
FILE_NAME(top, li);
|
1999-12-30 20:06:14 +01:00
|
|
|
|
2008-03-04 05:49:52 +01:00
|
|
|
lexical_scope->behaviors.push_back(top);
|
1999-12-30 20:06:14 +01:00
|
|
|
}
|
|
|
|
|
|
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,
|
2002-05-20 04:06:01 +02:00
|
|
|
NetNet::PortType port_type,
|
|
|
|
|
NetNet::Type type,
|
|
|
|
|
bool signed_flag,
|
2003-07-04 05:57:18 +02:00
|
|
|
svector<PExpr*>*range,
|
|
|
|
|
svector<named_pexpr_t*>*attr)
|
2002-05-20 04:06:01 +02:00
|
|
|
{
|
2008-02-25 04:40:54 +01:00
|
|
|
PWire*cur = lexical_scope->wires_find(name);
|
2002-05-20 04:06:01 +02:00
|
|
|
if (cur) {
|
2003-01-14 22:16:18 +01:00
|
|
|
ostringstream msg;
|
2008-02-25 04:40:54 +01:00
|
|
|
msg << name << " definition conflicts with "
|
2007-12-20 18:31:01 +01:00
|
|
|
<< "definition at " << cur->get_fileline()
|
2003-01-14 22:16:18 +01:00
|
|
|
<< ".";
|
|
|
|
|
VLerror(msg.str().c_str());
|
2002-05-20 04:06:01 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2005-07-07 18:22:49 +02:00
|
|
|
cur = new PWire(name, type, port_type, IVL_VT_LOGIC);
|
2007-12-20 18:31:01 +01:00
|
|
|
FILE_NAME(cur, li);
|
2002-05-20 04:06:01 +02:00
|
|
|
|
|
|
|
|
cur->set_signed(signed_flag);
|
|
|
|
|
|
|
|
|
|
if (range == 0) {
|
2007-08-22 04:52:42 +02:00
|
|
|
cur->set_range(0, 0, (type == NetNet::IMPLICIT) ? SR_PORT :
|
|
|
|
|
SR_BOTH);
|
2002-05-20 04:06:01 +02:00
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
assert(range->count() == 2);
|
|
|
|
|
assert((*range)[0]);
|
|
|
|
|
assert((*range)[1]);
|
2007-08-22 04:52:42 +02:00
|
|
|
cur->set_range((*range)[0], (*range)[1],
|
|
|
|
|
(type == NetNet::IMPLICIT) ? SR_PORT : SR_BOTH);
|
2002-05-20 04:06:01 +02:00
|
|
|
}
|
|
|
|
|
|
2003-07-04 05:57:18 +02:00
|
|
|
if (attr) {
|
|
|
|
|
for (unsigned idx = 0 ; idx < attr->count() ; idx += 1) {
|
|
|
|
|
named_pexpr_t*tmp = (*attr)[idx];
|
2004-02-20 19:53:33 +01:00
|
|
|
cur->attributes[tmp->name] = tmp->parm;
|
2003-07-04 05:57:18 +02:00
|
|
|
}
|
|
|
|
|
}
|
2008-02-25 04:40:54 +01:00
|
|
|
lexical_scope->wires[name] = cur;
|
2002-05-20 04:06:01 +02:00
|
|
|
}
|
|
|
|
|
|
2001-05-25 04:21:34 +02: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
|
2003-01-10 04:08:13 +01:00
|
|
|
* been seen already, so I do not do any checking with it yet. But I
|
2001-05-25 04:21:34 +02:00
|
|
|
* do check to see if the name has already been declared, as this
|
|
|
|
|
* function is called for every declaration.
|
|
|
|
|
*/
|
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.
|
|
|
|
|
*/
|
2008-02-25 04:40:54 +01:00
|
|
|
void pform_makewire(const vlltype&li, perm_string name,
|
2003-04-28 19:50:57 +02:00
|
|
|
NetNet::Type type, NetNet::PortType pt,
|
2005-07-07 18:22:49 +02:00
|
|
|
ivl_variable_type_t dt,
|
2003-04-28 19:50:57 +02:00
|
|
|
svector<named_pexpr_t*>*attr)
|
1998-11-04 00:28:49 +01:00
|
|
|
{
|
2008-05-12 02:30:33 +02:00
|
|
|
PWire*cur = pform_get_wire_in_scope(name);
|
2006-04-10 02:37:42 +02:00
|
|
|
|
2007-01-16 06:44:14 +01:00
|
|
|
// If this is not implicit ("implicit" meaning we don't know
|
2008-01-29 21:19:59 +01:00
|
|
|
// what the type is yet) then set the type now.
|
2007-01-16 06:44:14 +01:00
|
|
|
if (cur && type != NetNet::IMPLICIT) {
|
|
|
|
|
bool rc = cur->set_wire_type(type);
|
|
|
|
|
if (rc == false) {
|
2003-01-14 22:16:18 +01:00
|
|
|
ostringstream msg;
|
2008-02-25 04:40:54 +01:00
|
|
|
msg << name << " definition conflicts with "
|
2007-12-20 18:31:01 +01:00
|
|
|
<< "definition at " << cur->get_fileline()
|
2007-01-16 06:44:14 +01:00
|
|
|
<< ".";
|
2003-01-14 22:16:18 +01:00
|
|
|
VLerror(msg.str().c_str());
|
2007-01-16 06:44:14 +01:00
|
|
|
cerr << "XXXX type=" << type <<", curtype=" << cur->get_wire_type() << endl;
|
1999-01-25 06:45:56 +01:00
|
|
|
}
|
2001-05-25 04:21:34 +02:00
|
|
|
|
2007-01-16 06:44:14 +01:00
|
|
|
}
|
2007-08-05 06:50:06 +02:00
|
|
|
|
|
|
|
|
bool new_wire_flag = false;
|
|
|
|
|
if (! cur) {
|
|
|
|
|
new_wire_flag = true;
|
|
|
|
|
cur = new PWire(name, type, pt, dt);
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
2007-12-20 18:31:01 +01:00
|
|
|
FILE_NAME(cur, li.text, li.first_line);
|
2002-05-24 06:36:23 +02:00
|
|
|
|
2008-01-04 05:13:56 +01:00
|
|
|
bool flag;
|
2007-08-05 06:50:06 +02:00
|
|
|
switch (dt) {
|
|
|
|
|
case IVL_VT_REAL:
|
2008-01-04 05:13:56 +01:00
|
|
|
flag = cur->set_data_type(dt);
|
|
|
|
|
if (flag == false) {
|
|
|
|
|
cerr << cur->get_fileline() << ": internal error: "
|
|
|
|
|
<< " wire data type handling mismatch. Cannot change "
|
|
|
|
|
<< cur->get_data_type()
|
|
|
|
|
<< " to " << dt << "." << endl;
|
|
|
|
|
}
|
|
|
|
|
ivl_assert(*cur, flag);
|
2007-08-22 04:52:42 +02:00
|
|
|
cur->set_range(0, 0, SR_NET);
|
2007-08-05 06:50:06 +02:00
|
|
|
cur->set_signed(true);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2002-05-24 06:36:23 +02:00
|
|
|
if (attr) {
|
|
|
|
|
for (unsigned idx = 0 ; idx < attr->count() ; idx += 1) {
|
|
|
|
|
named_pexpr_t*tmp = (*attr)[idx];
|
2004-02-20 19:53:33 +01:00
|
|
|
cur->attributes[tmp->name] = tmp->parm;
|
2002-05-24 06:36:23 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2007-08-05 06:50:06 +02:00
|
|
|
if (new_wire_flag) {
|
|
|
|
|
if (pform_cur_generate)
|
2008-02-25 04:40:54 +01:00
|
|
|
pform_cur_generate->wires[name] = cur;
|
2007-08-05 06:50:06 +02:00
|
|
|
else
|
2008-02-25 04:40:54 +01:00
|
|
|
lexical_scope->wires[name] = cur;
|
2007-08-05 06:50:06 +02:00
|
|
|
}
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
2006-04-10 02:37:42 +02:00
|
|
|
/*
|
|
|
|
|
* This form takes a list of names and some type information, and
|
2007-08-22 04:52:42 +02:00
|
|
|
* generates a bunch of variables/nets. We use the basic
|
2006-04-10 02:37:42 +02:00
|
|
|
* pform_makewire above.
|
|
|
|
|
*/
|
2000-10-31 18:00:04 +01:00
|
|
|
void pform_makewire(const vlltype&li,
|
|
|
|
|
svector<PExpr*>*range,
|
2003-02-02 20:02:39 +01:00
|
|
|
bool signed_flag,
|
2004-05-25 21:21:06 +02:00
|
|
|
list<perm_string>*names,
|
2002-05-24 06:36:23 +02:00
|
|
|
NetNet::Type type,
|
2003-04-28 19:50:57 +02:00
|
|
|
NetNet::PortType pt,
|
2005-07-07 18:22:49 +02:00
|
|
|
ivl_variable_type_t dt,
|
2007-08-22 04:52:42 +02:00
|
|
|
svector<named_pexpr_t*>*attr,
|
|
|
|
|
PWSRType rt)
|
1998-11-04 00:28:49 +01:00
|
|
|
{
|
2004-05-25 21:21:06 +02:00
|
|
|
for (list<perm_string>::iterator cur = names->begin()
|
1998-11-04 00:28:49 +01:00
|
|
|
; cur != names->end()
|
2000-10-31 18:00:04 +01:00
|
|
|
; cur ++ ) {
|
2004-05-25 21:21:06 +02:00
|
|
|
perm_string txt = *cur;
|
2005-07-07 18:22:49 +02:00
|
|
|
pform_makewire(li, txt, type, pt, dt, attr);
|
2007-08-22 04:52:42 +02:00
|
|
|
/* This has already been done for real variables. */
|
|
|
|
|
if (dt != IVL_VT_REAL) {
|
|
|
|
|
pform_set_net_range(txt, range, signed_flag, dt, rt);
|
|
|
|
|
}
|
2000-10-31 18:00:04 +01:00
|
|
|
}
|
1998-11-04 00:28:49 +01:00
|
|
|
|
2000-10-31 18:00:04 +01:00
|
|
|
delete names;
|
|
|
|
|
if (range)
|
|
|
|
|
delete range;
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
2006-04-10 02:37:42 +02:00
|
|
|
/*
|
|
|
|
|
* This form makes nets with delays and continuous assignments.
|
|
|
|
|
*/
|
2001-11-29 18:37:51 +01:00
|
|
|
void pform_makewire(const vlltype&li,
|
|
|
|
|
svector<PExpr*>*range,
|
2003-02-02 20:02:39 +01:00
|
|
|
bool signed_flag,
|
2001-11-29 18:37:51 +01:00
|
|
|
svector<PExpr*>*delay,
|
2002-01-12 05:03:39 +01:00
|
|
|
str_pair_t str,
|
2001-11-29 18:37:51 +01:00
|
|
|
net_decl_assign_t*decls,
|
2005-07-07 18:22:49 +02:00
|
|
|
NetNet::Type type,
|
|
|
|
|
ivl_variable_type_t dt)
|
2001-11-29 18:37:51 +01:00
|
|
|
{
|
|
|
|
|
net_decl_assign_t*first = decls->next;
|
|
|
|
|
decls->next = 0;
|
|
|
|
|
|
|
|
|
|
while (first) {
|
|
|
|
|
net_decl_assign_t*next = first->next;
|
|
|
|
|
|
2005-07-07 18:22:49 +02:00
|
|
|
pform_makewire(li, first->name, type, NetNet::NOT_A_PORT, dt, 0);
|
2007-08-22 04:52:42 +02:00
|
|
|
/* This has already been done for real variables. */
|
|
|
|
|
if (dt != IVL_VT_REAL) {
|
|
|
|
|
pform_set_net_range(first->name, range, signed_flag, dt,
|
|
|
|
|
SR_NET);
|
|
|
|
|
}
|
2001-11-29 18:37:51 +01:00
|
|
|
|
2008-05-12 02:30:33 +02:00
|
|
|
PWire*cur = pform_get_wire_in_scope(first->name);
|
2001-11-29 18:37:51 +01:00
|
|
|
if (cur != 0) {
|
2008-02-25 04:40:54 +01:00
|
|
|
PEIdent*lval = new PEIdent(first->name);
|
2007-12-20 18:31:01 +01:00
|
|
|
FILE_NAME(lval, li.text, li.first_line);
|
2005-05-06 02:25:13 +02:00
|
|
|
PGAssign*ass = pform_make_pgassign(lval, first->expr,
|
|
|
|
|
delay, str);
|
2007-12-20 18:31:01 +01:00
|
|
|
FILE_NAME(ass, li.text, li.first_line);
|
2001-11-29 18:37:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
delete first;
|
|
|
|
|
first = next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-02-25 04:40:54 +01:00
|
|
|
void pform_set_port_type(perm_string name, NetNet::PortType pt,
|
2001-11-10 03:08:49 +01:00
|
|
|
const char*file, unsigned lineno)
|
1998-11-04 00:28:49 +01:00
|
|
|
{
|
2008-02-25 04:40:54 +01:00
|
|
|
PWire*cur = lexical_scope->wires_find(name);
|
1998-11-04 00:28:49 +01:00
|
|
|
if (cur == 0) {
|
2008-01-04 05:13:56 +01:00
|
|
|
cur = new PWire(name, NetNet::IMPLICIT, NetNet::PIMPLICIT, IVL_VT_NO_TYPE);
|
2007-12-20 18:31:01 +01:00
|
|
|
FILE_NAME(cur, file, lineno);
|
2008-02-25 04:40:54 +01:00
|
|
|
lexical_scope->wires[name] = cur;
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
2002-01-31 05:10:15 +01:00
|
|
|
switch (cur->get_port_type()) {
|
|
|
|
|
case NetNet::PIMPLICIT:
|
|
|
|
|
if (! cur->set_port_type(pt))
|
|
|
|
|
VLerror("error setting port direction.");
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case NetNet::NOT_A_PORT:
|
|
|
|
|
cerr << file << ":" << lineno << ": error: "
|
2008-02-25 04:40:54 +01:00
|
|
|
<< "port " << name << " is not in the port list."
|
2002-01-31 05:10:15 +01:00
|
|
|
<< endl;
|
|
|
|
|
error_count += 1;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
cerr << file << ":" << lineno << ": error: "
|
2008-02-25 04:40:54 +01:00
|
|
|
<< "port " << name << " already has a port declaration."
|
2002-01-31 05:10:15 +01:00
|
|
|
<< endl;
|
|
|
|
|
error_count += 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
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
|
|
|
*/
|
|
|
|
|
svector<PWire*>*pform_make_task_ports(NetNet::PortType pt,
|
2006-03-30 07:22:34 +02:00
|
|
|
ivl_variable_type_t vtype,
|
2003-06-13 02:27:09 +02:00
|
|
|
bool signed_flag,
|
2000-10-31 18:00:04 +01:00
|
|
|
svector<PExpr*>*range,
|
2004-05-25 21:21:06 +02:00
|
|
|
list<perm_string>*names,
|
2000-11-30 18:31:42 +01:00
|
|
|
const char* file,
|
1999-09-10 07:02:09 +02:00
|
|
|
unsigned lineno)
|
1999-07-24 04:11:19 +02:00
|
|
|
{
|
1999-09-10 07:02:09 +02:00
|
|
|
assert(names);
|
1999-07-24 04:11:19 +02:00
|
|
|
svector<PWire*>*res = new svector<PWire*>(0);
|
2004-05-25 21:21:06 +02:00
|
|
|
for (list<perm_string>::iterator cur = names->begin()
|
1999-07-24 04:11:19 +02:00
|
|
|
; cur != names->end() ; cur ++ ) {
|
|
|
|
|
|
2008-02-25 04:40:54 +01:00
|
|
|
perm_string name = *cur;
|
1999-07-24 04:11:19 +02:00
|
|
|
|
|
|
|
|
/* Look for a preexisting wire. If it exists, set the
|
|
|
|
|
port direction. If not, create it. */
|
2008-02-25 04:40:54 +01:00
|
|
|
PWire*curw = lexical_scope->wires_find(name);
|
1999-07-24 04:11:19 +02:00
|
|
|
if (curw) {
|
|
|
|
|
curw->set_port_type(pt);
|
|
|
|
|
} else {
|
2006-03-30 07:22:34 +02:00
|
|
|
curw = new PWire(name, NetNet::IMPLICIT_REG, pt, vtype);
|
2007-12-20 18:31:01 +01:00
|
|
|
FILE_NAME(curw, file, lineno);
|
2008-02-25 04:40:54 +01:00
|
|
|
lexical_scope->wires[name] = curw;
|
1999-07-24 04:11:19 +02:00
|
|
|
}
|
|
|
|
|
|
2003-06-13 02:27:09 +02:00
|
|
|
curw->set_signed(signed_flag);
|
|
|
|
|
|
1999-07-24 04:11:19 +02:00
|
|
|
/* If there is a range involved, it needs to be set. */
|
|
|
|
|
if (range)
|
2007-08-22 04:52:42 +02:00
|
|
|
curw->set_range((*range)[0], (*range)[1], SR_PORT);
|
1999-07-24 04:11:19 +02:00
|
|
|
|
|
|
|
|
svector<PWire*>*tmp = new svector<PWire*>(*res, curw);
|
2000-10-31 18:00:04 +01:00
|
|
|
|
1999-07-24 04:11:19 +02:00
|
|
|
delete res;
|
|
|
|
|
res = tmp;
|
|
|
|
|
}
|
|
|
|
|
|
2000-10-31 18:00:04 +01:00
|
|
|
if (range)
|
|
|
|
|
delete range;
|
|
|
|
|
delete names;
|
1999-07-24 04:11:19 +02:00
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
} else if (PGate*cur = pform_cur_module->get_gate(name)) {
|
2002-05-23 05:08:50 +02:00
|
|
|
cur->attributes[key] = new PEString(value);
|
1999-12-11 06:45:41 +01:00
|
|
|
|
|
|
|
|
} else {
|
2002-05-23 05:08:50 +02:00
|
|
|
free(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.");
|
2002-05-23 05:08:50 +02:00
|
|
|
free(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
|
|
|
}
|
|
|
|
|
|
1999-06-17 07:34:42 +02:00
|
|
|
/*
|
|
|
|
|
* This function attaches a memory index range to an existing
|
|
|
|
|
* register. (The named wire must be a register.
|
|
|
|
|
*/
|
2008-02-25 04:40:54 +01:00
|
|
|
void pform_set_reg_idx(perm_string name, PExpr*l, PExpr*r)
|
1999-04-19 03:59:36 +02:00
|
|
|
{
|
2007-11-09 00:12:02 +01:00
|
|
|
PWire*cur = 0;
|
|
|
|
|
if (pform_cur_generate) {
|
2008-02-25 04:40:54 +01:00
|
|
|
cur = pform_cur_generate->get_wire(name);
|
2007-11-09 00:12:02 +01:00
|
|
|
} else {
|
2008-02-25 04:40:54 +01:00
|
|
|
cur = lexical_scope->wires_find(name);
|
2007-11-09 00:12:02 +01:00
|
|
|
}
|
1999-04-19 03:59:36 +02:00
|
|
|
if (cur == 0) {
|
2001-01-10 06:32:44 +01:00
|
|
|
VLerror("internal error: name is not a valid memory for index.");
|
1999-04-19 03:59:36 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
1999-06-17 07:34:42 +02:00
|
|
|
cur->set_memory_idx(l, r);
|
1999-04-19 03:59:36 +02:00
|
|
|
}
|
|
|
|
|
|
2004-02-20 07:22:56 +01:00
|
|
|
void pform_set_parameter(perm_string name, bool signed_flag,
|
2008-05-06 04:46:30 +02:00
|
|
|
svector<PExpr*>*range, PExpr*expr,
|
|
|
|
|
const char*file, unsigned lineno)
|
1999-02-21 18:01:57 +01:00
|
|
|
{
|
2000-03-08 05:36:53 +01:00
|
|
|
assert(expr);
|
2002-08-19 04:39:16 +02:00
|
|
|
pform_cur_module->parameters[name].expr = expr;
|
|
|
|
|
|
|
|
|
|
if (range) {
|
|
|
|
|
assert(range->count() == 2);
|
|
|
|
|
assert((*range)[0]);
|
|
|
|
|
assert((*range)[1]);
|
|
|
|
|
pform_cur_module->parameters[name].msb = (*range)[0];
|
|
|
|
|
pform_cur_module->parameters[name].lsb = (*range)[1];
|
|
|
|
|
} else {
|
|
|
|
|
pform_cur_module->parameters[name].msb = 0;
|
|
|
|
|
pform_cur_module->parameters[name].lsb = 0;
|
|
|
|
|
}
|
2002-09-01 05:01:48 +02:00
|
|
|
pform_cur_module->parameters[name].signed_flag = signed_flag;
|
2008-05-06 04:46:30 +02:00
|
|
|
pform_cur_module->parameters[name].file = filename_strings.make(file);
|
|
|
|
|
pform_cur_module->parameters[name].lineno = lineno;
|
2002-08-19 04:39:16 +02:00
|
|
|
|
1999-08-23 18:48:39 +02:00
|
|
|
pform_cur_module->param_names.push_back(name);
|
1999-02-21 18:01:57 +01:00
|
|
|
}
|
|
|
|
|
|
2004-08-26 06:02:03 +02:00
|
|
|
void pform_set_localparam(perm_string name, bool signed_flag,
|
2008-05-06 04:46:30 +02:00
|
|
|
svector<PExpr*>*range, PExpr*expr,
|
|
|
|
|
const char*file, unsigned lineno)
|
2000-03-12 18:09:40 +01:00
|
|
|
{
|
|
|
|
|
assert(expr);
|
2002-08-19 04:39:16 +02:00
|
|
|
pform_cur_module->localparams[name].expr = expr;
|
2004-08-26 06:02:03 +02:00
|
|
|
|
|
|
|
|
if (range) {
|
|
|
|
|
assert(range->count() == 2);
|
|
|
|
|
assert((*range)[0]);
|
|
|
|
|
assert((*range)[1]);
|
|
|
|
|
pform_cur_module->localparams[name].msb = (*range)[0];
|
|
|
|
|
pform_cur_module->localparams[name].lsb = (*range)[1];
|
|
|
|
|
} else {
|
|
|
|
|
pform_cur_module->localparams[name].msb = 0;
|
|
|
|
|
pform_cur_module->localparams[name].lsb = 0;
|
|
|
|
|
}
|
|
|
|
|
pform_cur_module->localparams[name].signed_flag = signed_flag;
|
2008-05-06 04:46:30 +02:00
|
|
|
pform_cur_module->localparams[name].file = filename_strings.make(file);
|
|
|
|
|
pform_cur_module->localparams[name].lineno = lineno;
|
2000-03-12 18:09:40 +01:00
|
|
|
}
|
|
|
|
|
|
2004-05-25 21:21:06 +02:00
|
|
|
void pform_set_specparam(perm_string name, PExpr*expr)
|
2003-02-27 07:45:11 +01:00
|
|
|
{
|
|
|
|
|
assert(expr);
|
|
|
|
|
pform_cur_module->specparams[name] = expr;
|
|
|
|
|
}
|
|
|
|
|
|
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);
|
|
|
|
|
pform_cur_module->defparms[name] = expr;
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
{
|
2006-09-23 06:57:19 +02:00
|
|
|
PSpecPath*path = new PSpecPath(src->size(), dst->size());
|
2007-12-20 18:31:01 +01:00
|
|
|
FILE_NAME(path, li.text, li.first_line);
|
2006-09-23 06:57:19 +02:00
|
|
|
|
|
|
|
|
unsigned idx;
|
|
|
|
|
list<perm_string>::const_iterator cur;
|
|
|
|
|
|
|
|
|
|
idx = 0;
|
|
|
|
|
for (idx = 0, cur = src->begin() ; cur != src->end() ; idx++, cur++) {
|
|
|
|
|
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
|
|
|
|
|
|
|
|
for (idx = 0, cur = dst->begin() ; cur != dst->end() ; idx++, cur++) {
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2006-09-23 06:57:19 +02:00
|
|
|
extern PSpecPath* pform_assign_path_delay(PSpecPath*path, svector<PExpr*>*del)
|
|
|
|
|
{
|
2007-02-12 02:52:21 +01:00
|
|
|
if (path == 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2006-09-23 06:57:19 +02:00
|
|
|
assert(path->delays.size() == 0);
|
|
|
|
|
|
|
|
|
|
path->delays.resize(del->count());
|
|
|
|
|
for (unsigned idx = 0 ; idx < path->delays.size() ; idx += 1)
|
|
|
|
|
path->delays[idx] = (*del)[idx];
|
|
|
|
|
|
|
|
|
|
delete del;
|
|
|
|
|
|
|
|
|
|
return path;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extern void pform_module_specify_path(PSpecPath*obj)
|
|
|
|
|
{
|
2007-02-12 02:52:21 +01:00
|
|
|
if (obj == 0)
|
|
|
|
|
return;
|
2006-09-23 06:57:19 +02:00
|
|
|
pform_cur_module->specify_paths.push_back(obj);
|
2003-02-27 07:45:11 +01:00
|
|
|
}
|
|
|
|
|
|
2001-11-10 03:08:49 +01:00
|
|
|
void pform_set_port_type(const struct vlltype&li,
|
2004-05-25 21:21:06 +02:00
|
|
|
list<perm_string>*names,
|
2000-10-31 18:00:04 +01:00
|
|
|
svector<PExpr*>*range,
|
2003-02-02 20:02:39 +01:00
|
|
|
bool signed_flag,
|
2000-10-31 18:00:04 +01:00
|
|
|
NetNet::PortType pt)
|
1998-11-04 00:28:49 +01:00
|
|
|
{
|
2004-05-25 21:21:06 +02:00
|
|
|
for (list<perm_string>::iterator cur = names->begin()
|
1998-11-04 00:28:49 +01:00
|
|
|
; cur != names->end()
|
|
|
|
|
; cur ++ ) {
|
2004-05-25 21:21:06 +02:00
|
|
|
perm_string txt = *cur;
|
2001-11-10 03:08:49 +01:00
|
|
|
pform_set_port_type(txt, pt, li.text, li.first_line);
|
2007-08-22 04:52:42 +02:00
|
|
|
pform_set_net_range(txt, range, signed_flag, IVL_VT_NO_TYPE,
|
|
|
|
|
SR_PORT);
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
2000-10-31 18:00:04 +01:00
|
|
|
|
|
|
|
|
delete names;
|
|
|
|
|
if (range)
|
|
|
|
|
delete range;
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
2008-02-25 04:40:54 +01:00
|
|
|
static void pform_set_reg_integer(perm_string name)
|
1998-11-04 00:28:49 +01:00
|
|
|
{
|
2008-02-25 04:40:54 +01:00
|
|
|
PWire*cur = lexical_scope->wires_find(name);
|
1999-09-15 03:55:06 +02:00
|
|
|
if (cur == 0) {
|
2005-07-07 18:22:49 +02:00
|
|
|
cur = new PWire(name, NetNet::INTEGER,
|
|
|
|
|
NetNet::NOT_A_PORT,
|
|
|
|
|
IVL_VT_LOGIC);
|
2001-01-06 03:29:35 +01:00
|
|
|
cur->set_signed(true);
|
2008-02-25 04:40:54 +01:00
|
|
|
lexical_scope->wires[name] = cur;
|
1999-09-15 03:55:06 +02:00
|
|
|
} else {
|
2002-06-21 06:59:35 +02:00
|
|
|
bool rc = cur->set_wire_type(NetNet::INTEGER);
|
1999-09-15 03:55:06 +02:00
|
|
|
assert(rc);
|
2005-07-07 18:22:49 +02:00
|
|
|
cur->set_data_type(IVL_VT_LOGIC);
|
2001-01-06 03:29:35 +01:00
|
|
|
cur->set_signed(true);
|
1999-09-15 03:55:06 +02:00
|
|
|
}
|
1999-06-06 22:45:38 +02:00
|
|
|
assert(cur);
|
1998-11-04 00:28:49 +01:00
|
|
|
|
2007-03-07 05:24:59 +01:00
|
|
|
cur->set_range(new PENumber(new verinum(integer_width-1, integer_width)),
|
2007-08-22 04:52:42 +02:00
|
|
|
new PENumber(new verinum((uint64_t)0, integer_width)),
|
|
|
|
|
SR_NET);
|
2000-12-11 01:31:43 +01:00
|
|
|
cur->set_signed(true);
|
1999-06-06 22:45:38 +02:00
|
|
|
}
|
|
|
|
|
|
2004-05-25 21:21:06 +02:00
|
|
|
void pform_set_reg_integer(list<perm_string>*names)
|
1999-06-06 22:45:38 +02:00
|
|
|
{
|
2004-05-25 21:21:06 +02:00
|
|
|
for (list<perm_string>::iterator cur = names->begin()
|
1998-11-04 00:28:49 +01:00
|
|
|
; cur != names->end()
|
|
|
|
|
; cur ++ ) {
|
2004-05-25 21:21:06 +02:00
|
|
|
perm_string txt = *cur;
|
2000-10-31 18:00:04 +01:00
|
|
|
pform_set_reg_integer(txt);
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
2000-10-31 18:00:04 +01:00
|
|
|
delete names;
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
2008-02-25 04:40:54 +01:00
|
|
|
static void pform_set_reg_time(perm_string name)
|
2000-10-31 18:49:02 +01:00
|
|
|
{
|
2008-02-25 04:40:54 +01:00
|
|
|
PWire*cur = lexical_scope->wires_find(name);
|
2000-10-31 18:49:02 +01:00
|
|
|
if (cur == 0) {
|
2005-07-07 18:22:49 +02:00
|
|
|
cur = new PWire(name, NetNet::REG, NetNet::NOT_A_PORT, IVL_VT_LOGIC);
|
2008-02-25 04:40:54 +01:00
|
|
|
lexical_scope->wires[name] = cur;
|
2000-10-31 18:49:02 +01:00
|
|
|
} else {
|
2001-01-06 07:31:58 +01:00
|
|
|
bool rc = cur->set_wire_type(NetNet::REG);
|
2000-10-31 18:49:02 +01:00
|
|
|
assert(rc);
|
2005-07-07 18:22:49 +02:00
|
|
|
rc = cur->set_data_type(IVL_VT_LOGIC);
|
|
|
|
|
assert(rc);
|
2000-10-31 18:49:02 +01:00
|
|
|
}
|
|
|
|
|
assert(cur);
|
|
|
|
|
|
2007-03-07 05:24:59 +01:00
|
|
|
cur->set_range(new PENumber(new verinum(TIME_WIDTH-1, integer_width)),
|
2007-08-22 04:52:42 +02:00
|
|
|
new PENumber(new verinum((uint64_t)0, integer_width)),
|
|
|
|
|
SR_NET);
|
2000-10-31 18:49:02 +01:00
|
|
|
}
|
|
|
|
|
|
2004-05-25 21:21:06 +02:00
|
|
|
void pform_set_reg_time(list<perm_string>*names)
|
2000-10-31 18:49:02 +01:00
|
|
|
{
|
2004-05-25 21:21:06 +02:00
|
|
|
for (list<perm_string>::iterator cur = names->begin()
|
2000-10-31 18:49:02 +01:00
|
|
|
; cur != names->end()
|
|
|
|
|
; cur ++ ) {
|
2004-05-25 21:21:06 +02:00
|
|
|
perm_string txt = *cur;
|
2000-10-31 18:49:02 +01:00
|
|
|
pform_set_reg_time(txt);
|
|
|
|
|
}
|
|
|
|
|
delete names;
|
|
|
|
|
}
|
|
|
|
|
|
2004-05-25 21:21:06 +02:00
|
|
|
svector<PWire*>* pform_make_udp_input_ports(list<perm_string>*names)
|
1998-11-25 03:35:53 +01:00
|
|
|
{
|
1999-06-12 22:35:27 +02:00
|
|
|
svector<PWire*>*out = new svector<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()
|
1998-11-25 03:35:53 +01: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;
|
|
|
|
|
}
|
|
|
|
|
|
2002-05-26 03:39:02 +02:00
|
|
|
PProcess* pform_make_behavior(PProcess::Type type, Statement*st,
|
|
|
|
|
svector<named_pexpr_t*>*attr)
|
1998-11-04 00:28:49 +01:00
|
|
|
{
|
|
|
|
|
PProcess*pp = new PProcess(type, st);
|
2002-05-26 03:39:02 +02:00
|
|
|
|
|
|
|
|
if (attr) {
|
|
|
|
|
for (unsigned idx = 0 ; idx < attr->count() ; idx += 1) {
|
|
|
|
|
named_pexpr_t*tmp = (*attr)[idx];
|
2004-02-20 19:53:33 +01:00
|
|
|
pp->attributes[tmp->name] = tmp->parm;
|
2002-05-26 03:39:02 +02:00
|
|
|
}
|
|
|
|
|
delete attr;
|
|
|
|
|
}
|
|
|
|
|
|
2007-03-05 06:59:10 +01:00
|
|
|
if (pform_cur_generate)
|
|
|
|
|
pform_cur_generate->add_behavior(pp);
|
|
|
|
|
else
|
2008-03-04 05:49:52 +01:00
|
|
|
pform_cur_module->behaviors.push_back(pp);
|
2007-03-05 06:59:10 +01:00
|
|
|
|
1999-01-25 06:45:56 +01:00
|
|
|
return pp;
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
FILE*vl_input = 0;
|
2001-10-21 01:02:39 +02:00
|
|
|
extern void reset_lexor();
|
|
|
|
|
|
|
|
|
|
int pform_parse(const char*path, FILE*file)
|
1998-11-04 00:28:49 +01:00
|
|
|
{
|
1998-12-09 05:02:47 +01:00
|
|
|
vl_file = path;
|
2001-10-21 01:02:39 +02:00
|
|
|
if (file == 0) {
|
|
|
|
|
|
|
|
|
|
if (strcmp(path, "-") == 0)
|
|
|
|
|
vl_input = stdin;
|
|
|
|
|
else
|
|
|
|
|
vl_input = fopen(path, "r");
|
|
|
|
|
if (vl_input == 0) {
|
|
|
|
|
cerr << "Unable to open " <<vl_file << "." << endl;
|
|
|
|
|
return 11;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
vl_input = file;
|
1998-12-09 05:02:47 +01:00
|
|
|
}
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
if (file == 0)
|
|
|
|
|
fclose(vl_input);
|
|
|
|
|
|
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
|
|
|
|
1998-11-07 18:05:05 +01:00
|
|
|
return error_count;
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
2007-08-17 19:10:28 +02:00
|
|
|
|
|
|
|
|
void pform_error_nested_modules()
|
|
|
|
|
{
|
|
|
|
|
assert( pform_cur_module != 0 );
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << pform_cur_module->get_fileline() << ": error: original module "
|
2007-08-17 19:10:28 +02:00
|
|
|
"(" << pform_cur_module->mod_name() << ") defined here." << endl;
|
|
|
|
|
}
|