Add support for constant $countones, $isunknown, $onehot, $onehot0

This commit is contained in:
Cary R 2018-09-03 08:29:07 -07:00
parent 2b030ce27a
commit 1da9b2cea0
5 changed files with 165 additions and 42 deletions

View File

@ -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;

View File

@ -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. */

View File

@ -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

View File

@ -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);

View File

@ -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