Add support for constant $countones, $isunknown, $onehot, $onehot0
This commit is contained in:
parent
2b030ce27a
commit
1da9b2cea0
166
eval_tree.cc
166
eval_tree.cc
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1999-2017 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1999-2018 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -1908,15 +1908,62 @@ NetExpr* NetESFunc::evaluate_min_max_(ID id, const NetExpr*arg0_,
|
|||
return res;
|
||||
}
|
||||
|
||||
NetEConst* NetESFunc::evaluate_countbits_(const NetExpr* /*arg0*/,
|
||||
const NetExpr* /*arg1*/) const
|
||||
static void no_string_arg(const NetESFunc*info)
|
||||
{
|
||||
return 0;
|
||||
cerr << info->get_fileline() << ": error: constant function "
|
||||
<< info->name() << "() does not support a string argument."
|
||||
<< endl;
|
||||
}
|
||||
|
||||
NetEConst* NetESFunc::evaluate_countones_(const NetExpr* /*arg*/) const
|
||||
NetEConst* NetESFunc::evaluate_countbits_(const NetExpr* arg,
|
||||
const NetExpr* /*arg1*/) const
|
||||
{
|
||||
return 0;
|
||||
const NetEConst*tmpi = dynamic_cast<const NetEConst*>(arg);
|
||||
|
||||
NetEConst*res = 0;
|
||||
|
||||
if (tmpi) {
|
||||
verinum value = tmpi->value();
|
||||
|
||||
if (value.is_string()) {
|
||||
no_string_arg(this);
|
||||
return 0;
|
||||
}
|
||||
|
||||
cerr << get_fileline() << ": error: constant function "
|
||||
<< name_ << "() is not currently supported."
|
||||
<< endl;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
NetEConst* NetESFunc::evaluate_countones_(const NetExpr* arg) const
|
||||
{
|
||||
const NetEConst*tmpi = dynamic_cast<const NetEConst*>(arg);
|
||||
|
||||
NetEConst*res = 0;
|
||||
|
||||
if (tmpi) {
|
||||
verinum value = tmpi->value();
|
||||
int count = 0;
|
||||
|
||||
if (value.is_string()) {
|
||||
no_string_arg(this);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (unsigned bit=0; bit < value.len(); ++bit) {
|
||||
if (value[bit] == verinum::V1) count += 1;
|
||||
}
|
||||
|
||||
verinum tmp (count, integer_width);
|
||||
tmp.has_sign(true);
|
||||
res = new NetEConst(tmp);
|
||||
ivl_assert(*this, res);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Get the total number of dimensions for the given expression. */
|
||||
|
|
@ -1939,19 +1986,92 @@ NetEConst* NetESFunc::evaluate_dimensions_(const NetExpr*arg) const
|
|||
return new NetEConst(verinum(verinum(res), integer_width));
|
||||
}
|
||||
|
||||
NetEConst* NetESFunc::evaluate_isunknown_(const NetExpr* /*arg*/) const
|
||||
NetEConst* NetESFunc::evaluate_isunknown_(const NetExpr* arg) const
|
||||
{
|
||||
return 0;
|
||||
const NetEConst*tmpi = dynamic_cast<const NetEConst*>(arg);
|
||||
|
||||
NetEConst*res = 0;
|
||||
|
||||
if (tmpi) {
|
||||
verinum value = tmpi->value();
|
||||
unsigned is_unknown = 1;
|
||||
|
||||
if (value.is_string()) {
|
||||
no_string_arg(this);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (value.is_defined()) is_unknown = 0;
|
||||
|
||||
verinum tmp (is_unknown, 1U);
|
||||
tmp.has_sign(false);
|
||||
res = new NetEConst(tmp);
|
||||
ivl_assert(*this, res);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
NetEConst* NetESFunc::evaluate_onehot_(const NetExpr* /*arg*/) const
|
||||
static bool is_onehot(verinum&value, bool zero_is_okay)
|
||||
{
|
||||
return 0;
|
||||
bool found_a_one = false;
|
||||
|
||||
for (unsigned bit=0; bit < value.len(); ++bit) {
|
||||
if (value[bit] == verinum::V1) {
|
||||
if (found_a_one) return false;
|
||||
found_a_one = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* If no one bit was found return true if zero is okay. */
|
||||
if (zero_is_okay) found_a_one = true;
|
||||
return found_a_one;
|
||||
}
|
||||
|
||||
NetEConst* NetESFunc::evaluate_onehot0_(const NetExpr* /*arg*/) const
|
||||
NetEConst* NetESFunc::evaluate_onehot_(const NetExpr* arg) const
|
||||
{
|
||||
return 0;
|
||||
const NetEConst*tmpi = dynamic_cast<const NetEConst*>(arg);
|
||||
|
||||
NetEConst*res = 0;
|
||||
|
||||
if (tmpi) {
|
||||
verinum value = tmpi->value();
|
||||
|
||||
if (value.is_string()) {
|
||||
no_string_arg(this);
|
||||
return 0;
|
||||
}
|
||||
|
||||
verinum tmp (is_onehot(value, false), 1U);
|
||||
tmp.has_sign(false);
|
||||
res = new NetEConst(tmp);
|
||||
ivl_assert(*this, res);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
NetEConst* NetESFunc::evaluate_onehot0_(const NetExpr* arg) const
|
||||
{
|
||||
const NetEConst*tmpi = dynamic_cast<const NetEConst*>(arg);
|
||||
|
||||
NetEConst*res = 0;
|
||||
|
||||
if (tmpi) {
|
||||
verinum value = tmpi->value();
|
||||
|
||||
if (value.is_string()) {
|
||||
no_string_arg(this);
|
||||
return 0;
|
||||
}
|
||||
|
||||
verinum tmp (is_onehot(value, true), 1U);
|
||||
tmp.has_sign(false);
|
||||
res = new NetEConst(tmp);
|
||||
ivl_assert(*this, res);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Get the number of unpacked dimensions for the given expression. */
|
||||
|
|
@ -2194,12 +2314,12 @@ NetESFunc::ID NetESFunc::built_in_id_() const
|
|||
built_in_func["$unpacked_dimensions" ] = UPDIMS;
|
||||
}
|
||||
|
||||
/* These are available in 1800-2009 and later. */
|
||||
/* This is available in 1800-2009 and later. */
|
||||
if (funcs_need_init && (generation_flag >= GN_VER2009)) {
|
||||
built_in_func["$countones" ] = CTONES;
|
||||
}
|
||||
|
||||
/* These are available in 1800-2012 and later. */
|
||||
/* This is available in 1800-2012 and later. */
|
||||
if (funcs_need_init && (generation_flag >= GN_VER2012)) {
|
||||
built_in_func["$countbits" ] = CTBITS;
|
||||
}
|
||||
|
|
@ -2226,7 +2346,7 @@ NetESFunc::ID NetESFunc::built_in_id_() const
|
|||
|
||||
NetExpr* NetESFunc::eval_tree()
|
||||
{
|
||||
/* Get the ID for this system function if it is can be used as a
|
||||
/* Get the ID for this system function if it can be used as a
|
||||
* constant function. */
|
||||
ID id = built_in_id_();
|
||||
if (id == NOT_BUILT_IN) return 0;
|
||||
|
|
@ -2234,8 +2354,9 @@ NetExpr* NetESFunc::eval_tree()
|
|||
switch (parms_.size()) {
|
||||
case 1:
|
||||
if (! takes_nargs_(id, 1)) {
|
||||
cerr << get_fileline() << ": error: " << name_
|
||||
<< "() does not support a single argument." << endl;
|
||||
cerr << get_fileline() << ": error: constant function "
|
||||
<< name_ << "() does not support a single argument."
|
||||
<< endl;
|
||||
return 0;
|
||||
}
|
||||
eval_expr(parms_[0]);
|
||||
|
|
@ -2243,8 +2364,9 @@ NetExpr* NetESFunc::eval_tree()
|
|||
|
||||
case 2:
|
||||
if (! takes_nargs_(id, 2)) {
|
||||
cerr << get_fileline() << ": error: " << name_
|
||||
<< "() does not support two arguments." << endl;
|
||||
cerr << get_fileline() << ": error: constant function "
|
||||
<< name_ << "() does not support two arguments."
|
||||
<< endl;
|
||||
return 0;
|
||||
}
|
||||
eval_expr(parms_[0]);
|
||||
|
|
@ -2254,13 +2376,13 @@ NetExpr* NetESFunc::eval_tree()
|
|||
default:
|
||||
/* Check to see if the function was called correctly. */
|
||||
if (! takes_nargs_(id, parms_.size())) {
|
||||
cerr << get_fileline() << ": error: " << name_
|
||||
<< "() does not support " << parms_.size()
|
||||
cerr << get_fileline() << ": error: constant function "
|
||||
<< name_ << "() does not support " << parms_.size()
|
||||
<< " arguments." << endl;
|
||||
return 0;
|
||||
}
|
||||
// HERE: Need to add support for a multi argument $countbits().
|
||||
cerr << get_fileline() << ": sorry: functions with "
|
||||
cerr << get_fileline() << ": sorry: constant functions with "
|
||||
<< parms_.size() << " arguments are not supported: "
|
||||
<< name_ << "()." << endl;
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -4605,7 +4605,7 @@ class NetESFunc : public NetExpr {
|
|||
/* Added in SystemVerilog 2009 and later. */
|
||||
CTONES = 0x00020024, /* $countones takes one argument. */
|
||||
/* Added in SystemVerilog 2012 and later. */
|
||||
CTBITS = 0xfffe0025, /* $countbits takes one or more arguments. */
|
||||
CTBITS = 0xfffc0025, /* $countbits takes two or more arguments. */
|
||||
/* Added as Icarus extensions to Verilog-A. */
|
||||
ABS = 0x00020026, /* $abs takes one argument. */
|
||||
MAX = 0x00040027, /* $max takes two argument. */
|
||||
|
|
|
|||
|
|
@ -74,7 +74,8 @@ M = sys_clog2.o v2005_math.o
|
|||
# Object files for va_math.vpi
|
||||
V = va_math.o
|
||||
|
||||
V2009 = v2009_table.o v2009_array.o v2009_bitvec.o v2009_enum.o v2009_string.o
|
||||
V2009 = v2009_table.o v2009_array.o v2009_bitvec.o v2009_enum.o v2009_string.o \
|
||||
sys_priv.o
|
||||
|
||||
VHDL_SYS = vhdl_table.o sys_priv.o
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
/*
|
||||
* Check that $couintbits() is called with the correct arguments.
|
||||
*/
|
||||
static PLI_INT32 sys_countbits_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *name)
|
||||
static PLI_INT32 countbits_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *name)
|
||||
{
|
||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||
vpiHandle argv, arg;
|
||||
|
|
@ -100,7 +100,7 @@ static PLI_INT32 count_bits_in_expr(vpiHandle expr_arg, char search[4])
|
|||
return result;
|
||||
}
|
||||
|
||||
static PLI_INT32 sys_countbits_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name)
|
||||
static PLI_INT32 countbits_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name)
|
||||
{
|
||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||
|
|
@ -169,7 +169,7 @@ static PLI_INT32 count_ones_in_expr(vpiHandle expr_arg)
|
|||
return result;
|
||||
}
|
||||
|
||||
static PLI_INT32 sys_countones_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name)
|
||||
static PLI_INT32 countones_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name)
|
||||
{
|
||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||
|
|
@ -213,7 +213,7 @@ static PLI_INT32 is_onehot(vpiHandle expr_arg, unsigned zero_is_okay)
|
|||
return vpi0;
|
||||
}
|
||||
|
||||
static PLI_INT32 sys_onehot_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name)
|
||||
static PLI_INT32 onehot_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name)
|
||||
{
|
||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||
|
|
@ -227,7 +227,7 @@ static PLI_INT32 sys_onehot_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static PLI_INT32 sys_onehot0_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name)
|
||||
static PLI_INT32 onehot0_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name)
|
||||
{
|
||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||
|
|
@ -259,7 +259,7 @@ static PLI_INT32 is_unknown(vpiHandle expr_arg)
|
|||
return vpi0;
|
||||
}
|
||||
|
||||
static PLI_INT32 sys_isunknown_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name)
|
||||
static PLI_INT32 isunknown_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name)
|
||||
{
|
||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||
|
|
@ -273,7 +273,7 @@ static PLI_INT32 sys_isunknown_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static PLI_INT32 sys_bit_vec_sizetf(ICARUS_VPI_CONST PLI_BYTE8 *name)
|
||||
static PLI_INT32 bit_vec_sizetf(ICARUS_VPI_CONST PLI_BYTE8 *name)
|
||||
{
|
||||
(void)name; /* Parameter is not used. */
|
||||
|
||||
|
|
@ -283,15 +283,15 @@ static PLI_INT32 sys_bit_vec_sizetf(ICARUS_VPI_CONST PLI_BYTE8 *name)
|
|||
/*
|
||||
* Register the functions with Verilog.
|
||||
*/
|
||||
void sys_bitvec_register(void)
|
||||
void v2009_bitvec_register(void)
|
||||
{
|
||||
s_vpi_systf_data tf_data;
|
||||
vpiHandle res;
|
||||
|
||||
tf_data.type = vpiSysFunc;
|
||||
tf_data.sysfunctype = vpiIntFunc;
|
||||
tf_data.calltf = sys_countbits_calltf;
|
||||
tf_data.compiletf = sys_countbits_compiletf;
|
||||
tf_data.calltf = countbits_calltf;
|
||||
tf_data.compiletf = countbits_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.tfname = "$countbits";
|
||||
tf_data.user_data = 0;
|
||||
|
|
@ -300,7 +300,7 @@ void sys_bitvec_register(void)
|
|||
|
||||
tf_data.type = vpiSysFunc;
|
||||
tf_data.sysfunctype = vpiIntFunc;
|
||||
tf_data.calltf = sys_countones_calltf;
|
||||
tf_data.calltf = countones_calltf;
|
||||
tf_data.compiletf = sys_one_numeric_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.tfname = "$countones";
|
||||
|
|
@ -310,9 +310,9 @@ void sys_bitvec_register(void)
|
|||
|
||||
tf_data.type = vpiSysFunc;
|
||||
tf_data.sysfunctype = vpiSizedFunc;
|
||||
tf_data.calltf = sys_onehot_calltf;
|
||||
tf_data.calltf = onehot_calltf;
|
||||
tf_data.compiletf = sys_one_numeric_arg_compiletf;
|
||||
tf_data.sizetf = sys_bit_vec_sizetf;
|
||||
tf_data.sizetf = bit_vec_sizetf;
|
||||
tf_data.tfname = "$onehot";
|
||||
tf_data.user_data = "$onehot";
|
||||
res = vpi_register_systf(&tf_data);
|
||||
|
|
@ -320,9 +320,9 @@ void sys_bitvec_register(void)
|
|||
|
||||
tf_data.type = vpiSysFunc;
|
||||
tf_data.sysfunctype = vpiSizedFunc;
|
||||
tf_data.calltf = sys_onehot0_calltf;
|
||||
tf_data.calltf = onehot0_calltf;
|
||||
tf_data.compiletf = sys_one_numeric_arg_compiletf;
|
||||
tf_data.sizetf = sys_bit_vec_sizetf;
|
||||
tf_data.sizetf = bit_vec_sizetf;
|
||||
tf_data.tfname = "$onehot0";
|
||||
tf_data.user_data = "$onehot0";
|
||||
res = vpi_register_systf(&tf_data);
|
||||
|
|
@ -330,9 +330,9 @@ void sys_bitvec_register(void)
|
|||
|
||||
tf_data.type = vpiSysFunc;
|
||||
tf_data.sysfunctype = vpiSizedFunc;
|
||||
tf_data.calltf = sys_isunknown_calltf;
|
||||
tf_data.calltf = isunknown_calltf;
|
||||
tf_data.compiletf = sys_one_numeric_arg_compiletf;
|
||||
tf_data.sizetf = sys_bit_vec_sizetf;
|
||||
tf_data.sizetf = bit_vec_sizetf;
|
||||
tf_data.tfname = "$isunknown";
|
||||
tf_data.user_data = "$isunknown";
|
||||
res = vpi_register_systf(&tf_data);
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ extern void v2009_string_register(void);
|
|||
|
||||
void (*vlog_startup_routines[])(void) = {
|
||||
v2009_array_register,
|
||||
v2009_sys_bitvec_register,
|
||||
v2009_bitvec_register,
|
||||
v2009_enum_register,
|
||||
v2009_string_register,
|
||||
0
|
||||
|
|
|
|||
Loading…
Reference in New Issue