Fix various problems with VHDL `buffer' port generation
This patch corrects several bugs with the generation of VHDL `buffer' ports. The code generator should now generate a buffer only if the port needs to be read inside the architecture, otherwise it will stay `out'. This also correct a bug where an output port is connected directly to the output of an instantiated component. Generating `buffer's would work here, but a more idiomatic VHDL approach is to declare an intermediate signal which both outputs are connected to. This is implemented in the patch (fixes the regression of readout.v in the testsuite).
This commit is contained in:
parent
b8e350188e
commit
69e91e4065
|
|
@ -91,6 +91,10 @@ static vhdl_var_ref *translate_signal(ivl_expr_t e)
|
|||
vhdl_decl *decl = scope->get_decl(renamed);
|
||||
assert(decl);
|
||||
|
||||
// Make sure we can read from this declaration
|
||||
// E.g. if this is an `out' port then we need to make it a buffer
|
||||
decl->ensure_readable();
|
||||
|
||||
// Can't generate a constant initialiser for this signal
|
||||
// later as it has already been read
|
||||
if (scope->initializing())
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* VHDL code generation for logic devices.
|
||||
*
|
||||
* Copyright (C) 2008 Nick Gasson (nick@nickg.me.uk)
|
||||
* Copyright (C) 2008-2009 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
|
||||
|
|
@ -26,6 +26,17 @@
|
|||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
// Return a variable reference for a nexus that is guaranteed to
|
||||
// be readable.
|
||||
static vhdl_var_ref *readable_ref(vhdl_scope* scope, ivl_nexus_t nex)
|
||||
{
|
||||
vhdl_var_ref* ref = nexus_to_var_ref(scope, nex);
|
||||
|
||||
vhdl_decl* decl = scope->get_decl(ref->get_name());
|
||||
decl->ensure_readable();
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert the inputs of a logic gate to a binary expression.
|
||||
|
|
@ -41,7 +52,8 @@ static vhdl_expr *inputs_to_expr(vhdl_scope *scope, vhdl_binop_t op,
|
|||
int npins = ivl_logic_pins(log);
|
||||
for (int i = 1; i < npins; i++) {
|
||||
ivl_nexus_t input = ivl_logic_pin(log, i);
|
||||
gate->add_expr(nexus_to_var_ref(scope, input));
|
||||
|
||||
gate->add_expr(readable_ref(scope, input));
|
||||
}
|
||||
|
||||
return gate;
|
||||
|
|
@ -56,7 +68,7 @@ static vhdl_expr *input_to_expr(vhdl_scope *scope, vhdl_unaryop_t op,
|
|||
ivl_nexus_t input = ivl_logic_pin(log, 1);
|
||||
assert(input);
|
||||
|
||||
vhdl_expr *operand = nexus_to_var_ref(scope, input);
|
||||
vhdl_expr *operand = readable_ref(scope, input);
|
||||
return new vhdl_unaryop_expr(op, operand, vhdl_type::std_logic());
|
||||
}
|
||||
|
||||
|
|
@ -66,11 +78,9 @@ static void bufif_logic(vhdl_arch *arch, ivl_net_logic_t log, bool if0)
|
|||
vhdl_var_ref *lhs = nexus_to_var_ref(arch->get_scope(), output);
|
||||
assert(lhs);
|
||||
|
||||
vhdl_expr *val = nexus_to_var_ref(arch->get_scope(), ivl_logic_pin(log, 1));
|
||||
assert(val);
|
||||
vhdl_expr *val = readable_ref(arch->get_scope(), ivl_logic_pin(log, 1));
|
||||
|
||||
vhdl_expr *sel = nexus_to_var_ref(arch->get_scope(), ivl_logic_pin(log, 2));
|
||||
assert(val);
|
||||
vhdl_expr *sel = readable_ref(arch->get_scope(), ivl_logic_pin(log, 2));
|
||||
|
||||
vhdl_expr *cmp;
|
||||
if (ivl_logic_width(log) == 1) {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* VHDL code generation for scopes.
|
||||
*
|
||||
* Copyright (C) 2008 Nick Gasson (nick@nickg.me.uk)
|
||||
* Copyright (C) 2008-2009 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
|
||||
|
|
@ -550,22 +550,23 @@ static void map_signal(ivl_signal_t to, vhdl_entity *parent,
|
|||
// 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.
|
||||
// The VHDL equivalent of this is to make *both* output ports
|
||||
// a `buffer'.
|
||||
vhdl_decl *decl =
|
||||
// The solution used here is to create an intermediate signal
|
||||
// and connect it to both ports.
|
||||
vhdl_decl* from_decl =
|
||||
parent->get_arch()->get_scope()->get_decl(ref->get_name());
|
||||
vhdl_port_decl *pdecl;
|
||||
if ((pdecl = dynamic_cast<vhdl_port_decl*>(decl))
|
||||
&& pdecl->get_mode() == VHDL_PORT_OUT) {
|
||||
if (!from_decl->is_readable()
|
||||
&& !arch_scope->have_declared(name + "_Readable")) {
|
||||
vhdl_decl* tmp_decl =
|
||||
new vhdl_signal_decl(name + "_Readable", ref->get_type());
|
||||
|
||||
// First change the mode in the parent entity
|
||||
//pdecl->set_mode(VHDL_PORT_BUFFER);
|
||||
// Add a comment to explain what this is for
|
||||
tmp_decl->set_comment("Needed to connect outputs");
|
||||
|
||||
// Now change the mode in the child entity
|
||||
/* vhdl_port_decl *to_pdecl =
|
||||
dynamic_cast<vhdl_port_decl*>(find_scope_for_signal(to)->get_decl(name));
|
||||
assert(to_pdecl);
|
||||
to_pdecl->set_mode(VHDL_PORT_BUFFER);*/
|
||||
arch_scope->add_decl(tmp_decl);
|
||||
parent->get_arch()->add_stmt
|
||||
(new vhdl_cassign_stmt(from_decl->make_ref(), tmp_decl->make_ref()));
|
||||
|
||||
ref = tmp_decl->make_ref();
|
||||
}
|
||||
|
||||
inst->map_port(name.c_str(), ref);
|
||||
|
|
|
|||
|
|
@ -355,6 +355,12 @@ vhdl_decl::~vhdl_decl()
|
|||
|
||||
}
|
||||
|
||||
// Make a reference object to this declaration
|
||||
vhdl_var_ref* vhdl_decl::make_ref() const
|
||||
{
|
||||
return new vhdl_var_ref(name_, type_);
|
||||
}
|
||||
|
||||
const vhdl_type *vhdl_decl::get_type() const
|
||||
{
|
||||
assert(type_);
|
||||
|
|
@ -392,6 +398,19 @@ void vhdl_port_decl::emit(std::ostream &of, int level) const
|
|||
type_->emit(of, level);
|
||||
}
|
||||
|
||||
// If this is an `out' port make it a `buffer' so we can read from it
|
||||
void vhdl_port_decl::ensure_readable()
|
||||
{
|
||||
if (mode_ == VHDL_PORT_OUT)
|
||||
mode_ = VHDL_PORT_BUFFER;
|
||||
}
|
||||
|
||||
// A port is readable if it is not `out'.
|
||||
bool vhdl_port_decl::is_readable() const
|
||||
{
|
||||
return mode_ != VHDL_PORT_OUT;
|
||||
}
|
||||
|
||||
void vhdl_var_decl::emit(std::ostream &of, int level) const
|
||||
{
|
||||
of << "variable " << name_ << " : ";
|
||||
|
|
|
|||
|
|
@ -554,6 +554,9 @@ public:
|
|||
void set_initial(vhdl_expr *initial);
|
||||
bool has_initial() const { return has_initial_; }
|
||||
|
||||
// Return a new reference to this declaration
|
||||
vhdl_var_ref* make_ref() const;
|
||||
|
||||
// The different sorts of assignment statement
|
||||
// ASSIGN_CONST is used to generate a variable to shadow a
|
||||
// constant that cannot be assigned to (e.g. a function parameter)
|
||||
|
|
@ -565,6 +568,13 @@ public:
|
|||
// to assign to it so calling assignment_type just raises
|
||||
// an assertion failure
|
||||
virtual assign_type_t assignment_type() const { assert(false); }
|
||||
|
||||
// True if this declaration can be read from
|
||||
virtual bool is_readable() const { return true; }
|
||||
|
||||
// Modify this declaration so it can be read from
|
||||
// This does nothing for most declaration types
|
||||
virtual void ensure_readable() {}
|
||||
protected:
|
||||
std::string name_;
|
||||
const vhdl_type *type_;
|
||||
|
|
@ -618,7 +628,7 @@ public:
|
|||
*/
|
||||
class vhdl_signal_decl : public vhdl_decl {
|
||||
public:
|
||||
vhdl_signal_decl(const char *name, vhdl_type *type)
|
||||
vhdl_signal_decl(const string& name, const vhdl_type* type)
|
||||
: vhdl_decl(name, type) {}
|
||||
virtual void emit(std::ostream &of, int level) const;
|
||||
assign_type_t assignment_type() const { return ASSIGN_NONBLOCK; }
|
||||
|
|
@ -658,6 +668,8 @@ public:
|
|||
vhdl_port_mode_t get_mode() const { return mode_; }
|
||||
void set_mode(vhdl_port_mode_t m) { mode_ = m; }
|
||||
assign_type_t assignment_type() const { return ASSIGN_NONBLOCK; }
|
||||
void ensure_readable();
|
||||
bool is_readable() const;
|
||||
private:
|
||||
vhdl_port_mode_t mode_;
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue