Merge branch 'vhdl' of file:///media/disk/data/iverilog/ into vhdl
This commit is contained in:
commit
e25f946ac0
|
|
@ -50,7 +50,7 @@ dep:
|
|||
mv $*.d dep
|
||||
|
||||
O = vhdl.o vhdl_element.o vhdl_type.o vhdl_syntax.o scope.o process.o \
|
||||
stmt.o expr.o lpm.o display.o
|
||||
stmt.o expr.o lpm.o display.o support.o cast.o
|
||||
|
||||
ifeq (@WIN32@,yes)
|
||||
TGTLDFLAGS=-L.. -livl
|
||||
|
|
|
|||
|
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
* Generate code to convert between VHDL types.
|
||||
*
|
||||
* Copyright (C) 2008 Nick Gasson (nick@nickg.me.uk)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "vhdl_syntax.hh"
|
||||
|
||||
#include "vhdl_target.h"
|
||||
#include "support.hh"
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
vhdl_expr *vhdl_expr::cast(const vhdl_type *to)
|
||||
{
|
||||
//std::cout << "Cast: from=" << type_->get_string()
|
||||
// << " (" << type_->get_width() << ") "
|
||||
// << " to=" << to->get_string() << " ("
|
||||
// << to->get_width() << ")" << std::endl;
|
||||
|
||||
if (to->get_name() == type_->get_name()) {
|
||||
if (to->get_width() == type_->get_width())
|
||||
return this; // Identical
|
||||
else
|
||||
return resize(to->get_width());
|
||||
}
|
||||
else if (to->get_name() == VHDL_TYPE_BOOLEAN) {
|
||||
if (type_->get_name() == VHDL_TYPE_STD_LOGIC) {
|
||||
// '1' is true all else are false
|
||||
vhdl_const_bit *one = new vhdl_const_bit('1');
|
||||
return new vhdl_binop_expr
|
||||
(this, VHDL_BINOP_EQ, one, vhdl_type::boolean());
|
||||
}
|
||||
else if (type_->get_name() == VHDL_TYPE_UNSIGNED) {
|
||||
// Need to use a support function for this conversion
|
||||
require_support_function(SF_UNSIGNED_TO_BOOLEAN);
|
||||
|
||||
vhdl_fcall *conv =
|
||||
new vhdl_fcall(support_function::function_name(SF_UNSIGNED_TO_BOOLEAN),
|
||||
vhdl_type::boolean());
|
||||
conv->add_expr(this);
|
||||
return conv;
|
||||
}
|
||||
else if (type_->get_name() == VHDL_TYPE_SIGNED) {
|
||||
require_support_function(SF_SIGNED_TO_BOOLEAN);
|
||||
|
||||
vhdl_fcall *conv =
|
||||
new vhdl_fcall(support_function::function_name(SF_SIGNED_TO_BOOLEAN),
|
||||
vhdl_type::boolean());
|
||||
conv->add_expr(this);
|
||||
return conv;
|
||||
}
|
||||
else {
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
else if (to->get_name() == VHDL_TYPE_INTEGER) {
|
||||
vhdl_fcall *conv = new vhdl_fcall("To_Integer", new vhdl_type(*to));
|
||||
conv->add_expr(this);
|
||||
|
||||
return conv;
|
||||
}
|
||||
else if (to->get_name() == VHDL_TYPE_STD_LOGIC &&
|
||||
type_->get_name() == VHDL_TYPE_BOOLEAN) {
|
||||
require_support_function(SF_BOOLEAN_TO_LOGIC);
|
||||
|
||||
vhdl_fcall *ah =
|
||||
new vhdl_fcall(support_function::function_name(SF_BOOLEAN_TO_LOGIC),
|
||||
vhdl_type::std_logic());
|
||||
ah->add_expr(this);
|
||||
|
||||
return ah;
|
||||
}
|
||||
else {
|
||||
// We have to cast the expression before resizing or the
|
||||
// wrong sign bit may be extended (i.e. when casting between
|
||||
// signed/unsigned *and* resizing)
|
||||
vhdl_fcall *conv =
|
||||
new vhdl_fcall(to->get_string().c_str(), new vhdl_type(*to));
|
||||
conv->add_expr(this);
|
||||
|
||||
if (to->get_width() != type_->get_width())
|
||||
return conv->resize(to->get_width());
|
||||
else
|
||||
return conv;
|
||||
}
|
||||
}
|
||||
|
||||
vhdl_expr *vhdl_expr::resize(int newwidth)
|
||||
{
|
||||
vhdl_type *rtype;
|
||||
assert(type_);
|
||||
if (type_->get_name() == VHDL_TYPE_SIGNED)
|
||||
rtype = vhdl_type::nsigned(newwidth);
|
||||
else if (type_->get_name() == VHDL_TYPE_UNSIGNED)
|
||||
rtype = vhdl_type::nunsigned(newwidth);
|
||||
else
|
||||
return this; // Doesn't make sense to resize non-vector type
|
||||
|
||||
vhdl_fcall *resize = new vhdl_fcall("Resize", rtype);
|
||||
resize->add_expr(this);
|
||||
resize->add_expr(new vhdl_const_int(newwidth));
|
||||
|
||||
return resize;
|
||||
}
|
||||
|
||||
|
||||
int vhdl_const_bits::bits_to_int() const
|
||||
{
|
||||
char msb = value_[value_.size() - 1];
|
||||
int result = 0, bit;
|
||||
for (int i = sizeof(int)*8 - 1; i >= 0; i--) {
|
||||
if (i > (int)value_.size() - 1)
|
||||
bit = msb == '1' ? 1 : 0;
|
||||
else
|
||||
bit = value_[i] == '1' ? 1 : 0;
|
||||
result = (result << 1) | bit;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
vhdl_expr *vhdl_const_bits::cast(const vhdl_type *to)
|
||||
{
|
||||
if (to->get_name() == VHDL_TYPE_STD_LOGIC) {
|
||||
// VHDL won't let us cast directly between a vector and
|
||||
// a scalar type
|
||||
// But we don't need to here as we have the bits available
|
||||
|
||||
// Take the least significant bit
|
||||
char lsb = value_[0];
|
||||
|
||||
return new vhdl_const_bit(lsb);
|
||||
}
|
||||
else if (to->get_name() == VHDL_TYPE_STD_LOGIC_VECTOR) {
|
||||
// Don't need to do anything
|
||||
return this;
|
||||
}
|
||||
else if (to->get_name() == VHDL_TYPE_SIGNED
|
||||
|| to->get_name() == VHDL_TYPE_UNSIGNED) {
|
||||
|
||||
// Extend with sign bit
|
||||
value_.resize(to->get_width(), value_[0]);
|
||||
return this;
|
||||
}
|
||||
else if (to->get_name() == VHDL_TYPE_INTEGER)
|
||||
return new vhdl_const_int(bits_to_int());
|
||||
else
|
||||
return vhdl_expr::cast(to);
|
||||
}
|
||||
|
||||
vhdl_expr *vhdl_const_bit::cast(const vhdl_type *to)
|
||||
{
|
||||
if (to->get_name() == VHDL_TYPE_INTEGER)
|
||||
return new vhdl_const_int(bit_ == '1' ? 1 : 0);
|
||||
else
|
||||
return vhdl_expr::cast(to);
|
||||
}
|
||||
110
tgt-vhdl/expr.cc
110
tgt-vhdl/expr.cc
|
|
@ -19,14 +19,17 @@
|
|||
*/
|
||||
|
||||
#include "vhdl_target.h"
|
||||
#include "support.hh"
|
||||
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
|
||||
/*
|
||||
* Change the signdness of a vector.
|
||||
* Change the signedness of a vector.
|
||||
*/
|
||||
static vhdl_expr *change_signdness(vhdl_expr *e, bool issigned)
|
||||
static vhdl_expr *change_signedness(vhdl_expr *e, bool issigned)
|
||||
{
|
||||
int msb = e->get_type()->get_msb();
|
||||
int lsb = e->get_type()->get_lsb();
|
||||
|
|
@ -58,12 +61,29 @@ static vhdl_var_ref *translate_signal(ivl_expr_t e)
|
|||
|
||||
const char *renamed = get_renamed_signal(sig).c_str();
|
||||
|
||||
const vhdl_decl *decl = scope->get_decl(strip_var(renamed));
|
||||
vhdl_decl *decl = scope->get_decl(renamed);
|
||||
assert(decl);
|
||||
|
||||
vhdl_type *type = new vhdl_type(*decl->get_type());
|
||||
|
||||
return new vhdl_var_ref(renamed, type);
|
||||
// Can't generate a constant initialiser for this signal
|
||||
// later as it has already been read
|
||||
if (scope->initializing())
|
||||
decl->set_initial(NULL);
|
||||
|
||||
vhdl_var_ref *ref =
|
||||
new vhdl_var_ref(renamed, new vhdl_type(*decl->get_type()));
|
||||
|
||||
ivl_expr_t off;
|
||||
if (ivl_signal_array_count(sig) > 0 && (off = ivl_expr_oper1(e))) {
|
||||
// Select from an array
|
||||
vhdl_expr *vhd_off = translate_expr(off);
|
||||
if (NULL == vhd_off)
|
||||
return NULL;
|
||||
|
||||
vhdl_type integer(VHDL_TYPE_INTEGER);
|
||||
ref->set_slice(vhd_off->cast(&integer));
|
||||
}
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -71,8 +91,33 @@ static vhdl_var_ref *translate_signal(ivl_expr_t e)
|
|||
*/
|
||||
static vhdl_expr *translate_number(ivl_expr_t e)
|
||||
{
|
||||
return new vhdl_const_bits(ivl_expr_bits(e), ivl_expr_width(e),
|
||||
ivl_expr_signed(e) != 0);
|
||||
if (ivl_expr_width(e) == 1)
|
||||
return new vhdl_const_bit(ivl_expr_bits(e)[0]);
|
||||
else
|
||||
return new vhdl_const_bits(ivl_expr_bits(e), ivl_expr_width(e),
|
||||
ivl_expr_signed(e) != 0);
|
||||
}
|
||||
|
||||
static vhdl_expr *translate_ulong(ivl_expr_t e)
|
||||
{
|
||||
return new vhdl_const_int(ivl_expr_uvalue(e));
|
||||
}
|
||||
|
||||
static vhdl_expr *translate_reduction(support_function_t f, bool neg,
|
||||
vhdl_expr *operand)
|
||||
{
|
||||
require_support_function(f);
|
||||
vhdl_fcall *fcall =
|
||||
new vhdl_fcall(support_function::function_name(f),
|
||||
vhdl_type::std_logic());
|
||||
|
||||
vhdl_type std_logic_vector(VHDL_TYPE_STD_LOGIC_VECTOR);
|
||||
fcall->add_expr(operand->cast(&std_logic_vector));
|
||||
if (neg)
|
||||
return new vhdl_unaryop_expr(VHDL_UNARYOP_NOT, fcall,
|
||||
vhdl_type::std_logic());
|
||||
else
|
||||
return fcall;
|
||||
}
|
||||
|
||||
static vhdl_expr *translate_unary(ivl_expr_t e)
|
||||
|
|
@ -83,17 +128,19 @@ static vhdl_expr *translate_unary(ivl_expr_t e)
|
|||
|
||||
bool should_be_signed = ivl_expr_signed(e) != 0;
|
||||
|
||||
if (operand->get_type()->get_name() == VHDL_TYPE_UNSIGNED && should_be_signed) {
|
||||
if (operand->get_type()->get_name() == VHDL_TYPE_UNSIGNED
|
||||
&& should_be_signed) {
|
||||
//operand->print();
|
||||
//std::cout << "^ should be signed but is not" << std::endl;
|
||||
|
||||
operand = change_signdness(operand, true);
|
||||
operand = change_signedness(operand, true);
|
||||
}
|
||||
else if (operand->get_type()->get_name() == VHDL_TYPE_SIGNED && !should_be_signed) {
|
||||
else if (operand->get_type()->get_name() == VHDL_TYPE_SIGNED
|
||||
&& !should_be_signed) {
|
||||
//operand->print();
|
||||
//std::cout << "^ should be unsigned but is not" << std::endl;
|
||||
|
||||
operand = change_signdness(operand, false);
|
||||
operand = change_signedness(operand, false);
|
||||
}
|
||||
|
||||
char opcode = ivl_expr_opcode(e);
|
||||
|
|
@ -103,15 +150,13 @@ static vhdl_expr *translate_unary(ivl_expr_t e)
|
|||
return new vhdl_unaryop_expr
|
||||
(VHDL_UNARYOP_NOT, operand, new vhdl_type(*operand->get_type()));
|
||||
case 'N': // NOR
|
||||
return translate_reduction(SF_REDUCE_OR, true, operand);
|
||||
case '|':
|
||||
{
|
||||
vhdl_fcall *f = new vhdl_fcall("Reduce_OR", vhdl_type::std_logic());
|
||||
f->add_expr(operand);
|
||||
if ('N' == opcode)
|
||||
return new vhdl_unaryop_expr(VHDL_UNARYOP_NOT, f, vhdl_type::std_logic());
|
||||
else
|
||||
return f;
|
||||
}
|
||||
return translate_reduction(SF_REDUCE_OR, false, operand);
|
||||
case 'A': // NAND
|
||||
return translate_reduction(SF_REDUCE_AND, true, operand);
|
||||
case '&':
|
||||
return translate_reduction(SF_REDUCE_AND, false, operand);
|
||||
default:
|
||||
error("No translation for unary opcode '%c'\n",
|
||||
ivl_expr_opcode(e));
|
||||
|
|
@ -284,13 +329,13 @@ static vhdl_expr *translate_binary(ivl_expr_t e)
|
|||
//result->print();
|
||||
//std::cout << "^ should be signed but is not" << std::endl;
|
||||
|
||||
result = change_signdness(result, true);
|
||||
result = change_signedness(result, true);
|
||||
}
|
||||
else if (result->get_type()->get_name() == VHDL_TYPE_SIGNED && !should_be_signed) {
|
||||
//result->print();
|
||||
//std::cout << "^ should be unsigned but is not" << std::endl;
|
||||
|
||||
result = change_signdness(result, false);
|
||||
result = change_signedness(result, false);
|
||||
}
|
||||
|
||||
int actual_width = result->get_type()->get_width();
|
||||
|
|
@ -382,6 +427,23 @@ static vhdl_expr *translate_concat(ivl_expr_t e)
|
|||
return translate_parms<vhdl_binop_expr>(concat, e);
|
||||
}
|
||||
|
||||
vhdl_expr *translate_sfunc_time(ivl_expr_t e)
|
||||
{
|
||||
cerr << "warning: no translation for time (returning 0)" << endl;
|
||||
return new vhdl_const_int(0);
|
||||
}
|
||||
|
||||
vhdl_expr *translate_sfunc(ivl_expr_t e)
|
||||
{
|
||||
const char *name = ivl_expr_name(e);
|
||||
if (strcmp(name, "$time") == 0)
|
||||
return translate_sfunc_time(e);
|
||||
else {
|
||||
error("No translation for system function %s", name);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate a VHDL expression from a Verilog expression.
|
||||
*/
|
||||
|
|
@ -397,6 +459,8 @@ vhdl_expr *translate_expr(ivl_expr_t e)
|
|||
return translate_signal(e);
|
||||
case IVL_EX_NUMBER:
|
||||
return translate_number(e);
|
||||
case IVL_EX_ULONG:
|
||||
return translate_ulong(e);
|
||||
case IVL_EX_UNARY:
|
||||
return translate_unary(e);
|
||||
case IVL_EX_BINARY:
|
||||
|
|
@ -409,6 +473,8 @@ vhdl_expr *translate_expr(ivl_expr_t e)
|
|||
return translate_ternary(e);
|
||||
case IVL_EX_CONCAT:
|
||||
return translate_concat(e);
|
||||
case IVL_EX_SFUNC:
|
||||
return translate_sfunc(e);
|
||||
default:
|
||||
error("No VHDL translation for expression at %s:%d (type = %d)",
|
||||
ivl_expr_file(e), ivl_expr_lineno(e), type);
|
||||
|
|
|
|||
284
tgt-vhdl/lpm.cc
284
tgt-vhdl/lpm.cc
|
|
@ -23,54 +23,6 @@
|
|||
#include <iostream>
|
||||
#include <cassert>
|
||||
|
||||
static vhdl_expr *draw_concat_lpm(vhdl_scope *scope, ivl_lpm_t lpm)
|
||||
{
|
||||
vhdl_type *result_type =
|
||||
vhdl_type::type_for(ivl_lpm_width(lpm), ivl_lpm_signed(lpm) != 0);
|
||||
vhdl_binop_expr *expr =
|
||||
new vhdl_binop_expr(VHDL_BINOP_CONCAT, result_type);
|
||||
|
||||
for (int i = ivl_lpm_selects(lpm) - 1; i >= 0; i--) {
|
||||
vhdl_expr *e = nexus_to_var_ref(scope, ivl_lpm_data(lpm, i));
|
||||
if (NULL == e)
|
||||
return NULL;
|
||||
|
||||
expr->add_expr(e);
|
||||
}
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
static vhdl_expr *draw_binop_lpm(vhdl_scope *scope, ivl_lpm_t lpm, vhdl_binop_t op)
|
||||
{
|
||||
vhdl_type *result_type =
|
||||
vhdl_type::type_for(ivl_lpm_width(lpm), ivl_lpm_signed(lpm) != 0);
|
||||
vhdl_binop_expr *expr = new vhdl_binop_expr(op, result_type);
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
vhdl_expr *e = nexus_to_var_ref(scope, ivl_lpm_data(lpm, i));
|
||||
if (NULL == e)
|
||||
return NULL;
|
||||
|
||||
expr->add_expr(e);
|
||||
}
|
||||
|
||||
if (op == VHDL_BINOP_MULT) {
|
||||
// Need to resize the output to the desired size,
|
||||
// as this does not happen automatically in VHDL
|
||||
|
||||
unsigned out_width = ivl_lpm_width(lpm);
|
||||
vhdl_fcall *resize =
|
||||
new vhdl_fcall("Resize", vhdl_type::nsigned(out_width));
|
||||
resize->add_expr(expr);
|
||||
resize->add_expr(new vhdl_const_int(out_width));
|
||||
|
||||
return resize;
|
||||
}
|
||||
else
|
||||
return expr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the base of a part select.
|
||||
*/
|
||||
|
|
@ -88,12 +40,105 @@ static vhdl_expr *part_select_base(vhdl_scope *scope, ivl_lpm_t lpm)
|
|||
return off->cast(&integer);
|
||||
}
|
||||
|
||||
static vhdl_expr *draw_part_select_vp_lpm(vhdl_scope *scope, ivl_lpm_t lpm)
|
||||
vhdl_var_ref *lpm_output(vhdl_scope *scope, ivl_lpm_t lpm)
|
||||
{
|
||||
vhdl_var_ref *out = nexus_to_var_ref(scope, ivl_lpm_q(lpm, 0));
|
||||
if (NULL == out) {
|
||||
vhdl_type *type =
|
||||
vhdl_type::type_for(ivl_lpm_width(lpm),
|
||||
ivl_lpm_signed(lpm) != 0);
|
||||
string name("LPM");
|
||||
name += ivl_lpm_basename(lpm);
|
||||
name += "_Out";
|
||||
|
||||
if (!scope->have_declared(name)) {
|
||||
scope->add_decl
|
||||
(new vhdl_signal_decl(name.c_str(), new vhdl_type(*type)));
|
||||
}
|
||||
|
||||
out = new vhdl_var_ref(name.c_str(), type);
|
||||
}
|
||||
|
||||
if (ivl_lpm_type(lpm) == IVL_LPM_PART_PV) {
|
||||
vhdl_expr *off = part_select_base(scope, lpm);
|
||||
assert(off);
|
||||
|
||||
out->set_slice(off, ivl_lpm_width(lpm) - 1);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
static vhdl_expr *concat_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm)
|
||||
{
|
||||
vhdl_type *result_type =
|
||||
vhdl_type::type_for(ivl_lpm_width(lpm), ivl_lpm_signed(lpm) != 0);
|
||||
vhdl_binop_expr *expr =
|
||||
new vhdl_binop_expr(VHDL_BINOP_CONCAT, result_type);
|
||||
|
||||
for (int i = ivl_lpm_selects(lpm) - 1; i >= 0; i--) {
|
||||
vhdl_expr *e = nexus_to_var_ref(scope, ivl_lpm_data(lpm, i));
|
||||
if (NULL == e)
|
||||
return NULL;
|
||||
|
||||
expr->add_expr(e);
|
||||
}
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
static vhdl_expr *binop_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm, vhdl_binop_t op)
|
||||
{
|
||||
unsigned out_width = ivl_lpm_width(lpm);
|
||||
vhdl_type *result_type =
|
||||
vhdl_type::type_for(out_width, ivl_lpm_signed(lpm) != 0);
|
||||
vhdl_binop_expr *expr = new vhdl_binop_expr(op, result_type);
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
vhdl_expr *e = nexus_to_var_ref(scope, ivl_lpm_data(lpm, i));
|
||||
if (NULL == e)
|
||||
return NULL;
|
||||
|
||||
expr->add_expr(e->cast(result_type));
|
||||
}
|
||||
|
||||
if (op == VHDL_BINOP_MULT) {
|
||||
// Need to resize the output to the desired size,
|
||||
// as this does not happen automatically in VHDL
|
||||
|
||||
vhdl_fcall *resize =
|
||||
new vhdl_fcall("Resize", vhdl_type::nsigned(out_width));
|
||||
resize->add_expr(expr);
|
||||
resize->add_expr(new vhdl_const_int(out_width));
|
||||
|
||||
return resize;
|
||||
}
|
||||
else
|
||||
return expr;
|
||||
}
|
||||
|
||||
static vhdl_expr *rel_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm, vhdl_binop_t op)
|
||||
{
|
||||
vhdl_binop_expr *expr = new vhdl_binop_expr(op, vhdl_type::boolean());
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
vhdl_expr *e = nexus_to_var_ref(scope, ivl_lpm_data(lpm, i));
|
||||
if (NULL == e)
|
||||
return NULL;
|
||||
|
||||
expr->add_expr(e);
|
||||
}
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
static vhdl_expr *part_select_vp_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm)
|
||||
{
|
||||
vhdl_var_ref *selfrom = nexus_to_var_ref(scope, ivl_lpm_data(lpm, 0));
|
||||
if (NULL == selfrom)
|
||||
return NULL;
|
||||
|
||||
|
||||
vhdl_expr *off = part_select_base(scope, lpm);;
|
||||
if (NULL == off)
|
||||
return NULL;
|
||||
|
|
@ -102,28 +147,16 @@ static vhdl_expr *draw_part_select_vp_lpm(vhdl_scope *scope, ivl_lpm_t lpm)
|
|||
return selfrom;
|
||||
}
|
||||
|
||||
static int draw_part_select_pv_lpm(vhdl_arch *arch, ivl_lpm_t lpm)
|
||||
{
|
||||
vhdl_var_ref *selfrom = nexus_to_var_ref(arch->get_scope(), ivl_lpm_data(lpm, 0));
|
||||
if (NULL == selfrom)
|
||||
return 1;
|
||||
|
||||
vhdl_expr *off = part_select_base(arch->get_scope(), lpm);;
|
||||
if (NULL == off)
|
||||
return 1;
|
||||
|
||||
vhdl_var_ref *out = nexus_to_var_ref(arch->get_scope(), ivl_lpm_q(lpm, 0));
|
||||
if (NULL == out)
|
||||
return 1;
|
||||
|
||||
out->set_slice(off, ivl_lpm_width(lpm) - 1);
|
||||
arch->add_stmt(new vhdl_cassign_stmt(out, selfrom));
|
||||
return 0;
|
||||
static vhdl_expr *part_select_pv_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm)
|
||||
{
|
||||
return nexus_to_var_ref(scope, ivl_lpm_data(lpm, 0));
|
||||
}
|
||||
|
||||
static vhdl_expr *draw_ufunc_lpm(vhdl_scope *scope, ivl_lpm_t lpm)
|
||||
static vhdl_expr *ufunc_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm)
|
||||
{
|
||||
vhdl_fcall *fcall = new vhdl_fcall(ivl_lpm_basename(lpm), NULL);
|
||||
ivl_scope_t f_scope = ivl_lpm_define(lpm);
|
||||
vhdl_fcall *fcall = new vhdl_fcall(ivl_scope_basename(f_scope), NULL);
|
||||
|
||||
for (unsigned i = 0; i < ivl_lpm_size(lpm); i++) {
|
||||
vhdl_var_ref *ref = nexus_to_var_ref(scope, ivl_lpm_data(lpm, i));
|
||||
|
|
@ -136,16 +169,19 @@ static vhdl_expr *draw_ufunc_lpm(vhdl_scope *scope, ivl_lpm_t lpm)
|
|||
return fcall;
|
||||
}
|
||||
|
||||
static vhdl_expr *draw_reduction_lpm(vhdl_scope *scope, ivl_lpm_t lpm,
|
||||
const char *rfunc, bool invert)
|
||||
static vhdl_expr *reduction_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm,
|
||||
support_function_t f, bool invert)
|
||||
{
|
||||
vhdl_fcall *fcall = new vhdl_fcall(rfunc, vhdl_type::std_logic());
|
||||
require_support_function(f);
|
||||
vhdl_fcall *fcall = new vhdl_fcall(support_function::function_name(f),
|
||||
vhdl_type::std_logic());
|
||||
|
||||
vhdl_var_ref *ref = nexus_to_var_ref(scope, ivl_lpm_data(lpm, 0));
|
||||
if (NULL == ref)
|
||||
return NULL;
|
||||
|
||||
fcall->add_expr(ref);
|
||||
|
||||
vhdl_type std_logic_vector(VHDL_TYPE_STD_LOGIC_VECTOR);
|
||||
fcall->add_expr(ref->cast(&std_logic_vector));
|
||||
|
||||
if (invert)
|
||||
return new vhdl_unaryop_expr
|
||||
|
|
@ -154,7 +190,7 @@ static vhdl_expr *draw_reduction_lpm(vhdl_scope *scope, ivl_lpm_t lpm,
|
|||
return fcall;
|
||||
}
|
||||
|
||||
static vhdl_expr *draw_sign_extend_lpm(vhdl_scope *scope, ivl_lpm_t lpm)
|
||||
static vhdl_expr *sign_extend_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm)
|
||||
{
|
||||
vhdl_expr *ref = nexus_to_var_ref(scope, ivl_lpm_data(lpm, 0));
|
||||
if (ref)
|
||||
|
|
@ -163,35 +199,88 @@ static vhdl_expr *draw_sign_extend_lpm(vhdl_scope *scope, ivl_lpm_t lpm)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
vhdl_expr *lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm)
|
||||
static vhdl_expr *array_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm)
|
||||
{
|
||||
ivl_signal_t array = ivl_lpm_array(lpm);
|
||||
if (!seen_signal_before(array))
|
||||
return NULL;
|
||||
|
||||
const char *renamed = get_renamed_signal(array).c_str();
|
||||
|
||||
vhdl_decl *adecl = scope->get_decl(renamed);
|
||||
assert(adecl);
|
||||
|
||||
vhdl_type *atype = new vhdl_type(*adecl->get_type());
|
||||
|
||||
vhdl_expr *select = nexus_to_var_ref(scope, ivl_lpm_select(lpm));
|
||||
if (NULL == select)
|
||||
return NULL;
|
||||
|
||||
vhdl_var_ref *ref = new vhdl_var_ref(renamed, atype);
|
||||
vhdl_type integer(VHDL_TYPE_INTEGER);
|
||||
ref->set_slice(select->cast(&integer));
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
||||
static vhdl_expr *shift_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm,
|
||||
vhdl_binop_t shift_op)
|
||||
{
|
||||
vhdl_expr *lhs = nexus_to_var_ref(scope, ivl_lpm_data(lpm, 0));
|
||||
vhdl_expr *rhs = nexus_to_var_ref(scope, ivl_lpm_data(lpm, 1));
|
||||
if (!lhs || !rhs)
|
||||
return NULL;
|
||||
|
||||
// The RHS must be an integer
|
||||
vhdl_type integer(VHDL_TYPE_INTEGER);
|
||||
vhdl_expr *r_cast = rhs->cast(&integer);
|
||||
|
||||
vhdl_type *rtype = new vhdl_type(*lhs->get_type());
|
||||
return new vhdl_binop_expr(lhs, shift_op, r_cast, rtype);
|
||||
}
|
||||
|
||||
static vhdl_expr *lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm)
|
||||
{
|
||||
switch (ivl_lpm_type(lpm)) {
|
||||
case IVL_LPM_ADD:
|
||||
return draw_binop_lpm(scope, lpm, VHDL_BINOP_ADD);
|
||||
return binop_lpm_to_expr(scope, lpm, VHDL_BINOP_ADD);
|
||||
case IVL_LPM_SUB:
|
||||
return draw_binop_lpm(scope, lpm, VHDL_BINOP_SUB);
|
||||
return binop_lpm_to_expr(scope, lpm, VHDL_BINOP_SUB);
|
||||
case IVL_LPM_MULT:
|
||||
return draw_binop_lpm(scope, lpm, VHDL_BINOP_MULT);
|
||||
return binop_lpm_to_expr(scope, lpm, VHDL_BINOP_MULT);
|
||||
case IVL_LPM_CONCAT:
|
||||
return draw_concat_lpm(scope, lpm);
|
||||
return concat_lpm_to_expr(scope, lpm);
|
||||
case IVL_LPM_CMP_GE:
|
||||
return rel_lpm_to_expr(scope, lpm, VHDL_BINOP_GEQ);
|
||||
case IVL_LPM_CMP_EQ:
|
||||
case IVL_LPM_CMP_EEQ:
|
||||
return rel_lpm_to_expr(scope, lpm, VHDL_BINOP_EQ);
|
||||
case IVL_LPM_PART_VP:
|
||||
return draw_part_select_vp_lpm(scope, lpm);
|
||||
return part_select_vp_lpm_to_expr(scope, lpm);
|
||||
case IVL_LPM_PART_PV:
|
||||
return part_select_pv_lpm_to_expr(scope, lpm);
|
||||
case IVL_LPM_UFUNC:
|
||||
return draw_ufunc_lpm(scope, lpm);
|
||||
return ufunc_lpm_to_expr(scope, lpm);
|
||||
case IVL_LPM_RE_AND:
|
||||
return draw_reduction_lpm(scope, lpm, "Reduce_AND", false);
|
||||
return reduction_lpm_to_expr(scope, lpm, SF_REDUCE_AND, false);
|
||||
case IVL_LPM_RE_NAND:
|
||||
return draw_reduction_lpm(scope, lpm, "Reduce_AND", true);
|
||||
return reduction_lpm_to_expr(scope, lpm, SF_REDUCE_AND, true);
|
||||
case IVL_LPM_RE_NOR:
|
||||
return draw_reduction_lpm(scope, lpm, "Reduce_OR", true);
|
||||
return reduction_lpm_to_expr(scope, lpm, SF_REDUCE_OR, true);
|
||||
case IVL_LPM_RE_OR:
|
||||
return draw_reduction_lpm(scope, lpm, "Reduce_OR", false);
|
||||
return reduction_lpm_to_expr(scope, lpm, SF_REDUCE_OR, false);
|
||||
case IVL_LPM_RE_XOR:
|
||||
return draw_reduction_lpm(scope, lpm, "Reduce_XOR", false);
|
||||
return reduction_lpm_to_expr(scope, lpm, SF_REDUCE_XOR, false);
|
||||
case IVL_LPM_RE_XNOR:
|
||||
return draw_reduction_lpm(scope, lpm, "Reduce_XNOR", false);
|
||||
return reduction_lpm_to_expr(scope, lpm, SF_REDUCE_XOR, false);
|
||||
case IVL_LPM_SIGN_EXT:
|
||||
return draw_sign_extend_lpm(scope, lpm);
|
||||
return sign_extend_lpm_to_expr(scope, lpm);
|
||||
case IVL_LPM_ARRAY:
|
||||
return array_lpm_to_expr(scope, lpm);
|
||||
case IVL_LPM_SHIFTL:
|
||||
return shift_lpm_to_expr(scope, lpm, VHDL_BINOP_SL);
|
||||
case IVL_LPM_SHIFTR:
|
||||
return shift_lpm_to_expr(scope, lpm, VHDL_BINOP_SR);
|
||||
default:
|
||||
error("Unsupported LPM type: %d", ivl_lpm_type(lpm));
|
||||
return NULL;
|
||||
|
|
@ -200,18 +289,13 @@ vhdl_expr *lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm)
|
|||
|
||||
int draw_lpm(vhdl_arch *arch, ivl_lpm_t lpm)
|
||||
{
|
||||
if (ivl_lpm_type(lpm) == IVL_LPM_PART_PV)
|
||||
return draw_part_select_pv_lpm(arch, lpm);
|
||||
else {
|
||||
vhdl_expr *f = lpm_to_expr(arch->get_scope(), lpm);
|
||||
if (NULL == f)
|
||||
return 1;
|
||||
|
||||
vhdl_var_ref *out = nexus_to_var_ref(arch->get_scope(), ivl_lpm_q(lpm, 0));
|
||||
if (out)
|
||||
arch->add_stmt(new vhdl_cassign_stmt(out, f));
|
||||
|
||||
vhdl_expr *f = lpm_to_expr(arch->get_scope(), lpm);
|
||||
if (NULL == f)
|
||||
return 0;
|
||||
}
|
||||
|
||||
vhdl_var_ref *out = lpm_output(arch->get_scope(), lpm);
|
||||
arch->add_stmt(new vhdl_cassign_stmt(out, f));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,120 +24,6 @@
|
|||
#include <iostream>
|
||||
#include <cassert>
|
||||
#include <sstream>
|
||||
#include <map>
|
||||
|
||||
/*
|
||||
* Implementing blocking assignment is a little tricky since
|
||||
* the semantics are a little different to VHDL:
|
||||
*
|
||||
* In Verilog a blocking assignment (=) can be used anywhere
|
||||
* non-blocking assignment (<=) can be. In VHDL blocking
|
||||
* assignment (:=) can only be used with variables, and
|
||||
* non-blocking assignment (<=) can only be used with signals.
|
||||
* All Verilog variables are translated into signals in the
|
||||
* VHDL architecture. This means we cannot use the VHDL :=
|
||||
* operator directly. Furthermore, VHDL variables can only
|
||||
* be declared within processes, so it wouldn't help to
|
||||
* make all Verilog variables VHDL variables.
|
||||
*
|
||||
* The solution is to generate a VHDL variable in a process
|
||||
* whenever a blocking assignment is made to a signal. The
|
||||
* assignment is made to this variable instead, and
|
||||
* g_assign_vars below remembers the temporary variables
|
||||
* that have been generated. Any subsequent blocking assignments
|
||||
* are made to the same variable. At either the end of the
|
||||
* process or a `wait' statement, the temporaries are assigned
|
||||
* back to the signals, and the temporaries are forgotten.
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* initial begin
|
||||
* a = 5;
|
||||
* b = a + 3;
|
||||
* end
|
||||
*
|
||||
* Is translated to:
|
||||
*
|
||||
* process is
|
||||
* variable a_Var : Some_Type;
|
||||
* variable b_Var : Some_Type;
|
||||
* begin
|
||||
* a_Var := 5;
|
||||
* b_Var := a_Var + 3;
|
||||
* a <= a_Var;
|
||||
* b <= b_Var;
|
||||
* end process;
|
||||
*/
|
||||
typedef std::map<std::string, ivl_signal_t> var_temp_set_t;
|
||||
static var_temp_set_t g_assign_vars;
|
||||
|
||||
/*
|
||||
* Called whenever a blocking assignment is made to sig.
|
||||
*/
|
||||
void blocking_assign_to(vhdl_procedural *proc, ivl_signal_t sig)
|
||||
{
|
||||
std::string var(get_renamed_signal(sig));
|
||||
std::string tmpname(var + "_Var");
|
||||
|
||||
if (g_assign_vars.find(var) == g_assign_vars.end()) {
|
||||
// This is the first time a non-blocking assignment
|
||||
// has been made to this signal: create a variable
|
||||
// to shadow it.
|
||||
if (!proc->get_scope()->have_declared(tmpname)) {
|
||||
vhdl_decl *decl = proc->get_scope()->get_decl(var);
|
||||
assert(decl);
|
||||
vhdl_type *type = new vhdl_type(*decl->get_type());
|
||||
|
||||
proc->get_scope()->add_decl(new vhdl_var_decl(tmpname.c_str(), type));
|
||||
}
|
||||
|
||||
rename_signal(sig, tmpname);
|
||||
g_assign_vars[tmpname] = sig;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Assign all _Var variables to the corresponding signals. This makes
|
||||
* the new values visible outside the current process. This should be
|
||||
* called before any `wait' statement or the end of the process.
|
||||
*/
|
||||
void draw_blocking_assigns(vhdl_procedural *proc, stmt_container *container)
|
||||
{
|
||||
var_temp_set_t::const_iterator it;
|
||||
for (it = g_assign_vars.begin(); it != g_assign_vars.end(); ++it) {
|
||||
std::string stripped(strip_var((*it).first));
|
||||
|
||||
vhdl_decl *decl = proc->get_scope()->get_decl(stripped);
|
||||
assert(decl);
|
||||
vhdl_type *type = new vhdl_type(*decl->get_type());
|
||||
|
||||
vhdl_var_ref *lhs = new vhdl_var_ref(stripped.c_str(), NULL);
|
||||
vhdl_expr *rhs = new vhdl_var_ref((*it).first.c_str(), type);
|
||||
|
||||
container->add_stmt(new vhdl_nbassign_stmt(lhs, rhs));
|
||||
|
||||
// Undo the renaming (since the temporary is no longer needed)
|
||||
rename_signal((*it).second, stripped);
|
||||
}
|
||||
|
||||
// If this this wait is within e.g. an `if' statement then
|
||||
// we cannot correctly clear the variables list here (since
|
||||
// they might not be assigned on another path)
|
||||
if (container == proc->get_container())
|
||||
g_assign_vars.clear();
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove _Var from the end of a string, if it is present.
|
||||
*/
|
||||
std::string strip_var(const std::string &str)
|
||||
{
|
||||
std::string result(str);
|
||||
size_t pos = result.find("_Var");
|
||||
if (pos != std::string::npos)
|
||||
result.erase(pos, 4);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a Verilog process to VHDL and add it to the architecture
|
||||
|
|
@ -145,6 +31,8 @@ std::string strip_var(const std::string &str)
|
|||
*/
|
||||
static int generate_vhdl_process(vhdl_entity *ent, ivl_process_t proc)
|
||||
{
|
||||
set_active_entity(ent);
|
||||
|
||||
// Create a new process and store it in the entity's
|
||||
// architecture. This needs to be done first or the
|
||||
// parent link won't be valid (and draw_stmt needs this
|
||||
|
|
@ -154,18 +42,14 @@ static int generate_vhdl_process(vhdl_entity *ent, ivl_process_t proc)
|
|||
|
||||
// If this is an initial process, push signal initialisation
|
||||
// into the declarations
|
||||
if (ivl_process_type(proc) == IVL_PR_INITIAL)
|
||||
vhdl_proc->get_scope()->set_initializing(true);
|
||||
vhdl_proc->get_scope()->set_initializing
|
||||
(ivl_process_type(proc) == IVL_PR_INITIAL);
|
||||
|
||||
ivl_statement_t stmt = ivl_process_stmt(proc);
|
||||
int rc = draw_stmt(vhdl_proc, vhdl_proc->get_container(), stmt);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
// Output any remaning blocking assignments
|
||||
draw_blocking_assigns(vhdl_proc, vhdl_proc->get_container());
|
||||
g_assign_vars.clear();
|
||||
|
||||
// Initial processes are translated to VHDL processes with
|
||||
// no sensitivity list and and indefinite wait statement at
|
||||
// the end
|
||||
|
|
|
|||
|
|
@ -28,40 +28,39 @@
|
|||
static vhdl_expr *translate_logic(vhdl_scope *scope, ivl_net_logic_t log);
|
||||
static std::string make_safe_name(ivl_signal_t sig);
|
||||
|
||||
/*
|
||||
* Given a nexus find a constant value in it that can be used
|
||||
* as an initial signal value.
|
||||
*/
|
||||
static vhdl_expr *nexus_to_const(ivl_nexus_t nexus)
|
||||
{
|
||||
int nptrs = ivl_nexus_ptrs(nexus);
|
||||
for (int i = 0; i < nptrs; i++) {
|
||||
ivl_nexus_ptr_t nexus_ptr = ivl_nexus_ptr(nexus, i);
|
||||
static vhdl_entity *g_active_entity = NULL;
|
||||
|
||||
ivl_net_const_t con;
|
||||
if ((con = ivl_nexus_ptr_con(nexus_ptr))) {
|
||||
if (ivl_const_width(con) == 1)
|
||||
return new vhdl_const_bit(ivl_const_bits(con)[0]);
|
||||
else
|
||||
return new vhdl_const_bits
|
||||
(ivl_const_bits(con), ivl_const_width(con),
|
||||
ivl_const_signed(con) != 0);
|
||||
}
|
||||
else {
|
||||
// Ignore other types of nexus pointer
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
vhdl_entity *get_active_entity()
|
||||
{
|
||||
return g_active_entity;
|
||||
}
|
||||
|
||||
void set_active_entity(vhdl_entity *ent)
|
||||
{
|
||||
g_active_entity = ent;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Given a nexus and an architecture scope, find the first signal
|
||||
* that is connected to the nexus, if there is one. Never return
|
||||
* a reference to 'ignore' if it is found in the nexus.
|
||||
* The types of VHDL object a nexus can be converted into.
|
||||
*/
|
||||
enum vhdl_nexus_obj_t {
|
||||
NEXUS_TO_VAR_REF = 1<<0,
|
||||
NEXUS_TO_CONST = 1<<1,
|
||||
NEXUS_TO_OTHER = 1<<2,
|
||||
};
|
||||
#define NEXUS_TO_ANY \
|
||||
NEXUS_TO_VAR_REF | NEXUS_TO_CONST | NEXUS_TO_OTHER
|
||||
|
||||
/*
|
||||
* Given a nexus, generate a VHDL expression object to represent it.
|
||||
* The allowed VHDL expression types are given by vhdl_nexus_obj_t.
|
||||
*
|
||||
* If a vhdl_var_ref is returned, the reference is guaranteed to be
|
||||
* to a signal in arch_scope or its parent (the entity's ports).
|
||||
*/
|
||||
static vhdl_expr *nexus_to_expr(vhdl_scope *arch_scope, ivl_nexus_t nexus,
|
||||
ivl_signal_t ignore = NULL)
|
||||
int allowed = NEXUS_TO_ANY)
|
||||
{
|
||||
int nptrs = ivl_nexus_ptrs(nexus);
|
||||
for (int i = 0; i < nptrs; i++) {
|
||||
|
|
@ -70,61 +69,58 @@ static vhdl_expr *nexus_to_expr(vhdl_scope *arch_scope, ivl_nexus_t nexus,
|
|||
ivl_signal_t sig;
|
||||
ivl_net_logic_t log;
|
||||
ivl_lpm_t lpm;
|
||||
if ((sig = ivl_nexus_ptr_sig(nexus_ptr))) {
|
||||
if (!seen_signal_before(sig) || sig == ignore)
|
||||
ivl_net_const_t con;
|
||||
ivl_switch_t sw;
|
||||
if ((allowed & NEXUS_TO_VAR_REF) &&
|
||||
(sig = ivl_nexus_ptr_sig(nexus_ptr))) {
|
||||
if (!seen_signal_before(sig) ||
|
||||
(find_scope_for_signal(sig) != arch_scope
|
||||
&& find_scope_for_signal(sig) != arch_scope->get_parent()))
|
||||
continue;
|
||||
|
||||
|
||||
const char *signame = get_renamed_signal(sig).c_str();
|
||||
|
||||
vhdl_decl *decl = arch_scope->get_decl(signame);
|
||||
if (NULL == decl)
|
||||
continue; // Not in this scope
|
||||
|
||||
vhdl_type *type = new vhdl_type(*(decl->get_type()));
|
||||
return new vhdl_var_ref(signame, type);
|
||||
}
|
||||
else if ((log = ivl_nexus_ptr_log(nexus_ptr))) {
|
||||
else if ((allowed & NEXUS_TO_OTHER) &&
|
||||
(log = ivl_nexus_ptr_log(nexus_ptr))) {
|
||||
return translate_logic(arch_scope, log);
|
||||
}
|
||||
else if ((lpm = ivl_nexus_ptr_lpm(nexus_ptr))) {
|
||||
vhdl_expr *e = lpm_to_expr(arch_scope, lpm);
|
||||
if (e)
|
||||
return e;
|
||||
else if ((allowed & NEXUS_TO_OTHER) &&
|
||||
(lpm = ivl_nexus_ptr_lpm(nexus_ptr))) {
|
||||
return lpm_output(arch_scope, lpm);
|
||||
}
|
||||
else if ((allowed & NEXUS_TO_CONST) &&
|
||||
(con = ivl_nexus_ptr_con(nexus_ptr))) {
|
||||
if (ivl_const_width(con) == 1)
|
||||
return new vhdl_const_bit(ivl_const_bits(con)[0]);
|
||||
else
|
||||
return new vhdl_const_bits
|
||||
(ivl_const_bits(con), ivl_const_width(con),
|
||||
ivl_const_signed(con) != 0);
|
||||
}
|
||||
else if ((allowed & NEXUS_TO_OTHER) &&
|
||||
(sw = ivl_nexus_ptr_switch(nexus_ptr))) {
|
||||
std::cout << "SWITCH type=" << ivl_switch_type(sw) << std::endl;
|
||||
assert(false);
|
||||
}
|
||||
else {
|
||||
// Ignore other types of nexus pointer
|
||||
}
|
||||
}
|
||||
|
||||
assert(false);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Guarantees the result will never be NULL.
|
||||
*/
|
||||
vhdl_var_ref *nexus_to_var_ref(vhdl_scope *arch_scope, ivl_nexus_t nexus)
|
||||
{
|
||||
int nptrs = ivl_nexus_ptrs(nexus);
|
||||
for (int i = 0; i < nptrs; i++) {
|
||||
ivl_nexus_ptr_t nexus_ptr = ivl_nexus_ptr(nexus, i);
|
||||
|
||||
ivl_signal_t sig;
|
||||
if ((sig = ivl_nexus_ptr_sig(nexus_ptr))) {
|
||||
if (!seen_signal_before(sig))
|
||||
continue;
|
||||
|
||||
const char *signame = get_renamed_signal(sig).c_str();
|
||||
|
||||
vhdl_decl *decl = arch_scope->get_decl(signame);
|
||||
if (NULL == decl)
|
||||
continue; // Not in this scope
|
||||
|
||||
vhdl_type *type = new vhdl_type(*(decl->get_type()));
|
||||
return new vhdl_var_ref(signame, type);
|
||||
}
|
||||
else {
|
||||
// Ignore other types of nexus pointer
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return dynamic_cast<vhdl_var_ref*>
|
||||
(nexus_to_expr(arch_scope, nexus, NEXUS_TO_VAR_REF));
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -160,6 +156,42 @@ static vhdl_expr *input_to_expr(vhdl_scope *scope, vhdl_unaryop_t op,
|
|||
return new vhdl_unaryop_expr(op, operand, vhdl_type::std_logic());
|
||||
}
|
||||
|
||||
static void bufif_logic(vhdl_arch *arch, ivl_net_logic_t log, bool if0)
|
||||
{
|
||||
ivl_nexus_t output = ivl_logic_pin(log, 0);
|
||||
vhdl_var_ref *lhs = nexus_to_var_ref(arch->get_scope(), output);
|
||||
assert(lhs);
|
||||
|
||||
vhdl_expr *val = nexus_to_expr(arch->get_scope(), ivl_logic_pin(log, 1));
|
||||
assert(val);
|
||||
|
||||
vhdl_expr *sel = nexus_to_expr(arch->get_scope(), ivl_logic_pin(log, 2));
|
||||
assert(val);
|
||||
|
||||
vhdl_expr *on = new vhdl_const_bit(if0 ? '0' : '1');
|
||||
vhdl_expr *cmp = new vhdl_binop_expr(sel, VHDL_BINOP_EQ, on, NULL);
|
||||
|
||||
ivl_signal_t sig = find_signal_named(lhs->get_name(), arch->get_scope());
|
||||
char zbit;
|
||||
switch (ivl_signal_type(sig)) {
|
||||
case IVL_SIT_TRI0:
|
||||
zbit = '0';
|
||||
break;
|
||||
case IVL_SIT_TRI1:
|
||||
zbit = '1';
|
||||
break;
|
||||
case IVL_SIT_TRI:
|
||||
default:
|
||||
zbit = 'Z';
|
||||
}
|
||||
|
||||
vhdl_const_bit *z = new vhdl_const_bit(zbit);
|
||||
vhdl_cassign_stmt *cass = new vhdl_cassign_stmt(lhs, z);
|
||||
cass->add_condition(val, cmp);
|
||||
|
||||
arch->add_stmt(cass);
|
||||
}
|
||||
|
||||
static vhdl_expr *translate_logic(vhdl_scope *scope, ivl_net_logic_t log)
|
||||
{
|
||||
switch (ivl_logic_type(log)) {
|
||||
|
|
@ -174,8 +206,12 @@ static vhdl_expr *translate_logic(vhdl_scope *scope, ivl_net_logic_t log)
|
|||
case IVL_LO_BUF:
|
||||
case IVL_LO_BUFZ:
|
||||
return nexus_to_expr(scope, ivl_logic_pin(log, 1));
|
||||
case IVL_LO_PULLUP:
|
||||
return new vhdl_const_bit('1');
|
||||
case IVL_LO_PULLDOWN:
|
||||
return new vhdl_const_bit('0');
|
||||
default:
|
||||
error("Don't know how to translate logic type = %d",
|
||||
error("Don't know how to translate logic type = %d to expression",
|
||||
ivl_logic_type(log));
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -191,16 +227,26 @@ static void declare_logic(vhdl_arch *arch, ivl_scope_t scope)
|
|||
for (int i = 0; i < nlogs; i++) {
|
||||
ivl_net_logic_t log = ivl_scope_log(scope, i);
|
||||
|
||||
// The output is always pin zero
|
||||
ivl_nexus_t output = ivl_logic_pin(log, 0);
|
||||
vhdl_var_ref *lhs =
|
||||
dynamic_cast<vhdl_var_ref*>(nexus_to_expr(arch->get_scope(), output));
|
||||
if (NULL == lhs)
|
||||
continue; // Not suitable for continuous assignment
|
||||
|
||||
vhdl_expr *rhs = translate_logic(arch->get_scope(), log);
|
||||
|
||||
arch->add_stmt(new vhdl_cassign_stmt(lhs, rhs));
|
||||
switch (ivl_logic_type(log)) {
|
||||
case IVL_LO_BUFIF0:
|
||||
bufif_logic(arch, log, true);
|
||||
break;
|
||||
case IVL_LO_BUFIF1:
|
||||
bufif_logic(arch, log, false);
|
||||
break;
|
||||
default:
|
||||
{
|
||||
// The output is always pin zero
|
||||
ivl_nexus_t output = ivl_logic_pin(log, 0);
|
||||
vhdl_var_ref *lhs =
|
||||
dynamic_cast<vhdl_var_ref*>(nexus_to_expr(arch->get_scope(), output));
|
||||
if (NULL == lhs)
|
||||
continue; // Not suitable for continuous assignment
|
||||
|
||||
vhdl_expr *rhs = translate_logic(arch->get_scope(), log);
|
||||
arch->add_stmt(new vhdl_cassign_stmt(lhs, rhs));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -227,20 +273,6 @@ static std::string make_safe_name(ivl_signal_t sig)
|
|||
return name;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a VHDL type for a Verilog signal.
|
||||
*/
|
||||
static vhdl_type *get_signal_type(ivl_signal_t sig)
|
||||
{
|
||||
int width = ivl_signal_width(sig);
|
||||
if (width == 1)
|
||||
return vhdl_type::std_logic();
|
||||
else if (ivl_signal_signed(sig))
|
||||
return vhdl_type::nsigned(width);
|
||||
else
|
||||
return vhdl_type::nunsigned(width);
|
||||
}
|
||||
|
||||
/*
|
||||
* Declare all signals and ports for a scope.
|
||||
*/
|
||||
|
|
@ -251,12 +283,39 @@ static void declare_signals(vhdl_entity *ent, ivl_scope_t scope)
|
|||
ivl_signal_t sig = ivl_scope_sig(scope, i);
|
||||
remember_signal(sig, ent->get_arch()->get_scope());
|
||||
|
||||
vhdl_type *sig_type =
|
||||
vhdl_type::type_for(ivl_signal_width(sig), ivl_signal_signed(sig) != 0);
|
||||
|
||||
std::string name = make_safe_name(sig);
|
||||
string name(make_safe_name(sig));
|
||||
rename_signal(sig, name);
|
||||
|
||||
vhdl_type *sig_type;
|
||||
unsigned dimensions = ivl_signal_dimensions(sig);
|
||||
if (dimensions > 0) {
|
||||
// Arrays are implemented by generating a separate type
|
||||
// declaration for each array, and then declaring a
|
||||
// signal of that type
|
||||
|
||||
if (dimensions > 1) {
|
||||
error("> 1 dimension arrays not implemented yet");
|
||||
return;
|
||||
}
|
||||
|
||||
string type_name = name + "_Type";
|
||||
vhdl_type *base_type =
|
||||
vhdl_type::type_for(ivl_signal_width(sig), ivl_signal_signed(sig) != 0);
|
||||
|
||||
int lsb = ivl_signal_array_base(sig);
|
||||
int msb = lsb + ivl_signal_array_count(sig) - 1;
|
||||
|
||||
vhdl_type *array_type =
|
||||
vhdl_type::array_of(base_type, type_name, msb, lsb);
|
||||
vhdl_decl *array_decl = new vhdl_type_decl(type_name.c_str(), array_type);
|
||||
ent->get_arch()->get_scope()->add_decl(array_decl);
|
||||
|
||||
sig_type = new vhdl_type(*array_type);
|
||||
}
|
||||
else
|
||||
sig_type =
|
||||
vhdl_type::type_for(ivl_signal_width(sig), ivl_signal_signed(sig) != 0);
|
||||
|
||||
ivl_signal_port_t mode = ivl_signal_port(sig);
|
||||
switch (mode) {
|
||||
case IVL_SIP_NONE:
|
||||
|
|
@ -266,7 +325,9 @@ static void declare_signals(vhdl_entity *ent, ivl_scope_t scope)
|
|||
// A local signal can have a constant initializer in VHDL
|
||||
// This may be found in the signal's nexus
|
||||
// TODO: Make this work for multiple words
|
||||
vhdl_expr *init = nexus_to_const(ivl_signal_nex(sig, 0));
|
||||
vhdl_expr *init =
|
||||
nexus_to_expr(ent->get_scope(), ivl_signal_nex(sig, 0),
|
||||
NEXUS_TO_CONST);
|
||||
if (init != NULL)
|
||||
decl->set_initial(init);
|
||||
|
||||
|
|
@ -278,8 +339,23 @@ static void declare_signals(vhdl_entity *ent, ivl_scope_t scope)
|
|||
(new vhdl_port_decl(name.c_str(), sig_type, VHDL_PORT_IN));
|
||||
break;
|
||||
case IVL_SIP_OUTPUT:
|
||||
ent->get_scope()->add_decl
|
||||
(new vhdl_port_decl(name.c_str(), sig_type, VHDL_PORT_OUT));
|
||||
{
|
||||
vhdl_port_decl *decl =
|
||||
new vhdl_port_decl(name.c_str(), sig_type, VHDL_PORT_OUT);
|
||||
|
||||
// Check for constant values
|
||||
// For outputs these must be continuous assigns of
|
||||
// the constant to the port
|
||||
vhdl_expr *init =
|
||||
nexus_to_expr(ent->get_scope(), ivl_signal_nex(sig, 0),
|
||||
NEXUS_TO_CONST);
|
||||
if (init != NULL) {
|
||||
vhdl_var_ref *ref = new vhdl_var_ref(name.c_str(), NULL);
|
||||
ent->get_arch()->add_stmt(new vhdl_cassign_stmt(ref, init));
|
||||
}
|
||||
|
||||
ent->get_scope()->add_decl(decl);
|
||||
}
|
||||
|
||||
if (ivl_signal_type(sig) == IVL_SIT_REG) {
|
||||
// A registered output
|
||||
|
|
@ -292,7 +368,8 @@ static void declare_signals(vhdl_entity *ent, ivl_scope_t scope)
|
|||
rename_signal(sig, newname.c_str());
|
||||
|
||||
vhdl_type *reg_type = new vhdl_type(*sig_type);
|
||||
ent->get_arch()->get_scope()->add_decl(new vhdl_signal_decl(newname.c_str(), reg_type));
|
||||
ent->get_arch()->get_scope()->add_decl
|
||||
(new vhdl_signal_decl(newname.c_str(), reg_type));
|
||||
|
||||
// Create a concurrent assignment statement to
|
||||
// connect the register to the output
|
||||
|
|
@ -319,8 +396,9 @@ static void declare_lpm(vhdl_arch *arch, ivl_scope_t scope)
|
|||
{
|
||||
int nlpms = ivl_scope_lpms(scope);
|
||||
for (int i = 0; i < nlpms; i++) {
|
||||
if (draw_lpm(arch, ivl_scope_lpm(scope, i)) != 0)
|
||||
error("Failed to translate LPM");
|
||||
ivl_lpm_t lpm = ivl_scope_lpm(scope, i);
|
||||
if (draw_lpm(arch, lpm) != 0)
|
||||
error("Failed to translate LPM %s", ivl_lpm_name(lpm));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -344,6 +422,8 @@ static vhdl_entity *create_entity_for(ivl_scope_t scope)
|
|||
// retain a 1-to-1 mapping of scope to VHDL element)
|
||||
vhdl_arch *arch = new vhdl_arch(tname, "FromVerilog");
|
||||
vhdl_entity *ent = new vhdl_entity(tname, derived_from, arch);
|
||||
|
||||
set_active_entity(ent);
|
||||
|
||||
// Locate all the signals in this module and add them to
|
||||
// the architecture
|
||||
|
|
@ -372,11 +452,12 @@ static vhdl_entity *create_entity_for(ivl_scope_t scope)
|
|||
*/
|
||||
static void map_signal(ivl_signal_t to, vhdl_entity *parent,
|
||||
vhdl_comp_inst *inst)
|
||||
{
|
||||
{
|
||||
// TODO: Work for multiple words
|
||||
ivl_nexus_t nexus = ivl_signal_nex(to, 0);
|
||||
|
||||
vhdl_expr *to_e = nexus_to_expr(parent->get_arch()->get_scope(), nexus, to);
|
||||
vhdl_expr *to_e = nexus_to_expr(parent->get_arch()->get_scope(),
|
||||
nexus, NEXUS_TO_ANY);
|
||||
assert(to_e);
|
||||
|
||||
// The expressions in a VHDL port map must be 'globally static'
|
||||
|
|
@ -389,7 +470,49 @@ static void map_signal(ivl_signal_t to, vhdl_entity *parent,
|
|||
std::string name = make_safe_name(to);
|
||||
vhdl_var_ref *to_ref;
|
||||
if ((to_ref = dynamic_cast<vhdl_var_ref*>(to_e))) {
|
||||
inst->map_port(name.c_str(), to_ref);
|
||||
// If we're mapping an output of this entity to an output of
|
||||
// the child entity, then VHDL will not let us read the value
|
||||
// of the signal (i.e. it must pass straight through).
|
||||
// However, Verilog allows the signal to be read in the parent.
|
||||
// To get around this we create an internal signal name_Sig
|
||||
// that takes the value of the output and can be read.
|
||||
vhdl_decl *decl =
|
||||
parent->get_arch()->get_scope()->get_decl(to_ref->get_name());
|
||||
vhdl_port_decl *pdecl;
|
||||
if ((pdecl = dynamic_cast<vhdl_port_decl*>(decl))
|
||||
&& pdecl->get_mode() == VHDL_PORT_OUT) {
|
||||
|
||||
// We need to create a readable signal to shadow this output
|
||||
std::string shadow_name(to_ref->get_name());
|
||||
shadow_name += "_Sig";
|
||||
|
||||
vhdl_signal_decl *shadow =
|
||||
new vhdl_signal_decl(shadow_name.c_str(),
|
||||
new vhdl_type(*decl->get_type()));
|
||||
shadow->set_comment("Needed to make output readable");
|
||||
|
||||
parent->get_arch()->get_scope()->add_decl(shadow);
|
||||
|
||||
// Make a continuous assignment of the shadow to the output
|
||||
parent->get_arch()->add_stmt
|
||||
(new vhdl_cassign_stmt
|
||||
(to_ref, new vhdl_var_ref(shadow_name.c_str(), NULL)));
|
||||
|
||||
// Make sure any future references to this signal read the
|
||||
// shadow not the output
|
||||
ivl_signal_t sig = find_signal_named(to_ref->get_name(),
|
||||
parent->get_arch()->get_scope());
|
||||
rename_signal(sig, shadow_name);
|
||||
|
||||
// Finally map the child port to the shadow signal
|
||||
inst->map_port(name.c_str(),
|
||||
new vhdl_var_ref(shadow_name.c_str(), NULL));
|
||||
}
|
||||
else {
|
||||
// Not an output port declaration therefore we can
|
||||
// definitely read it
|
||||
inst->map_port(name.c_str(), to_ref);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Not a static expression
|
||||
|
|
@ -450,6 +573,7 @@ static int draw_module(ivl_scope_t scope, ivl_scope_t parent)
|
|||
if (NULL == ent)
|
||||
ent = create_entity_for(scope);
|
||||
assert(ent);
|
||||
set_active_entity(ent);
|
||||
|
||||
// Is this module instantiated inside another?
|
||||
if (parent != NULL) {
|
||||
|
|
@ -470,11 +594,21 @@ static int draw_module(ivl_scope_t scope, ivl_scope_t parent)
|
|||
}
|
||||
|
||||
// And an instantiation statement
|
||||
std::string inst_name(ivl_scope_basename(scope));
|
||||
string inst_name(ivl_scope_basename(scope));
|
||||
if (inst_name == ent->get_name()) {
|
||||
// Cannot have instance name the same as type in VHDL
|
||||
inst_name += "_Inst";
|
||||
}
|
||||
|
||||
// Need to replace any [ and ] characters that result
|
||||
// from generate statements
|
||||
string::size_type loc = inst_name.find('[', 0);
|
||||
if (loc != string::npos)
|
||||
inst_name.erase(loc, 1);
|
||||
|
||||
loc = inst_name.find(']', 0);
|
||||
if (loc != string::npos)
|
||||
inst_name.erase(loc, 1);
|
||||
|
||||
vhdl_comp_inst *inst =
|
||||
new vhdl_comp_inst(inst_name.c_str(), ent->get_name().c_str());
|
||||
|
|
@ -516,7 +650,9 @@ int draw_function(ivl_scope_t scope, ivl_scope_t parent)
|
|||
int nsigs = ivl_scope_sigs(scope);
|
||||
for (int i = 0; i < nsigs; i++) {
|
||||
ivl_signal_t sig = ivl_scope_sig(scope, i);
|
||||
vhdl_type *sigtype = get_signal_type(sig);
|
||||
vhdl_type *sigtype =
|
||||
vhdl_type::type_for(ivl_signal_width(sig),
|
||||
ivl_signal_signed(sig) != 0);
|
||||
|
||||
std::string signame = make_safe_name(sig);
|
||||
|
||||
|
|
|
|||
400
tgt-vhdl/stmt.cc
400
tgt-vhdl/stmt.cc
|
|
@ -102,28 +102,24 @@ static int draw_noop(vhdl_procedural *proc, stmt_container *container,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate an assignment of VHDL expr rhs to signal sig. This, unlike
|
||||
* the procedure below, is a generic routine used for more than just
|
||||
* Verilog signal assignment (e.g. it is used to expand ternary
|
||||
* expressions).
|
||||
*/
|
||||
template <class T>
|
||||
static T *make_vhdl_assignment(vhdl_procedural *proc, stmt_container *container,
|
||||
ivl_signal_t sig, vhdl_expr *rhs, bool blocking,
|
||||
vhdl_expr *base = NULL, unsigned lval_width = 0)
|
||||
static vhdl_expr *make_assign_rhs(ivl_signal_t sig, vhdl_scope *scope,
|
||||
ivl_expr_t e, vhdl_expr *base,
|
||||
int lval_width)
|
||||
{
|
||||
std::string signame(get_renamed_signal(sig));
|
||||
string signame(get_renamed_signal(sig));
|
||||
|
||||
vhdl_decl *decl = proc->get_scope()->get_decl(signame);
|
||||
vhdl_decl *decl = scope->get_decl(signame);
|
||||
assert(decl);
|
||||
|
||||
vhdl_expr *rhs = translate_expr(e);
|
||||
if (rhs == NULL)
|
||||
return rhs;
|
||||
|
||||
if (base == NULL)
|
||||
rhs = rhs->cast(decl->get_type());
|
||||
return rhs->cast(decl->get_type());
|
||||
else if (decl->get_type()->get_name() == VHDL_TYPE_ARRAY)
|
||||
return rhs->cast(decl->get_type()->get_base());
|
||||
else {
|
||||
vhdl_type integer(VHDL_TYPE_INTEGER);
|
||||
base = base->cast(&integer);
|
||||
|
||||
// Doesn't make sense to part select on something that's
|
||||
// not a vector
|
||||
vhdl_type_name_t tname = decl->get_type()->get_name();
|
||||
|
|
@ -131,81 +127,31 @@ static T *make_vhdl_assignment(vhdl_procedural *proc, stmt_container *container,
|
|||
|
||||
if (lval_width == 1) {
|
||||
vhdl_type t(VHDL_TYPE_STD_LOGIC);
|
||||
rhs = rhs->cast(&t);
|
||||
return rhs->cast(&t);
|
||||
}
|
||||
else {
|
||||
vhdl_type t(tname, lval_width);
|
||||
rhs = rhs->cast(&t);
|
||||
vhdl_type t(tname, lval_width - 1);
|
||||
return rhs->cast(&t);
|
||||
}
|
||||
}
|
||||
|
||||
bool isvar = strip_var(signame) != signame;
|
||||
}
|
||||
|
||||
// Where possible, move constant assignments into the
|
||||
// declaration as initializers. This optimisation is only
|
||||
// performed on assignments of constant values to prevent
|
||||
// ordering problems.
|
||||
|
||||
// This also has another application: If this is an `inital'
|
||||
// process and we haven't yet generated a `wait' statement then
|
||||
// moving the assignment to the initialization preserves the
|
||||
// expected Verilog behaviour: VHDL does not distinguish
|
||||
// `initial' and `always' processes so an `always' process might
|
||||
// be activatated before an `initial' process at time 0. The
|
||||
// `always' process may then use the uninitialized signal value.
|
||||
// The second test ensures that we only try to initialise
|
||||
// internal signals not ports
|
||||
if (proc->get_scope()->initializing()
|
||||
&& ivl_signal_port(sig) == IVL_SIP_NONE
|
||||
&& !decl->has_initial() && rhs->constant()
|
||||
&& container == proc->get_container() // Top-level container
|
||||
&& !isvar) {
|
||||
|
||||
decl->set_initial(rhs);
|
||||
|
||||
if (blocking && proc->get_scope()->allow_signal_assignment()) {
|
||||
// This signal may be used e.g. in a loop test so we need
|
||||
// to make a variable as well
|
||||
blocking_assign_to(proc, sig);
|
||||
|
||||
// The signal may have been renamed by the above call
|
||||
const std::string &renamed = get_renamed_signal(sig);
|
||||
|
||||
vhdl_var_ref *lval_ref = new vhdl_var_ref(renamed.c_str(), NULL);
|
||||
vhdl_var_ref *sig_ref = new vhdl_var_ref(signame.c_str(), NULL);
|
||||
|
||||
if (base)
|
||||
lval_ref->set_slice(base, lval_width-1);
|
||||
|
||||
T *a = new T(lval_ref, sig_ref);
|
||||
container->add_stmt(a);
|
||||
|
||||
return a;
|
||||
}
|
||||
static vhdl_var_ref *make_assign_lhs(ivl_signal_t sig, vhdl_scope *scope,
|
||||
vhdl_expr *base, int lval_width)
|
||||
{
|
||||
string signame(get_renamed_signal(sig));
|
||||
vhdl_decl *decl = scope->get_decl(signame);
|
||||
|
||||
vhdl_type *ltype = new vhdl_type(*decl->get_type());
|
||||
vhdl_var_ref *lval_ref = new vhdl_var_ref(signame.c_str(), ltype);
|
||||
if (base) {
|
||||
if (decl->get_type()->get_name() == VHDL_TYPE_ARRAY)
|
||||
lval_ref->set_slice(base, 0);
|
||||
else
|
||||
return NULL; // No statement need be emitted
|
||||
lval_ref->set_slice(base, lval_width - 1);
|
||||
}
|
||||
else {
|
||||
if (blocking && proc->get_scope()->allow_signal_assignment()) {
|
||||
// Remember we need to write the variable back to the
|
||||
// original signal
|
||||
blocking_assign_to(proc, sig);
|
||||
|
||||
// The signal may have been renamed by the above call
|
||||
signame = get_renamed_signal(sig);
|
||||
}
|
||||
|
||||
vhdl_type *ltype =
|
||||
new vhdl_type(*proc->get_scope()->get_decl(signame)->get_type());
|
||||
vhdl_var_ref *lval_ref = new vhdl_var_ref(signame.c_str(), ltype);
|
||||
if (base)
|
||||
lval_ref->set_slice(base, lval_width-1);
|
||||
|
||||
T *a = new T(lval_ref, rhs);
|
||||
container->add_stmt(a);
|
||||
|
||||
return a;
|
||||
}
|
||||
return lval_ref;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -213,7 +159,7 @@ static T *make_vhdl_assignment(vhdl_procedural *proc, stmt_container *container,
|
|||
*/
|
||||
template <class T>
|
||||
static T *make_assignment(vhdl_procedural *proc, stmt_container *container,
|
||||
ivl_statement_t stmt, bool blocking)
|
||||
ivl_statement_t stmt, bool blocking, vhdl_expr *after)
|
||||
{
|
||||
int nlvals = ivl_stmt_lvals(stmt);
|
||||
if (nlvals != 1) {
|
||||
|
|
@ -227,9 +173,14 @@ static T *make_assignment(vhdl_procedural *proc, stmt_container *container,
|
|||
|
||||
vhdl_expr *base = NULL;
|
||||
ivl_expr_t e_off = ivl_lval_part_off(lval);
|
||||
if (NULL == e_off)
|
||||
e_off = ivl_lval_idx(lval);
|
||||
if (e_off) {
|
||||
if ((base = translate_expr(e_off)) == NULL)
|
||||
return NULL;
|
||||
|
||||
vhdl_type integer(VHDL_TYPE_INTEGER);
|
||||
base = base->cast(&integer);
|
||||
}
|
||||
|
||||
unsigned lval_width = ivl_lval_width(lval);
|
||||
|
|
@ -238,27 +189,104 @@ static T *make_assignment(vhdl_procedural *proc, stmt_container *container,
|
|||
if (ivl_expr_type(rval) == IVL_EX_TERNARY) {
|
||||
// Expand ternary expressions into an if statement
|
||||
vhdl_expr *test = translate_expr(ivl_expr_oper1(rval));
|
||||
vhdl_expr *true_part = translate_expr(ivl_expr_oper2(rval));
|
||||
vhdl_expr *false_part = translate_expr(ivl_expr_oper3(rval));
|
||||
vhdl_expr *true_part =
|
||||
make_assign_rhs(sig, proc->get_scope(),
|
||||
ivl_expr_oper2(rval), base, lval_width);
|
||||
vhdl_expr *false_part =
|
||||
make_assign_rhs(sig, proc->get_scope(),
|
||||
ivl_expr_oper3(rval), base, lval_width);
|
||||
|
||||
if (!test || !true_part || !false_part)
|
||||
return NULL;
|
||||
|
||||
vhdl_if_stmt *vhdif = new vhdl_if_stmt(test);
|
||||
make_vhdl_assignment<T>(proc, vhdif->get_then_container(), sig,
|
||||
true_part, blocking, base, lval_width);
|
||||
make_vhdl_assignment<T>(proc, vhdif->get_else_container(), sig,
|
||||
false_part, blocking, base, lval_width);
|
||||
|
||||
// True part
|
||||
{
|
||||
vhdl_var_ref *lval_ref =
|
||||
make_assign_lhs(sig, proc->get_scope(), base, lval_width);
|
||||
|
||||
T *a = new T(lval_ref, true_part);
|
||||
vhdif->get_then_container()->add_stmt(a);
|
||||
}
|
||||
|
||||
// False part
|
||||
{
|
||||
vhdl_var_ref *lval_ref =
|
||||
make_assign_lhs(sig, proc->get_scope(), base, lval_width);
|
||||
|
||||
T *a = new T(lval_ref, false_part);
|
||||
vhdif->get_else_container()->add_stmt(a);
|
||||
}
|
||||
|
||||
container->add_stmt(vhdif);
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
vhdl_expr *rhs = translate_expr(rval);
|
||||
vhdl_expr *rhs =
|
||||
make_assign_rhs(sig, proc->get_scope(), rval, base, lval_width);
|
||||
if (NULL == rhs)
|
||||
return NULL;
|
||||
|
||||
string signame(get_renamed_signal(sig));
|
||||
vhdl_decl *decl = proc->get_scope()->get_decl(signame);
|
||||
|
||||
// Where possible, move constant assignments into the
|
||||
// declaration as initializers. This optimisation is only
|
||||
// performed on assignments of constant values to prevent
|
||||
// ordering problems.
|
||||
|
||||
return make_vhdl_assignment<T>(proc, container, sig, rhs, blocking, base, lval_width);
|
||||
// This also has another application: If this is an `inital'
|
||||
// process and we haven't yet generated a `wait' statement then
|
||||
// moving the assignment to the initialization preserves the
|
||||
// expected Verilog behaviour: VHDL does not distinguish
|
||||
// `initial' and `always' processes so an `always' process might
|
||||
// be activatated before an `initial' process at time 0. The
|
||||
// `always' process may then use the uninitialized signal value.
|
||||
// The second test ensures that we only try to initialise
|
||||
// internal signals not ports
|
||||
if (proc->get_scope()->initializing()
|
||||
&& ivl_signal_port(sig) == IVL_SIP_NONE
|
||||
&& !decl->has_initial()
|
||||
&& rhs->constant()
|
||||
&& decl->get_type()->get_name() != VHDL_TYPE_ARRAY) {
|
||||
|
||||
// If this assignment is not in the top-level container
|
||||
// it will not be made on all paths through the code
|
||||
// This precludes any future extraction of an initialiser
|
||||
if (container != proc->get_container())
|
||||
decl->set_initial(NULL); // Default initial value
|
||||
else {
|
||||
decl->set_initial(rhs);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
vhdl_var_ref *lval_ref =
|
||||
make_assign_lhs(sig, proc->get_scope(), base, lval_width);
|
||||
|
||||
T *a = new T(lval_ref, rhs);
|
||||
container->add_stmt(a);
|
||||
|
||||
ivl_expr_t i_delay;
|
||||
if (NULL == after && (i_delay = ivl_stmt_delay_expr(stmt))) {
|
||||
if ((after = translate_expr(i_delay)) == NULL)
|
||||
return NULL;
|
||||
|
||||
// Need to make 'after' a time value
|
||||
// we can do this by multiplying by 1ns
|
||||
vhdl_type integer(VHDL_TYPE_INTEGER);
|
||||
after = after->cast(&integer);
|
||||
|
||||
vhdl_expr *ns1 = new vhdl_const_time(1, TIME_UNIT_NS);
|
||||
after = new vhdl_binop_expr(after, VHDL_BINOP_MULT, ns1,
|
||||
vhdl_type::time());
|
||||
}
|
||||
|
||||
if (after != NULL)
|
||||
a->set_after(after);
|
||||
|
||||
return a;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
|
@ -277,22 +305,27 @@ static int draw_nbassign(vhdl_procedural *proc, stmt_container *container,
|
|||
{
|
||||
assert(proc->get_scope()->allow_signal_assignment());
|
||||
|
||||
vhdl_nbassign_stmt *a =
|
||||
make_assignment<vhdl_nbassign_stmt>(proc, container, stmt, false);
|
||||
|
||||
if (a != NULL) {
|
||||
// Assignment is a statement and not moved into the initialisation
|
||||
if (after != NULL)
|
||||
a->set_after(after);
|
||||
}
|
||||
|
||||
make_assignment<vhdl_nbassign_stmt>(proc, container, stmt, false, after);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int draw_assign(vhdl_procedural *proc, stmt_container *container,
|
||||
ivl_statement_t stmt)
|
||||
{
|
||||
make_assignment<vhdl_assign_stmt>(proc, container, stmt, true);
|
||||
if (proc->get_scope()->allow_signal_assignment()) {
|
||||
// Blocking assignment is implemented as non-blocking assignment
|
||||
// followed by a zero-time wait
|
||||
// This follows the Verilog semantics fairly closely.
|
||||
|
||||
make_assignment<vhdl_nbassign_stmt>(proc, container, stmt, false, NULL);
|
||||
|
||||
container->add_stmt
|
||||
(new vhdl_wait_stmt(VHDL_WAIT_FOR, new vhdl_const_time(0)));
|
||||
}
|
||||
else
|
||||
make_assignment<vhdl_assign_stmt>(proc, container, stmt, true, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -336,11 +369,7 @@ static int draw_delay(vhdl_procedural *proc, stmt_container *container,
|
|||
if (type == IVL_ST_ASSIGN_NB) {
|
||||
draw_nbassign(proc, container, sub_stmt, time);
|
||||
}
|
||||
else {
|
||||
// All blocking assignments need to be made visible
|
||||
// at this point
|
||||
draw_blocking_assigns(proc, container);
|
||||
|
||||
else {
|
||||
vhdl_wait_stmt *wait =
|
||||
new vhdl_wait_stmt(VHDL_WAIT_FOR, time);
|
||||
container->add_stmt(wait);
|
||||
|
|
@ -360,25 +389,12 @@ static int draw_delay(vhdl_procedural *proc, stmt_container *container,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make edge detectors from the signals in `nexus' and add them
|
||||
* to the expression `test'. Also adds the signals to the process
|
||||
* sensitivity list. Type should be one of `rising_edge' or
|
||||
* `falling_edge'.
|
||||
*/
|
||||
static void edge_detector(ivl_nexus_t nexus, vhdl_process *proc,
|
||||
vhdl_binop_expr *test, const char *type)
|
||||
{
|
||||
vhdl_var_ref *ref = nexus_to_var_ref(proc->get_scope()->get_parent(), nexus);
|
||||
vhdl_fcall *detect = new vhdl_fcall(type, vhdl_type::boolean());
|
||||
detect->add_expr(ref);
|
||||
test->add_expr(detect);
|
||||
proc->add_sensitivity(ref->get_name().c_str());
|
||||
}
|
||||
|
||||
/*
|
||||
* A wait statement waits for a level change on a @(..) list of
|
||||
* signals.
|
||||
* signals. Purely combinatorial processes (i.e. no posedge/negedge
|
||||
* events) produce a `wait on' statement at the end of the process.
|
||||
* Sequential processes produce a `wait until' statement at the
|
||||
* start of the process.
|
||||
*/
|
||||
static int draw_wait(vhdl_procedural *_proc, stmt_container *container,
|
||||
ivl_statement_t stmt)
|
||||
|
|
@ -386,82 +402,76 @@ static int draw_wait(vhdl_procedural *_proc, stmt_container *container,
|
|||
// Wait statements only occur in processes
|
||||
vhdl_process *proc = dynamic_cast<vhdl_process*>(_proc);
|
||||
assert(proc); // Catch not process
|
||||
|
||||
vhdl_binop_expr *test =
|
||||
new vhdl_binop_expr(VHDL_BINOP_OR, vhdl_type::boolean());
|
||||
|
||||
ivl_statement_t sub_stmt = ivl_stmt_sub_stmt(stmt);
|
||||
|
||||
|
||||
// TODO: This should really be merged with the
|
||||
// nexus_to_XXX code
|
||||
int nevents = ivl_stmt_nevent(stmt);
|
||||
|
||||
bool combinatorial = true; // True if no negedge/posedge events
|
||||
for (int i = 0; i < nevents; i++) {
|
||||
ivl_event_t event = ivl_stmt_events(stmt, i);
|
||||
if (ivl_event_npos(event) > 0 || ivl_event_nneg(event) > 0)
|
||||
combinatorial = false;
|
||||
}
|
||||
|
||||
// A list of the non-edge triggered signals to they can
|
||||
// be added to the edge-detecting `if' statement later
|
||||
string_list_t non_edges;
|
||||
|
||||
int nany = ivl_event_nany(event);
|
||||
for (int i = 0; i < nany; i++) {
|
||||
ivl_nexus_t nexus = ivl_event_any(event, i);
|
||||
|
||||
int nptrs = ivl_nexus_ptrs(nexus);
|
||||
for (int j = 0; j < nptrs; j++) {
|
||||
ivl_nexus_ptr_t nexus_ptr = ivl_nexus_ptr(nexus, j);
|
||||
|
||||
ivl_signal_t sig;
|
||||
if ((sig = ivl_nexus_ptr_sig(nexus_ptr))) {
|
||||
if (!seen_signal_before(sig))
|
||||
continue;
|
||||
|
||||
std::string signame(get_renamed_signal(sig));
|
||||
|
||||
// Only add this signal to the sensitivity if it's part
|
||||
// of the containing architecture (i.e. it has already
|
||||
// been declared)
|
||||
if (proc->get_scope()->get_parent()->have_declared(signame)) {
|
||||
proc->add_sensitivity(signame.c_str());
|
||||
non_edges.push_back(signame);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Ignore all other types of nexus pointer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int nneg = ivl_event_nneg(event);
|
||||
int npos = ivl_event_npos(event);
|
||||
if (nneg + npos > 0) {
|
||||
vhdl_binop_expr *test =
|
||||
new vhdl_binop_expr(VHDL_BINOP_OR, vhdl_type::boolean());
|
||||
|
||||
// Generate falling_edge(..) calls for each negedge event
|
||||
for (int i = 0; i < nneg; i++)
|
||||
edge_detector(ivl_event_neg(event, i), proc, test, "falling_edge");
|
||||
|
||||
// Generate rising_edge(..) calls for each posedge event
|
||||
for (int i = 0; i < npos; i++)
|
||||
edge_detector(ivl_event_pos(event, i), proc, test, "rising_edge");
|
||||
|
||||
// Add Name'Event terms for each non-edge-triggered signal
|
||||
string_list_t::iterator it;
|
||||
for (it = non_edges.begin(); it != non_edges.end(); ++it) {
|
||||
test->add_expr
|
||||
(new vhdl_var_ref((*it + "'Event").c_str(),
|
||||
vhdl_type::boolean()));
|
||||
}
|
||||
|
||||
vhdl_if_stmt *edge_det = new vhdl_if_stmt(test);
|
||||
container->add_stmt(edge_det);
|
||||
if (combinatorial) {
|
||||
vhdl_wait_stmt *wait = new vhdl_wait_stmt(VHDL_WAIT_ON);
|
||||
|
||||
for (int i = 0; i < nevents; i++) {
|
||||
ivl_event_t event = ivl_stmt_events(stmt, i);
|
||||
|
||||
draw_stmt(proc, edge_det->get_then_container(), sub_stmt);
|
||||
int nany = ivl_event_nany(event);
|
||||
for (int i = 0; i < nany; i++) {
|
||||
ivl_nexus_t nexus = ivl_event_any(event, i);
|
||||
vhdl_var_ref *ref = nexus_to_var_ref(proc->get_scope(), nexus);
|
||||
|
||||
wait->add_sensitivity(ref->get_name());
|
||||
delete ref;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Don't bother generating an edge detector if there
|
||||
// are no edge-triggered events
|
||||
draw_stmt(proc, container, sub_stmt);
|
||||
|
||||
draw_stmt(proc, container, ivl_stmt_sub_stmt(stmt));
|
||||
container->add_stmt(wait);
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < nevents; i++) {
|
||||
ivl_event_t event = ivl_stmt_events(stmt, i);
|
||||
|
||||
int nany = ivl_event_nany(event);
|
||||
for (int i = 0; i < nany; i++) {
|
||||
ivl_nexus_t nexus = ivl_event_any(event, i);
|
||||
vhdl_var_ref *ref = nexus_to_var_ref(proc->get_scope(), nexus);
|
||||
|
||||
ref->set_name(ref->get_name() + "'Event");
|
||||
test->add_expr(ref);
|
||||
}
|
||||
|
||||
int nneg = ivl_event_nneg(event);
|
||||
for (int i = 0; i < nneg; i++) {
|
||||
ivl_nexus_t nexus = ivl_event_neg(event, i);
|
||||
vhdl_var_ref *ref = nexus_to_var_ref(proc->get_scope(), nexus);
|
||||
vhdl_fcall *detect =
|
||||
new vhdl_fcall("falling_edge", vhdl_type::boolean());
|
||||
detect->add_expr(ref);
|
||||
|
||||
test->add_expr(detect);
|
||||
}
|
||||
|
||||
int npos = ivl_event_npos(event);
|
||||
for (int i = 0; i < npos; i++) {
|
||||
ivl_nexus_t nexus = ivl_event_pos(event, i);
|
||||
vhdl_var_ref *ref = nexus_to_var_ref(proc->get_scope(), nexus);
|
||||
vhdl_fcall *detect =
|
||||
new vhdl_fcall("rising_edge", vhdl_type::boolean());
|
||||
detect->add_expr(ref);
|
||||
|
||||
test->add_expr(detect);
|
||||
}
|
||||
}
|
||||
|
||||
container->add_stmt(new vhdl_wait_stmt(VHDL_WAIT_UNTIL, test));
|
||||
draw_stmt(proc, container, ivl_stmt_sub_stmt(stmt));
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -476,8 +486,9 @@ static int draw_if(vhdl_procedural *proc, stmt_container *container,
|
|||
|
||||
vhdl_if_stmt *vhdif = new vhdl_if_stmt(test);
|
||||
|
||||
draw_stmt(proc, vhdif->get_then_container(),
|
||||
ivl_stmt_cond_true(stmt));
|
||||
ivl_statement_t cond_true_stmt = ivl_stmt_cond_true(stmt);
|
||||
if (cond_true_stmt)
|
||||
draw_stmt(proc, vhdif->get_then_container(), cond_true_stmt);
|
||||
|
||||
ivl_statement_t cond_false_stmt = ivl_stmt_cond_false(stmt);
|
||||
if (cond_false_stmt)
|
||||
|
|
@ -596,6 +607,7 @@ int draw_stmt(vhdl_procedural *proc, stmt_container *container,
|
|||
case IVL_ST_CONDIT:
|
||||
return draw_if(proc, container, stmt);
|
||||
case IVL_ST_CASE:
|
||||
case IVL_ST_CASEX:
|
||||
return draw_case(proc, container, stmt);
|
||||
case IVL_ST_WHILE:
|
||||
return draw_while(proc, container, stmt);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* Support functions for VHDL output.
|
||||
*
|
||||
* Copyright (C) 2008 Nick Gasson (nick@nickg.me.uk)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "vhdl_target.h"
|
||||
#include "support.hh"
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
void require_support_function(support_function_t f)
|
||||
{
|
||||
vhdl_scope *scope = get_active_entity()->get_arch()->get_scope();
|
||||
if (!scope->have_declared(support_function::function_name(f)))
|
||||
scope->add_decl(new support_function(f));
|
||||
}
|
||||
|
||||
const char *support_function::function_name(support_function_t type)
|
||||
{
|
||||
switch (type) {
|
||||
case SF_UNSIGNED_TO_BOOLEAN:
|
||||
return "Unsigned_To_Boolean";
|
||||
case SF_SIGNED_TO_BOOLEAN:
|
||||
return "Signed_To_Boolean";
|
||||
case SF_BOOLEAN_TO_LOGIC:
|
||||
return "Boolean_To_Logic";
|
||||
case SF_REDUCE_OR:
|
||||
return "Reduce_OR";
|
||||
case SF_REDUCE_AND:
|
||||
return "Reduce_AND";
|
||||
case SF_REDUCE_XOR:
|
||||
return "Reduce_XOR";
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
vhdl_type *support_function::function_type(support_function_t type)
|
||||
{
|
||||
switch (type) {
|
||||
case SF_UNSIGNED_TO_BOOLEAN:
|
||||
case SF_SIGNED_TO_BOOLEAN:
|
||||
return vhdl_type::boolean();
|
||||
case SF_BOOLEAN_TO_LOGIC:
|
||||
case SF_REDUCE_OR:
|
||||
case SF_REDUCE_AND:
|
||||
case SF_REDUCE_XOR:
|
||||
return vhdl_type::std_logic();
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
void support_function::emit(std::ostream &of, int level) const
|
||||
{
|
||||
of << "function " << function_name(type_);
|
||||
|
||||
switch (type_) {
|
||||
case SF_UNSIGNED_TO_BOOLEAN:
|
||||
of << "(X : unsigned) return Boolean is" << nl_string(level)
|
||||
<< "begin" << nl_string(indent(level))
|
||||
<< "return X /= To_Unsigned(0, X'Length);" << nl_string(level);
|
||||
break;
|
||||
case SF_SIGNED_TO_BOOLEAN:
|
||||
of << "(X : signed) return Boolean is" << nl_string(level)
|
||||
<< "begin" << nl_string(indent(level))
|
||||
<< "return X /= To_Signed(0, X'Length);" << nl_string (level);
|
||||
break;
|
||||
case SF_BOOLEAN_TO_LOGIC:
|
||||
of << "(B : Boolean) return std_logic is" << nl_string(level)
|
||||
<< "begin" << nl_string(indent(level))
|
||||
<< "if B then" << nl_string(indent(indent(level)))
|
||||
<< "return '1'" << nl_string(indent(level))
|
||||
<< "else" << nl_string(indent(indent(level)))
|
||||
<< "return '0'" << nl_string(indent(level))
|
||||
<< "end if;" << nl_string(level);
|
||||
break;
|
||||
case SF_REDUCE_OR:
|
||||
of << "(X : std_logic_vector) return std_logic is" << nl_string(level)
|
||||
<< "begin" << nl_string(indent(level))
|
||||
<< "for I in X'Range loop" << nl_string(indent(indent(level)))
|
||||
<< "if X(I) = '1' then" << nl_string(indent(indent(indent(level))))
|
||||
<< "return '1';" << nl_string(indent(indent(level)))
|
||||
<< "end if;" << nl_string(indent(level))
|
||||
<< "end loop;" << nl_string(indent(level))
|
||||
<< "return '0';" << nl_string(level);
|
||||
break;
|
||||
case SF_REDUCE_AND:
|
||||
of << "(X : std_logic_vector) return std_logic is" << nl_string(level)
|
||||
<< "begin" << nl_string(indent(level))
|
||||
<< "for I in X'Range loop" << nl_string(indent(indent(level)))
|
||||
<< "if X(I) = '0' then" << nl_string(indent(indent(indent(level))))
|
||||
<< "return '0';" << nl_string(indent(indent(level)))
|
||||
<< "end if;" << nl_string(indent(level))
|
||||
<< "end loop;" << nl_string(indent(level))
|
||||
<< "return '1';" << nl_string(level);
|
||||
break;
|
||||
case SF_REDUCE_XOR:
|
||||
of << "(X : std_logic_vector) return std_logic is"
|
||||
<< nl_string(indent(level))
|
||||
<< "variable R : std_logic := '0';" << nl_string(level)
|
||||
<< "begin" << nl_string(indent(level))
|
||||
<< "for I in X'Range loop" << nl_string(indent(indent(level)))
|
||||
<< "R := X(I) xor R;" << nl_string(indent(level))
|
||||
<< "end loop;" << nl_string(indent(level))
|
||||
<< "return R;" << nl_string(level);
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
|
||||
of << "end function;" << nl_string(level);
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Support functions for VHDL output.
|
||||
*
|
||||
* Copyright (C) 2008 Nick Gasson (nick@nickg.me.uk)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef INC_SUPPORT_HH
|
||||
#define INC_SUPPORT_HH
|
||||
|
||||
#include "vhdl_syntax.hh"
|
||||
|
||||
enum support_function_t {
|
||||
SF_UNSIGNED_TO_BOOLEAN,
|
||||
SF_SIGNED_TO_BOOLEAN,
|
||||
SF_BOOLEAN_TO_LOGIC,
|
||||
SF_REDUCE_OR,
|
||||
SF_REDUCE_AND,
|
||||
SF_REDUCE_XOR,
|
||||
};
|
||||
|
||||
class support_function : public vhdl_function {
|
||||
public:
|
||||
support_function(support_function_t type)
|
||||
: vhdl_function(function_name(type), function_type(type)),
|
||||
type_(type) {}
|
||||
void emit(std::ostream &of, int level) const;
|
||||
static const char *function_name(support_function_t type);
|
||||
static vhdl_type *function_type(support_function_t type);
|
||||
|
||||
private:
|
||||
support_function_t type_;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -15,6 +15,7 @@ package Verilog_Support is
|
|||
|
||||
-- Routines to implement Verilog reduction operators
|
||||
function Reduce_OR(X : unsigned) return std_logic;
|
||||
function Reduce_Or(X : std_logic) return std_logic;
|
||||
|
||||
-- Convert Boolean to std_logic
|
||||
function Active_High(B : Boolean) return std_logic;
|
||||
|
|
@ -40,6 +41,11 @@ package body Verilog_Support is
|
|||
return '0';
|
||||
end function;
|
||||
|
||||
function Reduce_OR(X : std_logic) return std_logic is
|
||||
begin
|
||||
return X;
|
||||
end function;
|
||||
|
||||
function Active_High(B : Boolean) return std_logic is
|
||||
begin
|
||||
if B then
|
||||
|
|
|
|||
|
|
@ -130,6 +130,18 @@ const std::string &get_renamed_signal(ivl_signal_t sig)
|
|||
return g_known_signals[sig].renamed;
|
||||
}
|
||||
|
||||
ivl_signal_t find_signal_named(const std::string &name, const vhdl_scope *scope)
|
||||
{
|
||||
signal_defn_map_t::const_iterator it;
|
||||
for (it = g_known_signals.begin(); it != g_known_signals.end(); ++it) {
|
||||
if (((*it).second.scope == scope
|
||||
|| (*it).second.scope == scope->get_parent())
|
||||
&& (*it).second.renamed == name)
|
||||
return (*it).first;
|
||||
}
|
||||
assert(false);
|
||||
}
|
||||
|
||||
ivl_design_t get_vhdl_design()
|
||||
{
|
||||
return g_design;
|
||||
|
|
|
|||
|
|
@ -35,6 +35,13 @@ int indent(int level)
|
|||
return level + VHDL_INDENT;
|
||||
}
|
||||
|
||||
std::string nl_string(int level)
|
||||
{
|
||||
std::ostringstream ss;
|
||||
newline(ss, level);
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
/*
|
||||
* Emit a newline and indent to the correct level.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ typedef std::list<vhdl_element*> element_list_t;
|
|||
|
||||
int indent(int level);
|
||||
void newline(std::ostream &of, int level);
|
||||
std::string nl_string(int level);
|
||||
void blank_line(std::ostream &of, int level);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@
|
|||
vhdl_scope::vhdl_scope()
|
||||
: parent_(NULL), init_(false), sig_assign_(true)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
vhdl_scope::~vhdl_scope()
|
||||
|
|
@ -36,6 +36,13 @@ vhdl_scope::~vhdl_scope()
|
|||
delete_children<vhdl_decl>(decls_);
|
||||
}
|
||||
|
||||
void vhdl_scope::set_initializing(bool i)
|
||||
{
|
||||
init_ = i;
|
||||
if (parent_)
|
||||
parent_->set_initializing(i);
|
||||
}
|
||||
|
||||
void vhdl_scope::add_decl(vhdl_decl *decl)
|
||||
{
|
||||
decls_.push_back(decl);
|
||||
|
|
@ -57,7 +64,7 @@ bool vhdl_scope::have_declared(const std::string &name) const
|
|||
return get_decl(name) != NULL;
|
||||
}
|
||||
|
||||
vhdl_scope *vhdl_scope::get_parent()
|
||||
vhdl_scope *vhdl_scope::get_parent() const
|
||||
{
|
||||
assert(parent_);
|
||||
return parent_;
|
||||
|
|
@ -88,6 +95,7 @@ void vhdl_entity::emit(std::ostream &of, int level) const
|
|||
of << "use ieee.std_logic_1164.all;" << std::endl;
|
||||
of << "use ieee.numeric_std.all;" << std::endl;
|
||||
of << "use std.textio.all;" << std::endl;
|
||||
//of << "use work.verilog_support.all;" << std::endl;
|
||||
of << std::endl;
|
||||
|
||||
emit_comment(of, level);
|
||||
|
|
@ -292,6 +300,22 @@ void vhdl_wait_stmt::emit(std::ostream &of, int level) const
|
|||
of << " for ";
|
||||
expr_->emit(of, level);
|
||||
break;
|
||||
case VHDL_WAIT_UNTIL:
|
||||
assert(expr_);
|
||||
of << " until ";
|
||||
expr_->emit(of, level);
|
||||
break;
|
||||
case VHDL_WAIT_ON:
|
||||
{
|
||||
of << " on ";
|
||||
string_list_t::const_iterator it = sensitivity_.begin();
|
||||
while (it != sensitivity_.end()) {
|
||||
of << *it;
|
||||
if (++it != sensitivity_.end())
|
||||
of << ", ";
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
of << ";";
|
||||
|
|
@ -312,10 +336,12 @@ const vhdl_type *vhdl_decl::get_type() const
|
|||
}
|
||||
|
||||
void vhdl_decl::set_initial(vhdl_expr *initial)
|
||||
{
|
||||
if (initial_ != NULL)
|
||||
delete initial_;
|
||||
initial_ = initial;
|
||||
{
|
||||
if (!has_initial_) {
|
||||
assert(initial_ == NULL);
|
||||
initial_ = initial;
|
||||
has_initial_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
void vhdl_port_decl::emit(std::ostream &of, int level) const
|
||||
|
|
@ -365,84 +391,19 @@ void vhdl_signal_decl::emit(std::ostream &of, int level) const
|
|||
emit_comment(of, level, true);
|
||||
}
|
||||
|
||||
void vhdl_type_decl::emit(std::ostream &of, int level) const
|
||||
{
|
||||
of << "type " << name_ << " is ";
|
||||
of << type_->get_type_decl_string() << ";";
|
||||
emit_comment(of, level, true);
|
||||
}
|
||||
|
||||
vhdl_expr::~vhdl_expr()
|
||||
{
|
||||
if (type_ != NULL)
|
||||
delete type_;
|
||||
}
|
||||
|
||||
/*
|
||||
* The default cast just assumes there's a VHDL cast function to
|
||||
* do the job for us.
|
||||
*/
|
||||
vhdl_expr *vhdl_expr::cast(const vhdl_type *to)
|
||||
{
|
||||
//std::cout << "Cast: from=" << type_->get_string()
|
||||
// << " (" << type_->get_width() << ") "
|
||||
// << " to=" << to->get_string() << " ("
|
||||
// << to->get_width() << ")" << std::endl;
|
||||
|
||||
if (to->get_name() == type_->get_name()) {
|
||||
if (to->get_width() == type_->get_width())
|
||||
return this; // Identical
|
||||
else
|
||||
return resize(to->get_width());
|
||||
}
|
||||
else if (to->get_name() == VHDL_TYPE_BOOLEAN) {
|
||||
// '1' is true all else are false
|
||||
vhdl_const_bit *one = new vhdl_const_bit('1');
|
||||
return new vhdl_binop_expr
|
||||
(this, VHDL_BINOP_EQ, one, vhdl_type::boolean());
|
||||
}
|
||||
else if (to->get_name() == VHDL_TYPE_INTEGER) {
|
||||
vhdl_fcall *conv = new vhdl_fcall("To_Integer", new vhdl_type(*to));
|
||||
conv->add_expr(this);
|
||||
|
||||
return conv;
|
||||
}
|
||||
else if (to->get_name() == VHDL_TYPE_STD_LOGIC &&
|
||||
type_->get_name() == VHDL_TYPE_BOOLEAN) {
|
||||
// Verilog assumes active-high logic and there
|
||||
// is a special routine in verilog_support.vhd
|
||||
// to do this for us
|
||||
vhdl_fcall *ah = new vhdl_fcall("Active_High", vhdl_type::std_logic());
|
||||
ah->add_expr(this);
|
||||
|
||||
return ah;
|
||||
}
|
||||
else {
|
||||
// We have to cast the expression before resizing or the
|
||||
// wrong sign bit may be extended (i.e. when casting between
|
||||
// signed/unsigned *and* resizing)
|
||||
vhdl_fcall *conv =
|
||||
new vhdl_fcall(to->get_string().c_str(), new vhdl_type(*to));
|
||||
conv->add_expr(this);
|
||||
|
||||
if (to->get_width() != type_->get_width())
|
||||
return conv->resize(to->get_width());
|
||||
else
|
||||
return conv;
|
||||
}
|
||||
}
|
||||
|
||||
vhdl_expr *vhdl_expr::resize(int newwidth)
|
||||
{
|
||||
vhdl_type *rtype;
|
||||
assert(type_);
|
||||
if (type_->get_name() == VHDL_TYPE_SIGNED)
|
||||
rtype = vhdl_type::nsigned(newwidth);
|
||||
else if (type_->get_name() == VHDL_TYPE_UNSIGNED)
|
||||
rtype = vhdl_type::nunsigned(newwidth);
|
||||
else
|
||||
return this; // Doesn't make sense to resize non-vector type
|
||||
|
||||
vhdl_fcall *resize = new vhdl_fcall("Resize", rtype);
|
||||
resize->add_expr(this);
|
||||
resize->add_expr(new vhdl_const_int(newwidth));
|
||||
|
||||
return resize;
|
||||
}
|
||||
|
||||
void vhdl_expr_list::add_expr(vhdl_expr *e)
|
||||
{
|
||||
exprs_.push_back(e);
|
||||
|
|
@ -485,22 +446,27 @@ vhdl_var_ref::~vhdl_var_ref()
|
|||
void vhdl_var_ref::set_slice(vhdl_expr *s, int w)
|
||||
{
|
||||
assert(type_);
|
||||
|
||||
vhdl_type_name_t tname = type_->get_name();
|
||||
assert(tname == VHDL_TYPE_UNSIGNED || tname == VHDL_TYPE_SIGNED);
|
||||
|
||||
|
||||
slice_ = s;
|
||||
slice_width_ = w;
|
||||
|
||||
vhdl_type_name_t tname = type_->get_name();
|
||||
if (tname == VHDL_TYPE_ARRAY) {
|
||||
type_ = new vhdl_type(*type_->get_base());
|
||||
}
|
||||
else {
|
||||
assert(tname == VHDL_TYPE_UNSIGNED || tname == VHDL_TYPE_SIGNED);
|
||||
|
||||
if (type_)
|
||||
delete type_;
|
||||
|
||||
if (w > 0)
|
||||
type_ = new vhdl_type(tname, w);
|
||||
else
|
||||
type_ = vhdl_type::std_logic();
|
||||
if (type_)
|
||||
delete type_;
|
||||
|
||||
if (w > 0)
|
||||
type_ = new vhdl_type(tname, w);
|
||||
else
|
||||
type_ = vhdl_type::std_logic();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void vhdl_var_ref::emit(std::ostream &of, int level) const
|
||||
{
|
||||
of << name_;
|
||||
|
|
@ -576,40 +542,6 @@ vhdl_const_bits::vhdl_const_bits(const char *value, int width, bool issigned)
|
|||
value_.push_back(*value++);
|
||||
}
|
||||
|
||||
vhdl_expr *vhdl_const_bits::cast(const vhdl_type *to)
|
||||
{
|
||||
if (to->get_name() == VHDL_TYPE_STD_LOGIC) {
|
||||
// VHDL won't let us cast directly between a vector and
|
||||
// a scalar type
|
||||
// But we don't need to here as we have the bits available
|
||||
|
||||
// Take the least significant bit
|
||||
char lsb = value_[0];
|
||||
|
||||
return new vhdl_const_bit(lsb);
|
||||
}
|
||||
else if (to->get_name() == VHDL_TYPE_STD_LOGIC_VECTOR) {
|
||||
// Don't need to do anything
|
||||
return this;
|
||||
}
|
||||
else if (to->get_name() == VHDL_TYPE_SIGNED
|
||||
|| to->get_name() == VHDL_TYPE_UNSIGNED) {
|
||||
|
||||
// Extend with sign bit
|
||||
value_.resize(to->get_width(), value_[0]);
|
||||
return this;
|
||||
}
|
||||
else if (to->get_name() == VHDL_TYPE_INTEGER) {
|
||||
// Need to explicitly qualify the type (or the VHDL
|
||||
// compiler gets confused between signed/unsigned)
|
||||
qualified_ = true;
|
||||
|
||||
return vhdl_expr::cast(to);
|
||||
}
|
||||
else
|
||||
return vhdl_expr::cast(to);
|
||||
}
|
||||
|
||||
void vhdl_const_bits::emit(std::ostream &of, int level) const
|
||||
{
|
||||
if (qualified_)
|
||||
|
|
@ -648,12 +580,36 @@ vhdl_cassign_stmt::~vhdl_cassign_stmt()
|
|||
{
|
||||
delete lhs_;
|
||||
delete rhs_;
|
||||
|
||||
for (std::list<when_part_t>::const_iterator it = whens_.begin();
|
||||
it != whens_.end();
|
||||
++it) {
|
||||
delete (*it).value;
|
||||
delete (*it).cond;
|
||||
}
|
||||
}
|
||||
|
||||
void vhdl_cassign_stmt::add_condition(vhdl_expr *value, vhdl_expr *cond)
|
||||
{
|
||||
when_part_t when = { value, cond };
|
||||
whens_.push_back(when);
|
||||
}
|
||||
|
||||
void vhdl_cassign_stmt::emit(std::ostream &of, int level) const
|
||||
{
|
||||
lhs_->emit(of, level);
|
||||
of << " <= ";
|
||||
if (!whens_.empty()) {
|
||||
for (std::list<when_part_t>::const_iterator it = whens_.begin();
|
||||
it != whens_.end();
|
||||
++it) {
|
||||
(*it).value->emit(of, level);
|
||||
of << " when ";
|
||||
(*it).cond->emit(of, level);
|
||||
of << " ";
|
||||
}
|
||||
of << "else ";
|
||||
}
|
||||
rhs_->emit(of, level);
|
||||
of << ";";
|
||||
}
|
||||
|
|
@ -818,6 +774,7 @@ void vhdl_function::emit(std::ostream &of, int level) const
|
|||
of << " return Verilog_Result;";
|
||||
newline(of, level);
|
||||
of << "end function;";
|
||||
newline(of, level);
|
||||
}
|
||||
|
||||
void vhdl_param_decl::emit(std::ostream &of, int level) const
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ public:
|
|||
|
||||
void emit(std::ostream &of, int level) const;
|
||||
const std::string &get_name() const { return name_; }
|
||||
void set_name(const std::string &name) { name_ = name; }
|
||||
void set_slice(vhdl_expr *s, int w=0);
|
||||
private:
|
||||
std::string name_;
|
||||
|
|
@ -139,6 +140,8 @@ public:
|
|||
const std::string &get_value() const { return value_; }
|
||||
vhdl_expr *cast(const vhdl_type *to);
|
||||
private:
|
||||
int bits_to_int() const;
|
||||
|
||||
std::string value_;
|
||||
bool qualified_, signed_;
|
||||
};
|
||||
|
|
@ -148,6 +151,7 @@ public:
|
|||
vhdl_const_bit(char bit)
|
||||
: vhdl_expr(vhdl_type::std_logic(), true), bit_(bit) {}
|
||||
void emit(std::ostream &of, int level) const;
|
||||
vhdl_expr *cast(const vhdl_type *to);
|
||||
private:
|
||||
char bit_;
|
||||
};
|
||||
|
|
@ -158,7 +162,7 @@ enum time_unit_t {
|
|||
|
||||
class vhdl_const_time : public vhdl_expr {
|
||||
public:
|
||||
vhdl_const_time(int64_t value, time_unit_t units)
|
||||
vhdl_const_time(int64_t value, time_unit_t units = TIME_UNIT_NS)
|
||||
: vhdl_expr(vhdl_type::time(), true), value_(value), units_(units) {}
|
||||
void emit(std::ostream &of, int level) const;
|
||||
private:
|
||||
|
|
@ -216,6 +220,8 @@ typedef std::list<vhdl_conc_stmt*> conc_stmt_list_t;
|
|||
|
||||
/*
|
||||
* A concurrent signal assignment (i.e. not part of a process).
|
||||
* Can have any number of `when' clauses, in which case the original
|
||||
* rhs becomes the `else' part.
|
||||
*/
|
||||
class vhdl_cassign_stmt : public vhdl_conc_stmt {
|
||||
public:
|
||||
|
|
@ -224,9 +230,15 @@ public:
|
|||
~vhdl_cassign_stmt();
|
||||
|
||||
void emit(std::ostream &of, int level) const;
|
||||
void add_condition(vhdl_expr *value, vhdl_expr *cond);
|
||||
private:
|
||||
vhdl_var_ref *lhs_;
|
||||
vhdl_expr *rhs_;
|
||||
|
||||
struct when_part_t {
|
||||
vhdl_expr *value, *cond;
|
||||
};
|
||||
std::list<when_part_t> whens_;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -295,6 +307,8 @@ public:
|
|||
enum vhdl_wait_type_t {
|
||||
VHDL_WAIT_INDEF, // Suspend indefinitely
|
||||
VHDL_WAIT_FOR, // Wait for a constant amount of time
|
||||
VHDL_WAIT_UNTIL, // Wait on an expression
|
||||
VHDL_WAIT_ON, // Wait on a sensitivity list
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -309,9 +323,11 @@ public:
|
|||
~vhdl_wait_stmt();
|
||||
|
||||
void emit(std::ostream &of, int level) const;
|
||||
void add_sensitivity(const std::string &s) { sensitivity_.push_back(s); }
|
||||
private:
|
||||
vhdl_wait_type_t type_;
|
||||
vhdl_expr *expr_;
|
||||
string_list_t sensitivity_;
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -415,18 +431,20 @@ class vhdl_decl : public vhdl_element {
|
|||
public:
|
||||
vhdl_decl(const char *name, vhdl_type *type = NULL,
|
||||
vhdl_expr *initial = NULL)
|
||||
: name_(name), type_(type), initial_(initial) {}
|
||||
: name_(name), type_(type), initial_(initial),
|
||||
has_initial_(initial != NULL) {}
|
||||
virtual ~vhdl_decl();
|
||||
|
||||
const std::string &get_name() const { return name_; }
|
||||
const vhdl_type *get_type() const;
|
||||
void set_type(vhdl_type *t) { type_ = t; }
|
||||
void set_initial(vhdl_expr *initial);
|
||||
bool has_initial() const { return initial_ != NULL; }
|
||||
bool has_initial() const { return has_initial_; }
|
||||
protected:
|
||||
std::string name_;
|
||||
vhdl_type *type_;
|
||||
vhdl_expr *initial_;
|
||||
bool has_initial_;
|
||||
};
|
||||
|
||||
typedef std::list<vhdl_decl*> decl_list_t;
|
||||
|
|
@ -450,6 +468,14 @@ private:
|
|||
};
|
||||
|
||||
|
||||
class vhdl_type_decl : public vhdl_decl {
|
||||
public:
|
||||
vhdl_type_decl(const char *name, vhdl_type *base)
|
||||
: vhdl_decl(name, base) {}
|
||||
void emit(std::ostream &of, int level) const;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* A variable declaration inside a process (although this isn't
|
||||
* enforced here).
|
||||
|
|
@ -501,6 +527,7 @@ public:
|
|||
: vhdl_decl(name, type), mode_(mode) {}
|
||||
|
||||
void emit(std::ostream &of, int level) const;
|
||||
vhdl_port_mode_t get_mode() const { return mode_; }
|
||||
private:
|
||||
vhdl_port_mode_t mode_;
|
||||
};
|
||||
|
|
@ -548,14 +575,14 @@ public:
|
|||
void add_decl(vhdl_decl *decl);
|
||||
vhdl_decl *get_decl(const std::string &name) const;
|
||||
bool have_declared(const std::string &name) const;
|
||||
vhdl_scope *get_parent();
|
||||
vhdl_scope *get_parent() const;
|
||||
|
||||
bool empty() const { return decls_.empty(); }
|
||||
const decl_list_t &get_decls() const { return decls_; }
|
||||
void set_parent(vhdl_scope *p) { parent_ = p; }
|
||||
|
||||
bool initializing() const { return init_; }
|
||||
void set_initializing(bool i) { init_ = i; }
|
||||
void set_initializing(bool i);
|
||||
|
||||
void set_allow_signal_assignment(bool b) { sig_assign_ = b; }
|
||||
bool allow_signal_assignment() const { return sig_assign_; }
|
||||
|
|
@ -587,7 +614,7 @@ class vhdl_function : public vhdl_decl, public vhdl_procedural {
|
|||
public:
|
||||
vhdl_function(const char *name, vhdl_type *ret_type);
|
||||
|
||||
void emit(std::ostream &of, int level) const;
|
||||
virtual void emit(std::ostream &of, int level) const;
|
||||
vhdl_scope *get_scope() { return &variables_; }
|
||||
void add_param(vhdl_param_decl *p) { scope_.add_decl(p); }
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -7,8 +7,12 @@
|
|||
#include "vhdl_syntax.hh"
|
||||
#include "vhdl_type.hh"
|
||||
|
||||
#include "support.hh"
|
||||
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
void error(const char *fmt, ...);
|
||||
|
||||
int draw_scope(ivl_scope_t scope, void *_parent);
|
||||
|
|
@ -17,29 +21,29 @@ int draw_stmt(vhdl_procedural *proc, stmt_container *container,
|
|||
ivl_statement_t stmt);
|
||||
int draw_lpm(vhdl_arch *arch, ivl_lpm_t lpm);
|
||||
|
||||
vhdl_expr *lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm);
|
||||
vhdl_expr *translate_expr(ivl_expr_t e);
|
||||
vhdl_var_ref *lpm_output(vhdl_scope *scope, ivl_lpm_t lpm);
|
||||
|
||||
void remember_entity(vhdl_entity *ent);
|
||||
vhdl_entity *find_entity(const std::string &tname);
|
||||
vhdl_entity *find_entity(const string &tname);
|
||||
|
||||
ivl_design_t get_vhdl_design();
|
||||
vhdl_entity *get_active_entity();
|
||||
void set_active_entity(vhdl_entity *ent);
|
||||
|
||||
vhdl_var_ref *nexus_to_var_ref(vhdl_scope *arch_scope, ivl_nexus_t nexus);
|
||||
|
||||
bool seen_signal_before(ivl_signal_t sig);
|
||||
void remember_signal(ivl_signal_t sig, const vhdl_scope *scope);
|
||||
void rename_signal(ivl_signal_t sig, const std::string &renamed);
|
||||
void rename_signal(ivl_signal_t sig, const string &renamed);
|
||||
const vhdl_scope *find_scope_for_signal(ivl_signal_t sig);
|
||||
const std::string &get_renamed_signal(ivl_signal_t sig);
|
||||
|
||||
void blocking_assign_to(vhdl_procedural *proc, ivl_signal_t sig);
|
||||
std::string strip_var(const std::string &str);
|
||||
void draw_blocking_assigns(vhdl_procedural *proc, stmt_container *container);
|
||||
const string &get_renamed_signal(ivl_signal_t sig);
|
||||
ivl_signal_t find_signal_named(const string &name, const vhdl_scope *scope);
|
||||
|
||||
int draw_stask_display(vhdl_procedural *proc, stmt_container *container,
|
||||
ivl_statement_t stmt, bool newline = true);
|
||||
|
||||
void require_support_function(support_function_t f);
|
||||
|
||||
#endif /* #ifndef INC_VHDL_TARGET_H */
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,9 @@
|
|||
|
||||
#include "vhdl_type.hh"
|
||||
|
||||
#include <cassert>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
vhdl_type *vhdl_type::std_logic()
|
||||
|
|
@ -63,6 +65,12 @@ vhdl_type *vhdl_type::time()
|
|||
return new vhdl_type(VHDL_TYPE_TIME);
|
||||
}
|
||||
|
||||
vhdl_type *vhdl_type::get_base() const
|
||||
{
|
||||
assert(name_ == VHDL_TYPE_ARRAY);
|
||||
return base_;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is just the name of the type, without any parameters.
|
||||
*/
|
||||
|
|
@ -87,6 +95,9 @@ std::string vhdl_type::get_string() const
|
|||
return std::string("signed");
|
||||
case VHDL_TYPE_UNSIGNED:
|
||||
return std::string("unsigned");
|
||||
case VHDL_TYPE_ARRAY:
|
||||
// Each array has its own type declaration
|
||||
return array_name_;
|
||||
default:
|
||||
return std::string("BadType");
|
||||
}
|
||||
|
|
@ -112,11 +123,46 @@ std::string vhdl_type::get_decl_string() const
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Like get_decl_string but completely expands array declarations.
|
||||
*/
|
||||
std::string vhdl_type::get_type_decl_string() const
|
||||
{
|
||||
switch (name_) {
|
||||
case VHDL_TYPE_ARRAY:
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << "array (" << msb_ << " downto "
|
||||
<< lsb_ << ") of "
|
||||
<< base_->get_decl_string();
|
||||
return ss.str();
|
||||
}
|
||||
default:
|
||||
return get_decl_string();
|
||||
}
|
||||
}
|
||||
|
||||
void vhdl_type::emit(std::ostream &of, int level) const
|
||||
{
|
||||
of << get_decl_string();
|
||||
}
|
||||
|
||||
vhdl_type::vhdl_type(const vhdl_type &other)
|
||||
: name_(other.name_), msb_(other.msb_), lsb_(other.lsb_),
|
||||
array_name_(other.array_name_)
|
||||
{
|
||||
if (other.base_ != NULL)
|
||||
base_ = new vhdl_type(*other.base_);
|
||||
else
|
||||
base_ = NULL;
|
||||
}
|
||||
|
||||
vhdl_type::~vhdl_type()
|
||||
{
|
||||
if (base_ != NULL)
|
||||
delete base_;
|
||||
}
|
||||
|
||||
vhdl_type *vhdl_type::std_logic_vector(int msb, int lsb)
|
||||
{
|
||||
return new vhdl_type(VHDL_TYPE_STD_LOGIC_VECTOR, msb, lsb);
|
||||
|
|
@ -131,3 +177,8 @@ vhdl_type *vhdl_type::type_for(int width, bool issigned, int lsb)
|
|||
else
|
||||
return vhdl_type::nunsigned(width, lsb);
|
||||
}
|
||||
|
||||
vhdl_type *vhdl_type::array_of(vhdl_type *b, std::string &n, int m, int l)
|
||||
{
|
||||
return new vhdl_type(b, n, m, l);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ enum vhdl_type_name_t {
|
|||
VHDL_TYPE_SIGNED,
|
||||
VHDL_TYPE_UNSIGNED,
|
||||
VHDL_TYPE_TIME,
|
||||
VHDL_TYPE_ARRAY,
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -43,14 +44,27 @@ enum vhdl_type_name_t {
|
|||
*/
|
||||
class vhdl_type : public vhdl_element {
|
||||
public:
|
||||
// Scalar constructor
|
||||
vhdl_type(vhdl_type_name_t name, int msb = 0, int lsb = 0)
|
||||
: name_(name), msb_(msb), lsb_(lsb) {}
|
||||
virtual ~vhdl_type() {}
|
||||
: name_(name), msb_(msb), lsb_(lsb), base_(NULL) {}
|
||||
|
||||
// Array constructor
|
||||
vhdl_type(vhdl_type *base, const std::string &array_name,
|
||||
int msb, int lsb)
|
||||
: name_(VHDL_TYPE_ARRAY), msb_(msb), lsb_(lsb), base_(base),
|
||||
array_name_(array_name) {}
|
||||
|
||||
// Copy constructor
|
||||
vhdl_type(const vhdl_type &other);
|
||||
|
||||
virtual ~vhdl_type();
|
||||
|
||||
void emit(std::ostream &of, int level) const;
|
||||
vhdl_type_name_t get_name() const { return name_; }
|
||||
std::string get_string() const;
|
||||
std::string get_decl_string() const;
|
||||
std::string get_type_decl_string() const;
|
||||
vhdl_type *get_base() const;
|
||||
int get_width() const { return msb_ - lsb_ + 1; }
|
||||
int get_msb() const { return msb_; }
|
||||
int get_lsb() const { return lsb_; }
|
||||
|
|
@ -67,9 +81,12 @@ public:
|
|||
static vhdl_type *time();
|
||||
|
||||
static vhdl_type *type_for(int width, bool issigned, int lsb=0);
|
||||
static vhdl_type *array_of(vhdl_type *b, std::string &n, int m, int l);
|
||||
protected:
|
||||
vhdl_type_name_t name_;
|
||||
int msb_, lsb_;
|
||||
vhdl_type *base_; // Array base type for VHDL_TYPE_ARRAY
|
||||
std::string array_name_; // Type name for the array `type array_name_ is ...'
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Reference in New Issue