From bc77a1905927ba9ef11e5b31bd861ba1bd619852 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 26 May 2013 18:16:59 -0700 Subject: [PATCH] Use $ivl_unsigned to implement VHDL to_unsigned function. The VHDL to_unsigned function with to arguments is best handled in the ivl elaborator, so have it generate an $ivlh_to_unsigned function call in the vhdlpp code, and implement it in the ivl core. Also, implement the 'length attribute as a $bits() call for similar reasons. --- elab_expr.cc | 42 +++++++++++++++++++++++++++++++++++++++ vhdlpp/expression_emit.cc | 42 ++++++++++++++++++++++++++------------- 2 files changed, 70 insertions(+), 14 deletions(-) diff --git a/elab_expr.cc b/elab_expr.cc index d82b82b11..d14602f09 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -933,6 +933,35 @@ unsigned PECallFunction::test_width_sfunc_(Design*des, NetScope*scope, { perm_string name = peek_tail_name(path_); + if (name=="$ivlh_to_unsigned") { + ivl_assert(*this, parms_.size() == 2); + // The Icarus Verilog specific $ivl_unsigned() system + // task takes a second argument which is the output + // size. This can be an arbitrary constant function. + PExpr*pexpr = parms_[1]; + if (pexpr == 0) { + cerr << get_fileline() << ": error: " + << "Missing $ivlh_to_unsigned width." << endl; + return 0; + } + + NetExpr*nexpr = elab_and_eval(des, scope, pexpr, -1, true); + if (nexpr == 0) { + cerr << get_fileline() << ": error: " + << "Unable to evaluate " << name + << " width argument: " << *pexpr << endl; + return 0; + } + + long value = 0; + bool rc = eval_as_long(value, nexpr); + ivl_assert(*this, rc && value>=0); + + expr_width_ = value; + signed_flag_= false; + return expr_width_; + } + if (name=="$signed" || name=="$unsigned") { PExpr*expr = parms_[0]; if (expr == 0) @@ -1228,6 +1257,19 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope, { perm_string name = peek_tail_name(path_); + /* Catch the special case that the system function is the + $ivl_unsigned function. In this case the second argument is + the size of the expression, but should already be accounted + for so treat this very much like the $unsigned() function. */ + if (name=="$ivlh_to_unsigned") { + ivl_assert(*this, parms_.size()==2); + + PExpr*expr = parms_[0]; + ivl_assert(*this, expr); + NetExpr*sub = expr->elaborate_expr(des, scope, expr_width_, flags); + return cast_to_width_(sub, expr_wid); + } + /* Catch the special case that the system function is the $signed function. Its argument will be evaluated as a self-determined expression. */ diff --git a/vhdlpp/expression_emit.cc b/vhdlpp/expression_emit.cc index 2c1b43114..d4fa884e1 100644 --- a/vhdlpp/expression_emit.cc +++ b/vhdlpp/expression_emit.cc @@ -1,5 +1,6 @@ /* - * Copyright (c) 2011-2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com) + * Copyright CERN 2012-2013 / 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 @@ -24,6 +25,7 @@ # include # include # include +# include # include "ivl_assert.h" # include @@ -278,16 +280,14 @@ int ExpAttribute::emit(ostream&out, Entity*ent, Architecture*arc) the down to a literal integer at compile time, and all it needs is the type of the base expression. (The base expression doesn't even need to be evaluated.) */ - if (name_ == "length") { - int64_t val; - bool rc = evaluate(ent, arc, val); - out << val; - if (rc) - return errors; - else - return errors + 1; + if (name_=="length") { + out << "$bits("; + errors += base_->emit(out, ent, arc); + out << ")"; + return errors; } + out << "$ivl_attribute("; errors += base_->emit(out, ent, arc); out << ", \"" << name_ << "\")"; @@ -539,13 +539,12 @@ int ExpFunc::emit(ostream&out, Entity*ent, Architecture*arc) out << ")"; } else if (name_ == "to_unsigned" && argv_.size() == 2) { - int64_t use_size; - bool rc = argv_[1]->evaluate(ent, arc, use_size); - ivl_assert(*this, rc); - out << "$unsigned(" << use_size << "'("; + out << "$ivlh_to_unsigned("; errors += argv_[0]->emit(out, ent, arc); - out << "))"; + out << ", "; + errors += argv_[1]->emit(out, ent, arc); + out << ")"; } else if (name_ == "conv_std_logic_vector" && argv_.size() == 2) { int64_t use_size; @@ -727,6 +726,18 @@ int ExpString::emit_as_array_(ostream& out, Entity*, Architecture*, const VTypeA const VTypePrimitive*etype = dynamic_cast (arr->element_type()); assert(etype); + // Detect the special case that this is an array of + // CHARACTER. In this case, emit at a Verilog string. + if (etype->type()==VTypePrimitive::CHARACTER) { + vector tmp (value_.size() + 3); + tmp[0] = '"'; + memcpy(&tmp[1], &value_[0], value_.size()); + tmp[value_.size()+1] = '"'; + tmp[value_.size()+2] = 0; + out << &tmp[0]; + return errors; + } + assert(etype->type() != VTypePrimitive::INTEGER); out << value_.size() << "'b"; for (size_t idx = 0 ; idx < value_.size() ; idx += 1) { @@ -742,6 +753,9 @@ int ExpString::emit_as_array_(ostream& out, Entity*, Architecture*, const VTypeA out << "z"; break; default: + cerr << get_fileline() << ": internal error: " + << "Don't know how to handle bit " << value_[idx] + << " with etype==" << etype->type() << endl; assert(etype->type() == VTypePrimitive::STDLOGIC); out << "x"; break;