Tasks functions with atom2 arguments.
Parse 2-value atoms as arguments to functions and tasks.
This commit is contained in:
parent
e03ff763fb
commit
af6fd66648
4
PTask.h
4
PTask.h
|
|
@ -37,7 +37,9 @@ enum PTaskFuncEnum {
|
||||||
PTF_INTEGER,
|
PTF_INTEGER,
|
||||||
PTF_REAL,
|
PTF_REAL,
|
||||||
PTF_REALTIME,
|
PTF_REALTIME,
|
||||||
PTF_TIME
|
PTF_TIME,
|
||||||
|
PTF_ATOM2,
|
||||||
|
PTF_ATOM2_S
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PTaskFuncArg {
|
struct PTaskFuncArg {
|
||||||
|
|
|
||||||
59
elab_sig.cc
59
elab_sig.cc
|
|
@ -69,6 +69,15 @@ static bool get_const_argument(NetExpr*exp, verinum&res)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool get_const_argument(NetExpr*exp, long&res)
|
||||||
|
{
|
||||||
|
verinum tmp;
|
||||||
|
bool rc = get_const_argument(exp, tmp);
|
||||||
|
if (rc == false) return false;
|
||||||
|
res = tmp.as_long();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void Statement::elaborate_sig(Design*des, NetScope*scope) const
|
void Statement::elaborate_sig(Design*des, NetScope*scope) const
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
@ -472,18 +481,14 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const
|
||||||
need_constant_expr = false;
|
need_constant_expr = false;
|
||||||
|
|
||||||
long mnum = 0, lnum = 0;
|
long mnum = 0, lnum = 0;
|
||||||
if (NetEConst*tmp = dynamic_cast<NetEConst*>(me)) {
|
if ( ! get_const_argument(me, mnum) ) {
|
||||||
mnum = tmp->value().as_long();
|
|
||||||
} else {
|
|
||||||
cerr << me->get_fileline() << ": error: "
|
cerr << me->get_fileline() << ": error: "
|
||||||
"Unable to evaluate constant expression "
|
"Unable to evaluate constant expression "
|
||||||
<< *me << "." << endl;
|
<< *me << "." << endl;
|
||||||
des->errors += 1;
|
des->errors += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NetEConst*tmp = dynamic_cast<NetEConst*>(le)) {
|
if ( ! get_const_argument(le, lnum) ) {
|
||||||
lnum = tmp->value().as_long();
|
|
||||||
} else {
|
|
||||||
cerr << le->get_fileline() << ": error: "
|
cerr << le->get_fileline() << ": error: "
|
||||||
"Unable to evaluate constant expression "
|
"Unable to evaluate constant expression "
|
||||||
<< *le << "." << endl;
|
<< *le << "." << endl;
|
||||||
|
|
@ -534,6 +539,48 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const
|
||||||
ret_sig->data_type(IVL_VT_REAL);
|
ret_sig->data_type(IVL_VT_REAL);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PTF_ATOM2:
|
||||||
|
case PTF_ATOM2_S:
|
||||||
|
ivl_assert(*this, return_type_.range != 0);
|
||||||
|
probe_expr_width(des, scope, (*return_type_.range)[0]);
|
||||||
|
probe_expr_width(des, scope, (*return_type_.range)[1]);
|
||||||
|
long use_wid;
|
||||||
|
{
|
||||||
|
need_constant_expr = true;
|
||||||
|
NetExpr*me = elab_and_eval(des, scope,
|
||||||
|
(*return_type_.range)[0], -1);
|
||||||
|
assert(me);
|
||||||
|
NetExpr*le = elab_and_eval(des, scope,
|
||||||
|
(*return_type_.range)[1], -1);
|
||||||
|
assert(le);
|
||||||
|
need_constant_expr = false;
|
||||||
|
|
||||||
|
long mnum = 0, lnum = 0;
|
||||||
|
if ( ! get_const_argument(me, mnum) ) {
|
||||||
|
cerr << me->get_fileline() << ": error: "
|
||||||
|
"Unable to evaluate constant expression "
|
||||||
|
<< *me << "." << endl;
|
||||||
|
des->errors += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! get_const_argument(le, lnum) ) {
|
||||||
|
cerr << le->get_fileline() << ": error: "
|
||||||
|
"Unable to evaluate constant expression "
|
||||||
|
<< *le << "." << endl;
|
||||||
|
des->errors += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
use_wid = mnum - lnum + 1;
|
||||||
|
}
|
||||||
|
ret_sig = new NetNet(scope, fname, NetNet::REG, use_wid);
|
||||||
|
ret_sig->set_line(*this);
|
||||||
|
ret_sig->set_signed(return_type_.type == PTF_ATOM2_S? true : false);
|
||||||
|
ret_sig->set_isint(true);
|
||||||
|
ret_sig->set_scalar(false);
|
||||||
|
ret_sig->port_type(NetNet::POUTPUT);
|
||||||
|
ret_sig->data_type(IVL_VT_BOOL);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (ports_) {
|
if (ports_) {
|
||||||
cerr << get_fileline() << ": internal error: I don't know "
|
cerr << get_fileline() << ": internal error: I don't know "
|
||||||
|
|
|
||||||
219
parse.y
219
parse.y
|
|
@ -106,6 +106,16 @@ static list<pair<perm_string,PExpr*> >* make_port_list(list<pair<perm_string,
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static svector<PExpr*>* make_range_from_width(uint64_t wid)
|
||||||
|
{
|
||||||
|
svector<PExpr*>*range = new svector<PExpr*>(2);
|
||||||
|
|
||||||
|
(*range)[0] = new PENumber(new verinum(wid-1, integer_width));
|
||||||
|
(*range)[1] = new PENumber(new verinum((uint64_t)0, integer_width));
|
||||||
|
|
||||||
|
return range;
|
||||||
|
}
|
||||||
|
|
||||||
static list<perm_string>* list_from_identifier(char*id)
|
static list<perm_string>* list_from_identifier(char*id)
|
||||||
{
|
{
|
||||||
list<perm_string>*tmp = new list<perm_string>;
|
list<perm_string>*tmp = new list<perm_string>;
|
||||||
|
|
@ -167,6 +177,7 @@ static PECallFunction*make_call_function(perm_string tn, PExpr*arg1, PExpr*arg2)
|
||||||
bool flag;
|
bool flag;
|
||||||
|
|
||||||
char letter;
|
char letter;
|
||||||
|
int int_val;
|
||||||
|
|
||||||
/* text items are C strings allocated by the lexor using
|
/* text items are C strings allocated by the lexor using
|
||||||
strdup. They can be put into lists with the texts type. */
|
strdup. They can be put into lists with the texts type. */
|
||||||
|
|
@ -394,6 +405,8 @@ static PECallFunction*make_call_function(perm_string tn, PExpr*arg1, PExpr*arg2)
|
||||||
%type <specpath> specify_simple_path specify_simple_path_decl
|
%type <specpath> specify_simple_path specify_simple_path_decl
|
||||||
%type <specpath> specify_edge_path specify_edge_path_decl
|
%type <specpath> specify_edge_path specify_edge_path_decl
|
||||||
|
|
||||||
|
%type <int_val> atom2_type
|
||||||
|
|
||||||
%token K_TAND
|
%token K_TAND
|
||||||
%right '?' ':'
|
%right '?' ':'
|
||||||
%left K_LOR
|
%left K_LOR
|
||||||
|
|
@ -531,23 +544,8 @@ block_item_decl
|
||||||
if ($1) delete $1;
|
if ($1) delete $1;
|
||||||
}
|
}
|
||||||
|
|
||||||
| attribute_list_opt K_byte signed_unsigned_opt register_variable_list ';'
|
| attribute_list_opt atom2_type signed_unsigned_opt register_variable_list ';'
|
||||||
{ pform_set_integer_2atom(8, $3, $4);
|
{ pform_set_integer_2atom($2, $3, $4);
|
||||||
if ($1) delete $1;
|
|
||||||
}
|
|
||||||
|
|
||||||
| attribute_list_opt K_shortint signed_unsigned_opt register_variable_list ';'
|
|
||||||
{ pform_set_integer_2atom(16, $3, $4);
|
|
||||||
if ($1) delete $1;
|
|
||||||
}
|
|
||||||
|
|
||||||
| attribute_list_opt K_int signed_unsigned_opt register_variable_list ';'
|
|
||||||
{ pform_set_integer_2atom(32, $3, $4);
|
|
||||||
if ($1) delete $1;
|
|
||||||
}
|
|
||||||
|
|
||||||
| attribute_list_opt K_longint signed_unsigned_opt register_variable_list ';'
|
|
||||||
{ pform_set_integer_2atom(64, $3, $4);
|
|
||||||
if ($1) delete $1;
|
if ($1) delete $1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2024,6 +2022,17 @@ signed_unsigned_opt
|
||||||
| { $$ = true; }
|
| { $$ = true; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* In some places we can take any of the 4 2-value atom-type
|
||||||
|
* names. All the context needs to know if that type is its width.
|
||||||
|
*/
|
||||||
|
atom2_type
|
||||||
|
: K_byte { $$ = 8; }
|
||||||
|
| K_shortint { $$ = 16; }
|
||||||
|
| K_int { $$ = 32; }
|
||||||
|
| K_longint { $$ = 64; }
|
||||||
|
;
|
||||||
|
|
||||||
/* An lpvalue is the expression that can go on the left side of a
|
/* An lpvalue is the expression that can go on the left side of a
|
||||||
procedural assignment. This rule handles only procedural
|
procedural assignment. This rule handles only procedural
|
||||||
assignments. It is more limited then the general expr_primary
|
assignments. It is more limited then the general expr_primary
|
||||||
|
|
@ -2680,10 +2689,11 @@ net_decl_assigns
|
||||||
;
|
;
|
||||||
|
|
||||||
primitive_type
|
primitive_type
|
||||||
: K_logic { $$ = IVL_VT_LOGIC; }
|
: K_logic { $$ = IVL_VT_LOGIC; }
|
||||||
| K_bool { $$ = IVL_VT_BOOL; }
|
| K_bool { $$ = IVL_VT_BOOL; /* Icarus Verilog xtypes */}
|
||||||
| K_real { $$ = IVL_VT_REAL; }
|
| K_bit { $$ = IVL_VT_BOOL; /* IEEE1800 / IEEE1364-2009 */}
|
||||||
;
|
| K_real { $$ = IVL_VT_REAL; }
|
||||||
|
;
|
||||||
|
|
||||||
primitive_type_opt : primitive_type { $$ = $1; } | { $$ = IVL_VT_NO_TYPE; } ;
|
primitive_type_opt : primitive_type { $$ = $1; } | { $$ = IVL_VT_NO_TYPE; } ;
|
||||||
|
|
||||||
|
|
@ -3236,14 +3246,17 @@ dimensions
|
||||||
|
|
||||||
/* This is used to express the return type of a function. */
|
/* This is used to express the return type of a function. */
|
||||||
function_range_or_type_opt
|
function_range_or_type_opt
|
||||||
: range { $$.range = $1; $$.type = PTF_REG; }
|
: range { $$.range = $1; $$.type = PTF_REG; }
|
||||||
| K_signed range { $$.range = $2; $$.type = PTF_REG_S; }
|
| K_signed range { $$.range = $2; $$.type = PTF_REG_S; }
|
||||||
| K_integer { $$.range = 0; $$.type = PTF_INTEGER; }
|
| K_integer { $$.range = 0; $$.type = PTF_INTEGER; }
|
||||||
| K_real { $$.range = 0; $$.type = PTF_REAL; }
|
| K_real { $$.range = 0; $$.type = PTF_REAL; }
|
||||||
| K_realtime { $$.range = 0; $$.type = PTF_REALTIME; }
|
| K_realtime { $$.range = 0; $$.type = PTF_REALTIME; }
|
||||||
| K_time { $$.range = 0; $$.type = PTF_TIME; }
|
| K_time { $$.range = 0; $$.type = PTF_TIME; }
|
||||||
| { $$.range = 0; $$.type = PTF_REG; }
|
| atom2_type { $$.range = make_range_from_width($1); $$.type = PTF_ATOM2_S; }
|
||||||
;
|
| atom2_type K_signed { $$.range = make_range_from_width($1); $$.type = PTF_ATOM2_S; }
|
||||||
|
| atom2_type K_unsigned { $$.range = make_range_from_width($1); $$.type = PTF_ATOM2; }
|
||||||
|
| { $$.range = 0; $$.type = PTF_REG; }
|
||||||
|
;
|
||||||
|
|
||||||
/* The register_variable rule is matched only when I am parsing
|
/* The register_variable rule is matched only when I am parsing
|
||||||
variables in a "reg" definition. I therefore know that I am
|
variables in a "reg" definition. I therefore know that I am
|
||||||
|
|
@ -4356,66 +4369,48 @@ task_port_decl
|
||||||
|
|
||||||
/* Ports can be time with a width of [63:0] (unsigned). */
|
/* Ports can be time with a width of [63:0] (unsigned). */
|
||||||
|
|
||||||
| K_input K_time IDENTIFIER
|
| K_input K_time IDENTIFIER
|
||||||
{ svector<PExpr*>*range_stub = new svector<PExpr*>(2);
|
{ svector<PExpr*>*range_stub = make_range_from_width(64);
|
||||||
PExpr*re;
|
port_declaration_context.port_type = NetNet::PINPUT;
|
||||||
re = new PENumber(new verinum((uint64_t)63, integer_width));
|
port_declaration_context.var_type = IVL_VT_LOGIC;
|
||||||
(*range_stub)[0] = re;
|
port_declaration_context.sign_flag = false;
|
||||||
re = new PENumber(new verinum((uint64_t)0, integer_width));
|
delete port_declaration_context.range;
|
||||||
(*range_stub)[1] = re;
|
port_declaration_context.range = copy_range(range_stub);
|
||||||
port_declaration_context.port_type = NetNet::PINPUT;
|
svector<PWire*>*tmp = pform_make_task_ports(NetNet::PINPUT,
|
||||||
port_declaration_context.var_type = IVL_VT_LOGIC;
|
IVL_VT_LOGIC, false,
|
||||||
port_declaration_context.sign_flag = false;
|
range_stub,
|
||||||
delete port_declaration_context.range;
|
list_from_identifier($3),
|
||||||
port_declaration_context.range = copy_range(range_stub);
|
@1.text, @1.first_line);
|
||||||
svector<PWire*>*tmp
|
$$ = tmp;
|
||||||
= pform_make_task_ports(NetNet::PINPUT,
|
}
|
||||||
IVL_VT_LOGIC, false,
|
| K_output K_time IDENTIFIER
|
||||||
range_stub,
|
{ svector<PExpr*>*range_stub = make_range_from_width(64);
|
||||||
list_from_identifier($3),
|
port_declaration_context.port_type = NetNet::POUTPUT;
|
||||||
@1.text, @1.first_line);
|
port_declaration_context.var_type = IVL_VT_LOGIC;
|
||||||
$$ = tmp;
|
port_declaration_context.sign_flag = false;
|
||||||
}
|
delete port_declaration_context.range;
|
||||||
| K_output K_time IDENTIFIER
|
port_declaration_context.range = copy_range(range_stub);
|
||||||
{ svector<PExpr*>*range_stub = new svector<PExpr*>(2);
|
svector<PWire*>*tmp = pform_make_task_ports(NetNet::POUTPUT,
|
||||||
PExpr*re;
|
IVL_VT_LOGIC, false,
|
||||||
re = new PENumber(new verinum((uint64_t)63, integer_width));
|
range_stub,
|
||||||
(*range_stub)[0] = re;
|
list_from_identifier($3),
|
||||||
re = new PENumber(new verinum((uint64_t)0, integer_width));
|
@1.text, @1.first_line);
|
||||||
(*range_stub)[1] = re;
|
$$ = tmp;
|
||||||
port_declaration_context.port_type = NetNet::POUTPUT;
|
}
|
||||||
port_declaration_context.var_type = IVL_VT_LOGIC;
|
| K_inout K_time IDENTIFIER
|
||||||
port_declaration_context.sign_flag = false;
|
{ svector<PExpr*>*range_stub = make_range_from_width(64);
|
||||||
delete port_declaration_context.range;
|
port_declaration_context.port_type = NetNet::PINOUT;
|
||||||
port_declaration_context.range = copy_range(range_stub);
|
port_declaration_context.var_type = IVL_VT_LOGIC;
|
||||||
svector<PWire*>*tmp
|
port_declaration_context.sign_flag = false;
|
||||||
= pform_make_task_ports(NetNet::POUTPUT,
|
delete port_declaration_context.range;
|
||||||
IVL_VT_LOGIC, false,
|
port_declaration_context.range = copy_range(range_stub);
|
||||||
range_stub,
|
svector<PWire*>*tmp = pform_make_task_ports(NetNet::PINOUT,
|
||||||
list_from_identifier($3),
|
IVL_VT_LOGIC, false,
|
||||||
@1.text, @1.first_line);
|
range_stub,
|
||||||
$$ = tmp;
|
list_from_identifier($3),
|
||||||
}
|
@1.text, @1.first_line);
|
||||||
| K_inout K_time IDENTIFIER
|
$$ = tmp;
|
||||||
{ svector<PExpr*>*range_stub = new svector<PExpr*>(2);
|
}
|
||||||
PExpr*re;
|
|
||||||
re = new PENumber(new verinum((uint64_t)63, integer_width));
|
|
||||||
(*range_stub)[0] = re;
|
|
||||||
re = new PENumber(new verinum((uint64_t)0, integer_width));
|
|
||||||
(*range_stub)[1] = re;
|
|
||||||
port_declaration_context.port_type = NetNet::PINOUT;
|
|
||||||
port_declaration_context.var_type = IVL_VT_LOGIC;
|
|
||||||
port_declaration_context.sign_flag = false;
|
|
||||||
delete port_declaration_context.range;
|
|
||||||
port_declaration_context.range = copy_range(range_stub);
|
|
||||||
svector<PWire*>*tmp
|
|
||||||
= pform_make_task_ports(NetNet::PINOUT,
|
|
||||||
IVL_VT_LOGIC, false,
|
|
||||||
range_stub,
|
|
||||||
list_from_identifier($3),
|
|
||||||
@1.text, @1.first_line);
|
|
||||||
$$ = tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Ports can be real or realtime. */
|
/* Ports can be real or realtime. */
|
||||||
|
|
||||||
|
|
@ -4458,7 +4453,51 @@ task_port_decl
|
||||||
@1.text, @1.first_line);
|
@1.text, @1.first_line);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
;
|
|
||||||
|
/* Ports can be 2-value atom types. */
|
||||||
|
|
||||||
|
| K_input atom2_type signed_unsigned_opt IDENTIFIER
|
||||||
|
{ svector<PExpr*>*range_stub = make_range_from_width($2);
|
||||||
|
port_declaration_context.port_type = NetNet::PINPUT;
|
||||||
|
port_declaration_context.var_type = IVL_VT_BOOL;
|
||||||
|
port_declaration_context.sign_flag = $3;
|
||||||
|
delete port_declaration_context.range;
|
||||||
|
port_declaration_context.range = copy_range(range_stub);
|
||||||
|
svector<PWire*>*tmp = pform_make_task_ports(NetNet::PINPUT,
|
||||||
|
IVL_VT_BOOL, $3,
|
||||||
|
range_stub, list_from_identifier($4),
|
||||||
|
@1.text, @1.first_line);
|
||||||
|
$$ = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
| K_output atom2_type signed_unsigned_opt IDENTIFIER
|
||||||
|
{ svector<PExpr*>*range_stub = make_range_from_width($2);
|
||||||
|
port_declaration_context.port_type = NetNet::POUTPUT;
|
||||||
|
port_declaration_context.var_type = IVL_VT_BOOL;
|
||||||
|
port_declaration_context.sign_flag = $3;
|
||||||
|
delete port_declaration_context.range;
|
||||||
|
port_declaration_context.range = copy_range(range_stub);
|
||||||
|
svector<PWire*>*tmp = pform_make_task_ports(NetNet::POUTPUT,
|
||||||
|
IVL_VT_BOOL, $3,
|
||||||
|
range_stub, list_from_identifier($4),
|
||||||
|
@1.text, @1.first_line);
|
||||||
|
$$ = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
| K_inout atom2_type signed_unsigned_opt IDENTIFIER
|
||||||
|
{ svector<PExpr*>*range_stub = make_range_from_width($2);
|
||||||
|
port_declaration_context.port_type = NetNet::PINOUT;
|
||||||
|
port_declaration_context.var_type = IVL_VT_BOOL;
|
||||||
|
port_declaration_context.sign_flag = $3;
|
||||||
|
delete port_declaration_context.range;
|
||||||
|
port_declaration_context.range = copy_range(range_stub);
|
||||||
|
svector<PWire*>*tmp = pform_make_task_ports(NetNet::PINOUT,
|
||||||
|
IVL_VT_BOOL, $3,
|
||||||
|
range_stub, list_from_identifier($4),
|
||||||
|
@1.text, @1.first_line);
|
||||||
|
$$ = tmp;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
task_port_decl_list
|
task_port_decl_list
|
||||||
: task_port_decl_list ',' task_port_decl
|
: task_port_decl_list ',' task_port_decl
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,12 @@ static void function_argument_real(ivl_signal_t port, ivl_expr_t expr)
|
||||||
clr_word(res);
|
clr_word(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void function_argument_bool(ivl_signal_t port, ivl_expr_t expr)
|
||||||
|
{
|
||||||
|
/* For now, treat bit2 variables as bit4 variables. */
|
||||||
|
function_argument_logic(port, expr);
|
||||||
|
}
|
||||||
|
|
||||||
static void draw_function_argument(ivl_signal_t port, ivl_expr_t expr)
|
static void draw_function_argument(ivl_signal_t port, ivl_expr_t expr)
|
||||||
{
|
{
|
||||||
ivl_variable_type_t dtype = ivl_signal_data_type(port);
|
ivl_variable_type_t dtype = ivl_signal_data_type(port);
|
||||||
|
|
@ -65,6 +71,9 @@ static void draw_function_argument(ivl_signal_t port, ivl_expr_t expr)
|
||||||
case IVL_VT_REAL:
|
case IVL_VT_REAL:
|
||||||
function_argument_real(port, expr);
|
function_argument_real(port, expr);
|
||||||
break;
|
break;
|
||||||
|
case IVL_VT_BOOL:
|
||||||
|
function_argument_bool(port, expr);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "XXXX function argument %s type=%d?!\n",
|
fprintf(stderr, "XXXX function argument %s type=%d?!\n",
|
||||||
ivl_signal_basename(port), dtype);
|
ivl_signal_basename(port), dtype);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue