Merge pull request #805 from larsclausen/sv-type-params
Support type parameters
This commit is contained in:
commit
4ead552203
2
PScope.h
2
PScope.h
|
|
@ -113,6 +113,8 @@ class LexicalScope {
|
|||
bool local_flag;
|
||||
// Whether the parameter can be overridden
|
||||
bool overridable;
|
||||
// Whether the parameter is a type parameter
|
||||
bool type_flag = false;
|
||||
|
||||
SymbolType symbol_type() const;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -128,9 +128,7 @@ static void collect_parm_item(Design*des, NetScope*scope, perm_string name,
|
|||
// not yet known, don't try to guess here, put the type guess off. Also
|
||||
// don't try to elaborate it here, because there may be references to
|
||||
// other parameters still being located during scope elaboration.
|
||||
scope->set_parameter(name, is_annotatable, cur.expr, cur.data_type,
|
||||
cur.local_flag, cur.overridable, range_list, cur);
|
||||
|
||||
scope->set_parameter(name, is_annotatable, cur, range_list);
|
||||
}
|
||||
|
||||
static void collect_scope_parameters(Design*des, NetScope*scope,
|
||||
|
|
|
|||
13
elab_type.cc
13
elab_type.cc
|
|
@ -476,3 +476,16 @@ ivl_type_t typedef_t::elaborate_type(Design *des, NetScope *scope)
|
|||
|
||||
return elab_type;
|
||||
}
|
||||
|
||||
ivl_type_t type_parameter_t::elaborate_type_raw(Design *des, NetScope*scope) const
|
||||
{
|
||||
ivl_type_t type;
|
||||
|
||||
scope->get_parameter(des, name, type);
|
||||
|
||||
// Recover
|
||||
if (!type)
|
||||
return netvector_t::integer_type();
|
||||
|
||||
return type;
|
||||
}
|
||||
|
|
|
|||
1
ivl.def
1
ivl.def
|
|
@ -172,6 +172,7 @@ ivl_nexus_ptr_switch
|
|||
ivl_parameter_basename
|
||||
ivl_parameter_expr
|
||||
ivl_parameter_file
|
||||
ivl_parameter_is_type
|
||||
ivl_parameter_lineno
|
||||
ivl_parameter_local
|
||||
ivl_parameter_lsb
|
||||
|
|
|
|||
|
|
@ -1695,6 +1695,9 @@ extern ivl_signal_t ivl_nexus_ptr_sig(ivl_nexus_ptr_t net);
|
|||
* Return whether parameter was local (localparam, implicit genvar etc)
|
||||
* or not.
|
||||
*
|
||||
* ivl_parameter_is_type
|
||||
* Return whether the parameter is a type parameter or not.
|
||||
*
|
||||
* ivl_parameter_file
|
||||
* ivl_parameter_lineno
|
||||
* Returns the file and line where this parameter is defined
|
||||
|
|
@ -1707,6 +1710,7 @@ extern int ivl_parameter_lsb(ivl_parameter_t net);
|
|||
extern unsigned ivl_parameter_width(ivl_parameter_t net);
|
||||
extern int ivl_parameter_signed(ivl_parameter_t net);
|
||||
extern int ivl_parameter_local(ivl_parameter_t net);
|
||||
extern int ivl_parameter_is_type(ivl_parameter_t net);
|
||||
extern const char* ivl_parameter_file(ivl_parameter_t net);
|
||||
extern unsigned ivl_parameter_lineno(ivl_parameter_t net);
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
// Check that basic type parameter syntax is supported
|
||||
|
||||
bit failed = 1'b0;
|
||||
|
||||
`define check(expr, val) \
|
||||
if (expr != val) begin \
|
||||
$display("failed: %s, expected %0d, got %0d", `"expr`", val, expr); \
|
||||
failed = 1'b1; \
|
||||
end
|
||||
|
||||
module test #(
|
||||
parameter type T1 = integer
|
||||
);
|
||||
T1 x;
|
||||
|
||||
initial begin
|
||||
`check($bits(x), $bits(integer))
|
||||
`check($bits(T1), $bits(integer))
|
||||
|
||||
if (!failed) begin
|
||||
$display("PASSED");
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Check that it is possible to declare multiple type parameters as a list with
|
||||
// a single type keyword.
|
||||
|
||||
bit failed = 1'b0;
|
||||
|
||||
`define check(expr, val) \
|
||||
if (expr != val) begin \
|
||||
$display("failed: %s, expected %0d, got %0d", `"expr`", val, expr); \
|
||||
failed = 1'b1; \
|
||||
end
|
||||
|
||||
module test #(
|
||||
parameter type T1 = integer, T2 = real
|
||||
);
|
||||
T1 x;
|
||||
T2 y = 1.23;
|
||||
|
||||
initial begin
|
||||
`check($bits(x), $bits(integer))
|
||||
`check($bits(T1), $bits(integer))
|
||||
`check(y, 1.23)
|
||||
|
||||
if (!failed) begin
|
||||
$display("PASSED");
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
// Check that it is possible to declare type parameters when omitting the
|
||||
// parameter keyword.
|
||||
|
||||
bit failed = 1'b0;
|
||||
|
||||
`define check(expr, val) \
|
||||
if (expr != val) begin \
|
||||
$display("failed: %s, expected %0d, got %0d", `"expr`", val, expr); \
|
||||
failed = 1'b1; \
|
||||
end
|
||||
|
||||
module test #(
|
||||
type T1 = integer
|
||||
);
|
||||
T1 x;
|
||||
|
||||
initial begin
|
||||
`check($bits(x), $bits(integer))
|
||||
`check($bits(T1), $bits(integer))
|
||||
|
||||
if (!failed) begin
|
||||
$display("PASSED");
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
// Check that it is possible to reference other parameters in the default value
|
||||
// of a type parameter.
|
||||
|
||||
bit failed = 1'b0;
|
||||
|
||||
`define check(expr, val) \
|
||||
if (expr != val) begin \
|
||||
$display("failed: %s, expected %0d, got %0d", `"expr`", val, expr); \
|
||||
failed = 1'b1; \
|
||||
end
|
||||
|
||||
module test #(
|
||||
parameter A = 10,
|
||||
parameter type T1 = logic [A-1:0]
|
||||
);
|
||||
T1 x;
|
||||
|
||||
initial begin
|
||||
`check($bits(x), A)
|
||||
`check($bits(T1), A)
|
||||
|
||||
if (!failed) begin
|
||||
$display("PASSED");
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
// Check that it is possible to declare local type parameters.
|
||||
|
||||
bit failed = 1'b0;
|
||||
|
||||
`define check(expr, val) \
|
||||
if (expr != val) begin \
|
||||
$display("failed: %s, expected %0d, got %0d", `"expr`", val, expr); \
|
||||
failed = 1'b1; \
|
||||
end
|
||||
|
||||
module test;
|
||||
|
||||
parameter A = 10;
|
||||
localparam type T1 = logic [A-1:0];
|
||||
|
||||
T1 x;
|
||||
|
||||
initial begin
|
||||
`check($bits(x), A)
|
||||
`check($bits(T1), A)
|
||||
|
||||
if (!failed) begin
|
||||
$display("PASSED");
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
// Check that various syntax variations for type parameters without a default
|
||||
// value are supported.
|
||||
|
||||
bit failed = 1'b0;
|
||||
|
||||
`define check(expr, val) \
|
||||
if (expr != val) begin \
|
||||
$display("failed: %s, expected %0d, got %0d", `"expr`", val, expr); \
|
||||
failed = 1'b1; \
|
||||
end
|
||||
|
||||
module M1 #(
|
||||
parameter type T1
|
||||
);
|
||||
T1 x;
|
||||
|
||||
initial begin
|
||||
`check($bits(x), $bits(integer))
|
||||
`check($bits(T1), $bits(integer))
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
module M2 #(
|
||||
type T1
|
||||
);
|
||||
T1 x;
|
||||
|
||||
initial begin
|
||||
`check($bits(x), $bits(integer))
|
||||
`check($bits(T1), $bits(integer))
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
module M3 #(
|
||||
parameter type T1, T2
|
||||
);
|
||||
T1 x;
|
||||
T2 y = 1.23;
|
||||
|
||||
initial begin
|
||||
`check($bits(x), $bits(integer))
|
||||
`check($bits(T1), $bits(integer))
|
||||
`check(y, 1.23)
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
module M4 #(
|
||||
type T1, T2
|
||||
);
|
||||
T1 x;
|
||||
T2 y = 1.23;
|
||||
|
||||
initial begin
|
||||
`check($bits(x), $bits(integer))
|
||||
`check($bits(T1), $bits(integer))
|
||||
`check(y, 1.23)
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
module test;
|
||||
|
||||
M1 #(
|
||||
.T1 (integer)
|
||||
) i_m1 ();
|
||||
|
||||
M2 #(
|
||||
.T1 (integer)
|
||||
) i_m2 ();
|
||||
|
||||
M3 #(
|
||||
.T1 (integer),
|
||||
.T2 (real)
|
||||
) i_m3();
|
||||
|
||||
M4 #(
|
||||
.T1 (integer),
|
||||
.T2 (real)
|
||||
) i_m4 ();
|
||||
|
||||
initial begin
|
||||
#1
|
||||
if (!failed) begin
|
||||
$display("PASSED");
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
// Check that it is possible to overwrite type parameters and that the provided
|
||||
// type is evaluated in the scope instantiating the module.
|
||||
|
||||
bit failed = 1'b0;
|
||||
|
||||
`define check(expr, val) \
|
||||
if (expr != val) begin \
|
||||
$display("failed: %s, expected %0d, got %0d", `"expr`", val, expr); \
|
||||
failed = 1'b1; \
|
||||
end
|
||||
|
||||
module M #(
|
||||
parameter type T1 = integer,
|
||||
parameter WIDTH = 0
|
||||
);
|
||||
typedef logic [1:0] T2;
|
||||
localparam A = 2;
|
||||
T1 x;
|
||||
|
||||
initial begin
|
||||
`check($bits(x), WIDTH)
|
||||
`check($bits(T1), WIDTH)
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
module test;
|
||||
localparam A = 4;
|
||||
typedef logic [A-1:0] T2;
|
||||
|
||||
M #(
|
||||
.WIDTH ($bits(integer))
|
||||
) i_m1 ();
|
||||
|
||||
M #(
|
||||
.T1 (logic [15:0]),
|
||||
.WIDTH (16)
|
||||
) i_m2 ();
|
||||
|
||||
// `A` must be evauluated in this context
|
||||
M #(
|
||||
.T1 (logic [A-1:0]),
|
||||
.WIDTH (4)
|
||||
) i_m3 ();
|
||||
|
||||
// `T2` must be evauluated in this context
|
||||
M #(
|
||||
.T1 (T2),
|
||||
.WIDTH (4)
|
||||
) i_m4 ();
|
||||
|
||||
initial begin
|
||||
#1
|
||||
if (!failed) begin
|
||||
$display("PASSED");
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
// Check that overrideing a type parameter with an expression that is not a type
|
||||
// generates an error.
|
||||
|
||||
module M #(
|
||||
type T = int
|
||||
);
|
||||
|
||||
T x;
|
||||
|
||||
initial begin
|
||||
$display("FAILED");
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
module test;
|
||||
|
||||
M #(
|
||||
.T(10)
|
||||
) m();
|
||||
|
||||
endmodule
|
||||
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// Check that trying to override a type parameter using a defparam statement
|
||||
// generates an error.
|
||||
|
||||
module M #(
|
||||
type T = int
|
||||
);
|
||||
|
||||
T x;
|
||||
|
||||
initial begin
|
||||
$display("FAILED");
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
module test;
|
||||
|
||||
M m();
|
||||
defparam m.T = real; // Error, this is illegal
|
||||
|
||||
endmodule
|
||||
|
|
@ -716,6 +716,15 @@ sv_timeunit_prec_fail2 CE,-g2009,-u,\
|
|||
./ivltests/sv_timeunit_prec_fail2a.v,\
|
||||
./ivltests/sv_timeunit_prec_fail2b.v,\
|
||||
./ivltests/sv_timeunit_prec_fail2c.v, ivltests gold=sv_timeunit_prec_fail2.gold
|
||||
sv_type_param1 normal,-g2005-sv ivltests
|
||||
sv_type_param2 normal,-g2005-sv ivltests
|
||||
sv_type_param3 normal,-g2005-sv ivltests
|
||||
sv_type_param4 normal,-g2005-sv ivltests
|
||||
sv_type_param5 normal,-g2005-sv ivltests
|
||||
sv_type_param6 normal,-g2005-sv ivltests
|
||||
sv_type_param7 normal,-g2005-sv ivltests
|
||||
sv_type_param_fail1 CE,-g2005-sv ivltests
|
||||
sv_type_param_fail2 CE,-g2005-sv ivltests
|
||||
sv_typedef_array_base1 normal,-g2009 ivltests
|
||||
sv_typedef_array_base2 normal,-g2009 ivltests
|
||||
sv_typedef_array_base3 normal,-g2009 ivltests
|
||||
|
|
|
|||
|
|
@ -433,7 +433,7 @@ void NetScope::run_defparams(Design*des)
|
|||
continue;
|
||||
}
|
||||
|
||||
targ_scope->replace_parameter(des, perm_name, val, this);
|
||||
targ_scope->replace_parameter(des, perm_name, val, this, true);
|
||||
}
|
||||
|
||||
// If some of the defparams didn't find a scope in the name,
|
||||
|
|
@ -468,7 +468,7 @@ void NetScope::run_defparams_later(Design*des)
|
|||
continue;
|
||||
}
|
||||
|
||||
targ_scope->replace_parameter(des, name, val, this);
|
||||
targ_scope->replace_parameter(des, name, val, this, true);
|
||||
|
||||
// We'll need to re-evaluate parameters in this scope
|
||||
target_scopes.insert(targ_scope);
|
||||
|
|
@ -814,20 +814,31 @@ void NetScope::evaluate_parameter_string_(Design*des, param_ref_t cur)
|
|||
}
|
||||
}
|
||||
|
||||
void NetScope::evaluate_parameter_(Design*des, param_ref_t cur)
|
||||
void NetScope::evaluate_type_parameter_(Design *des, param_ref_t cur)
|
||||
{
|
||||
ivl_type_t param_type = cur->second.ivl_type;
|
||||
const PETypename *type_expr = dynamic_cast<const PETypename*>(cur->second.val_expr);
|
||||
if (!type_expr) {
|
||||
cerr << this->get_fileline() << ": error: "
|
||||
<< "Type parameter `" << cur->first << "` value `"
|
||||
<< *cur->second.val_expr << "` is not a type."
|
||||
<< endl;
|
||||
des->errors++;
|
||||
|
||||
// If the parameter type is present, then elaborate it now. Elaborate
|
||||
// the type in the current scope, and not the scope of the expression.
|
||||
if (cur->second.val_type) {
|
||||
param_type = cur->second.val_type->elaborate_type(des, this);
|
||||
cur->second.ivl_type = param_type;
|
||||
cur->second.val_type = 0;
|
||||
// Recover
|
||||
cur->second.ivl_type = netvector_t::integer_type();
|
||||
return;
|
||||
}
|
||||
|
||||
data_type_t *type = type_expr->get_type();
|
||||
NetScope *type_scope = cur->second.val_scope;
|
||||
cur->second.ivl_type = type->elaborate_type(des, type_scope);
|
||||
}
|
||||
|
||||
void NetScope::evaluate_parameter_(Design*des, param_ref_t cur)
|
||||
{
|
||||
|
||||
// If the parameter has already been evaluated, quietly return.
|
||||
if (cur->second.val != 0)
|
||||
if (cur->second.val || cur->second.ivl_type)
|
||||
return;
|
||||
|
||||
if (cur->second.val_expr == 0) {
|
||||
|
|
@ -840,6 +851,21 @@ void NetScope::evaluate_parameter_(Design*des, param_ref_t cur)
|
|||
return;
|
||||
}
|
||||
|
||||
if (cur->second.type_flag) {
|
||||
evaluate_type_parameter_(des, cur);
|
||||
return;
|
||||
}
|
||||
|
||||
ivl_type_t param_type = cur->second.ivl_type;
|
||||
|
||||
// If the parameter type is present, then elaborate it now. Elaborate
|
||||
// the type in the current scope, and not the scope of the expression.
|
||||
if (cur->second.val_type) {
|
||||
param_type = cur->second.val_type->elaborate_type(des, this);
|
||||
cur->second.ivl_type = param_type;
|
||||
cur->second.val_type = 0;
|
||||
}
|
||||
|
||||
// Guess the varaiable type of the parameter. If the parameter has no
|
||||
// given type, then guess the type from the expression and use that to
|
||||
// evaluate (this is currently handled in evaluate_parameter_logic_()).
|
||||
|
|
|
|||
32
net_scope.cc
32
net_scope.cc
|
|
@ -269,23 +269,22 @@ NetScope*NetScope::find_typedef_scope(const Design*des, const typedef_t*type)
|
|||
* member.
|
||||
*/
|
||||
void NetScope::set_parameter(perm_string key, bool is_annotatable,
|
||||
PExpr*val, data_type_t*val_type,
|
||||
bool local_flag, bool overridable,
|
||||
NetScope::range_t*range_list,
|
||||
const LineInfo&file_line)
|
||||
const LexicalScope::param_expr_t ¶m,
|
||||
NetScope::range_t *range_list)
|
||||
{
|
||||
param_expr_t&ref = parameters[key];
|
||||
ref.is_annotatable = is_annotatable;
|
||||
ref.val_expr = val;
|
||||
ref.val_type = val_type;
|
||||
ref.val_expr = param.expr;
|
||||
ref.val_type = param.data_type;
|
||||
ref.val_scope = this;
|
||||
ref.local_flag = local_flag;
|
||||
ref.overridable = overridable;
|
||||
ivl_assert(file_line, ref.range == 0);
|
||||
ref.local_flag = param.local_flag;
|
||||
ref.overridable = param.overridable;
|
||||
ref.type_flag = param.type_flag;
|
||||
ivl_assert(param, !ref.range);
|
||||
ref.range = range_list;
|
||||
ref.val = 0;
|
||||
ref.ivl_type = 0;
|
||||
ref.set_line(file_line);
|
||||
ref.set_line(param);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -348,7 +347,8 @@ bool NetScope::auto_name(const char*prefix, char pad, const char* suffix)
|
|||
* Return false if the parameter does not already exist.
|
||||
* A parameter is not automatically created.
|
||||
*/
|
||||
void NetScope::replace_parameter(Design *des, perm_string key, PExpr*val, NetScope*scope)
|
||||
void NetScope::replace_parameter(Design *des, perm_string key, PExpr*val,
|
||||
NetScope*scope, bool defparam)
|
||||
{
|
||||
if (parameters.find(key) == parameters.end()) {
|
||||
cerr << val->get_fileline() << ": error: parameter `"
|
||||
|
|
@ -376,6 +376,16 @@ void NetScope::replace_parameter(Design *des, perm_string key, PExpr*val, NetSco
|
|||
return;
|
||||
}
|
||||
|
||||
if (ref.type_flag && defparam) {
|
||||
cerr << val->get_fileline() << ": error: "
|
||||
<< "Cannot override type parameter `" << key << "` in `"
|
||||
<< scope_path(this) << "`. It is not allowed to override type"
|
||||
<< " parameters using a defparam statement."
|
||||
<< endl;
|
||||
des->errors++;
|
||||
return;
|
||||
}
|
||||
|
||||
ref.val_expr = val;
|
||||
ref.val_scope = scope;
|
||||
}
|
||||
|
|
|
|||
23
netlist.h
23
netlist.h
|
|
@ -44,6 +44,7 @@
|
|||
# include "HName.h"
|
||||
# include "LineInfo.h"
|
||||
# include "Attrib.h"
|
||||
# include "PScope.h"
|
||||
# include "PUdp.h"
|
||||
|
||||
#ifdef HAVE_IOSFWD
|
||||
|
|
@ -952,10 +953,8 @@ class NetScope : public Definitions, public Attrib {
|
|||
|
||||
struct range_t;
|
||||
void set_parameter(perm_string name, bool is_annotatable,
|
||||
PExpr*val, data_type_t*data_type,
|
||||
bool local_flag, bool overridable,
|
||||
NetScope::range_t*range_list,
|
||||
const LineInfo&file_line);
|
||||
const LexicalScope::param_expr_t ¶m,
|
||||
NetScope::range_t *range_list);
|
||||
void set_parameter(perm_string name, NetExpr*val,
|
||||
const LineInfo&file_line);
|
||||
|
||||
|
|
@ -968,7 +967,8 @@ class NetScope : public Definitions, public Attrib {
|
|||
expression with a new expression, without affecting the
|
||||
range or signed_flag. Return false if the name does not
|
||||
exist. */
|
||||
void replace_parameter(Design *des, perm_string name, PExpr*val, NetScope*scope);
|
||||
void replace_parameter(Design *des, perm_string name, PExpr*val,
|
||||
NetScope*scope, bool defparam = false);
|
||||
|
||||
/* This is used to ensure the value of a parameter cannot be
|
||||
changed at run-time. This is required if a specparam is used
|
||||
|
|
@ -1213,11 +1213,19 @@ class NetScope : public Definitions, public Attrib {
|
|||
// Is this a localparam?
|
||||
bool local_flag;
|
||||
// Can it be overriden?
|
||||
bool overridable;
|
||||
bool overridable = false;
|
||||
// Is it a type parameter
|
||||
bool type_flag = false;
|
||||
// range constraints
|
||||
struct range_t*range;
|
||||
// Expression value and type (elaborated versoins of val_expr/val_type)
|
||||
|
||||
// Expression value. Elaborated version of val_expr.
|
||||
// For type parameters this will always be 0.
|
||||
NetExpr*val;
|
||||
|
||||
// For non-type parameter this contains the elaborate type of the
|
||||
// parameter itself. For type parameters this contains the
|
||||
// elaborated assigned type value.
|
||||
ivl_type_t ivl_type;
|
||||
};
|
||||
std::map<perm_string,param_expr_t>parameters;
|
||||
|
|
@ -1240,6 +1248,7 @@ class NetScope : public Definitions, public Attrib {
|
|||
std::map<perm_string,LocalVar> loop_index_tmp;
|
||||
|
||||
private:
|
||||
void evaluate_type_parameter_(Design*des, param_ref_t cur);
|
||||
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);
|
||||
|
|
|
|||
22
parse.y
22
parse.y
|
|
@ -41,6 +41,7 @@ extern void lex_end_table();
|
|||
|
||||
static data_type_t* param_data_type = 0;
|
||||
static bool param_is_local = false;
|
||||
static bool param_is_type = false;
|
||||
static std::list<pform_range_t>* specparam_active_range = 0;
|
||||
|
||||
/* Port declaration lists use this structure for context. */
|
||||
|
|
@ -4748,6 +4749,10 @@ module_parameter_port_list_opt
|
|||
')'
|
||||
;
|
||||
|
||||
type_param
|
||||
: K_type { param_is_type = true; }
|
||||
;
|
||||
|
||||
module_parameter
|
||||
: parameter param_type parameter_assign
|
||||
| localparam param_type parameter_assign
|
||||
|
|
@ -4760,20 +4765,28 @@ module_parameter_port_list
|
|||
| data_type_opt
|
||||
{ param_data_type = $1;
|
||||
param_is_local = false;
|
||||
param_is_type = false;
|
||||
}
|
||||
parameter_assign
|
||||
{ pform_requires_sv(@3, "Omitting initial `parameter` in parameter port "
|
||||
"list");
|
||||
}
|
||||
| type_param
|
||||
{
|
||||
param_is_local = false;
|
||||
}
|
||||
parameter_assign
|
||||
| module_parameter_port_list ',' module_parameter
|
||||
| module_parameter_port_list ',' data_type_opt
|
||||
{ if ($3) {
|
||||
pform_requires_sv(@3, "Omitting `parameter`/`localparam` before "
|
||||
"data type in parameter port list");
|
||||
param_data_type = $3;
|
||||
param_is_type = false;
|
||||
}
|
||||
}
|
||||
parameter_assign
|
||||
| module_parameter_port_list ',' type_param parameter_assign
|
||||
;
|
||||
|
||||
module_item
|
||||
|
|
@ -5393,7 +5406,12 @@ net_type_or_var_opt
|
|||
This is used by parameter_assign, which is found to the right of
|
||||
the param_type in various rules. */
|
||||
|
||||
param_type : data_type_or_implicit { param_data_type = $1; }
|
||||
param_type
|
||||
: data_type_or_implicit
|
||||
{ param_is_type = false;
|
||||
param_data_type = $1;
|
||||
}
|
||||
| type_param
|
||||
|
||||
parameter : K_parameter { param_is_local = false; };
|
||||
localparam : K_localparam { param_is_local = true; };
|
||||
|
|
@ -5419,7 +5437,7 @@ parameter_assign_list
|
|||
parameter_assign
|
||||
: IDENTIFIER initializer_opt parameter_value_ranges_opt
|
||||
{ pform_set_parameter(@1, lex_strings.make($1), param_is_local,
|
||||
param_data_type, $2, $3);
|
||||
param_is_type, param_data_type, $2, $3);
|
||||
delete[]$1;
|
||||
}
|
||||
;
|
||||
|
|
|
|||
21
pform.cc
21
pform.cc
|
|
@ -2963,8 +2963,21 @@ LexicalScope::range_t* pform_parameter_value_range(bool exclude_flag,
|
|||
return tmp;
|
||||
}
|
||||
|
||||
static void pform_set_type_parameter(const struct vlltype&loc, perm_string name,
|
||||
LexicalScope::range_t*value_range)
|
||||
{
|
||||
pform_requires_sv(loc, "Type parameter");
|
||||
|
||||
if (value_range)
|
||||
VLerror(loc, "error: type parameter must not have value range.");
|
||||
|
||||
type_parameter_t *type = new type_parameter_t(name);
|
||||
pform_set_typedef(loc, name, type, 0);
|
||||
}
|
||||
|
||||
void pform_set_parameter(const struct vlltype&loc,
|
||||
perm_string name, bool is_local, data_type_t*data_type, PExpr*expr,
|
||||
perm_string name, bool is_local, bool is_type,
|
||||
data_type_t*data_type, PExpr*expr,
|
||||
LexicalScope::range_t*value_range)
|
||||
{
|
||||
LexicalScope*scope = lexical_scope;
|
||||
|
|
@ -3010,13 +3023,17 @@ void pform_set_parameter(const struct vlltype&loc,
|
|||
Module::param_expr_t*parm = new Module::param_expr_t();
|
||||
FILE_NAME(parm, loc);
|
||||
|
||||
add_local_symbol(scope, name, parm);
|
||||
if (is_type)
|
||||
pform_set_type_parameter(loc, name, value_range);
|
||||
else
|
||||
add_local_symbol(scope, name, parm);
|
||||
|
||||
parm->expr = expr;
|
||||
parm->data_type = data_type;
|
||||
parm->range = value_range;
|
||||
parm->local_flag = is_local;
|
||||
parm->overridable = overridable;
|
||||
parm->type_flag = is_type;
|
||||
|
||||
scope->parameters[name] = parm;
|
||||
|
||||
|
|
|
|||
2
pform.h
2
pform.h
|
|
@ -390,7 +390,7 @@ extern LexicalScope::range_t* pform_parameter_value_range(bool exclude_flag,
|
|||
|
||||
extern void pform_set_parameter(const struct vlltype&loc,
|
||||
perm_string name,
|
||||
bool is_local,
|
||||
bool is_local, bool is_type,
|
||||
data_type_t*data_type,
|
||||
PExpr*expr, LexicalScope::range_t*value_range);
|
||||
extern void pform_set_specparam(const struct vlltype&loc,
|
||||
|
|
|
|||
|
|
@ -212,6 +212,13 @@ private:
|
|||
typedef_t *type;
|
||||
};
|
||||
|
||||
struct type_parameter_t : data_type_t {
|
||||
explicit type_parameter_t(perm_string n) : name(n) { }
|
||||
ivl_type_t elaborate_type_raw(Design *des, NetScope *scope) const;
|
||||
|
||||
perm_string name;
|
||||
};
|
||||
|
||||
struct void_type_t : public data_type_t {
|
||||
virtual void pform_dump(std::ostream&out, unsigned indent) const;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1877,6 +1877,12 @@ extern "C" int ivl_parameter_local(ivl_parameter_t net)
|
|||
return net->local;
|
||||
}
|
||||
|
||||
extern "C" int ivl_parameter_is_type(ivl_parameter_t net)
|
||||
{
|
||||
assert(net);
|
||||
return net->is_type;
|
||||
}
|
||||
|
||||
extern "C" int ivl_parameter_signed(ivl_parameter_t net)
|
||||
{
|
||||
assert(net);
|
||||
|
|
|
|||
28
t-dll.cc
28
t-dll.cc
|
|
@ -509,10 +509,7 @@ void dll_target::make_scope_parameters(ivl_scope_t scop, const NetScope*net)
|
|||
cur_par->basename = cur_pit->first;
|
||||
cur_par->local = cur_pit->second.local_flag ||
|
||||
!cur_pit->second.overridable;
|
||||
calculate_param_range(cur_pit->second,
|
||||
cur_pit->second.ivl_type,
|
||||
cur_par->msb, cur_par->lsb,
|
||||
cur_pit->second.val->expr_width());
|
||||
cur_par->is_type = cur_pit->second.type_flag;
|
||||
|
||||
if (cur_pit->second.ivl_type == 0) {
|
||||
cerr << "?:?: internal error: "
|
||||
|
|
@ -525,14 +522,23 @@ void dll_target::make_scope_parameters(ivl_scope_t scop, const NetScope*net)
|
|||
cur_par->scope = scop;
|
||||
FILE_NAME(cur_par, &(cur_pit->second));
|
||||
|
||||
NetExpr*etmp = cur_pit->second.val;
|
||||
if (etmp == 0) {
|
||||
cerr << "?:?: internal error: What is the parameter "
|
||||
<< "expression for " << cur_pit->first
|
||||
<< " in " << net->fullname() << "?" << endl;
|
||||
// Type parameters don't have a range or expression
|
||||
if (!cur_pit->second.type_flag) {
|
||||
calculate_param_range(cur_pit->second,
|
||||
cur_pit->second.ivl_type,
|
||||
cur_par->msb, cur_par->lsb,
|
||||
cur_pit->second.val->expr_width());
|
||||
|
||||
NetExpr*etmp = cur_pit->second.val;
|
||||
if (etmp == 0) {
|
||||
cerr << "?:?: internal error: What is the parameter "
|
||||
<< "expression for " << cur_pit->first
|
||||
<< " in " << net->fullname() << "?" << endl;
|
||||
}
|
||||
assert(etmp);
|
||||
make_scope_param_expr(cur_par, etmp);
|
||||
}
|
||||
assert(etmp);
|
||||
make_scope_param_expr(cur_par, etmp);
|
||||
|
||||
idx += 1;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
1
t-dll.h
1
t-dll.h
|
|
@ -638,6 +638,7 @@ struct ivl_parameter_s {
|
|||
long lsb;
|
||||
bool signed_flag;
|
||||
bool local;
|
||||
bool is_type;
|
||||
perm_string file;
|
||||
unsigned lineno;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -940,9 +940,15 @@ static void create_skeleton_entity_for(ivl_scope_t scope, int depth)
|
|||
unsigned nparams = ivl_scope_params(scope);
|
||||
for (unsigned i = 0; i < nparams; i++) {
|
||||
ivl_parameter_t param = ivl_scope_param(scope, i);
|
||||
ss << "\n " << ivl_parameter_basename(param) << " = ";
|
||||
|
||||
// Type parameter usages get replaced with their actual type
|
||||
if (ivl_parameter_is_type(param))
|
||||
continue;
|
||||
|
||||
ivl_expr_t value = ivl_parameter_expr(param);
|
||||
|
||||
ss << "\n " << ivl_parameter_basename(param) << " = ";
|
||||
|
||||
switch (ivl_expr_type(value)) {
|
||||
case IVL_EX_STRING:
|
||||
ss << "\"" << ivl_expr_string(value) << "\"";
|
||||
|
|
|
|||
|
|
@ -264,6 +264,14 @@ static bool same_scope_type_name(ivl_scope_t a, ivl_scope_t b)
|
|||
ivl_parameter_basename(param_b)) != 0)
|
||||
return false;
|
||||
|
||||
if (ivl_parameter_local(param_a) && ivl_parameter_local(param_b))
|
||||
continue;
|
||||
|
||||
// If this is a type parameter consider the scopes not equal since we do
|
||||
// not have support for comparing the actual types yet.
|
||||
if (ivl_parameter_is_type(param_a) || ivl_parameter_is_type(param_b))
|
||||
return false;
|
||||
|
||||
ivl_expr_t value_a = ivl_parameter_expr(param_a);
|
||||
ivl_expr_t value_b = ivl_parameter_expr(param_b);
|
||||
|
||||
|
|
|
|||
|
|
@ -309,6 +309,13 @@ void emit_scope_variables(ivl_scope_t scope)
|
|||
count = ivl_scope_params(scope);
|
||||
for (idx = 0; idx < count; idx += 1) {
|
||||
ivl_parameter_t par = ivl_scope_param(scope, idx);
|
||||
// vlog95 does not support type parameters. Places where type
|
||||
// parameters have been used it will be replaced with the actual
|
||||
// type that the module was instantiated with. Similar to
|
||||
// typedefs.
|
||||
if (ivl_parameter_is_type(par))
|
||||
continue;
|
||||
|
||||
ivl_expr_t pex = ivl_parameter_expr(par);
|
||||
fprintf(vlog_out, "%*cparameter ", indent, ' ');
|
||||
emit_id(ivl_parameter_basename(par));
|
||||
|
|
|
|||
|
|
@ -2415,6 +2415,13 @@ int draw_scope(ivl_scope_t net, ivl_scope_t parent)
|
|||
|
||||
for (idx = 0 ; idx < ivl_scope_params(net) ; idx += 1) {
|
||||
ivl_parameter_t par = ivl_scope_param(net, idx);
|
||||
|
||||
// Skip type parameters for now. Support for type parameters
|
||||
// should be added together with support for quering types through
|
||||
// VPI.
|
||||
if (ivl_parameter_is_type(par))
|
||||
continue;
|
||||
|
||||
ivl_expr_t pex = ivl_parameter_expr(par);
|
||||
switch (ivl_expr_type(pex)) {
|
||||
case IVL_EX_STRING:
|
||||
|
|
|
|||
Loading…
Reference in New Issue