Merge branch 'master' into elaborate-net-rework

This commit is contained in:
Stephen Williams 2008-08-21 18:11:21 -07:00
commit 04d49fcf35
41 changed files with 626 additions and 117 deletions

View File

@ -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 * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -20,6 +20,7 @@
# include "config.h" # include "config.h"
# include <iostream> # include <iostream>
# include <cstring>
# include "PExpr.h" # include "PExpr.h"
# include "Module.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) PEConcat::PEConcat(const svector<PExpr*>&p, PExpr*r)
: parms_(p), repeat_(r) : parms_(p), repeat_(r)
{ {
@ -299,4 +320,3 @@ bool PEUnary::is_constant(Module*m) const
{ {
return expr_->is_constant(m); return expr_->is_constant(m);
} }

View File

@ -710,6 +710,8 @@ class PECallFunction : public PExpr {
explicit PECallFunction(perm_string n); explicit PECallFunction(perm_string n);
~PECallFunction(); ~PECallFunction();
virtual bool is_constant(Module*) const;
virtual void dump(ostream &) const; virtual void dump(ostream &) const;
virtual NetNet* elaborate_net(Design*des, NetScope*scope, virtual NetNet* elaborate_net(Design*des, NetScope*scope,
@ -721,6 +723,7 @@ class PECallFunction : public PExpr {
Link::strength_t drive1) const; Link::strength_t drive1) const;
virtual NetExpr*elaborate_expr(Design*des, NetScope*scope, virtual NetExpr*elaborate_expr(Design*des, NetScope*scope,
int expr_wid, bool sys_task_arg) const; 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, virtual unsigned test_width(Design*des, NetScope*scope,
unsigned min, unsigned lval, unsigned min, unsigned lval,

View File

@ -21,9 +21,10 @@
#include "PTask.h" #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) : PScope(name, parent), ports_(0), statement_(0)
{ {
is_auto_ = is_auto;
return_type_.type = PTF_NONE; return_type_.type = PTF_NONE;
} }

View File

@ -21,9 +21,10 @@
# include "PTask.h" # 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) : PScope(name, parent), ports_(0), statement_(0)
{ {
is_auto_ = is_auto;
} }
PTask::~PTask() PTask::~PTask()
@ -41,31 +42,3 @@ void PTask::set_statement(Statement*s)
assert(statement_ == 0); assert(statement_ == 0);
statement_ = s; 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
View File

@ -51,7 +51,7 @@ struct PTaskFuncArg {
class PTask : public PScope, public LineInfo { class PTask : public PScope, public LineInfo {
public: public:
explicit PTask(perm_string name, PScope*parent); explicit PTask(perm_string name, PScope*parent, bool is_auto);
~PTask(); ~PTask();
void set_ports(svector<PWire *>*p); 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. // Elaborate the statement to finish off the task definition.
void elaborate(Design*des, NetScope*scope) const; void elaborate(Design*des, NetScope*scope) const;
bool is_auto() const { return is_auto_; };
void dump(ostream&, unsigned) const; void dump(ostream&, unsigned) const;
private: private:
svector<PWire*>*ports_; svector<PWire*>*ports_;
Statement*statement_; Statement*statement_;
bool is_auto_;
private: // Not implemented private: // Not implemented
PTask(const PTask&); PTask(const PTask&);
@ -90,7 +93,7 @@ class PTask : public PScope, public LineInfo {
class PFunction : public PScope, public LineInfo { class PFunction : public PScope, public LineInfo {
public: public:
explicit PFunction(perm_string name, PScope*parent); explicit PFunction(perm_string name, PScope*parent, bool is_auto);
~PFunction(); ~PFunction();
void set_ports(svector<PWire *>*p); void set_ports(svector<PWire *>*p);
@ -105,12 +108,15 @@ class PFunction : public PScope, public LineInfo {
/* Elaborate the behavioral statement. */ /* Elaborate the behavioral statement. */
void elaborate(Design *des, NetScope*) const; void elaborate(Design *des, NetScope*) const;
bool is_auto() const { return is_auto_; };
void dump(ostream&, unsigned) const; void dump(ostream&, unsigned) const;
private: private:
PTaskFuncArg return_type_; PTaskFuncArg return_type_;
svector<PWire *> *ports_; svector<PWire *> *ports_;
Statement *statement_; Statement *statement_;
bool is_auto_;
}; };
#endif #endif

View File

@ -998,6 +998,7 @@ void NetScope::dump(ostream&o) const
o << " generate block"; o << " generate block";
break; break;
} }
if (is_auto()) o << " (automatic)";
o << endl; o << endl;
for (unsigned idx = 0 ; idx < attr_cnt() ; idx += 1) for (unsigned idx = 0 ; idx < attr_cnt() ; idx += 1)

View File

@ -653,7 +653,7 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope, int expr_w
delete tmp; 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); NetEConst*sub = new NetEConst(val);
sub->set_line(*this); 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. // Recalculate the constant address with the adjusted base.
unsigned use_addr = net->array_index_to_address(addr); unsigned use_addr = net->array_index_to_address(addr);
if (addr < 0 || use_addr != (unsigned long)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); NetEConst*tmp = new NetEConst(val);
tmp->set_line(*this); tmp->set_line(*this);
delete word_index; delete word_index;

View File

@ -25,6 +25,7 @@
# include "netmisc.h" # include "netmisc.h"
# include <cstdlib> # include <cstdlib>
# include <cstring>
# include <iostream> # include <iostream>
# include "ivl_assert.h" # include "ivl_assert.h"
@ -267,3 +268,40 @@ NetExpr*PEUnary::elaborate_pexpr (Design*des, NetScope*scope) const
return tmp; 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;
}

View File

@ -150,6 +150,7 @@ static void elaborate_scope_tasks(Design*des, NetScope*scope,
} }
NetScope*task_scope = new NetScope(scope, use_name, NetScope*task_scope = new NetScope(scope, use_name,
NetScope::TASK); NetScope::TASK);
task_scope->is_auto((*cur).second->is_auto());
task_scope->set_line((*cur).second); task_scope->set_line((*cur).second);
if (debug_scopes) 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_scope = new NetScope(scope, use_name,
NetScope::FUNC); NetScope::FUNC);
func_scope->is_auto((*cur).second->is_auto());
func_scope->set_line((*cur).second); func_scope->set_line((*cur).second);
if (debug_scopes) if (debug_scopes)

View File

@ -2532,8 +2532,8 @@ NetProc* PEventStatement::elaborate_st(Design*des, NetScope*scope,
} }
NexusSet*nset = enet->nex_input(rem_out); NexusSet*nset = enet->nex_input(rem_out);
if (nset == 0) { if (nset == 0) {
cerr << get_fileline() << ": internal error: No NexusSet" cerr << get_fileline() << ": error: Unable to elaborate:"
<< " from statement." << endl; << endl;
enet->dump(cerr, 6); enet->dump(cerr, 6);
des->errors += 1; des->errors += 1;
return enet; return enet;

View File

@ -22,6 +22,8 @@
# include <iostream> # include <iostream>
# include <cstdlib> # include <cstdlib>
# include <cstring>
# include <math.h>
# include "netlist.h" # include "netlist.h"
# include "ivl_assert.h" # include "ivl_assert.h"
@ -1620,3 +1622,67 @@ NetEConst* NetEUReduce::eval_tree(int prune_to_width)
return new NetEConst(verinum(res, 1)); 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;
}

View File

@ -143,6 +143,7 @@ ivl_scope_def_lineno
ivl_scope_event ivl_scope_event
ivl_scope_events ivl_scope_events
ivl_scope_file ivl_scope_file
ivl_scope_is_auto
ivl_scope_lineno ivl_scope_lineno
ivl_scope_logs ivl_scope_logs
ivl_scope_log ivl_scope_log

View File

@ -1447,6 +1447,9 @@ extern unsigned ivl_parameter_lineno(ivl_parameter_t net);
* ivl_scope_lineno * ivl_scope_lineno
* Returns the instantiation file and line for this scope. * 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_var
* ivl_scope_vars * ivl_scope_vars
* REMOVED * 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 unsigned ivl_scope_events(ivl_scope_t net);
extern ivl_event_t ivl_scope_event(ivl_scope_t net, unsigned idx); extern ivl_event_t ivl_scope_event(ivl_scope_t net, unsigned idx);
extern const char* ivl_scope_file(ivl_scope_t net); 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_lineno(ivl_scope_t net);
extern unsigned ivl_scope_logs(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); extern ivl_net_logic_t ivl_scope_log(ivl_scope_t net, unsigned idx);

View File

@ -25,6 +25,7 @@ assign, GN_KEYWORDS_1364_1995, K_assign
atan, GN_KEYWORDS_VAMS_2_3, K_atan atan, GN_KEYWORDS_VAMS_2_3, K_atan
atan2, GN_KEYWORDS_VAMS_2_3, K_atan2 atan2, GN_KEYWORDS_VAMS_2_3, K_atan2
atanh, GN_KEYWORDS_VAMS_2_3, K_atanh atanh, GN_KEYWORDS_VAMS_2_3, K_atanh
automatic, GN_KEYWORDS_1364_2001, K_automatic
begin, GN_KEYWORDS_1364_1995, K_begin begin, GN_KEYWORDS_1364_1995, K_begin
bool, GN_KEYWORDS_ICARUS, K_bool bool, GN_KEYWORDS_ICARUS, K_bool
buf, GN_KEYWORDS_1364_1995, K_buf buf, GN_KEYWORDS_1364_1995, K_buf

View File

@ -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 * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * 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) NexusSet* NetEConcat::nex_input(bool rem_out)
{ {
if (parms_[0] == NULL) return NULL;
NexusSet*result = parms_[0]->nex_input(rem_out); NexusSet*result = parms_[0]->nex_input(rem_out);
for (unsigned idx = 1 ; idx < parms_.count() ; idx += 1) { 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); NexusSet*tmp = parms_[idx]->nex_input(rem_out);
result->add(*tmp); result->add(*tmp);
delete 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*result = base_? base_->nex_input(rem_out) : new NexusSet();
NexusSet*tmp = expr_->nex_input(rem_out); NexusSet*tmp = expr_->nex_input(rem_out);
if (tmp == NULL) {
delete result;
return NULL;
}
result->add(*tmp); result->add(*tmp);
delete tmp; delete tmp;
return result; return result;
@ -381,4 +390,3 @@ NexusSet* NetWhile::nex_input(bool rem_out)
delete tmp; delete tmp;
return result; return result;
} }

View File

@ -41,6 +41,7 @@ NetScope::NetScope(NetScope*up, const hname_t&n, NetScope::TYPE t)
signals_ = 0; signals_ = 0;
events_ = 0; events_ = 0;
lcounter_ = 0; lcounter_ = 0;
is_auto_ = false;
if (up) { if (up) {
default_nettype_ = up->default_nettype(); default_nettype_ = up->default_nettype();
@ -261,6 +262,7 @@ NetFuncDef* NetScope::func_def()
assert( type_ == FUNC ); assert( type_ == FUNC );
return func_; return func_;
} }
bool NetScope::in_func() bool NetScope::in_func()
{ {
return (type_ == FUNC) ? true : false; return (type_ == FUNC) ? true : false;

View File

@ -697,6 +697,9 @@ class NetScope : public Attrib {
unsigned get_def_lineno() const { return def_lineno_; }; unsigned get_def_lineno() const { return def_lineno_; };
bool in_func(); 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 NetTaskDef* task_def() const;
const NetFuncDef* func_def() const; const NetFuncDef* func_def() const;
@ -840,6 +843,7 @@ class NetScope : public Attrib {
NetScope*sub_; NetScope*sub_;
unsigned lcounter_; unsigned lcounter_;
bool is_auto_;
}; };
/* /*
@ -3455,6 +3459,8 @@ class NetESFunc : public NetExpr {
NetExpr* parm(unsigned idx); NetExpr* parm(unsigned idx);
const NetExpr* parm(unsigned idx) const; const NetExpr* parm(unsigned idx) const;
virtual NetExpr* eval_tree(int prune_to_width = -1);
virtual ivl_variable_type_t expr_type() const; virtual ivl_variable_type_t expr_type() const;
virtual NexusSet* nex_input(bool rem_out = true); virtual NexusSet* nex_input(bool rem_out = true);
virtual bool set_width(unsigned, bool last_chance); virtual bool set_width(unsigned, bool last_chance);

61
parse.y
View File

@ -205,7 +205,7 @@ static PECallFunction*make_call_function(perm_string tn, PExpr*arg1, PExpr*arg2)
%token K_PSTAR K_STARP %token K_PSTAR K_STARP
%token K_LOR K_LAND K_NAND K_NOR K_NXOR K_TRIGGER %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_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_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_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 %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 <flag> from_exclude
%type <number> number %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 <drive> drive_strength drive_strength_opt dr_strength0 dr_strength1
%type <letter> udp_input_sym udp_output_sym %type <letter> udp_input_sym udp_output_sym
%type <text> udp_input_list udp_sequ_entry udp_comb_entry %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 statements in the task body. But we continue to accept it as an
extension. */ extension. */
| K_task IDENTIFIER ';' | K_task automatic_opt IDENTIFIER ';'
{ assert(current_task == 0); { assert(current_task == 0);
current_task = pform_push_task_scope($2); current_task = pform_push_task_scope($3, $2);
FILE_NAME(current_task, @1); FILE_NAME(current_task, @1);
} }
task_item_list_opt task_item_list_opt
statement_or_null statement_or_null
K_endtask K_endtask
{ current_task->set_ports($5); { current_task->set_ports($6);
current_task->set_statement($6); current_task->set_statement($7);
pform_pop_scope(); pform_pop_scope();
current_task = 0; current_task = 0;
delete[]$2; delete[]$3;
} }
| K_task IDENTIFIER | K_task automatic_opt IDENTIFIER
{ assert(current_task == 0); { assert(current_task == 0);
current_task = pform_push_task_scope($2); current_task = pform_push_task_scope($3, $2);
FILE_NAME(current_task, @1); FILE_NAME(current_task, @1);
} }
'(' task_port_decl_list ')' ';' '(' task_port_decl_list ')' ';'
block_item_decls_opt block_item_decls_opt
statement_or_null statement_or_null
K_endtask K_endtask
{ current_task->set_ports($5); { current_task->set_ports($6);
current_task->set_statement($9); current_task->set_statement($10);
pform_pop_scope(); pform_pop_scope();
current_task = 0; current_task = 0;
delete[]$2; delete[]$3;
} }
| K_task IDENTIFIER error K_endtask | K_task automatic_opt IDENTIFIER error K_endtask
{ {
pform_pop_scope(); pform_pop_scope();
current_task = 0; current_task = 0;
delete[]$2; delete[]$3;
} }
/* The function declaration rule matches the function declaration /* 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 definitions in the func_body to take on the scope of the function
instead of the module. */ 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); { assert(current_function == 0);
current_function = pform_push_function_scope($3); current_function = pform_push_function_scope($4, $2);
FILE_NAME(current_function, @1); FILE_NAME(current_function, @1);
} }
function_item_list statement function_item_list statement
K_endfunction K_endfunction
{ current_function->set_ports($6); { current_function->set_ports($7);
current_function->set_statement($7); current_function->set_statement($8);
current_function->set_return($2); current_function->set_return($3);
pform_pop_scope(); pform_pop_scope();
current_function = 0; 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); { assert(current_function == 0);
current_function = pform_push_function_scope($3); current_function = pform_push_function_scope($4, $2);
FILE_NAME(current_function, @1); FILE_NAME(current_function, @1);
} }
'(' task_port_decl_list ')' ';' '(' task_port_decl_list ')' ';'
block_item_decls_opt block_item_decls_opt
statement statement
K_endfunction K_endfunction
{ current_function->set_ports($6); { current_function->set_ports($7);
current_function->set_statement($10); current_function->set_statement($11);
current_function->set_return($2); current_function->set_return($3);
pform_pop_scope(); pform_pop_scope();
current_function = 0; 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(); pform_pop_scope();
current_task = 0; current_task = 0;
delete[]$3; delete[]$4;
} }
/* A generate region can contain further module items. Actually, it /* A generate region can contain further module items. Actually, it
@ -2278,6 +2278,11 @@ module_item
{ yyerror(@1, "error: Malformed $attribute parameter list."); } { 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_if : K_if '(' expression ')' { pform_start_generate_if(@1, $3); }
generate_case_items generate_case_items

View File

@ -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); perm_string task_name = lex_strings.make(name);
PTask*task; PTask*task;
if (pform_cur_generate) { 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->tasks[task->pscope_name()] = task;
pform_cur_generate->lexical_scope = task; pform_cur_generate->lexical_scope = task;
} else { } 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; pform_cur_module->tasks[task->pscope_name()] = task;
lexical_scope = task; lexical_scope = task;
} }
@ -121,17 +122,18 @@ PTask* pform_push_task_scope(char*name)
return task; 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); perm_string func_name = lex_strings.make(name);
PFunction*func; PFunction*func;
if (pform_cur_generate) { 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->funcs[func->pscope_name()] = func;
pform_cur_generate->lexical_scope = func; pform_cur_generate->lexical_scope = func;
} else { } 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; pform_cur_module->funcs[func->pscope_name()] = func;
lexical_scope = func; lexical_scope = func;
} }

View File

@ -175,8 +175,8 @@ extern void pform_make_udp(perm_string name,
*/ */
extern void pform_pop_scope(); extern void pform_pop_scope();
extern PTask*pform_push_task_scope(char*name); extern PTask*pform_push_task_scope(char*name, bool is_auto);
extern PFunction*pform_push_function_scope(char*name); extern PFunction*pform_push_function_scope(char*name, bool is_auto);
extern PBlock*pform_push_block_scope(char*name, PBlock::BL_TYPE tt); extern PBlock*pform_push_block_scope(char*name, PBlock::BL_TYPE tt);

View File

@ -715,6 +715,7 @@ void PForStatement::dump(ostream&out, unsigned ind) const
void PFunction::dump(ostream&out, unsigned ind) const void PFunction::dump(ostream&out, unsigned ind) const
{ {
out << setw(ind) << "" << "function "; out << setw(ind) << "" << "function ";
if (is_auto_) cout << "automatic ";
switch (return_type_.type) { switch (return_type_.type) {
case PTF_NONE: case PTF_NONE:
out << "?none? "; out << "?none? ";
@ -775,6 +776,9 @@ void PRepeat::dump(ostream&out, unsigned ind) const
void PTask::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_) if (ports_)
for (unsigned idx = 0 ; idx < ports_->count() ; idx += 1) { for (unsigned idx = 0 ; idx < ports_->count() ; idx += 1) {
out << setw(ind) << ""; out << setw(ind) << "";

View File

@ -1547,6 +1547,12 @@ extern "C" const char*ivl_scope_file(ivl_scope_t net)
return net->file.str(); 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) extern "C" unsigned ivl_scope_lineno(ivl_scope_t net)
{ {
assert(net); assert(net);

View File

@ -575,6 +575,7 @@ void dll_target::add_root(ivl_design_s &des_, const NetScope *s)
root_->time_units = s->time_unit(); root_->time_units = s->time_unit();
root_->nattr = s->attr_cnt(); root_->nattr = s->attr_cnt();
root_->attr = fill_in_attributes(s); root_->attr = fill_in_attributes(s);
root_->is_auto = 0;
des_.nroots_++; des_.nroots_++;
if (des_.roots_) if (des_.roots_)
@ -2319,7 +2320,8 @@ void dll_target::scope(const NetScope*net)
scope->time_precision = net->time_precision(); scope->time_precision = net->time_precision();
scope->time_units = net->time_unit(); scope->time_units = net->time_unit();
scope->nattr = net->attr_cnt(); 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()) { switch (net->type()) {
case NetScope::MODULE: case NetScope::MODULE:

View File

@ -590,6 +590,7 @@ struct ivl_scope_s {
/* Scopes that are tasks/functions have a definition. */ /* Scopes that are tasks/functions have a definition. */
ivl_statement_t def; ivl_statement_t def;
unsigned is_auto;
unsigned ports; unsigned ports;
ivl_signal_t*port; ivl_signal_t*port;

View File

@ -1448,12 +1448,13 @@ static int show_scope(ivl_scope_t net, void*x)
ivl_scope_name(net), ivl_scope_params(net), ivl_scope_name(net), ivl_scope_params(net),
ivl_scope_sigs(net), ivl_scope_logs(net)); ivl_scope_sigs(net), ivl_scope_logs(net));
char *is_auto = ivl_scope_is_auto(net) ? "automatic " : "";
switch (ivl_scope_type(net)) { switch (ivl_scope_type(net)) {
case IVL_SCT_MODULE: case IVL_SCT_MODULE:
fprintf(out, " module %s", ivl_scope_tname(net)); fprintf(out, " module %s", ivl_scope_tname(net));
break; break;
case IVL_SCT_FUNCTION: case IVL_SCT_FUNCTION:
fprintf(out, " function %s", ivl_scope_tname(net)); fprintf(out, " function %s%s", is_auto, ivl_scope_tname(net));
break; break;
case IVL_SCT_BEGIN: case IVL_SCT_BEGIN:
fprintf(out, " begin : %s", ivl_scope_tname(net)); 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)); fprintf(out, " fork : %s", ivl_scope_tname(net));
break; break;
case IVL_SCT_TASK: case IVL_SCT_TASK:
fprintf(out, " task %s", ivl_scope_tname(net)); fprintf(out, " task %s%s", is_auto, ivl_scope_tname(net));
break; break;
default: default:
fprintf(out, " type(%u) %s", ivl_scope_type(net), fprintf(out, " type(%u) %s", ivl_scope_type(net),

View File

@ -1769,6 +1769,13 @@ int draw_scope(ivl_scope_t net, ivl_scope_t parent)
{ {
unsigned idx; unsigned idx;
const char *type; 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)) { switch (ivl_scope_type(net)) {
case IVL_SCT_MODULE: type = "module"; break; case IVL_SCT_MODULE: type = "module"; break;
case IVL_SCT_FUNCTION: type = "function"; break; case IVL_SCT_FUNCTION: type = "function"; break;

View File

@ -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) verinum::verinum(const verinum&that)
{ {
string_flag_ = that.string_flag_; string_flag_ = that.string_flag_;
@ -336,14 +442,9 @@ double verinum::as_double() const
{ {
if (nbits_ == 0) return 0.0; 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; double val = 0.0;
if (signed_flag) { /* Do we have/want a signed value? */
if (has_sign_ && bits_[nbits_-1] == V1) {
V carry = V1; V carry = V1;
for (unsigned idx = 0; idx < nbits_; idx += 1) { for (unsigned idx = 0; idx < nbits_; idx += 1) {
V sum = add_with_carry(~bits_[idx], V0, carry); 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 += pow(2.0, (double)idx);
} }
val *= -1.0; val *= -1.0;
// val = (double) as_long();
} else { } else {
for (unsigned idx = 0; idx < nbits_; idx += 1) { for (unsigned idx = 0; idx < nbits_; idx += 1) {
if (bits_[idx] == V1) if (bits_[idx] == V1)

View File

@ -46,6 +46,7 @@ class verinum {
verinum(const V*v, unsigned nbits, bool has_len =true); verinum(const V*v, unsigned nbits, bool has_len =true);
verinum(V, unsigned nbits =1, bool has_len =true); verinum(V, unsigned nbits =1, bool has_len =true);
verinum(uint64_t val, unsigned bits); verinum(uint64_t val, unsigned bits);
verinum(double val, bool dummy);
verinum(const verinum&); verinum(const verinum&);
// Create a signed number, with an unspecified number of bits. // Create a signed number, with an unspecified number of bits.
@ -93,6 +94,8 @@ class verinum {
signed long as_long() const; signed long as_long() const;
double as_double() const; double as_double() const;
string as_string() const; string as_string() const;
private:
void signed_trim();
private: private:
V* bits_; V* bits_;

View File

@ -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_readmem.o sys_readmem_lex.o sys_scanf.o sys_sdf.o \
sys_time.o sys_vcd.o sys_vcdoff.o vcd_priv.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 \ 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_LIBZ@,yes)
ifeq (@HAVE_LIBBZ2@,yes) ifeq (@HAVE_LIBBZ2@,yes)

109
vpi/sys_clog2.c Normal file
View File

@ -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);
}

View File

@ -38,6 +38,7 @@ extern void sys_time_register();
extern void sys_vcd_register(); extern void sys_vcd_register();
extern void sys_vcdoff_register(); extern void sys_vcdoff_register();
extern void sys_special_register(); extern void sys_special_register();
extern void sys_clog2_register();
extern void vams_simparam_register(); extern void vams_simparam_register();
#ifdef HAVE_LIBZ #ifdef HAVE_LIBZ
@ -181,6 +182,7 @@ void (*vlog_startup_routines[])() = {
sys_lxt_or_vcd_register, sys_lxt_or_vcd_register,
sys_sdf_register, sys_sdf_register,
sys_special_register, sys_special_register,
sys_clog2_register,
vams_simparam_register, vams_simparam_register,
0 0
}; };

View File

@ -14,6 +14,7 @@ $dist_poisson vpiSysFuncInt
$dist_chi_square vpiSysFuncInt $dist_chi_square vpiSysFuncInt
$dist_t vpiSysFuncInt $dist_t vpiSysFuncInt
$dist_erlang vpiSysFuncInt $dist_erlang vpiSysFuncInt
$clog2 vpiSysFuncInt
$simparam vpiSysFuncReal $simparam vpiSysFuncReal
$simparam$str vpiSysFuncSized 1024 unsigned $simparam$str vpiSysFuncSized 1024 unsigned

View File

@ -566,6 +566,7 @@ extern DLLEXPORT void (*vlog_startup_routines[])();
buffer. The value must be a vpiStrengthVal. */ buffer. The value must be a vpiStrengthVal. */
extern void vpip_format_strength(char*str, s_vpi_value*value, unsigned bit); extern void vpip_format_strength(char*str, s_vpi_value*value, unsigned bit);
extern void vpip_set_return_value(int value); extern void vpip_set_return_value(int value);
extern s_vpi_vecval vpip_calc_clog2(vpiHandle arg);
EXTERN_C_END EXTERN_C_END

View File

@ -127,6 +127,12 @@ static struct __vpiCallback* make_value_change(p_cb_data data)
obj->cb_time.type = vpiSuppressTime; obj->cb_time.type = vpiSuppressTime;
} }
obj->cb_data.time = &obj->cb_time; 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);
assert(data->obj->vpi_type); assert(data->obj->vpi_type);
@ -457,8 +463,25 @@ void callback_execute(struct __vpiCallback*cur)
vpi_mode_flag = VPI_MODE_RWSYNC; vpi_mode_flag = VPI_MODE_RWSYNC;
assert(cur->cb_data.cb_rtn); assert(cur->cb_data.cb_rtn);
cur->cb_data.time->type = vpiSimTime; switch (cur->cb_data.time->type) {
vpip_time_to_timestruct(cur->cb_data.time, schedule_simtime()); 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); (cur->cb_data.cb_rtn)(&cur->cb_data);
vpi_mode_flag = save_mode; vpi_mode_flag = save_mode;
@ -546,10 +569,32 @@ void vvp_fun_signal::get_value(struct t_vpi_value*vp)
{ {
switch (vp->format) { switch (vp->format) {
case vpiScalarVal: 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); vp->value.scalar = value(0);
break; 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: case vpiSuppressVal:
break; break;
default: default:
fprintf(stderr, "vpi_callback: value " fprintf(stderr, "vpi_callback: value "
"format %d not supported (fun_signal)\n", "format %d not supported (fun_signal)\n",
@ -622,6 +667,9 @@ void vvp_fun_signal_real::get_value(struct t_vpi_value*vp)
break; break;
} }
case vpiSuppressVal:
break;
default: default:
fprintf(stderr, "vpi_callback: value " fprintf(stderr, "vpi_callback: value "
"format %d not supported (fun_signal_real)\n", "format %d not supported (fun_signal_real)\n",

View File

@ -456,6 +456,13 @@ void vpip_vec4_get_value(const vvp_vector4_t&word_val, unsigned width,
vp->format); vp->format);
assert(0 && "format not implemented"); assert(0 && "format not implemented");
case vpiObjTypeVal:
vp->format = vpiVectorVal;
break;
case vpiSuppressVal:
break;
case vpiBinStrVal: case vpiBinStrVal:
rbuf = need_result_buf(width+1, RBUF_VAL); rbuf = need_result_buf(width+1, RBUF_VAL);
for (unsigned idx = 0 ; idx < width ; idx += 1) { 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; break;
case BIT4_X: case BIT4_X:
vp->value.scalar = vpiX; vp->value.scalar = vpiX;
break;
case BIT4_Z: case BIT4_Z:
vp->value.scalar = vpiZ; vp->value.scalar = vpiZ;
break; break;
@ -1029,3 +1037,63 @@ extern "C" void vpi_control(PLI_INT32 operation, ...)
vpi_sim_vcontrol(operation, ap); vpi_sim_vcontrol(operation, ap);
va_end(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;
}

View File

@ -137,6 +137,7 @@ struct __vpiCallback {
// user supplied callback data // user supplied callback data
struct t_cb_data cb_data; struct t_cb_data cb_data;
struct t_vpi_time cb_time; struct t_vpi_time cb_time;
struct t_vpi_value cb_value;
// scheduled event // scheduled event
struct sync_cb* cb_sync; struct sync_cb* cb_sync;

View File

@ -728,23 +728,6 @@ static vvp_vector4_t from_stringval(const char*str, unsigned wid)
return val; 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) static vpiHandle signal_put_value(vpiHandle ref, s_vpi_value*vp, int flags)
{ {
unsigned wid; unsigned wid;

View File

@ -2071,7 +2071,14 @@ bool of_FORK(vthread_t thr, vvp_code_t cp)
thr->fork_count += 1; 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; return true;
} }

View File

@ -37,3 +37,4 @@ vpi_vprintf
vpip_format_strength vpip_format_strength
vpip_set_return_value vpip_set_return_value
vpip_calc_clog2

View File

@ -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) vvp_bit4_t operator ^ (vvp_bit4_t a, vvp_bit4_t b)
{ {
if (bit4_is_xz(a)) if (bit4_is_xz(a))
@ -372,19 +389,12 @@ vvp_vector4_t::vvp_vector4_t(unsigned size, double val)
double fraction; double fraction;
int exponent; int exponent;
/* We return 'bx for a NaN. */ /* We return 'bx for a NaN or +/- infinity. */
if (val != val) { if (val != val || (val && (val == 0.5*val))) {
allocate_words_(size, WORD_X_ABITS, WORD_X_BBITS); allocate_words_(size, WORD_X_ABITS, WORD_X_BBITS);
return; 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. */ /* Convert to a positive result. */
if (val < 0.0) { if (val < 0.0) {
is_neg = true; is_neg = true;
@ -1618,6 +1628,15 @@ void vvp_vector2_t::trim()
while (value(wid_-1) == 0 && wid_ > 1) wid_ -= 1; 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 int vvp_vector2_t::value(unsigned idx) const
{ {
if (idx >= wid_) if (idx >= wid_)

View File

@ -20,6 +20,7 @@
*/ */
# include "config.h" # include "config.h"
# include "vpi_user.h"
# include <stddef.h> # include <stddef.h>
# include <string.h> # include <string.h>
# include <new> # 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 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 /* Return TRUE if the bit is BIT4_X or BIT4_Z. The fast
implementation here relies on the encoding of vvp_bit4_t values. */ implementation here relies on the encoding of vvp_bit4_t values. */
inline bool bit4_is_xz(vvp_bit4_t a) { return a >= 2; } 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); void set_bit(unsigned idx, int bit);
// Make the size just big enough to hold the first 1 bit. // Make the size just big enough to hold the first 1 bit.
void trim(); void trim();
// Trim off extra 1 bit since this is representing a negative value.
// Always keep at least 32 bits.
void trim_neg();
private: private:
enum { BITS_PER_WORD = 8 * sizeof(unsigned long) }; enum { BITS_PER_WORD = 8 * sizeof(unsigned long) };