Merge branch 'master' of github.com:steveicarus/iverilog
This commit is contained in:
commit
b7b7280794
21
elab_expr.cc
21
elab_expr.cc
|
|
@ -2623,6 +2623,27 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope,
|
|||
return sys_expr;
|
||||
}
|
||||
|
||||
if (method_name == "atoi") {
|
||||
NetESFunc*sys_expr = new NetESFunc("$ivl_string_method$atoi",
|
||||
IVL_VT_BOOL, integer_width, 1);
|
||||
sys_expr->parm(0, new NetESignal(net));
|
||||
return sys_expr;
|
||||
}
|
||||
|
||||
if (method_name == "atoreal") {
|
||||
NetESFunc*sys_expr = new NetESFunc("$ivl_string_method$atoreal",
|
||||
IVL_VT_REAL, 1, 1);
|
||||
sys_expr->parm(0, new NetESignal(net));
|
||||
return sys_expr;
|
||||
}
|
||||
|
||||
if (method_name == "atohex") {
|
||||
NetESFunc*sys_expr = new NetESFunc("$ivl_string_method$atohex",
|
||||
IVL_VT_BOOL, integer_width, 1);
|
||||
sys_expr->parm(0, new NetESignal(net));
|
||||
return sys_expr;
|
||||
}
|
||||
|
||||
if (method_name == "substr") {
|
||||
NetESFunc*sys_expr = new NetESFunc("$ivl_string_method$substr",
|
||||
IVL_VT_STRING, 1, 3);
|
||||
|
|
|
|||
|
|
@ -1245,9 +1245,10 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
|
|||
} else if (netdarray) {
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": debug: Create signal " << wtype
|
||||
<< " dynamic array "
|
||||
<< name_ << " in scope " << scope_path(scope) << endl;
|
||||
cerr << get_fileline() << ": PWire::elaborate_sig: "
|
||||
<< "Create signal " << wtype
|
||||
<< " dynamic array " << name_
|
||||
<< " in scope " << scope_path(scope) << endl;
|
||||
}
|
||||
|
||||
ivl_assert(*this, packed_dimensions.empty());
|
||||
|
|
|
|||
|
|
@ -224,7 +224,7 @@ void NetPins::set_default_dir(Link::DIR d)
|
|||
default_dir_ = d;
|
||||
}
|
||||
|
||||
bool NetPins::is_linked(void)
|
||||
bool NetPins::is_linked(void) const
|
||||
{
|
||||
bool linked_flag = false;
|
||||
if (pins_ == NULL) return false;
|
||||
|
|
|
|||
|
|
@ -215,7 +215,7 @@ class NetPins : public LineInfo {
|
|||
void dump_node_pins(ostream&, unsigned, const char**pin_names =0) const;
|
||||
void set_default_dir(Link::DIR d);
|
||||
|
||||
bool is_linked();
|
||||
bool is_linked() const;
|
||||
bool pins_are_virtual(void) const;
|
||||
void devirtualize_pins(void);
|
||||
|
||||
|
|
|
|||
|
|
@ -915,12 +915,10 @@ bool dll_target::proc_wait(const NetEvWait*net)
|
|||
break;
|
||||
}
|
||||
|
||||
for (unsigned bit = 0
|
||||
; bit < pr->pin_count()
|
||||
; bit += 1) {
|
||||
for (unsigned bit = 0; bit < pr->pin_count(); bit += 1) {
|
||||
ivl_nexus_t nex = (ivl_nexus_t)
|
||||
pr->pin(bit).nexus()->t_cookie();
|
||||
assert(nex);
|
||||
ivl_assert(*ev, nex);
|
||||
ev_tmp->pins[base+bit] = nex;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
13
t-dll.cc
13
t-dll.cc
|
|
@ -2599,7 +2599,6 @@ void dll_target::signal(const NetNet*net)
|
|||
obj->discipline = net->get_discipline();
|
||||
|
||||
obj->array_dimensions_ = net->unpacked_dimensions();
|
||||
assert(obj->array_dimensions_ == net->unpacked_dimensions());
|
||||
|
||||
switch (net->port_type()) {
|
||||
|
||||
|
|
@ -2679,6 +2678,18 @@ void dll_target::signal(const NetNet*net)
|
|||
obj->nattr = net->attr_cnt();
|
||||
obj->attr = fill_in_attributes(net);
|
||||
|
||||
// Special case: IVL_VT_QUEUE objects don't normally show up in the
|
||||
// network, but can in certain special cases. In these cases, it is the
|
||||
// object itself and not the array elements that is in the network. of
|
||||
// course, only do this if there is at least one link to this signal.
|
||||
if (obj->net_type->base_type()==IVL_VT_QUEUE && net->is_linked()) {
|
||||
const Nexus*nex = net->pin(0).nexus();
|
||||
ivl_nexus_t tmp = nexus_sig_make(obj, 0);
|
||||
tmp->nexus_ = nex;
|
||||
tmp->name_ = 0;
|
||||
nex->t_cookie(tmp);
|
||||
}
|
||||
|
||||
/* Get the nexus objects for all the pins of the signal. If
|
||||
the signal has only one pin, then write the single
|
||||
ivl_nexus_t object into n.pin_. Otherwise, make an array of
|
||||
|
|
|
|||
|
|
@ -326,11 +326,19 @@ static void show_signal_expression(ivl_expr_t net, unsigned ind)
|
|||
ivl_expr_t word = ivl_expr_oper1(net);
|
||||
|
||||
ivl_signal_t sig = ivl_expr_signal(net);
|
||||
const char*vt_sig = data_type_string(ivl_signal_data_type(sig));
|
||||
ivl_variable_type_t data_type = ivl_signal_data_type(sig);
|
||||
const char*vt_sig = data_type_string(data_type);
|
||||
unsigned dimensions = ivl_signal_dimensions(sig);
|
||||
unsigned word_count = ivl_signal_array_count(sig);
|
||||
|
||||
if (dimensions == 0 && word_count != 1) {
|
||||
if (data_type==IVL_VT_QUEUE) {
|
||||
if (dimensions != 0) {
|
||||
fprintf(out, "%*sERROR: Queue objects expect dimensions==0, got %u.\n",
|
||||
ind, "", dimensions);
|
||||
stub_errors += 1;
|
||||
}
|
||||
|
||||
} else if (dimensions == 0 && word_count != 1) {
|
||||
fprintf(out, "%*sERROR: Word count = %u for non-array object\n",
|
||||
ind, "", word_count);
|
||||
stub_errors += 1;
|
||||
|
|
@ -353,7 +361,7 @@ static void show_signal_expression(ivl_expr_t net, unsigned ind)
|
|||
/* If this is not an array, then the expression with must
|
||||
match the signal width. We have IVL_EX_SELECT expressions
|
||||
for casting signal widths. */
|
||||
if (dimensions == 0 && ivl_signal_width(sig) != width) {
|
||||
if (dimensions == 0 && data_type!=IVL_VT_QUEUE && ivl_signal_width(sig) != width) {
|
||||
fprintf(out, "%*sERROR: Expression width (%u) doesn't match ivl_signal_width(sig)=%u\n",
|
||||
ind+2, "", width, ivl_signal_width(sig));
|
||||
stub_errors += 1;
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
# include "sys_priv.h"
|
||||
# include <assert.h>
|
||||
# include <ctype.h>
|
||||
# include <math.h>
|
||||
# include <stdlib.h>
|
||||
# include <string.h>
|
||||
|
|
@ -78,6 +79,136 @@ static PLI_INT32 len_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static PLI_INT32 atoi_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
|
||||
{
|
||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||
vpiHandle argv;
|
||||
vpiHandle arg;
|
||||
s_vpi_value value;
|
||||
|
||||
(void)name; /* Parameter not used */
|
||||
|
||||
argv = vpi_iterate(vpiArgument, callh);
|
||||
assert(argv);
|
||||
arg = vpi_scan(argv);
|
||||
assert(arg);
|
||||
vpi_free_object(argv);
|
||||
|
||||
int res = 0;
|
||||
|
||||
value.format = vpiStringVal;
|
||||
vpi_get_value(arg, &value);
|
||||
const char*bufp = value.value.str;
|
||||
while (bufp && *bufp) {
|
||||
if (isdigit(*bufp)) {
|
||||
res = (res * 10) + (*bufp - '0');
|
||||
bufp += 1;
|
||||
} else if (*bufp == '_') {
|
||||
bufp += 1;
|
||||
} else {
|
||||
bufp = 0;
|
||||
}
|
||||
}
|
||||
|
||||
value.format = vpiIntVal;
|
||||
value.value.integer = res;
|
||||
|
||||
vpi_put_value(callh, &value, 0, vpiNoDelay);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PLI_INT32 atoreal_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
|
||||
{
|
||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||
vpiHandle argv;
|
||||
vpiHandle arg;
|
||||
s_vpi_value value;
|
||||
|
||||
(void)name; /* Parameter not used */
|
||||
|
||||
argv = vpi_iterate(vpiArgument, callh);
|
||||
assert(argv);
|
||||
arg = vpi_scan(argv);
|
||||
assert(arg);
|
||||
vpi_free_object(argv);
|
||||
|
||||
double res = 0;
|
||||
|
||||
value.format = vpiStringVal;
|
||||
vpi_get_value(arg, &value);
|
||||
|
||||
res = strtod(value.value.str, 0);
|
||||
|
||||
value.format = vpiRealVal;
|
||||
value.value.real = res;
|
||||
|
||||
vpi_put_value(callh, &value, 0, vpiNoDelay);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PLI_INT32 atohex_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
|
||||
{
|
||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||
vpiHandle argv;
|
||||
vpiHandle arg;
|
||||
s_vpi_value value;
|
||||
|
||||
(void)name; /* Parameter not used */
|
||||
|
||||
argv = vpi_iterate(vpiArgument, callh);
|
||||
assert(argv);
|
||||
arg = vpi_scan(argv);
|
||||
assert(arg);
|
||||
vpi_free_object(argv);
|
||||
|
||||
int res = 0;
|
||||
|
||||
value.format = vpiStringVal;
|
||||
vpi_get_value(arg, &value);
|
||||
const char*bufp = value.value.str;
|
||||
while (bufp && *bufp) {
|
||||
switch (*bufp) {
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
res = (res * 16) + (*bufp - '0');
|
||||
bufp += 1;
|
||||
break;
|
||||
case 'a': case 'A':
|
||||
case 'b': case 'B':
|
||||
case 'c': case 'C':
|
||||
case 'd': case 'D':
|
||||
case 'e': case 'E':
|
||||
case 'f': case 'F':
|
||||
res = (res * 16) + (toupper(*bufp) - 'A' + 10);
|
||||
bufp += 1;
|
||||
break;
|
||||
case '_':
|
||||
bufp += 1;
|
||||
break;
|
||||
default:
|
||||
bufp = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
value.format = vpiIntVal;
|
||||
value.value.integer = res;
|
||||
|
||||
vpi_put_value(callh, &value, 0, vpiNoDelay);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void v2009_string_register(void)
|
||||
{
|
||||
s_vpi_systf_data tf_data;
|
||||
|
|
@ -92,4 +223,34 @@ void v2009_string_register(void)
|
|||
tf_data.user_data = "$ivl_string_method$len";
|
||||
res = vpi_register_systf(&tf_data);
|
||||
vpip_make_systf_system_defined(res);
|
||||
|
||||
tf_data.type = vpiSysFunc;
|
||||
tf_data.sysfunctype = vpiIntFunc;
|
||||
tf_data.tfname = "$ivl_string_method$atoi";
|
||||
tf_data.calltf = atoi_calltf;
|
||||
tf_data.compiletf = one_string_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$ivl_string_method$atoi";
|
||||
res = vpi_register_systf(&tf_data);
|
||||
vpip_make_systf_system_defined(res);
|
||||
|
||||
tf_data.type = vpiSysFunc;
|
||||
tf_data.sysfunctype = vpiRealFunc;
|
||||
tf_data.tfname = "$ivl_string_method$atoreal";
|
||||
tf_data.calltf = atoreal_calltf;
|
||||
tf_data.compiletf = one_string_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$ivl_string_method$atoreal";
|
||||
res = vpi_register_systf(&tf_data);
|
||||
vpip_make_systf_system_defined(res);
|
||||
|
||||
tf_data.type = vpiSysFunc;
|
||||
tf_data.sysfunctype = vpiIntFunc;
|
||||
tf_data.tfname = "$ivl_string_method$atohex";
|
||||
tf_data.calltf = atohex_calltf;
|
||||
tf_data.compiletf = one_string_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$ivl_string_method$atohex";
|
||||
res = vpi_register_systf(&tf_data);
|
||||
vpip_make_systf_system_defined(res);
|
||||
}
|
||||
|
|
|
|||
12
vvp/event.cc
12
vvp/event.cc
|
|
@ -627,6 +627,18 @@ void vvp_fun_anyedge_sa::recv_string(vvp_net_ptr_t port, const std::string&bit,
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* An anyedge receiving an object should do nothing with it, but should
|
||||
* trigger waiting threads.
|
||||
*/
|
||||
void vvp_fun_anyedge_sa::recv_object(vvp_net_ptr_t port, vvp_object_t bit,
|
||||
vvp_context_t)
|
||||
{
|
||||
run_waiting_threads_(threads_);
|
||||
vvp_net_t*net = port.ptr();
|
||||
net->send_vec4(vvp_vector4_t(), 0);
|
||||
}
|
||||
|
||||
vvp_fun_anyedge_aa::vvp_fun_anyedge_aa()
|
||||
{
|
||||
context_scope_ = vpip_peek_context_scope();
|
||||
|
|
|
|||
|
|
@ -264,6 +264,8 @@ class vvp_fun_anyedge_sa : public vvp_fun_anyedge {
|
|||
|
||||
void recv_string(vvp_net_ptr_t port, const std::string&bit,
|
||||
vvp_context_t context);
|
||||
void recv_object(vvp_net_ptr_t port, vvp_object_t bit,
|
||||
vvp_context_t context);
|
||||
|
||||
private:
|
||||
vthread_t threads_;
|
||||
|
|
|
|||
Loading…
Reference in New Issue