Add support for string parameters

Parameters can have string type and do the usual string stuff,
and also implement some of the string methods on string parameters
so that they evaluate down to constants.
This commit is contained in:
Stephen Williams 2020-12-27 18:53:34 -08:00
parent 16646c547c
commit a286764c1d
8 changed files with 207 additions and 12 deletions

11
PExpr.h
View File

@ -935,11 +935,12 @@ class PECallFunction : public PExpr {
NetExpr*elaborate_expr_method_(Design*des, NetScope*scope,
unsigned expr_wid,
bool add_this_flag = false) const;
#if 0
NetExpr*elaborate_expr_string_method_(Design*des, NetScope*scope) const;
NetExpr*elaborate_expr_enum_method_(Design*des, NetScope*scope,
unsigned expr_wid) const;
#endif
NetExpr*elaborate_expr_method_net_(Design*des, NetScope*scope,
NetNet*net, unsigned expr_wid) const;
NetExpr*elaborate_expr_method_par_(Design*des, NetScope*scope,
const NetExpr *par, ivl_type_t par_type,
unsigned expr_wid) const;
NetExpr* elaborate_sfunc_(Design*des, NetScope*scope,
unsigned expr_wid,

View File

@ -31,6 +31,7 @@
# include "netclass.h"
# include "netdarray.h"
# include "netqueue.h"
# include "netscalar.h"
# include "netvector.h"
# include "ivl_assert.h"
# include "PExpr.h"
@ -238,6 +239,17 @@ ostream& netqueue_t::debug_dump(ostream&fd) const
return fd;
}
ostream& netreal_t::debug_dump(ostream&fd) const
{
fd << "real";
return fd;
}
ostream& netstring_t::debug_dump(ostream&fd) const
{
fd << "string";
return fd;
}
ostream& netvector_t::debug_dump(ostream&o) const
{
o << "netvector_t:" << type_ << (signed_? " signed" : " unsigned") << packed_dims_;

View File

@ -2640,6 +2640,15 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope,
use_path.push_front(name_component_t(perm_string::literal(THIS_TOKEN)));
}
if (debug_elaborate) {
cerr << get_fileline() << ": " << __func__ << ": "
<< "use_path: " << use_path << endl;
cerr << get_fileline() << ": " << __func__ << ": "
<< "method_name: " << method_name << endl;
cerr << get_fileline() << ": " << __func__ << ": "
<< "expr_wid: " << expr_wid << endl;
}
// If there is no object to the left of the method name, then
// give up on the idea of looking for an object method.
if (use_path.empty()) return 0;
@ -2651,8 +2660,38 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope,
symbol_search(this, des, scope, use_path, net, par, eve, par_type);
if (net == 0)
return 0;
if (debug_elaborate) {
if (net) {
cerr << get_fileline() << ": " << __func__ << ": "
<< "net: " << net->name() << endl;
}
if (par) {
cerr << get_fileline() << ": " << __func__ << ": "
<< "par: " << *par << endl;
}
if (par_type) {
cerr << get_fileline() << ": " << __func__ << ": "
<< "par_type: " << *par_type << endl;
}
}
// If we found a net with a method...
if (net)
return elaborate_expr_method_net_(des, scope, net, expr_wid);
// If we found a parameter with a method...
if (par)
return elaborate_expr_method_par_(des, scope, par, par_type, expr_wid);
return 0;
}
NetExpr* PECallFunction::elaborate_expr_method_net_(Design*des, NetScope*scope,
NetNet*net, unsigned expr_wid) const
{
pform_name_t use_path = path_;
perm_string method_name = peek_tail_name(use_path);
use_path.pop_back();
if (net->data_type() == IVL_VT_STRING) {
@ -2812,6 +2851,70 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope,
return 0;
}
NetExpr* PECallFunction::elaborate_expr_method_par_(Design*, NetScope*scope,
const NetExpr*par,
ivl_type_t par_type,
unsigned expr_wid) const
{
pform_name_t use_path = path_;
perm_string method_name = peek_tail_name(use_path);
use_path.pop_back();
// If the parameter is of type string, then look for the standard string
// method. Return an error if not found. Since we are assured that the
// expression is a constant string, it should be able to calculate the
// result at compile time.
if (dynamic_cast<const netstring_t*>(par_type)) {
const NetECString*par_string = dynamic_cast<const NetECString*>(par);
ivl_assert(*par, par_string);
string par_value = par_string->value().as_string();
if (method_name == "len") {
NetEConst*use_val = make_const_val(par_value.size());
use_val->set_line(*this);
return pad_to_width(use_val, expr_wid, *this);
}
if (method_name == "atoi") {
NetEConst*use_val = make_const_val(atoi(par_value.c_str()));
use_val->set_line(*this);
return pad_to_width(use_val, expr_wid, true, *this);
}
if (method_name == "atoreal") {
NetECReal*use_val = new NetECReal(verireal(par_value.c_str()));
use_val->set_line(*this);
return use_val;
}
if (method_name == "atohex") {
NetEConst*use_val = make_const_val(strtoul(par_value.c_str(),0,16));
use_val->set_line(*this);
return pad_to_width(use_val, expr_wid, true, *this);
}
// Returning 0 here will cause the caller to print an error
// message and increment the error count, so there is no need to
// increment des->error_count here.
cerr << get_fileline() << ": error: "
<< "Unknown or unsupport string method: " << method_name
<< endl;
return 0;
}
// If we haven't figured out what to do with this method by now,
// something went wrong.
cerr << get_fileline() << ": sorry: Don't know how to handle methods of parameters of type:" << endl;
cerr << get_fileline() << ": : " << *par_type << endl;
cerr << get_fileline() << ": : in scope " << scope_path(scope) << endl;
// Returning 0 here will cause the caller to print an error message and
// increment the error count, so there is no need to increment
// des->error_count here.
return 0;
}
unsigned PECastSize::test_width(Design*des, NetScope*scope, width_mode_t&)
{
ivl_assert(*this, size_);
@ -4821,6 +4924,13 @@ NetExpr* PEIdent::elaborate_expr_param_(Design*des,
{
bool need_const = NEED_CONST & flags;
if (debug_elaborate) {
cerr << get_fileline() << ": " << __func__ << ": "
<< "Parameter: " << path_ << endl;
cerr << get_fileline() << ": " << __func__ << ": "
<< "par_type: " << *par_type << endl;
}
if (need_const && !(ANNOTATABLE & flags)) {
perm_string name = peek_tail_name(path_);
if (found_in->make_parameter_unannotatable(name)) {
@ -6034,16 +6144,19 @@ unsigned PEString::test_width(Design*, NetScope*, width_mode_t&)
return expr_width_;
}
NetEConst* PEString::elaborate_expr(Design*, NetScope*, ivl_type_t, unsigned)const
NetEConst* PEString::elaborate_expr(Design*, NetScope*, ivl_type_t, unsigned) const
{
verinum val(value());
NetEConst*tmp = new NetEConst(val);
NetECString*tmp = new NetECString(value());
tmp->cast_signed(signed_flag_);
tmp->set_line(*this);
return tmp;
}
/*
* When the expression is being elaborated with a width, then we are trying to
* make a vector, so create a NetEConst with the basic types.
*/
NetEConst* PEString::elaborate_expr(Design*, NetScope*,
unsigned expr_wid, unsigned) const
{

View File

@ -789,6 +789,41 @@ void NetScope::evaluate_parameter_real_(Design*des, param_ref_t cur)
}
}
/*
* Evaluate a parameter that is forced to type string. This comes to pass when
* the input is something like this:
*
* parameter string foo = <expr>;
*
* The param_type should be netstring_t, the val_expr is the pform of the
* input <expr>, and we try to elaborate/evaluate down to a IVL_VT_STRING
* expression.
*/
void NetScope::evaluate_parameter_string_(Design*des, param_ref_t cur)
{
PExpr*val_expr = (*cur).second.val_expr;
NetScope*val_scope = (*cur).second.val_scope;
ivl_type_t param_type = cur->second.ivl_type;
ivl_assert(cur->second, val_expr);
ivl_assert(cur->second, param_type);
NetExpr*expr = elab_and_eval(des, val_scope, val_expr, param_type, true);
if (! expr)
return;
cur->second.val = expr;
if (debug_elaborate) {
cerr << cur->second.get_fileline() << ": " << __func__ << ": "
<< "Parameter type: " << *param_type << endl;
cerr << cur->second.get_fileline() << ": " << __func__ << ": "
<< "Parameter value: " << *val_expr << endl;
cerr << cur->second.get_fileline() << ": " << __func__ << ": "
<< "Elaborated value: " << *expr << endl;
}
}
void NetScope::evaluate_parameter_(Design*des, param_ref_t cur)
{
ivl_type_t param_type = cur->second.ivl_type;
@ -832,12 +867,19 @@ void NetScope::evaluate_parameter_(Design*des, param_ref_t cur)
evaluate_parameter_real_(des, cur);
break;
case IVL_VT_STRING:
evaluate_parameter_string_(des, cur);
break;
default:
cerr << cur->second.get_fileline() << ": internal error: "
<< "Unexpected expression type " << use_type
<< "Unexpected parameter type " << use_type
<< "." << endl;
cerr << cur->second.get_fileline() << ": : "
<< "Parameter name: " << cur->first << endl;
if (param_type)
cerr << cur->second.get_fileline() << ": : "
<< "Parameter ivl_type: " << *param_type << endl;
cerr << cur->second.get_fileline() << ": : "
<< "Expression is: " << *cur->second.val_expr << endl;
ivl_assert(cur->second, 0);

View File

@ -320,6 +320,19 @@ const NetScope* NetECRealParam::scope() const
return scope_;
}
NetECString::NetECString(const std::string& val)
: NetEConst(verinum(val))
{
}
NetECString::~NetECString()
{
}
ivl_variable_type_t NetECString::expr_type() const
{
return IVL_VT_STRING;
}
NetELast::NetELast(NetNet*s)
: sig_(s)

View File

@ -1252,6 +1252,7 @@ class NetScope : public Definitions, public Attrib {
private:
void evaluate_parameter_logic_(Design*des, param_ref_t cur);
void evaluate_parameter_real_(Design*des, param_ref_t cur);
void evaluate_parameter_string_(Design*des, param_ref_t cur);
void evaluate_parameter_(Design*des, param_ref_t cur);
private:
@ -2219,6 +2220,15 @@ class NetECReal : public NetExpr {
verireal value_;
};
class NetECString : public NetEConst {
public:
explicit NetECString(const std::string& val);
~NetECString();
// The type of a string is IVL_VT_STRING
ivl_variable_type_t expr_type() const;
};
class NetECRealParam : public NetECReal {
public:

View File

@ -1004,7 +1004,7 @@ NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe,
ivl_type_t lv_net_type, bool need_const)
{
if (debug_elaborate) {
cerr << pe->get_fileline() << ": elab_and_eval: "
cerr << pe->get_fileline() << ": " << __func__ << ": "
<< "pe=" << *pe
<< ", lv_net_type=" << *lv_net_type << endl;
}

View File

@ -29,6 +29,8 @@ class netreal_t : public ivl_type_s {
ivl_variable_type_t base_type() const;
std::ostream& debug_dump(std::ostream&) const;
public:
static netreal_t type_real;
static netreal_t type_shortreal;
@ -42,6 +44,8 @@ class netstring_t : public ivl_type_s {
ivl_variable_type_t base_type() const;
std::ostream& debug_dump(std::ostream&) const;
public:
static netstring_t type_string;
};