Tasks functions with atom2 arguments.

Parse 2-value atoms as arguments to functions and tasks.
This commit is contained in:
Stephen Williams 2010-10-02 16:29:30 -07:00
parent e03ff763fb
commit af6fd66648
4 changed files with 194 additions and 97 deletions

View File

@ -37,7 +37,9 @@ enum PTaskFuncEnum {
PTF_INTEGER,
PTF_REAL,
PTF_REALTIME,
PTF_TIME
PTF_TIME,
PTF_ATOM2,
PTF_ATOM2_S
};
struct PTaskFuncArg {

View File

@ -69,6 +69,15 @@ static bool get_const_argument(NetExpr*exp, verinum&res)
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
{
}
@ -472,18 +481,14 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const
need_constant_expr = false;
long mnum = 0, lnum = 0;
if (NetEConst*tmp = dynamic_cast<NetEConst*>(me)) {
mnum = tmp->value().as_long();
} else {
if ( ! get_const_argument(me, mnum) ) {
cerr << me->get_fileline() << ": error: "
"Unable to evaluate constant expression "
<< *me << "." << endl;
des->errors += 1;
}
if (NetEConst*tmp = dynamic_cast<NetEConst*>(le)) {
lnum = tmp->value().as_long();
} else {
if ( ! get_const_argument(le, lnum) ) {
cerr << le->get_fileline() << ": error: "
"Unable to evaluate constant expression "
<< *le << "." << endl;
@ -534,6 +539,48 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const
ret_sig->data_type(IVL_VT_REAL);
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:
if (ports_) {
cerr << get_fileline() << ": internal error: I don't know "

219
parse.y
View File

@ -106,6 +106,16 @@ static list<pair<perm_string,PExpr*> >* make_port_list(list<pair<perm_string,
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)
{
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;
char letter;
int int_val;
/* text items are C strings allocated by the lexor using
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_edge_path specify_edge_path_decl
%type <int_val> atom2_type
%token K_TAND
%right '?' ':'
%left K_LOR
@ -531,23 +544,8 @@ block_item_decl
if ($1) delete $1;
}
| attribute_list_opt K_byte signed_unsigned_opt register_variable_list ';'
{ pform_set_integer_2atom(8, $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);
| attribute_list_opt atom2_type signed_unsigned_opt register_variable_list ';'
{ pform_set_integer_2atom($2, $3, $4);
if ($1) delete $1;
}
@ -2024,6 +2022,17 @@ signed_unsigned_opt
| { $$ = 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
procedural assignment. This rule handles only procedural
assignments. It is more limited then the general expr_primary
@ -2680,10 +2689,11 @@ net_decl_assigns
;
primitive_type
: K_logic { $$ = IVL_VT_LOGIC; }
| K_bool { $$ = IVL_VT_BOOL; }
| K_real { $$ = IVL_VT_REAL; }
;
: K_logic { $$ = IVL_VT_LOGIC; }
| K_bool { $$ = IVL_VT_BOOL; /* Icarus Verilog xtypes */}
| K_bit { $$ = IVL_VT_BOOL; /* IEEE1800 / IEEE1364-2009 */}
| K_real { $$ = IVL_VT_REAL; }
;
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. */
function_range_or_type_opt
: range { $$.range = $1; $$.type = PTF_REG; }
| K_signed range { $$.range = $2; $$.type = PTF_REG_S; }
| K_integer { $$.range = 0; $$.type = PTF_INTEGER; }
| K_real { $$.range = 0; $$.type = PTF_REAL; }
| K_realtime { $$.range = 0; $$.type = PTF_REALTIME; }
| K_time { $$.range = 0; $$.type = PTF_TIME; }
| { $$.range = 0; $$.type = PTF_REG; }
;
: range { $$.range = $1; $$.type = PTF_REG; }
| K_signed range { $$.range = $2; $$.type = PTF_REG_S; }
| K_integer { $$.range = 0; $$.type = PTF_INTEGER; }
| K_real { $$.range = 0; $$.type = PTF_REAL; }
| K_realtime { $$.range = 0; $$.type = PTF_REALTIME; }
| K_time { $$.range = 0; $$.type = PTF_TIME; }
| 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
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). */
| K_input K_time IDENTIFIER
{ 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::PINPUT;
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::PINPUT,
IVL_VT_LOGIC, false,
range_stub,
list_from_identifier($3),
@1.text, @1.first_line);
$$ = tmp;
}
| K_output K_time IDENTIFIER
{ 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::POUTPUT;
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::POUTPUT,
IVL_VT_LOGIC, false,
range_stub,
list_from_identifier($3),
@1.text, @1.first_line);
$$ = tmp;
}
| K_inout K_time IDENTIFIER
{ 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;
}
| K_input K_time IDENTIFIER
{ svector<PExpr*>*range_stub = make_range_from_width(64);
port_declaration_context.port_type = NetNet::PINPUT;
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::PINPUT,
IVL_VT_LOGIC, false,
range_stub,
list_from_identifier($3),
@1.text, @1.first_line);
$$ = tmp;
}
| K_output K_time IDENTIFIER
{ svector<PExpr*>*range_stub = make_range_from_width(64);
port_declaration_context.port_type = NetNet::POUTPUT;
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::POUTPUT,
IVL_VT_LOGIC, false,
range_stub,
list_from_identifier($3),
@1.text, @1.first_line);
$$ = tmp;
}
| K_inout K_time IDENTIFIER
{ svector<PExpr*>*range_stub = make_range_from_width(64);
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. */
@ -4458,7 +4453,51 @@ task_port_decl
@1.text, @1.first_line);
$$ = 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

View File

@ -55,6 +55,12 @@ static void function_argument_real(ivl_signal_t port, ivl_expr_t expr)
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)
{
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:
function_argument_real(port, expr);
break;
case IVL_VT_BOOL:
function_argument_bool(port, expr);
break;
default:
fprintf(stderr, "XXXX function argument %s type=%d?!\n",
ivl_signal_basename(port), dtype);