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.
This commit is contained in:
Stephen Williams 2013-05-26 18:16:59 -07:00
parent 1b178d56b7
commit bc77a19059
2 changed files with 70 additions and 14 deletions

View File

@ -933,6 +933,35 @@ unsigned PECallFunction::test_width_sfunc_(Design*des, NetScope*scope,
{ {
perm_string name = peek_tail_name(path_); 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") { if (name=="$signed" || name=="$unsigned") {
PExpr*expr = parms_[0]; PExpr*expr = parms_[0];
if (expr == 0) if (expr == 0)
@ -1228,6 +1257,19 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope,
{ {
perm_string name = peek_tail_name(path_); 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 /* Catch the special case that the system function is the $signed
function. Its argument will be evaluated as a self-determined function. Its argument will be evaluated as a self-determined
expression. */ expression. */

View File

@ -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 * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -24,6 +25,7 @@
# include <typeinfo> # include <typeinfo>
# include <iostream> # include <iostream>
# include <cstdlib> # include <cstdlib>
# include <cstring>
# include "ivl_assert.h" # include "ivl_assert.h"
# include <cassert> # include <cassert>
@ -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 the down to a literal integer at compile time, and all it
needs is the type of the base expression. (The base needs is the type of the base expression. (The base
expression doesn't even need to be evaluated.) */ expression doesn't even need to be evaluated.) */
if (name_ == "length") { if (name_=="length") {
int64_t val; out << "$bits(";
bool rc = evaluate(ent, arc, val); errors += base_->emit(out, ent, arc);
out << val; out << ")";
if (rc) return errors;
return errors;
else
return errors + 1;
} }
out << "$ivl_attribute("; out << "$ivl_attribute(";
errors += base_->emit(out, ent, arc); errors += base_->emit(out, ent, arc);
out << ", \"" << name_ << "\")"; out << ", \"" << name_ << "\")";
@ -539,13 +539,12 @@ int ExpFunc::emit(ostream&out, Entity*ent, Architecture*arc)
out << ")"; out << ")";
} else if (name_ == "to_unsigned" && argv_.size() == 2) { } 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); 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) { } else if (name_ == "conv_std_logic_vector" && argv_.size() == 2) {
int64_t use_size; int64_t use_size;
@ -727,6 +726,18 @@ int ExpString::emit_as_array_(ostream& out, Entity*, Architecture*, const VTypeA
const VTypePrimitive*etype = dynamic_cast<const VTypePrimitive*> (arr->element_type()); const VTypePrimitive*etype = dynamic_cast<const VTypePrimitive*> (arr->element_type());
assert(etype); 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<char> 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); assert(etype->type() != VTypePrimitive::INTEGER);
out << value_.size() << "'b"; out << value_.size() << "'b";
for (size_t idx = 0 ; idx < value_.size() ; idx += 1) { 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"; out << "z";
break; break;
default: 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); assert(etype->type() == VTypePrimitive::STDLOGIC);
out << "x"; out << "x";
break; break;