Merge branch 'master' into elaborate-net-rework
This commit is contained in:
commit
04d49fcf35
24
PExpr.cc
24
PExpr.cc
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1998-2007 Stephen Williams <steve@icarus.com>
|
||||
* Copyright (c) 1998-2008 Stephen Williams <steve@icarus.com>
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -20,6 +20,7 @@
|
|||
# include "config.h"
|
||||
|
||||
# include <iostream>
|
||||
# include <cstring>
|
||||
|
||||
# include "PExpr.h"
|
||||
# include "Module.h"
|
||||
|
|
@ -117,6 +118,26 @@ PECallFunction::~PECallFunction()
|
|||
{
|
||||
}
|
||||
|
||||
bool PECallFunction::is_constant(Module*mod) const
|
||||
{
|
||||
/* Only $clog2 can be a constant system function. */
|
||||
if (peek_tail_name(path_)[0] == '$') {
|
||||
if (strcmp(peek_tail_name(path_).str(), "$clog2") == 0) {
|
||||
if (parms_.count() != 1 || parms_[0] == 0) {
|
||||
cerr << get_fileline() << ": error: $clog2 takes a "
|
||||
"single argument." << endl;
|
||||
return false;
|
||||
}
|
||||
/* If the argument is constant $clog2 is constant. */
|
||||
return parms_[0]->is_constant(mod);
|
||||
}
|
||||
return false; /* Most system functions are not constant. */
|
||||
}
|
||||
|
||||
/* Checking for constant user functions goes here. */
|
||||
return false;
|
||||
}
|
||||
|
||||
PEConcat::PEConcat(const svector<PExpr*>&p, PExpr*r)
|
||||
: parms_(p), repeat_(r)
|
||||
{
|
||||
|
|
@ -299,4 +320,3 @@ bool PEUnary::is_constant(Module*m) const
|
|||
{
|
||||
return expr_->is_constant(m);
|
||||
}
|
||||
|
||||
|
|
|
|||
3
PExpr.h
3
PExpr.h
|
|
@ -710,6 +710,8 @@ class PECallFunction : public PExpr {
|
|||
explicit PECallFunction(perm_string n);
|
||||
~PECallFunction();
|
||||
|
||||
virtual bool is_constant(Module*) const;
|
||||
|
||||
virtual void dump(ostream &) const;
|
||||
|
||||
virtual NetNet* elaborate_net(Design*des, NetScope*scope,
|
||||
|
|
@ -721,6 +723,7 @@ class PECallFunction : public PExpr {
|
|||
Link::strength_t drive1) const;
|
||||
virtual NetExpr*elaborate_expr(Design*des, NetScope*scope,
|
||||
int expr_wid, bool sys_task_arg) const;
|
||||
virtual NetExpr*elaborate_pexpr(Design*des, NetScope*sc) const;
|
||||
|
||||
virtual unsigned test_width(Design*des, NetScope*scope,
|
||||
unsigned min, unsigned lval,
|
||||
|
|
|
|||
|
|
@ -21,9 +21,10 @@
|
|||
|
||||
#include "PTask.h"
|
||||
|
||||
PFunction::PFunction(perm_string name, PScope*parent)
|
||||
PFunction::PFunction(perm_string name, PScope*parent, bool is_auto)
|
||||
: PScope(name, parent), ports_(0), statement_(0)
|
||||
{
|
||||
is_auto_ = is_auto;
|
||||
return_type_.type = PTF_NONE;
|
||||
}
|
||||
|
||||
|
|
|
|||
31
PTask.cc
31
PTask.cc
|
|
@ -21,9 +21,10 @@
|
|||
|
||||
# include "PTask.h"
|
||||
|
||||
PTask::PTask(perm_string name, PScope*parent)
|
||||
PTask::PTask(perm_string name, PScope*parent, bool is_auto)
|
||||
: PScope(name, parent), ports_(0), statement_(0)
|
||||
{
|
||||
is_auto_ = is_auto;
|
||||
}
|
||||
|
||||
PTask::~PTask()
|
||||
|
|
@ -41,31 +42,3 @@ void PTask::set_statement(Statement*s)
|
|||
assert(statement_ == 0);
|
||||
statement_ = s;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* $Log: PTask.cc,v $
|
||||
* Revision 1.7 2002/08/12 01:34:58 steve
|
||||
* conditional ident string using autoconfig.
|
||||
*
|
||||
* Revision 1.6 2001/07/25 03:10:48 steve
|
||||
* Create a config.h.in file to hold all the config
|
||||
* junk, and support gcc 3.0. (Stephan Boettcher)
|
||||
*
|
||||
* Revision 1.5 2001/04/19 03:04:47 steve
|
||||
* Spurious assert of empty statemnt.
|
||||
*
|
||||
* Revision 1.4 2001/01/13 22:20:08 steve
|
||||
* Parse parameters within nested scopes.
|
||||
*
|
||||
* Revision 1.3 2000/02/23 02:56:53 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.2 1999/07/24 02:11:19 steve
|
||||
* Elaborate task input ports.
|
||||
*
|
||||
* Revision 1.1 1999/07/03 02:12:51 steve
|
||||
* Elaborate user defined tasks.
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
|
|||
10
PTask.h
10
PTask.h
|
|
@ -51,7 +51,7 @@ struct PTaskFuncArg {
|
|||
class PTask : public PScope, public LineInfo {
|
||||
|
||||
public:
|
||||
explicit PTask(perm_string name, PScope*parent);
|
||||
explicit PTask(perm_string name, PScope*parent, bool is_auto);
|
||||
~PTask();
|
||||
|
||||
void set_ports(svector<PWire *>*p);
|
||||
|
|
@ -69,11 +69,14 @@ class PTask : public PScope, public LineInfo {
|
|||
// Elaborate the statement to finish off the task definition.
|
||||
void elaborate(Design*des, NetScope*scope) const;
|
||||
|
||||
bool is_auto() const { return is_auto_; };
|
||||
|
||||
void dump(ostream&, unsigned) const;
|
||||
|
||||
private:
|
||||
svector<PWire*>*ports_;
|
||||
Statement*statement_;
|
||||
bool is_auto_;
|
||||
|
||||
private: // Not implemented
|
||||
PTask(const PTask&);
|
||||
|
|
@ -90,7 +93,7 @@ class PTask : public PScope, public LineInfo {
|
|||
class PFunction : public PScope, public LineInfo {
|
||||
|
||||
public:
|
||||
explicit PFunction(perm_string name, PScope*parent);
|
||||
explicit PFunction(perm_string name, PScope*parent, bool is_auto);
|
||||
~PFunction();
|
||||
|
||||
void set_ports(svector<PWire *>*p);
|
||||
|
|
@ -105,12 +108,15 @@ class PFunction : public PScope, public LineInfo {
|
|||
/* Elaborate the behavioral statement. */
|
||||
void elaborate(Design *des, NetScope*) const;
|
||||
|
||||
bool is_auto() const { return is_auto_; };
|
||||
|
||||
void dump(ostream&, unsigned) const;
|
||||
|
||||
private:
|
||||
PTaskFuncArg return_type_;
|
||||
svector<PWire *> *ports_;
|
||||
Statement *statement_;
|
||||
bool is_auto_;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -998,6 +998,7 @@ void NetScope::dump(ostream&o) const
|
|||
o << " generate block";
|
||||
break;
|
||||
}
|
||||
if (is_auto()) o << " (automatic)";
|
||||
o << endl;
|
||||
|
||||
for (unsigned idx = 0 ; idx < attr_cnt() ; idx += 1)
|
||||
|
|
|
|||
|
|
@ -653,7 +653,7 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope, int expr_w
|
|||
delete tmp;
|
||||
}
|
||||
|
||||
verinum val (sub_expr_width, 8*sizeof(unsigned));
|
||||
verinum val ( (uint64_t)sub_expr_width, 8*sizeof(unsigned));
|
||||
NetEConst*sub = new NetEConst(val);
|
||||
sub->set_line(*this);
|
||||
|
||||
|
|
@ -1653,7 +1653,7 @@ NetExpr* PEIdent::elaborate_expr_net_word_(Design*des, NetScope*scope,
|
|||
// Recalculate the constant address with the adjusted base.
|
||||
unsigned use_addr = net->array_index_to_address(addr);
|
||||
if (addr < 0 || use_addr != (unsigned long)addr) {
|
||||
verinum val (use_addr, 8*sizeof(use_addr));
|
||||
verinum val ( (uint64_t)use_addr, 8*sizeof(use_addr));
|
||||
NetEConst*tmp = new NetEConst(val);
|
||||
tmp->set_line(*this);
|
||||
delete word_index;
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
# include "netmisc.h"
|
||||
|
||||
# include <cstdlib>
|
||||
# include <cstring>
|
||||
# include <iostream>
|
||||
# include "ivl_assert.h"
|
||||
|
||||
|
|
@ -267,3 +268,40 @@ NetExpr*PEUnary::elaborate_pexpr (Design*des, NetScope*scope) const
|
|||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/* Reuse the routine from eval_tree.cc. */
|
||||
NetExpr* evaluate_clog2(NetExpr*arg);
|
||||
|
||||
NetExpr* PECallFunction::elaborate_pexpr(Design*des, NetScope*scope) const
|
||||
{
|
||||
/* For now only $clog2 can be a constant system function. */
|
||||
if (peek_tail_name(path_)[0] == '$') {
|
||||
if (strcmp(peek_tail_name(path_).str(), "$clog2") == 0) {
|
||||
if (parms_.count() != 1 || parms_[0] == 0) {
|
||||
cerr << get_fileline() << ": error: $clog2 takes a "
|
||||
"single argument." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
NetExpr*arg = parms_[0]->elaborate_pexpr(des, scope);
|
||||
eval_expr(arg);
|
||||
NetExpr*rtn = evaluate_clog2(arg);
|
||||
delete arg;
|
||||
if (rtn != 0) {
|
||||
rtn->set_line(*this);
|
||||
return rtn;
|
||||
}
|
||||
}
|
||||
|
||||
cerr << get_fileline() << ": error: this is not a constant "
|
||||
"system function (" << *this << ")." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Constant user function code goes here. */
|
||||
cerr << get_fileline() << ": sorry: constant user functions are not "
|
||||
"currently supported." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -150,6 +150,7 @@ static void elaborate_scope_tasks(Design*des, NetScope*scope,
|
|||
}
|
||||
NetScope*task_scope = new NetScope(scope, use_name,
|
||||
NetScope::TASK);
|
||||
task_scope->is_auto((*cur).second->is_auto());
|
||||
task_scope->set_line((*cur).second);
|
||||
|
||||
if (debug_scopes)
|
||||
|
|
@ -179,6 +180,7 @@ static void elaborate_scope_funcs(Design*des, NetScope*scope,
|
|||
}
|
||||
NetScope*func_scope = new NetScope(scope, use_name,
|
||||
NetScope::FUNC);
|
||||
func_scope->is_auto((*cur).second->is_auto());
|
||||
func_scope->set_line((*cur).second);
|
||||
|
||||
if (debug_scopes)
|
||||
|
|
|
|||
|
|
@ -2532,8 +2532,8 @@ NetProc* PEventStatement::elaborate_st(Design*des, NetScope*scope,
|
|||
}
|
||||
NexusSet*nset = enet->nex_input(rem_out);
|
||||
if (nset == 0) {
|
||||
cerr << get_fileline() << ": internal error: No NexusSet"
|
||||
<< " from statement." << endl;
|
||||
cerr << get_fileline() << ": error: Unable to elaborate:"
|
||||
<< endl;
|
||||
enet->dump(cerr, 6);
|
||||
des->errors += 1;
|
||||
return enet;
|
||||
|
|
|
|||
66
eval_tree.cc
66
eval_tree.cc
|
|
@ -22,6 +22,8 @@
|
|||
|
||||
# include <iostream>
|
||||
# include <cstdlib>
|
||||
# include <cstring>
|
||||
# include <math.h>
|
||||
|
||||
# include "netlist.h"
|
||||
# include "ivl_assert.h"
|
||||
|
|
@ -1620,3 +1622,67 @@ NetEConst* NetEUReduce::eval_tree(int prune_to_width)
|
|||
|
||||
return new NetEConst(verinum(res, 1));
|
||||
}
|
||||
|
||||
NetExpr* evaluate_clog2(NetExpr*arg)
|
||||
{
|
||||
NetEConst*tmpi = dynamic_cast<NetEConst *>(arg);
|
||||
NetECReal*tmpr = dynamic_cast<NetECReal *>(arg);
|
||||
bool is_neg = false;
|
||||
if (tmpi || tmpr) {
|
||||
verinum arg;
|
||||
if (tmpi) {
|
||||
arg = tmpi->value();
|
||||
} else {
|
||||
arg = verinum(tmpr->value().as_double(), true);
|
||||
}
|
||||
|
||||
/* If we have an x in the verinum we return 32'bx. */
|
||||
if (!arg.is_defined()) {
|
||||
verinum tmp (verinum::Vx, 32);
|
||||
tmp.has_sign(true);
|
||||
NetEConst*rtn = new NetEConst(tmp);
|
||||
return rtn;
|
||||
}
|
||||
|
||||
uint64_t res = 0;
|
||||
if (arg.is_negative()) is_neg = true;
|
||||
arg.has_sign(false); // $unsigned()
|
||||
if (!arg.is_zero()) {
|
||||
arg = arg - verinum((uint64_t)1, 1);
|
||||
while (!arg.is_zero()) {
|
||||
res += 1;
|
||||
arg = arg >> 1;
|
||||
}
|
||||
}
|
||||
if (is_neg && res < 32) res = 32;
|
||||
verinum tmp (res, 32);
|
||||
tmp.has_sign(true);
|
||||
NetEConst*rtn = new NetEConst(tmp);
|
||||
return rtn;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetExpr* NetESFunc::eval_tree(int prune_to_width)
|
||||
{
|
||||
/* For now only $clog2 can be a constant system function. */
|
||||
if (strcmp(name(), "$clog2") == 0) {
|
||||
if (nparms() != 1 || parm(0) == 0) {
|
||||
cerr << get_fileline() << ": error: $clog2 takes a single "
|
||||
"argument." << endl;
|
||||
return 0;
|
||||
}
|
||||
NetExpr*rtn = evaluate_clog2(parm(0));
|
||||
if (rtn != 0) {
|
||||
rtn->set_line(*this);
|
||||
if (debug_eval_tree) {
|
||||
cerr << get_fileline() << ": debug: Evaluate "
|
||||
"constant $clog2()." << endl;
|
||||
}
|
||||
return rtn;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
1
ivl.def
1
ivl.def
|
|
@ -143,6 +143,7 @@ ivl_scope_def_lineno
|
|||
ivl_scope_event
|
||||
ivl_scope_events
|
||||
ivl_scope_file
|
||||
ivl_scope_is_auto
|
||||
ivl_scope_lineno
|
||||
ivl_scope_logs
|
||||
ivl_scope_log
|
||||
|
|
|
|||
|
|
@ -1447,6 +1447,9 @@ extern unsigned ivl_parameter_lineno(ivl_parameter_t net);
|
|||
* ivl_scope_lineno
|
||||
* Returns the instantiation file and line for this scope.
|
||||
*
|
||||
* ivl_scope_is_auto
|
||||
* Is the task or function declared to be automatic?
|
||||
*
|
||||
* ivl_scope_var
|
||||
* ivl_scope_vars
|
||||
* REMOVED
|
||||
|
|
@ -1523,6 +1526,7 @@ extern unsigned ivl_scope_def_lineno(ivl_scope_t net);
|
|||
extern unsigned ivl_scope_events(ivl_scope_t net);
|
||||
extern ivl_event_t ivl_scope_event(ivl_scope_t net, unsigned idx);
|
||||
extern const char* ivl_scope_file(ivl_scope_t net);
|
||||
extern unsigned ivl_scope_is_auto(ivl_scope_t net);
|
||||
extern unsigned ivl_scope_lineno(ivl_scope_t net);
|
||||
extern unsigned ivl_scope_logs(ivl_scope_t net);
|
||||
extern ivl_net_logic_t ivl_scope_log(ivl_scope_t net, unsigned idx);
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ assign, GN_KEYWORDS_1364_1995, K_assign
|
|||
atan, GN_KEYWORDS_VAMS_2_3, K_atan
|
||||
atan2, GN_KEYWORDS_VAMS_2_3, K_atan2
|
||||
atanh, GN_KEYWORDS_VAMS_2_3, K_atanh
|
||||
automatic, GN_KEYWORDS_1364_2001, K_automatic
|
||||
begin, GN_KEYWORDS_1364_1995, K_begin
|
||||
bool, GN_KEYWORDS_ICARUS, K_bool
|
||||
buf, GN_KEYWORDS_1364_1995, K_buf
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2002-2007 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2002-2008 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -53,8 +53,13 @@ NexusSet* NetEBinary::nex_input(bool rem_out)
|
|||
|
||||
NexusSet* NetEConcat::nex_input(bool rem_out)
|
||||
{
|
||||
if (parms_[0] == NULL) return NULL;
|
||||
NexusSet*result = parms_[0]->nex_input(rem_out);
|
||||
for (unsigned idx = 1 ; idx < parms_.count() ; idx += 1) {
|
||||
if (parms_[idx] == NULL) {
|
||||
delete result;
|
||||
return NULL;
|
||||
}
|
||||
NexusSet*tmp = parms_[idx]->nex_input(rem_out);
|
||||
result->add(*tmp);
|
||||
delete tmp;
|
||||
|
|
@ -98,6 +103,10 @@ NexusSet* NetESelect::nex_input(bool rem_out)
|
|||
{
|
||||
NexusSet*result = base_? base_->nex_input(rem_out) : new NexusSet();
|
||||
NexusSet*tmp = expr_->nex_input(rem_out);
|
||||
if (tmp == NULL) {
|
||||
delete result;
|
||||
return NULL;
|
||||
}
|
||||
result->add(*tmp);
|
||||
delete tmp;
|
||||
return result;
|
||||
|
|
@ -381,4 +390,3 @@ NexusSet* NetWhile::nex_input(bool rem_out)
|
|||
delete tmp;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ NetScope::NetScope(NetScope*up, const hname_t&n, NetScope::TYPE t)
|
|||
signals_ = 0;
|
||||
events_ = 0;
|
||||
lcounter_ = 0;
|
||||
is_auto_ = false;
|
||||
|
||||
if (up) {
|
||||
default_nettype_ = up->default_nettype();
|
||||
|
|
@ -261,6 +262,7 @@ NetFuncDef* NetScope::func_def()
|
|||
assert( type_ == FUNC );
|
||||
return func_;
|
||||
}
|
||||
|
||||
bool NetScope::in_func()
|
||||
{
|
||||
return (type_ == FUNC) ? true : false;
|
||||
|
|
|
|||
|
|
@ -697,6 +697,9 @@ class NetScope : public Attrib {
|
|||
unsigned get_def_lineno() const { return def_lineno_; };
|
||||
|
||||
bool in_func();
|
||||
/* Is the task or function automatic. */
|
||||
void is_auto(bool is_auto) { is_auto_ = is_auto; };
|
||||
bool is_auto() const { return is_auto_; };
|
||||
|
||||
const NetTaskDef* task_def() const;
|
||||
const NetFuncDef* func_def() const;
|
||||
|
|
@ -840,6 +843,7 @@ class NetScope : public Attrib {
|
|||
NetScope*sub_;
|
||||
|
||||
unsigned lcounter_;
|
||||
bool is_auto_;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -3455,6 +3459,8 @@ class NetESFunc : public NetExpr {
|
|||
NetExpr* parm(unsigned idx);
|
||||
const NetExpr* parm(unsigned idx) const;
|
||||
|
||||
virtual NetExpr* eval_tree(int prune_to_width = -1);
|
||||
|
||||
virtual ivl_variable_type_t expr_type() const;
|
||||
virtual NexusSet* nex_input(bool rem_out = true);
|
||||
virtual bool set_width(unsigned, bool last_chance);
|
||||
|
|
|
|||
61
parse.y
61
parse.y
|
|
@ -205,7 +205,7 @@ static PECallFunction*make_call_function(perm_string tn, PExpr*arg1, PExpr*arg2)
|
|||
%token K_PSTAR K_STARP
|
||||
%token K_LOR K_LAND K_NAND K_NOR K_NXOR K_TRIGGER
|
||||
%token K_abs K_abstol K_access K_acos K_acosh K_asin K_analog K_asinh
|
||||
%token K_atan K_atanh K_atan2
|
||||
%token K_atan K_atanh K_atan2 K_automatic
|
||||
%token K_always K_and K_assign K_begin K_bool K_buf K_bufif0 K_bufif1 K_case
|
||||
%token K_casex K_casez K_ceil K_cmos K_continuous K_cos K_cosh
|
||||
%token K_ddt_nature K_deassign K_default K_defparam K_disable K_discrete
|
||||
|
|
@ -239,7 +239,7 @@ static PECallFunction*make_call_function(perm_string tn, PExpr*arg1, PExpr*arg2)
|
|||
|
||||
%type <flag> from_exclude
|
||||
%type <number> number
|
||||
%type <flag> signed_opt udp_reg_opt edge_operator
|
||||
%type <flag> signed_opt udp_reg_opt edge_operator automatic_opt
|
||||
%type <drive> drive_strength drive_strength_opt dr_strength0 dr_strength1
|
||||
%type <letter> udp_input_sym udp_output_sym
|
||||
%type <text> udp_input_list udp_sequ_entry udp_comb_entry
|
||||
|
|
@ -2094,41 +2094,41 @@ module_item
|
|||
statements in the task body. But we continue to accept it as an
|
||||
extension. */
|
||||
|
||||
| K_task IDENTIFIER ';'
|
||||
| K_task automatic_opt IDENTIFIER ';'
|
||||
{ assert(current_task == 0);
|
||||
current_task = pform_push_task_scope($2);
|
||||
current_task = pform_push_task_scope($3, $2);
|
||||
FILE_NAME(current_task, @1);
|
||||
}
|
||||
task_item_list_opt
|
||||
statement_or_null
|
||||
K_endtask
|
||||
{ current_task->set_ports($5);
|
||||
current_task->set_statement($6);
|
||||
{ current_task->set_ports($6);
|
||||
current_task->set_statement($7);
|
||||
pform_pop_scope();
|
||||
current_task = 0;
|
||||
delete[]$2;
|
||||
delete[]$3;
|
||||
}
|
||||
|
||||
| K_task IDENTIFIER
|
||||
| K_task automatic_opt IDENTIFIER
|
||||
{ assert(current_task == 0);
|
||||
current_task = pform_push_task_scope($2);
|
||||
current_task = pform_push_task_scope($3, $2);
|
||||
FILE_NAME(current_task, @1);
|
||||
}
|
||||
'(' task_port_decl_list ')' ';'
|
||||
block_item_decls_opt
|
||||
statement_or_null
|
||||
K_endtask
|
||||
{ current_task->set_ports($5);
|
||||
current_task->set_statement($9);
|
||||
{ current_task->set_ports($6);
|
||||
current_task->set_statement($10);
|
||||
pform_pop_scope();
|
||||
current_task = 0;
|
||||
delete[]$2;
|
||||
delete[]$3;
|
||||
}
|
||||
| K_task IDENTIFIER error K_endtask
|
||||
| K_task automatic_opt IDENTIFIER error K_endtask
|
||||
{
|
||||
pform_pop_scope();
|
||||
current_task = 0;
|
||||
delete[]$2;
|
||||
delete[]$3;
|
||||
}
|
||||
|
||||
/* The function declaration rule matches the function declaration
|
||||
|
|
@ -2136,42 +2136,42 @@ module_item
|
|||
definitions in the func_body to take on the scope of the function
|
||||
instead of the module. */
|
||||
|
||||
| K_function function_range_or_type_opt IDENTIFIER ';'
|
||||
| K_function automatic_opt function_range_or_type_opt IDENTIFIER ';'
|
||||
{ assert(current_function == 0);
|
||||
current_function = pform_push_function_scope($3);
|
||||
current_function = pform_push_function_scope($4, $2);
|
||||
FILE_NAME(current_function, @1);
|
||||
}
|
||||
function_item_list statement
|
||||
K_endfunction
|
||||
{ current_function->set_ports($6);
|
||||
current_function->set_statement($7);
|
||||
current_function->set_return($2);
|
||||
{ current_function->set_ports($7);
|
||||
current_function->set_statement($8);
|
||||
current_function->set_return($3);
|
||||
pform_pop_scope();
|
||||
current_function = 0;
|
||||
delete[]$3;
|
||||
delete[]$4;
|
||||
}
|
||||
|
||||
| K_function function_range_or_type_opt IDENTIFIER
|
||||
| K_function automatic_opt function_range_or_type_opt IDENTIFIER
|
||||
{ assert(current_function == 0);
|
||||
current_function = pform_push_function_scope($3);
|
||||
current_function = pform_push_function_scope($4, $2);
|
||||
FILE_NAME(current_function, @1);
|
||||
}
|
||||
'(' task_port_decl_list ')' ';'
|
||||
block_item_decls_opt
|
||||
statement
|
||||
K_endfunction
|
||||
{ current_function->set_ports($6);
|
||||
current_function->set_statement($10);
|
||||
current_function->set_return($2);
|
||||
{ current_function->set_ports($7);
|
||||
current_function->set_statement($11);
|
||||
current_function->set_return($3);
|
||||
pform_pop_scope();
|
||||
current_function = 0;
|
||||
delete[]$3;
|
||||
delete[]$4;
|
||||
}
|
||||
| K_function function_range_or_type_opt IDENTIFIER error K_endfunction
|
||||
| K_function automatic_opt function_range_or_type_opt IDENTIFIER error K_endfunction
|
||||
{
|
||||
pform_pop_scope();
|
||||
current_task = 0;
|
||||
delete[]$3;
|
||||
delete[]$4;
|
||||
}
|
||||
|
||||
/* A generate region can contain further module items. Actually, it
|
||||
|
|
@ -2278,6 +2278,11 @@ module_item
|
|||
{ yyerror(@1, "error: Malformed $attribute parameter list."); }
|
||||
;
|
||||
|
||||
automatic_opt
|
||||
: K_automatic { $$ = true; }
|
||||
| { $$ = false;}
|
||||
;
|
||||
|
||||
generate_if : K_if '(' expression ')' { pform_start_generate_if(@1, $3); }
|
||||
|
||||
generate_case_items
|
||||
|
|
|
|||
14
pform.cc
14
pform.cc
|
|
@ -103,17 +103,18 @@ void pform_pop_scope()
|
|||
}
|
||||
}
|
||||
|
||||
PTask* pform_push_task_scope(char*name)
|
||||
PTask* pform_push_task_scope(char*name, bool is_auto)
|
||||
{
|
||||
perm_string task_name = lex_strings.make(name);
|
||||
|
||||
PTask*task;
|
||||
if (pform_cur_generate) {
|
||||
task = new PTask(task_name, pform_cur_generate->lexical_scope);
|
||||
task = new PTask(task_name, pform_cur_generate->lexical_scope,
|
||||
is_auto);
|
||||
pform_cur_generate->tasks[task->pscope_name()] = task;
|
||||
pform_cur_generate->lexical_scope = task;
|
||||
} else {
|
||||
task = new PTask(task_name, lexical_scope);
|
||||
task = new PTask(task_name, lexical_scope, is_auto);
|
||||
pform_cur_module->tasks[task->pscope_name()] = task;
|
||||
lexical_scope = task;
|
||||
}
|
||||
|
|
@ -121,17 +122,18 @@ PTask* pform_push_task_scope(char*name)
|
|||
return task;
|
||||
}
|
||||
|
||||
PFunction* pform_push_function_scope(char*name)
|
||||
PFunction* pform_push_function_scope(char*name, bool is_auto)
|
||||
{
|
||||
perm_string func_name = lex_strings.make(name);
|
||||
|
||||
PFunction*func;
|
||||
if (pform_cur_generate) {
|
||||
func = new PFunction(func_name, pform_cur_generate->lexical_scope);
|
||||
func = new PFunction(func_name, pform_cur_generate->lexical_scope,
|
||||
is_auto);
|
||||
pform_cur_generate->funcs[func->pscope_name()] = func;
|
||||
pform_cur_generate->lexical_scope = func;
|
||||
} else {
|
||||
func = new PFunction(func_name, lexical_scope);
|
||||
func = new PFunction(func_name, lexical_scope, is_auto);
|
||||
pform_cur_module->funcs[func->pscope_name()] = func;
|
||||
lexical_scope = func;
|
||||
}
|
||||
|
|
|
|||
4
pform.h
4
pform.h
|
|
@ -175,8 +175,8 @@ extern void pform_make_udp(perm_string name,
|
|||
*/
|
||||
extern void pform_pop_scope();
|
||||
|
||||
extern PTask*pform_push_task_scope(char*name);
|
||||
extern PFunction*pform_push_function_scope(char*name);
|
||||
extern PTask*pform_push_task_scope(char*name, bool is_auto);
|
||||
extern PFunction*pform_push_function_scope(char*name, bool is_auto);
|
||||
extern PBlock*pform_push_block_scope(char*name, PBlock::BL_TYPE tt);
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -715,6 +715,7 @@ void PForStatement::dump(ostream&out, unsigned ind) const
|
|||
void PFunction::dump(ostream&out, unsigned ind) const
|
||||
{
|
||||
out << setw(ind) << "" << "function ";
|
||||
if (is_auto_) cout << "automatic ";
|
||||
switch (return_type_.type) {
|
||||
case PTF_NONE:
|
||||
out << "?none? ";
|
||||
|
|
@ -775,6 +776,9 @@ void PRepeat::dump(ostream&out, unsigned ind) const
|
|||
|
||||
void PTask::dump(ostream&out, unsigned ind) const
|
||||
{
|
||||
out << setw(ind) << "" << "task ";
|
||||
if (is_auto_) cout << "automatic ";
|
||||
out << pscope_name() << ";" << endl;
|
||||
if (ports_)
|
||||
for (unsigned idx = 0 ; idx < ports_->count() ; idx += 1) {
|
||||
out << setw(ind) << "";
|
||||
|
|
|
|||
|
|
@ -1547,6 +1547,12 @@ extern "C" const char*ivl_scope_file(ivl_scope_t net)
|
|||
return net->file.str();
|
||||
}
|
||||
|
||||
extern "C" unsigned ivl_scope_is_auto(ivl_scope_t net)
|
||||
{
|
||||
assert(net);
|
||||
return net->is_auto;
|
||||
}
|
||||
|
||||
extern "C" unsigned ivl_scope_lineno(ivl_scope_t net)
|
||||
{
|
||||
assert(net);
|
||||
|
|
|
|||
4
t-dll.cc
4
t-dll.cc
|
|
@ -575,6 +575,7 @@ void dll_target::add_root(ivl_design_s &des_, const NetScope *s)
|
|||
root_->time_units = s->time_unit();
|
||||
root_->nattr = s->attr_cnt();
|
||||
root_->attr = fill_in_attributes(s);
|
||||
root_->is_auto = 0;
|
||||
|
||||
des_.nroots_++;
|
||||
if (des_.roots_)
|
||||
|
|
@ -2319,7 +2320,8 @@ void dll_target::scope(const NetScope*net)
|
|||
scope->time_precision = net->time_precision();
|
||||
scope->time_units = net->time_unit();
|
||||
scope->nattr = net->attr_cnt();
|
||||
scope->attr = fill_in_attributes(net);
|
||||
scope->attr = fill_in_attributes(net);
|
||||
scope->is_auto = net->is_auto();
|
||||
|
||||
switch (net->type()) {
|
||||
case NetScope::MODULE:
|
||||
|
|
|
|||
1
t-dll.h
1
t-dll.h
|
|
@ -590,6 +590,7 @@ struct ivl_scope_s {
|
|||
|
||||
/* Scopes that are tasks/functions have a definition. */
|
||||
ivl_statement_t def;
|
||||
unsigned is_auto;
|
||||
|
||||
unsigned ports;
|
||||
ivl_signal_t*port;
|
||||
|
|
|
|||
|
|
@ -1448,12 +1448,13 @@ static int show_scope(ivl_scope_t net, void*x)
|
|||
ivl_scope_name(net), ivl_scope_params(net),
|
||||
ivl_scope_sigs(net), ivl_scope_logs(net));
|
||||
|
||||
char *is_auto = ivl_scope_is_auto(net) ? "automatic " : "";
|
||||
switch (ivl_scope_type(net)) {
|
||||
case IVL_SCT_MODULE:
|
||||
fprintf(out, " module %s", ivl_scope_tname(net));
|
||||
break;
|
||||
case IVL_SCT_FUNCTION:
|
||||
fprintf(out, " function %s", ivl_scope_tname(net));
|
||||
fprintf(out, " function %s%s", is_auto, ivl_scope_tname(net));
|
||||
break;
|
||||
case IVL_SCT_BEGIN:
|
||||
fprintf(out, " begin : %s", ivl_scope_tname(net));
|
||||
|
|
@ -1462,7 +1463,7 @@ static int show_scope(ivl_scope_t net, void*x)
|
|||
fprintf(out, " fork : %s", ivl_scope_tname(net));
|
||||
break;
|
||||
case IVL_SCT_TASK:
|
||||
fprintf(out, " task %s", ivl_scope_tname(net));
|
||||
fprintf(out, " task %s%s", is_auto, ivl_scope_tname(net));
|
||||
break;
|
||||
default:
|
||||
fprintf(out, " type(%u) %s", ivl_scope_type(net),
|
||||
|
|
|
|||
|
|
@ -1769,6 +1769,13 @@ int draw_scope(ivl_scope_t net, ivl_scope_t parent)
|
|||
{
|
||||
unsigned idx;
|
||||
const char *type;
|
||||
/* For now we do not support automatic tasks or functions. */
|
||||
if (ivl_scope_is_auto(net)) {
|
||||
fprintf(stderr, "%s:%u: vvp-tgt sorry: automatic tasks/functions "
|
||||
"are not supported!\n",
|
||||
ivl_scope_def_file(net), ivl_scope_def_lineno(net));
|
||||
exit(1);
|
||||
}
|
||||
switch (ivl_scope_type(net)) {
|
||||
case IVL_SCT_MODULE: type = "module"; break;
|
||||
case IVL_SCT_FUNCTION: type = "function"; break;
|
||||
|
|
|
|||
116
verinum.cc
116
verinum.cc
|
|
@ -152,6 +152,112 @@ verinum::verinum(uint64_t val, unsigned n)
|
|||
}
|
||||
}
|
||||
|
||||
/* The second argument is not used! It is there to make this
|
||||
* constructor unique. */
|
||||
verinum::verinum(double val, bool dummy)
|
||||
: has_len_(false), has_sign_(true), string_flag_(false)
|
||||
{
|
||||
bool is_neg = false;
|
||||
double fraction;
|
||||
int exponent;
|
||||
const unsigned BITS_IN_LONG = 8*sizeof(long);
|
||||
|
||||
/* We return `bx for a NaN or +/- infinity. */
|
||||
if (val != val || (val && (val == 0.5*val))) {
|
||||
nbits_ = 1;
|
||||
bits_ = new V[nbits_];
|
||||
bits_[0] = Vx;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Convert to a positive result. */
|
||||
if (val < 0.0) {
|
||||
is_neg = true;
|
||||
val = -val;
|
||||
}
|
||||
|
||||
/* Get the exponent and fractional part of the number. */
|
||||
fraction = frexp(val, &exponent);
|
||||
nbits_ = exponent+1;
|
||||
bits_ = new V[nbits_];
|
||||
const verinum const_one(1);
|
||||
|
||||
/* If the value is small enough just use lround(). */
|
||||
if (nbits_ <= BITS_IN_LONG) {
|
||||
long sval = lround(val);
|
||||
if (is_neg) sval = -sval;
|
||||
for (unsigned idx = 0; idx < nbits_; idx += 1) {
|
||||
bits_[idx] = (sval&1) ? V1 : V0;
|
||||
sval >>= 1;
|
||||
}
|
||||
/* Trim the result. */
|
||||
signed_trim();
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned nwords = (exponent-1)/BITS_IN_LONG;
|
||||
|
||||
fraction = ldexp(fraction, (exponent-1) % BITS_IN_LONG + 1);
|
||||
|
||||
if (nwords == 0) {
|
||||
unsigned long bits = (unsigned long) fraction;
|
||||
fraction = fraction - (double) bits;
|
||||
for (unsigned idx = 0; idx < nbits_; idx += 1) {
|
||||
bits_[idx] = (bits&1) ? V1 : V0;
|
||||
bits >>= 1;
|
||||
}
|
||||
if (fraction >= 0.5) *this = *this + const_one;
|
||||
} else {
|
||||
for (int wd = nwords; wd >= 0; wd -= 1) {
|
||||
unsigned long bits = (unsigned long) fraction;
|
||||
fraction = fraction - (double) bits;
|
||||
unsigned max = (wd+1)*BITS_IN_LONG;
|
||||
if (max > nbits_) max = nbits_;
|
||||
for (unsigned idx = wd*BITS_IN_LONG; idx < max; idx += 1) {
|
||||
bits_[idx] = (bits&1) ? V1 : V0;
|
||||
bits >>= 1;
|
||||
}
|
||||
fraction = ldexp(fraction, BITS_IN_LONG);
|
||||
}
|
||||
if (fraction >= ldexp(0.5, BITS_IN_LONG)) *this = *this + const_one;
|
||||
}
|
||||
|
||||
/* Convert a negative number if needed. */
|
||||
if (is_neg) {
|
||||
*this = v_not(*this) + const_one;
|
||||
}
|
||||
|
||||
/* Trim the result. */
|
||||
signed_trim();
|
||||
}
|
||||
|
||||
|
||||
/* This is used by the double constructor above. It is needed to remove
|
||||
* extra sign bits that can occur when calculating a negative value. */
|
||||
void verinum::signed_trim()
|
||||
{
|
||||
/* Do we have any extra digits? */
|
||||
unsigned tlen = nbits_-1;
|
||||
verinum::V sign = bits_[tlen];
|
||||
while ((tlen > 0) && (bits_[tlen] == sign)) tlen -= 1;
|
||||
|
||||
/* tlen now points to the first digit that is not the sign.
|
||||
* or bit 0. Set the length to include this bit and one proper
|
||||
* sign bit if needed. */
|
||||
if (bits_[tlen] != sign) tlen += 1;
|
||||
tlen += 1;
|
||||
|
||||
/* Trim the bits if needed. */
|
||||
if (tlen < nbits_) {
|
||||
V* tbits = new V[tlen];
|
||||
for (unsigned idx = 0; idx < tlen; idx += 1)
|
||||
tbits[idx] = bits_[idx];
|
||||
delete[] bits_;
|
||||
bits_ = tbits;
|
||||
nbits_ = tlen;
|
||||
}
|
||||
}
|
||||
|
||||
verinum::verinum(const verinum&that)
|
||||
{
|
||||
string_flag_ = that.string_flag_;
|
||||
|
|
@ -336,14 +442,9 @@ double verinum::as_double() const
|
|||
{
|
||||
if (nbits_ == 0) return 0.0;
|
||||
|
||||
/* Do we have a signed value? */
|
||||
bool signed_flag = false;
|
||||
if (bits_[nbits_-1] == V1) {
|
||||
signed_flag = true;
|
||||
}
|
||||
|
||||
double val = 0.0;
|
||||
if (signed_flag) {
|
||||
/* Do we have/want a signed value? */
|
||||
if (has_sign_ && bits_[nbits_-1] == V1) {
|
||||
V carry = V1;
|
||||
for (unsigned idx = 0; idx < nbits_; idx += 1) {
|
||||
V sum = add_with_carry(~bits_[idx], V0, carry);
|
||||
|
|
@ -351,7 +452,6 @@ double verinum::as_double() const
|
|||
val += pow(2.0, (double)idx);
|
||||
}
|
||||
val *= -1.0;
|
||||
// val = (double) as_long();
|
||||
} else {
|
||||
for (unsigned idx = 0; idx < nbits_; idx += 1) {
|
||||
if (bits_[idx] == V1)
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ class verinum {
|
|||
verinum(const V*v, unsigned nbits, bool has_len =true);
|
||||
verinum(V, unsigned nbits =1, bool has_len =true);
|
||||
verinum(uint64_t val, unsigned bits);
|
||||
verinum(double val, bool dummy);
|
||||
verinum(const verinum&);
|
||||
|
||||
// Create a signed number, with an unspecified number of bits.
|
||||
|
|
@ -93,6 +94,8 @@ class verinum {
|
|||
signed long as_long() const;
|
||||
double as_double() const;
|
||||
string as_string() const;
|
||||
private:
|
||||
void signed_trim();
|
||||
|
||||
private:
|
||||
V* bits_;
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ sys_finish.o sys_icarus.o sys_plusargs.o sys_random.o sys_random_mti.o \
|
|||
sys_readmem.o sys_readmem_lex.o sys_scanf.o sys_sdf.o \
|
||||
sys_time.o sys_vcd.o sys_vcdoff.o vcd_priv.o \
|
||||
mt19937int.o sys_priv.o sdf_lexor.o sdf_parse.o stringheap.o \
|
||||
vams_simparam.o
|
||||
sys_clog2.o vams_simparam.o
|
||||
|
||||
ifeq (@HAVE_LIBZ@,yes)
|
||||
ifeq (@HAVE_LIBBZ2@,yes)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* Copyright (C) 2008 Cary R. (cygcary@yahoo.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it 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.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <vpi_user.h>
|
||||
#include "sys_priv.h"
|
||||
|
||||
/*
|
||||
* Check that the function is called with the correct argument.
|
||||
*/
|
||||
static PLI_INT32 sys_clog2_compiletf(PLI_BYTE8 *name)
|
||||
{
|
||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||
assert(callh != 0);
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||
vpiHandle arg;
|
||||
(void) name; // Not used!
|
||||
|
||||
/* We must have an argument. */
|
||||
if (argv == 0) {
|
||||
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
vpi_printf("$clog2 requires one numeric argument.\n");
|
||||
vpi_control(vpiFinish, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The argument must be numeric. */
|
||||
arg = vpi_scan(argv);
|
||||
if (! is_numeric_obj(arg)) {
|
||||
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
vpi_printf("The first argument to $clog2 must be numeric.\n");
|
||||
vpi_control(vpiFinish, 1);
|
||||
}
|
||||
|
||||
/* We can have a maximum of one argument. */
|
||||
if (vpi_scan(argv) != 0) {
|
||||
char msg [64];
|
||||
snprintf(msg, 64, "ERROR: %s line %d:",
|
||||
vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
|
||||
unsigned argc = 1;
|
||||
while (vpi_scan(argv)) argc += 1;
|
||||
|
||||
vpi_printf("%s $clog2 takes at most one argument.\n", msg);
|
||||
vpi_printf("%*s Found %u extra argument%s.\n",
|
||||
strlen(msg), " ", argc, argc == 1 ? "" : "s");
|
||||
vpi_control(vpiFinish, 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PLI_INT32 sys_clog2_calltf(PLI_BYTE8 *name)
|
||||
{
|
||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||
vpiHandle arg;
|
||||
s_vpi_value val;
|
||||
s_vpi_vecval vec;
|
||||
(void) name; // Not used!/
|
||||
|
||||
/* Get the argument. */
|
||||
arg = vpi_scan(argv);
|
||||
vpi_free_object(argv);
|
||||
|
||||
vec = vpip_calc_clog2(arg);
|
||||
|
||||
val.format = vpiVectorVal;
|
||||
val.value.vector = &vec;
|
||||
vpi_put_value(callh, &val, 0, vpiNoDelay);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Register the function with Verilog.
|
||||
*/
|
||||
void sys_clog2_register(void)
|
||||
{
|
||||
s_vpi_systf_data tf_data;
|
||||
|
||||
tf_data.type = vpiSysFunc;
|
||||
tf_data.sysfunctype = vpiIntFunc;
|
||||
tf_data.calltf = sys_clog2_calltf;
|
||||
tf_data.compiletf = sys_clog2_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.tfname = "$clog2";
|
||||
tf_data.user_data = 0;
|
||||
vpi_register_systf(&tf_data);
|
||||
}
|
||||
|
|
@ -38,6 +38,7 @@ extern void sys_time_register();
|
|||
extern void sys_vcd_register();
|
||||
extern void sys_vcdoff_register();
|
||||
extern void sys_special_register();
|
||||
extern void sys_clog2_register();
|
||||
extern void vams_simparam_register();
|
||||
|
||||
#ifdef HAVE_LIBZ
|
||||
|
|
@ -181,6 +182,7 @@ void (*vlog_startup_routines[])() = {
|
|||
sys_lxt_or_vcd_register,
|
||||
sys_sdf_register,
|
||||
sys_special_register,
|
||||
sys_clog2_register,
|
||||
vams_simparam_register,
|
||||
0
|
||||
};
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ $dist_poisson vpiSysFuncInt
|
|||
$dist_chi_square vpiSysFuncInt
|
||||
$dist_t vpiSysFuncInt
|
||||
$dist_erlang vpiSysFuncInt
|
||||
$clog2 vpiSysFuncInt
|
||||
|
||||
$simparam vpiSysFuncReal
|
||||
$simparam$str vpiSysFuncSized 1024 unsigned
|
||||
|
|
|
|||
|
|
@ -566,6 +566,7 @@ extern DLLEXPORT void (*vlog_startup_routines[])();
|
|||
buffer. The value must be a vpiStrengthVal. */
|
||||
extern void vpip_format_strength(char*str, s_vpi_value*value, unsigned bit);
|
||||
extern void vpip_set_return_value(int value);
|
||||
extern s_vpi_vecval vpip_calc_clog2(vpiHandle arg);
|
||||
|
||||
EXTERN_C_END
|
||||
|
||||
|
|
|
|||
|
|
@ -127,6 +127,12 @@ static struct __vpiCallback* make_value_change(p_cb_data data)
|
|||
obj->cb_time.type = vpiSuppressTime;
|
||||
}
|
||||
obj->cb_data.time = &obj->cb_time;
|
||||
if (data->value) {
|
||||
obj->cb_value = *(data->value);
|
||||
} else {
|
||||
obj->cb_value.format = vpiSuppressVal;
|
||||
}
|
||||
obj->cb_data.value = &obj->cb_value;
|
||||
|
||||
assert(data->obj);
|
||||
assert(data->obj->vpi_type);
|
||||
|
|
@ -457,8 +463,25 @@ void callback_execute(struct __vpiCallback*cur)
|
|||
vpi_mode_flag = VPI_MODE_RWSYNC;
|
||||
|
||||
assert(cur->cb_data.cb_rtn);
|
||||
cur->cb_data.time->type = vpiSimTime;
|
||||
vpip_time_to_timestruct(cur->cb_data.time, schedule_simtime());
|
||||
switch (cur->cb_data.time->type) {
|
||||
case vpiSimTime:
|
||||
vpip_time_to_timestruct(cur->cb_data.time, schedule_simtime());
|
||||
break;
|
||||
case vpiScaledRealTime: {
|
||||
cur->cb_data.time->real =
|
||||
vpip_time_to_scaled_real(schedule_simtime(),
|
||||
(struct __vpiScope *) vpi_handle(vpiScope,
|
||||
cur->cb_data.obj));
|
||||
break;
|
||||
}
|
||||
case vpiSuppressTime:
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unsupported time format %d.\n",
|
||||
cur->cb_data.time->type);
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
(cur->cb_data.cb_rtn)(&cur->cb_data);
|
||||
|
||||
vpi_mode_flag = save_mode;
|
||||
|
|
@ -546,10 +569,32 @@ void vvp_fun_signal::get_value(struct t_vpi_value*vp)
|
|||
{
|
||||
switch (vp->format) {
|
||||
case vpiScalarVal:
|
||||
// This works because vvp_bit4_t has the same encoding
|
||||
// as a scalar value! See vpip_vec4_get_value() for a
|
||||
// more robust method.
|
||||
vp->value.scalar = value(0);
|
||||
break;
|
||||
|
||||
case vpiBinStrVal:
|
||||
case vpiOctStrVal:
|
||||
case vpiDecStrVal:
|
||||
case vpiHexStrVal:
|
||||
case vpiIntVal:
|
||||
case vpiVectorVal:
|
||||
case vpiStringVal:
|
||||
case vpiRealVal: {
|
||||
unsigned wid = size();
|
||||
vvp_vector4_t vec4(wid);
|
||||
for (unsigned idx = 0; idx < wid; idx += 1) {
|
||||
vec4.set_bit(idx, value(idx));
|
||||
}
|
||||
vpip_vec4_get_value(vec4, wid, false, vp);
|
||||
break;
|
||||
}
|
||||
|
||||
case vpiSuppressVal:
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "vpi_callback: value "
|
||||
"format %d not supported (fun_signal)\n",
|
||||
|
|
@ -622,6 +667,9 @@ void vvp_fun_signal_real::get_value(struct t_vpi_value*vp)
|
|||
break;
|
||||
}
|
||||
|
||||
case vpiSuppressVal:
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "vpi_callback: value "
|
||||
"format %d not supported (fun_signal_real)\n",
|
||||
|
|
|
|||
|
|
@ -456,6 +456,13 @@ void vpip_vec4_get_value(const vvp_vector4_t&word_val, unsigned width,
|
|||
vp->format);
|
||||
assert(0 && "format not implemented");
|
||||
|
||||
case vpiObjTypeVal:
|
||||
vp->format = vpiVectorVal;
|
||||
break;
|
||||
|
||||
case vpiSuppressVal:
|
||||
break;
|
||||
|
||||
case vpiBinStrVal:
|
||||
rbuf = need_result_buf(width+1, RBUF_VAL);
|
||||
for (unsigned idx = 0 ; idx < width ; idx += 1) {
|
||||
|
|
@ -504,6 +511,7 @@ void vpip_vec4_get_value(const vvp_vector4_t&word_val, unsigned width,
|
|||
break;
|
||||
case BIT4_X:
|
||||
vp->value.scalar = vpiX;
|
||||
break;
|
||||
case BIT4_Z:
|
||||
vp->value.scalar = vpiZ;
|
||||
break;
|
||||
|
|
@ -1029,3 +1037,63 @@ extern "C" void vpi_control(PLI_INT32 operation, ...)
|
|||
vpi_sim_vcontrol(operation, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine calculated the return value for $clog2.
|
||||
* It is easier to do it here vs trying to to use the VPI interface.
|
||||
*/
|
||||
extern "C" s_vpi_vecval vpip_calc_clog2(vpiHandle arg)
|
||||
{
|
||||
s_vpi_vecval rtn;
|
||||
s_vpi_value val;
|
||||
vvp_vector4_t vec4;
|
||||
bool is_neg = false; // At this point only a real can be negative.
|
||||
|
||||
/* Get the value as a vvp_vector4_t. */
|
||||
val.format = vpiObjTypeVal;
|
||||
vpi_get_value(arg, &val);
|
||||
if (val.format == vpiRealVal) {
|
||||
vpi_get_value(arg, &val);
|
||||
/* All double values can be represented in 1024 bits. */
|
||||
vec4 = vvp_vector4_t(1024, val.value.real);
|
||||
if (val.value.real < 0) is_neg = true;
|
||||
} else {
|
||||
val.format = vpiVectorVal;
|
||||
vpi_get_value(arg, &val);
|
||||
unsigned wid = vpi_get(vpiSize, arg);
|
||||
vec4 = vvp_vector4_t(wid, BIT4_0);
|
||||
for (unsigned idx=0; idx < wid; idx += 1) {
|
||||
PLI_INT32 aval = val.value.vector[idx/32].aval;
|
||||
PLI_INT32 bval = val.value.vector[idx/32].bval;
|
||||
aval >>= idx % 32;
|
||||
bval >>= idx % 32;
|
||||
int bitmask = (aval&1) | ((bval<<1)&2);
|
||||
vvp_bit4_t bit = scalar_to_bit4(bitmask);
|
||||
vec4.set_bit(idx, bit);
|
||||
}
|
||||
}
|
||||
|
||||
if (vec4.has_xz()) {
|
||||
rtn.aval = rtn.bval = 0xFFFFFFFFU; /* Set to 'bx. */
|
||||
return rtn;
|
||||
}
|
||||
|
||||
vvp_vector2_t vec2(vec4);
|
||||
|
||||
if (is_neg) vec2.trim_neg(); /* This is a special trim! */
|
||||
else vec2.trim(); /* This makes less work shifting. */
|
||||
|
||||
/* Calculate the clog2 result. */
|
||||
PLI_INT32 res = 0;
|
||||
if (!vec2.is_zero()) {
|
||||
vec2 -= vvp_vector2_t(1, vec2.size());
|
||||
while(!vec2.is_zero()) {
|
||||
res += 1;
|
||||
vec2 >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
rtn.aval = res;
|
||||
rtn.bval = 0;
|
||||
return rtn;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -137,6 +137,7 @@ struct __vpiCallback {
|
|||
// user supplied callback data
|
||||
struct t_cb_data cb_data;
|
||||
struct t_vpi_time cb_time;
|
||||
struct t_vpi_value cb_value;
|
||||
|
||||
// scheduled event
|
||||
struct sync_cb* cb_sync;
|
||||
|
|
|
|||
|
|
@ -728,23 +728,6 @@ static vvp_vector4_t from_stringval(const char*str, unsigned wid)
|
|||
return val;
|
||||
}
|
||||
|
||||
static vvp_bit4_t scalar_to_bit4(PLI_INT32 scalar)
|
||||
{
|
||||
switch(scalar) {
|
||||
case vpi0:
|
||||
return BIT4_0;
|
||||
case vpi1:
|
||||
return BIT4_1;
|
||||
case vpiX:
|
||||
return BIT4_X;
|
||||
case vpiZ:
|
||||
return BIT4_Z;
|
||||
default:
|
||||
fprintf(stderr, "Unsupported scalar value %d.\n", scalar);
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
static vpiHandle signal_put_value(vpiHandle ref, s_vpi_value*vp, int flags)
|
||||
{
|
||||
unsigned wid;
|
||||
|
|
|
|||
|
|
@ -2071,7 +2071,14 @@ bool of_FORK(vthread_t thr, vvp_code_t cp)
|
|||
|
||||
thr->fork_count += 1;
|
||||
|
||||
schedule_vthread(child, 0, true);
|
||||
/* If the new child was created to evaluate a function,
|
||||
run it immediately, then return to this thread. */
|
||||
if (cp->scope->base.vpi_type->type_code == vpiFunction) {
|
||||
child->is_scheduled = 1;
|
||||
vthread_run(child);
|
||||
} else {
|
||||
schedule_vthread(child, 0, true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,3 +37,4 @@ vpi_vprintf
|
|||
|
||||
vpip_format_strength
|
||||
vpip_set_return_value
|
||||
vpip_calc_clog2
|
||||
|
|
|
|||
|
|
@ -130,6 +130,23 @@ vvp_bit4_t add_with_carry(vvp_bit4_t a, vvp_bit4_t b, vvp_bit4_t&c)
|
|||
}
|
||||
}
|
||||
|
||||
vvp_bit4_t scalar_to_bit4(PLI_INT32 scalar)
|
||||
{
|
||||
switch(scalar) {
|
||||
case vpi0:
|
||||
return BIT4_0;
|
||||
case vpi1:
|
||||
return BIT4_1;
|
||||
case vpiX:
|
||||
return BIT4_X;
|
||||
case vpiZ:
|
||||
return BIT4_Z;
|
||||
default:
|
||||
fprintf(stderr, "Unsupported scalar value %d.\n", scalar);
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
vvp_bit4_t operator ^ (vvp_bit4_t a, vvp_bit4_t b)
|
||||
{
|
||||
if (bit4_is_xz(a))
|
||||
|
|
@ -372,19 +389,12 @@ vvp_vector4_t::vvp_vector4_t(unsigned size, double val)
|
|||
double fraction;
|
||||
int exponent;
|
||||
|
||||
/* We return 'bx for a NaN. */
|
||||
if (val != val) {
|
||||
/* We return 'bx for a NaN or +/- infinity. */
|
||||
if (val != val || (val && (val == 0.5*val))) {
|
||||
allocate_words_(size, WORD_X_ABITS, WORD_X_BBITS);
|
||||
return;
|
||||
}
|
||||
|
||||
/* We return 'b1 for + infinity or 'b0 for - infinity. */
|
||||
if (val && (val == 0.5*val)) {
|
||||
if (val > 0) allocate_words_(size, WORD_1_ABITS, WORD_1_BBITS);
|
||||
else allocate_words_(size, WORD_0_ABITS, WORD_0_BBITS);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Convert to a positive result. */
|
||||
if (val < 0.0) {
|
||||
is_neg = true;
|
||||
|
|
@ -1618,6 +1628,15 @@ void vvp_vector2_t::trim()
|
|||
while (value(wid_-1) == 0 && wid_ > 1) wid_ -= 1;
|
||||
}
|
||||
|
||||
/* This is a special trim that is used on numbers we know represent a
|
||||
* negative signed value (they came from a negative real value). */
|
||||
void vvp_vector2_t::trim_neg()
|
||||
{
|
||||
if (value(wid_-1) == 1 && wid_ > 32) {
|
||||
while (value(wid_-2) == 1 && wid_ > 32) wid_ -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
int vvp_vector2_t::value(unsigned idx) const
|
||||
{
|
||||
if (idx >= wid_)
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
*/
|
||||
|
||||
# include "config.h"
|
||||
# include "vpi_user.h"
|
||||
# include <stddef.h>
|
||||
# include <string.h>
|
||||
# include <new>
|
||||
|
|
@ -67,6 +68,8 @@ inline char vvp_bit4_to_ascii(vvp_bit4_t a) { return "01zx"[a]; }
|
|||
|
||||
extern vvp_bit4_t add_with_carry(vvp_bit4_t a, vvp_bit4_t b, vvp_bit4_t&c);
|
||||
|
||||
extern vvp_bit4_t scalar_to_bit4(PLI_INT32 scalar);
|
||||
|
||||
/* Return TRUE if the bit is BIT4_X or BIT4_Z. The fast
|
||||
implementation here relies on the encoding of vvp_bit4_t values. */
|
||||
inline bool bit4_is_xz(vvp_bit4_t a) { return a >= 2; }
|
||||
|
|
@ -470,6 +473,9 @@ class vvp_vector2_t {
|
|||
void set_bit(unsigned idx, int bit);
|
||||
// Make the size just big enough to hold the first 1 bit.
|
||||
void trim();
|
||||
// Trim off extra 1 bit since this is representing a negative value.
|
||||
// Always keep at least 32 bits.
|
||||
void trim_neg();
|
||||
|
||||
private:
|
||||
enum { BITS_PER_WORD = 8 * sizeof(unsigned long) };
|
||||
|
|
|
|||
Loading…
Reference in New Issue