From 1da9b2cea0cd0641344887b0a50bc809516e2971 Mon Sep 17 00:00:00 2001 From: Cary R Date: Mon, 3 Sep 2018 08:29:07 -0700 Subject: [PATCH] Add support for constant $countones, $isunknown, $onehot, $onehot0 --- eval_tree.cc | 166 +++++++++++++++++++++++++++++++++++++++------ netlist.h | 2 +- vpi/Makefile.in | 3 +- vpi/v2009_bitvec.c | 34 +++++----- vpi/v2009_table.c | 2 +- 5 files changed, 165 insertions(+), 42 deletions(-) diff --git a/eval_tree.cc b/eval_tree.cc index 7536bd56b..3140f8f4b 100644 --- a/eval_tree.cc +++ b/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(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(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(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(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(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; diff --git a/netlist.h b/netlist.h index 4ef652339..39130e3cd 100644 --- a/netlist.h +++ b/netlist.h @@ -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. */ diff --git a/vpi/Makefile.in b/vpi/Makefile.in index 88173cbda..cf62786e2 100644 --- a/vpi/Makefile.in +++ b/vpi/Makefile.in @@ -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 diff --git a/vpi/v2009_bitvec.c b/vpi/v2009_bitvec.c index 6f67cf43b..cc824b9bb 100644 --- a/vpi/v2009_bitvec.c +++ b/vpi/v2009_bitvec.c @@ -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); diff --git a/vpi/v2009_table.c b/vpi/v2009_table.c index a8d613ba2..1a3f8ee2b 100644 --- a/vpi/v2009_table.c +++ b/vpi/v2009_table.c @@ -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