Merge branch 'vhdl2'
This is Nick Gassen's work on the VHDL code generator.
This commit is contained in:
commit
f7ce0f3b79
|
|
@ -50,7 +50,7 @@ dep:
|
|||
mv $*.d dep
|
||||
|
||||
O = vhdl.o state.o vhdl_element.o vhdl_type.o vhdl_syntax.o scope.o process.o \
|
||||
stmt.o expr.o lpm.o display.o support.o cast.o logic.o
|
||||
stmt.o expr.o lpm.o support.o cast.o logic.o
|
||||
|
||||
ifeq (@WIN32@,yes)
|
||||
TGTLDFLAGS=-L.. -livl
|
||||
|
|
|
|||
|
|
@ -60,6 +60,8 @@ vhdl_expr *vhdl_expr::cast(const vhdl_type *to)
|
|||
return to_std_logic();
|
||||
case VHDL_TYPE_STD_ULOGIC:
|
||||
return to_std_ulogic();
|
||||
case VHDL_TYPE_STRING:
|
||||
return to_string();
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
|
|
@ -116,6 +118,25 @@ vhdl_expr *vhdl_expr::to_integer()
|
|||
return conv;
|
||||
}
|
||||
|
||||
vhdl_expr *vhdl_expr::to_string()
|
||||
{
|
||||
bool numeric = type_->get_name() == VHDL_TYPE_UNSIGNED
|
||||
|| type_->get_name() == VHDL_TYPE_SIGNED;
|
||||
|
||||
if (numeric) {
|
||||
vhdl_fcall *image = new vhdl_fcall("integer'image", vhdl_type::string());
|
||||
image->add_expr(this->cast(vhdl_type::integer()));
|
||||
return image;
|
||||
}
|
||||
else {
|
||||
// Assume type'image exists
|
||||
vhdl_fcall *image = new vhdl_fcall(type_->get_string() + "'image",
|
||||
vhdl_type::string());
|
||||
image->add_expr(this);
|
||||
return image;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a generic expression to a Boolean.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,200 +0,0 @@
|
|||
/*
|
||||
* VHDL implementation of $display.
|
||||
*
|
||||
* 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
|
||||
* 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 <iostream>
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
#include <cctype>
|
||||
#include <sstream>
|
||||
|
||||
static const char *DISPLAY_LINE = "Verilog_Display_Line";
|
||||
|
||||
/*
|
||||
* Write a VHDL expression into the current display line.
|
||||
*/
|
||||
static void display_write(stmt_container *container, vhdl_expr *expr)
|
||||
{
|
||||
vhdl_pcall_stmt *write = new vhdl_pcall_stmt("Write");
|
||||
vhdl_var_ref *ref =
|
||||
new vhdl_var_ref(DISPLAY_LINE, vhdl_type::line());
|
||||
write->add_expr(ref);
|
||||
|
||||
vhdl_type_name_t type = expr->get_type()->get_name();
|
||||
if (type == VHDL_TYPE_SIGNED || type == VHDL_TYPE_UNSIGNED) {
|
||||
vhdl_type integer(VHDL_TYPE_INTEGER);
|
||||
write->add_expr(expr->cast(&integer));
|
||||
}
|
||||
else if (type != VHDL_TYPE_STRING) {
|
||||
// Need to add a call to Type'Image for types not
|
||||
// supported by std.textio
|
||||
std::string name(expr->get_type()->get_string());
|
||||
name += "'Image";
|
||||
|
||||
vhdl_fcall *cast
|
||||
= new vhdl_fcall(name.c_str(), vhdl_type::string());
|
||||
cast->add_expr(expr);
|
||||
|
||||
write->add_expr(cast);
|
||||
}
|
||||
else
|
||||
write->add_expr(expr);
|
||||
|
||||
container->add_stmt(write);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the value of DISPLAY_LINE to the output.
|
||||
*/
|
||||
static void display_line(stmt_container *container)
|
||||
{
|
||||
vhdl_pcall_stmt *write_line = new vhdl_pcall_stmt("WriteLine");
|
||||
vhdl_var_ref *output_ref =
|
||||
new vhdl_var_ref("std.textio.Output", new vhdl_type(VHDL_TYPE_FILE));
|
||||
write_line->add_expr(output_ref);
|
||||
vhdl_var_ref *ref =
|
||||
new vhdl_var_ref(DISPLAY_LINE, vhdl_type::line());
|
||||
write_line->add_expr(ref);
|
||||
container->add_stmt(write_line);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse an octal escape sequence.
|
||||
*/
|
||||
static char parse_octal(const char *p)
|
||||
{
|
||||
assert(*p && *(p+1) && *(p+2));
|
||||
assert(isdigit(*p) && isdigit(*(p+1)) && isdigit(*(p+1)));
|
||||
|
||||
return (*p - '0') * 64
|
||||
+ (*(p+1) - '0') * 8
|
||||
+ (*(p+2) - '0') * 1;
|
||||
}
|
||||
|
||||
static void flush_string(std::ostringstream &ss, stmt_container *container)
|
||||
{
|
||||
display_write(container, new vhdl_const_string(ss.str().c_str()));
|
||||
|
||||
// Clear the stream
|
||||
ss.str("");
|
||||
}
|
||||
|
||||
// This should display the hierarchical module name, but we don't support
|
||||
// this in VHDL. So just emit a warning.
|
||||
static void display_m(stmt_container* container)
|
||||
{
|
||||
cerr << "Warning: no VHDL translation for %m format code" << endl;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate VHDL for the $display system task.
|
||||
* This is implemented using the functions in std.textio. Each
|
||||
* parameter is written to a line variable in the process and
|
||||
* then the line is written to the special variable `Output'
|
||||
* (which represents the console). Subsequent $displays will
|
||||
* use the same line variable.
|
||||
*
|
||||
* It's possible, although quite unlikely, that there will be
|
||||
* name collision with an existing variable called
|
||||
* `Verilog_Display_Line' -- do something about this?
|
||||
*/
|
||||
int draw_stask_display(vhdl_procedural *proc, stmt_container *container,
|
||||
ivl_statement_t stmt, bool newline)
|
||||
{
|
||||
if (!proc->get_scope()->have_declared(DISPLAY_LINE)) {
|
||||
vhdl_var_decl *line_var =
|
||||
new vhdl_var_decl(DISPLAY_LINE, vhdl_type::line());
|
||||
line_var->set_comment("For generating $display output");
|
||||
proc->get_scope()->add_decl(line_var);
|
||||
}
|
||||
|
||||
// Write the data into the line
|
||||
int count = ivl_stmt_parm_count(stmt), i = 0;
|
||||
while (i < count) {
|
||||
// $display may have an empty parameter, in which case
|
||||
// the expression will be null
|
||||
// The behaviour here seems to be to output a space
|
||||
ivl_expr_t net = ivl_stmt_parm(stmt, i++);
|
||||
if (net == NULL) {
|
||||
display_write(container, new vhdl_const_string(" "));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ivl_expr_type(net) == IVL_EX_STRING) {
|
||||
ostringstream ss;
|
||||
for (const char *p = ivl_expr_string(net); *p; p++) {
|
||||
if (*p == '\\') {
|
||||
// Octal escape
|
||||
char ch = parse_octal(p+1);
|
||||
if (ch == '\n') {
|
||||
flush_string(ss, container);
|
||||
display_line(container);
|
||||
}
|
||||
else
|
||||
ss << ch;
|
||||
p += 3;
|
||||
}
|
||||
else if (*p == '%' && *(++p) != '%') {
|
||||
flush_string(ss, container);
|
||||
|
||||
// Skip over width for now
|
||||
while (isdigit(*p)) ++p;
|
||||
|
||||
switch (*p) {
|
||||
case 'm':
|
||||
display_m(container);
|
||||
break;
|
||||
default:
|
||||
{
|
||||
assert(i < count);
|
||||
ivl_expr_t netp = ivl_stmt_parm(stmt, i++);
|
||||
assert(netp);
|
||||
|
||||
vhdl_expr *base = translate_expr(netp);
|
||||
if (NULL == base)
|
||||
return 1;
|
||||
|
||||
display_write(container, base);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
ss << *p;
|
||||
}
|
||||
|
||||
// Call Write on any non-empty string data left in the buffer
|
||||
if (!ss.str().empty())
|
||||
display_write(container, new vhdl_const_string(ss.str().c_str()));
|
||||
}
|
||||
else {
|
||||
vhdl_expr *base = translate_expr(net);
|
||||
if (NULL == base)
|
||||
return 1;
|
||||
|
||||
display_write(container, base);
|
||||
}
|
||||
}
|
||||
|
||||
if (newline)
|
||||
display_line(container);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -57,15 +57,12 @@ static int generate_vhdl_process(vhdl_entity *ent, ivl_process_t proc)
|
|||
// However, if no statements were added to the container
|
||||
// by draw_stmt, don't bother adding a wait as `emit'
|
||||
// will optimise the process out of the output
|
||||
if (ivl_process_type(proc) == IVL_PR_INITIAL) {
|
||||
// Get rid of any useless `wait for 0 ns's at the end of the process
|
||||
prune_wait_for_0(vhdl_proc->get_container());
|
||||
|
||||
// The above pruning might have removed all logic from the process
|
||||
if (!vhdl_proc->get_container()->empty()) {
|
||||
vhdl_wait_stmt *wait = new vhdl_wait_stmt();
|
||||
vhdl_proc->get_container()->add_stmt(wait);
|
||||
}
|
||||
bool is_initial = ivl_process_type(proc) == IVL_PR_INITIAL;
|
||||
bool is_empty = vhdl_proc->get_container()->empty();
|
||||
|
||||
if (is_initial && !is_empty) {
|
||||
vhdl_wait_stmt *wait = new vhdl_wait_stmt();
|
||||
vhdl_proc->get_container()->add_stmt(wait);
|
||||
}
|
||||
|
||||
// Add a comment indicating where it came from
|
||||
|
|
|
|||
|
|
@ -926,6 +926,26 @@ static void create_skeleton_entity_for(ivl_scope_t scope, int depth)
|
|||
<< " (" << ivl_scope_def_file(scope) << ":"
|
||||
<< ivl_scope_def_lineno(scope) << ")";
|
||||
|
||||
unsigned nparams = ivl_scope_params(scope);
|
||||
for (unsigned i = 0; i < nparams; i++) {
|
||||
ivl_parameter_t param = ivl_scope_param(scope, i);
|
||||
ss << "\n " << ivl_parameter_basename(param) << " = ";
|
||||
|
||||
ivl_expr_t value = ivl_parameter_expr(param);
|
||||
switch (ivl_expr_type(value)) {
|
||||
case IVL_EX_STRING:
|
||||
ss << "\"" << ivl_expr_string(value) << "\"";
|
||||
break;
|
||||
|
||||
case IVL_EX_NUMBER:
|
||||
ss << ivl_expr_uvalue(value);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
arch->set_comment(ss.str());
|
||||
ent->set_comment(ss.str());
|
||||
|
||||
|
|
|
|||
|
|
@ -25,8 +25,9 @@
|
|||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
|
@ -67,7 +68,7 @@ struct signal_defn_t {
|
|||
static entity_list_t g_entities;
|
||||
|
||||
// Store the mapping of ivl scope names to entity names
|
||||
typedef map<string, string> scope_name_map_t;
|
||||
typedef map<ivl_scope_t, string> scope_name_map_t;
|
||||
static scope_name_map_t g_scope_names;
|
||||
|
||||
typedef std::map<ivl_signal_t, signal_defn_t> signal_defn_map_t;
|
||||
|
|
@ -77,10 +78,9 @@ static vhdl_entity *g_active_entity = NULL;
|
|||
|
||||
// Set of scopes that are treated as the default examples of
|
||||
// that type. Any other scopes of the same type are ignored.
|
||||
typedef set<ivl_scope_t> default_scopes_t;
|
||||
typedef vector<ivl_scope_t> default_scopes_t;
|
||||
static default_scopes_t g_default_scopes;
|
||||
|
||||
|
||||
// True if signal `sig' has already been encountered by the code
|
||||
// generator. This means we have already assigned it to a VHDL code
|
||||
// object and possibly renamed it.
|
||||
|
|
@ -179,18 +179,31 @@ vhdl_entity* find_entity(ivl_scope_t scope)
|
|||
|
||||
assert(ivl_scope_type(scope) == IVL_SCT_MODULE);
|
||||
|
||||
scope_name_map_t::iterator it = g_scope_names.find(ivl_scope_tname(scope));
|
||||
if (it != g_scope_names.end())
|
||||
return find_entity((*it).second);
|
||||
else
|
||||
if (is_default_scope_instance(scope)) {
|
||||
scope_name_map_t::iterator it = g_scope_names.find(scope);
|
||||
if (it != g_scope_names.end())
|
||||
return find_entity((*it).second);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
const char *tname = ivl_scope_tname(scope);
|
||||
|
||||
for (scope_name_map_t::iterator it = g_scope_names.begin();
|
||||
it != g_scope_names.end(); ++it) {
|
||||
if (strcmp(tname, ivl_scope_tname((*it).first)) == 0)
|
||||
return find_entity((*it).second);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Add an entity/architecture pair to the list of entities to emit.
|
||||
void remember_entity(vhdl_entity* ent, ivl_scope_t scope)
|
||||
{
|
||||
g_entities.push_back(ent);
|
||||
g_scope_names[ivl_scope_tname(scope)] = ent->get_name();
|
||||
g_scope_names[scope] = ent->get_name();
|
||||
}
|
||||
|
||||
// Print all VHDL entities, in order, to the specified output stream.
|
||||
|
|
@ -228,12 +241,52 @@ void set_active_entity(vhdl_entity *ent)
|
|||
{
|
||||
g_active_entity = ent;
|
||||
}
|
||||
|
||||
/*
|
||||
* True if two scopes have the same type name.
|
||||
*/
|
||||
static bool same_scope_type_name(ivl_scope_t a, ivl_scope_t b)
|
||||
{
|
||||
return strcmp(ivl_scope_tname(a), ivl_scope_tname(b)) == 0;
|
||||
if (strcmp(ivl_scope_tname(a), ivl_scope_tname(b)) != 0)
|
||||
return false;
|
||||
|
||||
unsigned nparams_a = ivl_scope_params(a);
|
||||
unsigned nparams_b = ivl_scope_params(b);
|
||||
|
||||
if (nparams_a != nparams_b)
|
||||
return false;
|
||||
|
||||
for (unsigned i = 0; i < nparams_a; i++) {
|
||||
ivl_parameter_t param_a = ivl_scope_param(a, i);
|
||||
ivl_parameter_t param_b = ivl_scope_param(b, i);
|
||||
|
||||
if (strcmp(ivl_parameter_basename(param_a),
|
||||
ivl_parameter_basename(param_b)) != 0)
|
||||
return false;
|
||||
|
||||
ivl_expr_t value_a = ivl_parameter_expr(param_a);
|
||||
ivl_expr_t value_b = ivl_parameter_expr(param_b);
|
||||
|
||||
if (ivl_expr_type(value_a) != ivl_expr_type(value_b))
|
||||
return false;
|
||||
|
||||
switch (ivl_expr_type(value_a)) {
|
||||
case IVL_EX_STRING:
|
||||
if (strcmp(ivl_expr_string(value_a), ivl_expr_string(value_b)) != 0)
|
||||
return false;
|
||||
break;
|
||||
|
||||
case IVL_EX_NUMBER:
|
||||
if (ivl_expr_uvalue(value_a) != ivl_expr_uvalue(value_b))
|
||||
return false;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -246,7 +299,7 @@ bool seen_this_scope_type(ivl_scope_t s)
|
|||
if (find_if(g_default_scopes.begin(), g_default_scopes.end(),
|
||||
bind1st(ptr_fun(same_scope_type_name), s))
|
||||
== g_default_scopes.end()) {
|
||||
g_default_scopes.insert(s);
|
||||
g_default_scopes.push_back(s);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
|
|
|
|||
276
tgt-vhdl/stmt.cc
276
tgt-vhdl/stmt.cc
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* VHDL code generation for statements.
|
||||
*
|
||||
* Copyright (C) 2008-2009 Nick Gasson (nick@nickg.me.uk)
|
||||
* Copyright (C) 2008-2010 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
|
||||
|
|
@ -30,6 +30,9 @@
|
|||
#include <set>
|
||||
#include <algorithm>
|
||||
|
||||
static void emit_wait_for_0(vhdl_procedural *proc, stmt_container *container,
|
||||
ivl_statement_t stmt, vhdl_expr *expr);
|
||||
|
||||
/*
|
||||
* VHDL has no real equivalent of Verilog's $finish task. The
|
||||
* current solution is to use `assert false ...' to terminate
|
||||
|
|
@ -51,12 +54,114 @@ static int draw_stask_finish(vhdl_procedural *proc, stmt_container *container,
|
|||
container->add_stmt(new vhdl_pcall_stmt("work.Verilog_Support.Finish"));
|
||||
}
|
||||
else {
|
||||
container->add_stmt(new vhdl_assert_stmt("SIMULATION FINISHED"));
|
||||
container->add_stmt(
|
||||
new vhdl_report_stmt(new vhdl_const_string("SIMULATION FINISHED"),
|
||||
SEVERITY_FAILURE));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char parse_octal(const char *p)
|
||||
{
|
||||
assert(*p && *(p+1) && *(p+2));
|
||||
assert(isdigit(*p) && isdigit(*(p+1)) && isdigit(*(p+1)));
|
||||
|
||||
return (*p - '0') * 64
|
||||
+ (*(p+1) - '0') * 8
|
||||
+ (*(p+2) - '0') * 1;
|
||||
}
|
||||
|
||||
// Generate VHDL report statements for Verilog $display/$write
|
||||
static int draw_stask_display(vhdl_procedural *proc,
|
||||
stmt_container *container,
|
||||
ivl_statement_t stmt)
|
||||
{
|
||||
vhdl_binop_expr *text = new vhdl_binop_expr(VHDL_BINOP_CONCAT,
|
||||
vhdl_type::string());
|
||||
|
||||
const int count = ivl_stmt_parm_count(stmt);
|
||||
int i = 0;
|
||||
while (i < count) {
|
||||
// $display may have an empty parameter, in which case
|
||||
// the expression will be null
|
||||
// The behaviour here seems to be to output a space
|
||||
ivl_expr_t net = ivl_stmt_parm(stmt, i++);
|
||||
if (net == NULL) {
|
||||
text->add_expr(new vhdl_const_string(" "));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ivl_expr_type(net) == IVL_EX_STRING) {
|
||||
ostringstream ss;
|
||||
for (const char *p = ivl_expr_string(net); *p; p++) {
|
||||
if (*p == '\\') {
|
||||
// Octal escape
|
||||
char ch = parse_octal(p+1);
|
||||
if (ch == '\n') {
|
||||
// Is there a better way of handling newlines?
|
||||
// Maybe generate another report statement
|
||||
}
|
||||
else
|
||||
ss << ch;
|
||||
p += 3;
|
||||
}
|
||||
else if (*p == '%' && *(++p) != '%') {
|
||||
// Flush the output string up to this point
|
||||
text->add_expr(new vhdl_const_string(ss.str()));
|
||||
ss.str("");
|
||||
|
||||
// Skip over width for now
|
||||
while (isdigit(*p)) ++p;
|
||||
|
||||
switch (*p) {
|
||||
case 'm':
|
||||
// TOOD: we can get the module name via attributes
|
||||
cerr << "Warning: no VHDL translation for %m format code"
|
||||
<< endl;
|
||||
break;
|
||||
default:
|
||||
{
|
||||
assert(i < count);
|
||||
ivl_expr_t netp = ivl_stmt_parm(stmt, i++);
|
||||
assert(netp);
|
||||
|
||||
vhdl_expr *base = translate_expr(netp);
|
||||
if (NULL == base)
|
||||
return 1;
|
||||
|
||||
emit_wait_for_0(proc, container, stmt, base);
|
||||
|
||||
text->add_expr(base->cast(text->get_type()));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
ss << *p;
|
||||
}
|
||||
|
||||
// Emit any non-empty string data left in the buffer
|
||||
if (!ss.str().empty())
|
||||
text->add_expr(new vhdl_const_string(ss.str()));
|
||||
}
|
||||
else {
|
||||
vhdl_expr *base = translate_expr(net);
|
||||
if (NULL == base)
|
||||
return 1;
|
||||
|
||||
emit_wait_for_0(proc, container, stmt, base);
|
||||
|
||||
text->add_expr(base->cast(text->get_type()));
|
||||
}
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
text->add_expr(new vhdl_const_string(""));
|
||||
|
||||
container->add_stmt(new vhdl_report_stmt(text));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate VHDL for system tasks (like $display). Not all of
|
||||
* these are supported.
|
||||
|
|
@ -67,9 +172,9 @@ static int draw_stask(vhdl_procedural *proc, stmt_container *container,
|
|||
const char *name = ivl_stmt_name(stmt);
|
||||
|
||||
if (strcmp(name, "$display") == 0)
|
||||
return draw_stask_display(proc, container, stmt, true);
|
||||
return draw_stask_display(proc, container, stmt);
|
||||
else if (strcmp(name, "$write") == 0)
|
||||
return draw_stask_display(proc, container, stmt, false);
|
||||
return draw_stask_display(proc, container, stmt);
|
||||
else if (strcmp(name, "$finish") == 0)
|
||||
return draw_stask_finish(proc, container, stmt);
|
||||
else {
|
||||
|
|
@ -131,27 +236,6 @@ static int draw_noop(vhdl_procedural *proc, stmt_container *container,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The VHDL code generator inserts `wait for 0 ns' after each
|
||||
* not-last-in-block blocking assignment.
|
||||
* If this is immediately followed by another `wait for ...' then
|
||||
* we might as well not emit the first zero-time wait.
|
||||
*/
|
||||
void prune_wait_for_0(stmt_container *container)
|
||||
{
|
||||
vhdl_wait_stmt *wait0;
|
||||
stmt_container::stmt_list_t &stmts = container->get_stmts();
|
||||
while (stmts.size() > 0
|
||||
&& (wait0 = dynamic_cast<vhdl_wait_stmt*>(stmts.back()))) {
|
||||
if (wait0->get_type() == VHDL_WAIT_FOR0) {
|
||||
delete wait0;
|
||||
stmts.pop_back();
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static vhdl_var_ref *make_assign_lhs(ivl_lval_t lval, vhdl_scope *scope)
|
||||
{
|
||||
ivl_signal_t sig = ivl_lval_sig(lval);
|
||||
|
|
@ -263,12 +347,68 @@ bool check_valid_assignment(vhdl_decl::assign_type_t atype, vhdl_procedural *pro
|
|||
return true;
|
||||
}
|
||||
|
||||
// Generate a "wait for 0 ns" statement to emulate the behaviour of
|
||||
// Verilog blocking assignment using VHDL signals. This is only generated
|
||||
// if we read from the target of a blocking assignment in the same
|
||||
// process (i.e. it is only generated when required, not for every
|
||||
// blocking assignment). An example:
|
||||
//
|
||||
// begin
|
||||
// x = 5;
|
||||
// if (x == 2)
|
||||
// y = 7;
|
||||
// end
|
||||
//
|
||||
// Becomes:
|
||||
//
|
||||
// x <= 5;
|
||||
// wait for 0 ns; -- Required to implement assignment semantics
|
||||
// if x = 2 then
|
||||
// y <= 7; -- No need for wait here, not read
|
||||
// end if;
|
||||
//
|
||||
static void emit_wait_for_0(vhdl_procedural *proc,
|
||||
stmt_container *container,
|
||||
ivl_statement_t stmt,
|
||||
vhdl_expr *expr)
|
||||
{
|
||||
vhdl_var_set_t read;
|
||||
expr->find_vars(read);
|
||||
|
||||
bool need_wait_for_0 = false;
|
||||
for (vhdl_var_set_t::const_iterator it = read.begin();
|
||||
it != read.end(); ++it) {
|
||||
if (proc->is_blocking_target(*it))
|
||||
need_wait_for_0 = true;
|
||||
}
|
||||
|
||||
stmt_container::stmt_list_t &stmts = container->get_stmts();
|
||||
bool last_was_wait =
|
||||
!stmts.empty() && dynamic_cast<vhdl_wait_stmt*>(stmts.back());
|
||||
|
||||
if (need_wait_for_0 && !last_was_wait) {
|
||||
debug_msg("Generated wait-for-0 for %s:%d",
|
||||
ivl_stmt_file(stmt), ivl_stmt_lineno(stmt));
|
||||
|
||||
vhdl_seq_stmt *wait = new vhdl_wait_stmt(VHDL_WAIT_FOR0);
|
||||
|
||||
ostringstream ss;
|
||||
ss << "Read target of blocking assignment ("
|
||||
<< ivl_stmt_file(stmt)
|
||||
<< ":" << ivl_stmt_lineno(stmt) << ")";
|
||||
wait->set_comment(ss.str());
|
||||
|
||||
container->add_stmt(wait);
|
||||
proc->added_wait_stmt();
|
||||
}
|
||||
}
|
||||
|
||||
// Generate an assignment of type T for the Verilog statement stmt.
|
||||
// If a statement was generated then `assign_type' will contain the
|
||||
// type of assignment that was generated; this should be initialised
|
||||
// to some sensible default.
|
||||
void make_assignment(vhdl_procedural *proc, stmt_container *container,
|
||||
ivl_statement_t stmt, bool blocking,
|
||||
ivl_statement_t stmt, bool emul_blocking,
|
||||
vhdl_decl::assign_type_t& assign_type)
|
||||
{
|
||||
list<vhdl_var_ref*> lvals;
|
||||
|
|
@ -286,14 +426,23 @@ void make_assignment(vhdl_procedural *proc, stmt_container *container,
|
|||
if (rhs == NULL)
|
||||
return;
|
||||
|
||||
emit_wait_for_0(proc, container, stmt, rhs);
|
||||
if (rhs2)
|
||||
emit_wait_for_0(proc, container, stmt, rhs2);
|
||||
|
||||
if (lvals.size() == 1) {
|
||||
vhdl_var_ref *lhs = lvals.front();
|
||||
rhs = rhs->cast(lhs->get_type());
|
||||
|
||||
ivl_expr_t i_delay;
|
||||
vhdl_expr *after = NULL;
|
||||
if ((i_delay = ivl_stmt_delay_expr(stmt)) != NULL)
|
||||
if ((i_delay = ivl_stmt_delay_expr(stmt)) != NULL) {
|
||||
after = translate_time_expr(i_delay);
|
||||
if (after == NULL)
|
||||
return;
|
||||
|
||||
emit_wait_for_0(proc, container, stmt, after);
|
||||
}
|
||||
|
||||
// Find the declaration of the LHS so we know what type
|
||||
// of assignment statement to generate (is it a signal,
|
||||
|
|
@ -301,6 +450,9 @@ void make_assignment(vhdl_procedural *proc, stmt_container *container,
|
|||
vhdl_decl *decl = proc->get_scope()->get_decl(lhs->get_name());
|
||||
assign_type = decl->assignment_type();
|
||||
|
||||
if (assign_type == vhdl_decl::ASSIGN_NONBLOCK && emul_blocking)
|
||||
proc->add_blocking_target(lhs);
|
||||
|
||||
// A small optimisation is to expand ternary RHSs into an
|
||||
// if statement (eliminates a function call and produces
|
||||
// more idiomatic code)
|
||||
|
|
@ -313,6 +465,8 @@ void make_assignment(vhdl_procedural *proc, stmt_container *container,
|
|||
if (NULL == test)
|
||||
return;
|
||||
|
||||
emit_wait_for_0(proc, container, stmt, test);
|
||||
|
||||
if (!check_valid_assignment(decl->assignment_type(), proc, stmt))
|
||||
return;
|
||||
|
||||
|
|
@ -368,6 +522,7 @@ void make_assignment(vhdl_procedural *proc, stmt_container *container,
|
|||
decl->set_initial(NULL); // Default initial value
|
||||
else {
|
||||
decl->set_initial(rhs);
|
||||
proc->get_scope()->hoisted_initialiser(true);
|
||||
delete lhs;
|
||||
return;
|
||||
}
|
||||
|
|
@ -380,8 +535,7 @@ void make_assignment(vhdl_procedural *proc, stmt_container *container,
|
|||
assign_for(decl->assignment_type(), lhs, rhs);
|
||||
container->add_stmt(a);
|
||||
|
||||
if (after != NULL)
|
||||
a->set_after(after);
|
||||
a->set_after(after);
|
||||
}
|
||||
else {
|
||||
// Multiple lvals are implemented by first assigning the complete
|
||||
|
|
@ -408,8 +562,13 @@ void make_assignment(vhdl_procedural *proc, stmt_container *container,
|
|||
|
||||
ivl_expr_t i_delay;
|
||||
vhdl_expr *after = NULL;
|
||||
if ((i_delay = ivl_stmt_delay_expr(stmt)) != NULL)
|
||||
if ((i_delay = ivl_stmt_delay_expr(stmt)) != NULL) {
|
||||
after = translate_time_expr(i_delay);
|
||||
if (after == NULL)
|
||||
return;
|
||||
|
||||
emit_wait_for_0(proc, container, stmt, after);
|
||||
}
|
||||
|
||||
// Find the declaration of the LHS so we know what type
|
||||
// of assignment statement to generate (is it a signal,
|
||||
|
|
@ -428,10 +587,11 @@ void make_assignment(vhdl_procedural *proc, stmt_container *container,
|
|||
container->add_stmt(a);
|
||||
|
||||
width_so_far += lval_width;
|
||||
|
||||
if (assign_type == vhdl_decl::ASSIGN_NONBLOCK && emul_blocking)
|
||||
proc->add_blocking_target(*it);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -454,26 +614,10 @@ static int draw_assign(vhdl_procedural *proc, stmt_container *container,
|
|||
ivl_statement_t stmt, bool is_last)
|
||||
{
|
||||
vhdl_decl::assign_type_t assign_type = vhdl_decl::ASSIGN_NONBLOCK;
|
||||
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(proc, container, stmt, false, assign_type);
|
||||
|
||||
// Don't generate a zero-wait if either:
|
||||
// a) this is the last statement in the process
|
||||
// c) a blocking assignment was generated
|
||||
if (!is_last && assign_type == vhdl_decl::ASSIGN_NONBLOCK) {
|
||||
prune_wait_for_0(container);
|
||||
container->add_stmt
|
||||
(new vhdl_wait_stmt(VHDL_WAIT_FOR0));
|
||||
proc->added_wait_stmt();
|
||||
}
|
||||
}
|
||||
else
|
||||
make_assignment(proc, container, stmt, true, assign_type);
|
||||
|
||||
bool emulate_blocking = proc->get_scope()->allow_signal_assignment();
|
||||
|
||||
make_assignment(proc, container, stmt, emulate_blocking, assign_type);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -501,9 +645,7 @@ static int draw_delay(vhdl_procedural *proc, stmt_container *container,
|
|||
if (NULL == time)
|
||||
return 1;
|
||||
}
|
||||
|
||||
prune_wait_for_0(container);
|
||||
|
||||
|
||||
ivl_statement_t sub_stmt = ivl_stmt_sub_stmt(stmt);
|
||||
vhdl_wait_stmt *wait =
|
||||
new vhdl_wait_stmt(VHDL_WAIT_FOR, time);
|
||||
|
|
@ -523,8 +665,8 @@ static int draw_delay(vhdl_procedural *proc, stmt_container *container,
|
|||
// Any further assignments occur after simulation time 0
|
||||
// so they cannot be used to initialise signal declarations
|
||||
// (if this scope is an initial process)
|
||||
proc->get_scope()->set_initializing(false);
|
||||
|
||||
proc->get_scope()->set_initializing(false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -743,9 +885,12 @@ static int draw_wait(vhdl_procedural *_proc, stmt_container *container,
|
|||
|
||||
// If this container is the top-level statement (i.e. it is the
|
||||
// first thing inside a process) then we can extract these
|
||||
// events out into the sensitivity list
|
||||
bool is_top_level = container == proc->get_container()
|
||||
&& container->empty();
|
||||
// events out into the sensitivity list as long as we haven't
|
||||
// promoted any preceding assignments to initialisers
|
||||
bool is_top_level =
|
||||
container == proc->get_container()
|
||||
&& container->empty()
|
||||
&& !proc->get_scope()->hoisted_initialiser();
|
||||
|
||||
// See if this can be implemented in a more idiomatic way before we
|
||||
// fall back on the generic translation
|
||||
|
|
@ -876,8 +1021,11 @@ static int draw_if(vhdl_procedural *proc, stmt_container *container,
|
|||
if (NULL == test)
|
||||
return 1;
|
||||
|
||||
emit_wait_for_0(proc, container, stmt, test);
|
||||
|
||||
vhdl_if_stmt *vhdif = new vhdl_if_stmt(test);
|
||||
|
||||
container->add_stmt(vhdif);
|
||||
|
||||
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, is_last);
|
||||
|
|
@ -886,8 +1034,6 @@ static int draw_if(vhdl_procedural *proc, stmt_container *container,
|
|||
if (cond_false_stmt)
|
||||
draw_stmt(proc, vhdif->get_else_container(), cond_false_stmt, is_last);
|
||||
|
||||
container->add_stmt(vhdif);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1403,9 +1549,13 @@ int draw_while(vhdl_procedural *proc, stmt_container *container,
|
|||
vhdl_type boolean(VHDL_TYPE_BOOLEAN);
|
||||
test = test->cast(&boolean);
|
||||
|
||||
emit_wait_for_0(proc, container, stmt, test);
|
||||
|
||||
vhdl_while_stmt *loop = new vhdl_while_stmt(test);
|
||||
draw_stmt(proc, loop->get_container(), ivl_stmt_sub_stmt(stmt));
|
||||
|
||||
emit_wait_for_0(proc, loop->get_container(), stmt, test);
|
||||
|
||||
container->add_stmt(loop);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,10 +81,21 @@ void vhdl_element::emit_comment(std::ostream &of, int level,
|
|||
{
|
||||
if (comment_.size() > 0) {
|
||||
if (end_of_line)
|
||||
of << " ";
|
||||
of << "-- " << comment_;
|
||||
if (!end_of_line)
|
||||
of << " -- " << comment_;
|
||||
else {
|
||||
// Comment may contain embedded newlines
|
||||
of << "-- ";
|
||||
for (string::const_iterator it = comment_.begin();
|
||||
it != comment_.end(); ++it) {
|
||||
if (*it == '\n') {
|
||||
newline(of, level);
|
||||
of << "-- ";
|
||||
}
|
||||
else
|
||||
of << *it;
|
||||
}
|
||||
newline(of, level);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* VHDL abstract syntax elements.
|
||||
*
|
||||
* Copyright (C) 2008 Nick Gasson (nick@nickg.me.uk)
|
||||
* Copyright (C) 2008-2010 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
|
||||
|
|
@ -31,7 +31,8 @@
|
|||
using namespace std;
|
||||
|
||||
vhdl_scope::vhdl_scope()
|
||||
: parent_(NULL), init_(false), sig_assign_(true)
|
||||
: parent_(NULL), init_(false), sig_assign_(true),
|
||||
hoisted_init_(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
|
@ -100,6 +101,16 @@ vhdl_scope *vhdl_scope::get_parent() const
|
|||
return parent_;
|
||||
}
|
||||
|
||||
bool vhdl_scope::hoisted_initialiser() const
|
||||
{
|
||||
return hoisted_init_;
|
||||
}
|
||||
|
||||
void vhdl_scope::hoisted_initialiser(bool h)
|
||||
{
|
||||
hoisted_init_ = h;
|
||||
}
|
||||
|
||||
vhdl_entity::vhdl_entity(const string& name, vhdl_arch *arch, int depth__)
|
||||
: depth(depth__), name_(name), arch_(arch),
|
||||
time_unit_(TIME_UNIT_NS)
|
||||
|
|
@ -124,7 +135,6 @@ void vhdl_entity::emit(std::ostream &of, int level) const
|
|||
of << "library ieee;" << std::endl;
|
||||
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 << std::endl;
|
||||
|
||||
emit_comment(of, level);
|
||||
|
|
@ -193,6 +203,16 @@ void vhdl_arch::emit(std::ostream &of, int level) const
|
|||
blank_line(of, level); // Extra blank line after architectures;
|
||||
}
|
||||
|
||||
void vhdl_procedural::add_blocking_target(vhdl_var_ref* ref)
|
||||
{
|
||||
blocking_targets_.insert(ref->get_name());
|
||||
}
|
||||
|
||||
bool vhdl_procedural::is_blocking_target(vhdl_var_ref* ref) const
|
||||
{
|
||||
return blocking_targets_.find(ref->get_name()) != blocking_targets_.end();
|
||||
}
|
||||
|
||||
void vhdl_process::add_sensitivity(const std::string &name)
|
||||
{
|
||||
sens_.push_back(name);
|
||||
|
|
@ -399,6 +419,7 @@ void vhdl_wait_stmt::emit(std::ostream &of, int level) const
|
|||
}
|
||||
|
||||
of << ";";
|
||||
emit_comment(of, level, true);
|
||||
}
|
||||
|
||||
vhdl_decl::~vhdl_decl()
|
||||
|
|
@ -598,11 +619,7 @@ void vhdl_var_ref::emit(std::ostream &of, int level) const
|
|||
|
||||
void vhdl_const_string::emit(std::ostream &of, int level) const
|
||||
{
|
||||
// In some instances a string literal can be ambiguous between
|
||||
// a String type and some other types (e.g. std_logic_vector)
|
||||
// The explicit cast to String removes this ambiguity (although
|
||||
// isn't always strictly necessary)
|
||||
of << "String'(\"" << value_ << "\")";
|
||||
of << "\"" << value_ << "\"";
|
||||
}
|
||||
|
||||
void vhdl_null_stmt::emit(std::ostream &of, int level) const
|
||||
|
|
@ -630,7 +647,7 @@ vhdl_abstract_assign_stmt::~vhdl_abstract_assign_stmt()
|
|||
void vhdl_abstract_assign_stmt::find_vars(vhdl_var_set_t& read,
|
||||
vhdl_var_set_t& write)
|
||||
{
|
||||
write.insert(lhs_);
|
||||
lhs_->find_vars(write);
|
||||
rhs_->find_vars(read);
|
||||
}
|
||||
|
||||
|
|
@ -766,10 +783,42 @@ void vhdl_cassign_stmt::emit(std::ostream &of, int level) const
|
|||
of << ";";
|
||||
}
|
||||
|
||||
vhdl_report_stmt::vhdl_report_stmt(vhdl_expr *text,
|
||||
vhdl_severity_t severity)
|
||||
: severity_(severity),
|
||||
text_(text)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void vhdl_report_stmt::emit(ostream& of, int level) const
|
||||
{
|
||||
of << "report ";
|
||||
text_->emit(of, level);
|
||||
|
||||
if (severity_ != SEVERITY_NOTE) {
|
||||
const char *levels[] = { "note", "warning", "error", "failure" };
|
||||
of << " severity " << levels[severity_];
|
||||
}
|
||||
|
||||
of << ";";
|
||||
}
|
||||
|
||||
void vhdl_report_stmt::find_vars(vhdl_var_set_t& read, vhdl_var_set_t& write)
|
||||
{
|
||||
text_->find_vars(read);
|
||||
}
|
||||
|
||||
vhdl_assert_stmt::vhdl_assert_stmt(const char *reason)
|
||||
: vhdl_report_stmt(new vhdl_const_string(reason), SEVERITY_FAILURE)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void vhdl_assert_stmt::emit(std::ostream &of, int level) const
|
||||
{
|
||||
of << "assert false"; // TODO: Allow arbitrary expression
|
||||
of << " report \"" << reason_ << "\" severity failure;";
|
||||
of << "assert false "; // TODO: Allow arbitrary expression
|
||||
vhdl_report_stmt::emit(of, level);
|
||||
}
|
||||
|
||||
vhdl_if_stmt::vhdl_if_stmt(vhdl_expr *test)
|
||||
|
|
|
|||
|
|
@ -52,7 +52,8 @@ public:
|
|||
virtual vhdl_expr *to_std_logic();
|
||||
virtual vhdl_expr *to_std_ulogic();
|
||||
virtual vhdl_expr *to_vector(vhdl_type_name_t name, int w);
|
||||
virtual void find_vars(vhdl_var_set_t& read) const {}
|
||||
virtual vhdl_expr *to_string();
|
||||
virtual void find_vars(vhdl_var_set_t& read) {}
|
||||
|
||||
protected:
|
||||
static void open_parens(ostream& of);
|
||||
|
|
@ -176,7 +177,7 @@ private:
|
|||
|
||||
class vhdl_const_string : public vhdl_expr {
|
||||
public:
|
||||
vhdl_const_string(const char *value)
|
||||
vhdl_const_string(const string& value)
|
||||
: vhdl_expr(vhdl_type::string(), true), value_(value) {}
|
||||
|
||||
void emit(std::ostream &of, int level) const;
|
||||
|
|
@ -270,7 +271,7 @@ private:
|
|||
*/
|
||||
class vhdl_fcall : public vhdl_expr {
|
||||
public:
|
||||
vhdl_fcall(const char *name, vhdl_type *rtype)
|
||||
vhdl_fcall(const string& name, vhdl_type *rtype)
|
||||
: vhdl_expr(rtype), name_(name) {};
|
||||
~vhdl_fcall() {}
|
||||
|
||||
|
|
@ -453,15 +454,32 @@ public:
|
|||
};
|
||||
|
||||
|
||||
class vhdl_assert_stmt : public vhdl_seq_stmt {
|
||||
public:
|
||||
vhdl_assert_stmt(const char *reason)
|
||||
: reason_(reason) {}
|
||||
enum vhdl_severity_t {
|
||||
SEVERITY_NOTE,
|
||||
SEVERITY_WARNING,
|
||||
SEVERITY_ERROR,
|
||||
SEVERITY_FAILURE
|
||||
};
|
||||
|
||||
void emit(std::ostream &of, int level) const;
|
||||
void find_vars(vhdl_var_set_t& read, vhdl_var_set_t& write) {}
|
||||
class vhdl_report_stmt : public vhdl_seq_stmt {
|
||||
public:
|
||||
vhdl_report_stmt(vhdl_expr *text,
|
||||
vhdl_severity_t severity = SEVERITY_NOTE);
|
||||
virtual ~vhdl_report_stmt() {}
|
||||
|
||||
virtual void emit(ostream& of, int level) const;
|
||||
void find_vars(vhdl_var_set_t& read, vhdl_var_set_t& write);
|
||||
private:
|
||||
std::string reason_;
|
||||
vhdl_severity_t severity_;
|
||||
vhdl_expr *text_;
|
||||
};
|
||||
|
||||
|
||||
class vhdl_assert_stmt : public vhdl_report_stmt {
|
||||
public:
|
||||
vhdl_assert_stmt(const char *reason);
|
||||
|
||||
void emit(ostream &of, int level) const;
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -770,6 +788,8 @@ public:
|
|||
|
||||
bool initializing() const { return init_; }
|
||||
void set_initializing(bool i);
|
||||
bool hoisted_initialiser() const;
|
||||
void hoisted_initialiser(bool h);
|
||||
|
||||
void set_allow_signal_assignment(bool b) { sig_assign_ = b; }
|
||||
bool allow_signal_assignment() const { return sig_assign_; }
|
||||
|
|
@ -777,6 +797,7 @@ private:
|
|||
decl_list_t decls_;
|
||||
vhdl_scope *parent_;
|
||||
bool init_, sig_assign_;
|
||||
bool hoisted_init_;
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -795,6 +816,11 @@ public:
|
|||
|
||||
void added_wait_stmt() { contains_wait_stmt_ = true; }
|
||||
bool contains_wait_stmt() const { return contains_wait_stmt_; }
|
||||
|
||||
// Managing set of blocking assignment targets in this block
|
||||
void add_blocking_target(vhdl_var_ref* ref);
|
||||
bool is_blocking_target(vhdl_var_ref* ref) const;
|
||||
|
||||
protected:
|
||||
stmt_container stmts_;
|
||||
vhdl_scope scope_;
|
||||
|
|
@ -804,6 +830,10 @@ protected:
|
|||
// If this is the case then we can't use a sensitivity list for
|
||||
// the process
|
||||
bool contains_wait_stmt_;
|
||||
|
||||
// The set of variable we have performed a blocking
|
||||
// assignment to
|
||||
set<string> blocking_targets_;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// -*- mode: c++ -*-
|
||||
#ifndef INC_VHDL_TARGET_H
|
||||
#define INC_VHDL_TARGET_H
|
||||
|
||||
|
|
@ -28,10 +29,6 @@ ivl_design_t get_vhdl_design();
|
|||
vhdl_var_ref *nexus_to_var_ref(vhdl_scope *arch_scope, ivl_nexus_t nexus);
|
||||
vhdl_var_ref* readable_ref(vhdl_scope* scope, ivl_nexus_t nex);
|
||||
string make_safe_name(ivl_signal_t sig);
|
||||
|
||||
int draw_stask_display(vhdl_procedural *proc, stmt_container *container,
|
||||
ivl_statement_t stmt, bool newline = true);
|
||||
void prune_wait_for_0(stmt_container *container);
|
||||
void require_support_function(support_function_t f);
|
||||
|
||||
#endif /* #ifndef INC_VHDL_TARGET_H */
|
||||
|
|
|
|||
Loading…
Reference in New Issue