Merge branch 'master' into verilog-ams
This commit is contained in:
commit
810686d88e
117
tgt-vhdl/stmt.cc
117
tgt-vhdl/stmt.cc
|
|
@ -501,12 +501,12 @@ static int draw_if(vhdl_procedural *proc, stmt_container *container,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int draw_case(vhdl_procedural *proc, stmt_container *container,
|
||||
ivl_statement_t stmt, bool is_last)
|
||||
static vhdl_var_ref *draw_case_test(vhdl_procedural *proc, stmt_container *container,
|
||||
ivl_statement_t stmt)
|
||||
{
|
||||
vhdl_expr *test = translate_expr(ivl_stmt_cond_expr(stmt));
|
||||
if (NULL == test)
|
||||
return 1;
|
||||
return NULL;
|
||||
|
||||
// VHDL case expressions are required to be quite simple: variable
|
||||
// references or slices. So we may need to create a temporary
|
||||
|
|
@ -523,8 +523,18 @@ static int draw_case(vhdl_procedural *proc, stmt_container *container,
|
|||
vhdl_var_ref *tmp_ref = new vhdl_var_ref(tmp_name, NULL);
|
||||
container->add_stmt(new vhdl_assign_stmt(tmp_ref, test));
|
||||
|
||||
test = new vhdl_var_ref(tmp_name, test_type);
|
||||
return new vhdl_var_ref(tmp_name, test_type);
|
||||
}
|
||||
else
|
||||
return dynamic_cast<vhdl_var_ref*>(test);
|
||||
}
|
||||
|
||||
static int draw_case(vhdl_procedural *proc, stmt_container *container,
|
||||
ivl_statement_t stmt, bool is_last)
|
||||
{
|
||||
vhdl_var_ref *test = draw_case_test(proc, container, stmt);
|
||||
if (NULL == test)
|
||||
return 1;
|
||||
|
||||
vhdl_case_stmt *vhdlcase = new vhdl_case_stmt(test);
|
||||
container->add_stmt(vhdlcase);
|
||||
|
|
@ -565,6 +575,100 @@ static int draw_case(vhdl_procedural *proc, stmt_container *container,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* A casex statement cannot be directly translated to a VHDL case
|
||||
* statement as VHDL does not treat the don't-care bit as special.
|
||||
* The solution here is to generate an if statement from the casex
|
||||
* which compares only the non-don't-care bit positions.
|
||||
*/
|
||||
int draw_casezx(vhdl_procedural *proc, stmt_container *container,
|
||||
ivl_statement_t stmt, bool is_last)
|
||||
{
|
||||
vhdl_var_ref *test = draw_case_test(proc, container, stmt);
|
||||
if (NULL == test)
|
||||
return 1;
|
||||
|
||||
vhdl_if_stmt *result = NULL;
|
||||
|
||||
int nbranches = ivl_stmt_case_count(stmt);
|
||||
for (int i = 0; i < nbranches; i++) {
|
||||
stmt_container *where = NULL;
|
||||
|
||||
ivl_expr_t net = ivl_stmt_case_expr(stmt, i);
|
||||
if (net) {
|
||||
// The net must be a constant value otherwise we can't
|
||||
// generate the terms for the comparison expression
|
||||
if (ivl_expr_type(net) != IVL_EX_NUMBER) {
|
||||
error("Sorry, only casex statements with constant labels can "
|
||||
"be translated to VHDL");
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char *bits = ivl_expr_bits(net);
|
||||
|
||||
vhdl_binop_expr *all =
|
||||
new vhdl_binop_expr(VHDL_BINOP_AND, vhdl_type::boolean());
|
||||
for (unsigned i = 0; i < ivl_expr_width(net); i++) {
|
||||
switch (bits[i]) {
|
||||
case '?':
|
||||
case 'z':
|
||||
case 'x':
|
||||
// Ignore it
|
||||
break;
|
||||
default:
|
||||
{
|
||||
// Generate a comparison for this bit position
|
||||
vhdl_binop_expr *cmp =
|
||||
new vhdl_binop_expr(VHDL_BINOP_EQ, vhdl_type::boolean());
|
||||
|
||||
vhdl_type *type = vhdl_type::nunsigned(ivl_expr_width(net));
|
||||
vhdl_var_ref *lhs =
|
||||
new vhdl_var_ref(test->get_name().c_str(), type);
|
||||
lhs->set_slice(new vhdl_const_int(i));
|
||||
|
||||
cmp->add_expr(lhs);
|
||||
cmp->add_expr(new vhdl_const_bit(bits[i]));
|
||||
|
||||
all->add_expr(cmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result)
|
||||
where = result->add_elsif(all);
|
||||
else {
|
||||
result = new vhdl_if_stmt(all);
|
||||
where = result->get_then_container();
|
||||
}
|
||||
}
|
||||
else {
|
||||
// This the default case and therefore the `else' branch
|
||||
assert(result);
|
||||
where = result->get_else_container();
|
||||
}
|
||||
|
||||
// `where' now points to a branch of an if statement which
|
||||
// corresponds to this casex/z branch
|
||||
assert(where);
|
||||
draw_stmt(proc, where, ivl_stmt_case_stmt(stmt, i), is_last);
|
||||
}
|
||||
|
||||
// Add a comment to say that this corresponds to a casex/z statement
|
||||
// as this may not be obvious
|
||||
ostringstream ss;
|
||||
ss << "Generated from case"
|
||||
<< (ivl_statement_type(stmt) == IVL_ST_CASEX ? 'x' : 'z')
|
||||
<< " statement at " << ivl_stmt_file(stmt) << ":" << ivl_stmt_lineno(stmt);
|
||||
result->set_comment(ss.str());
|
||||
|
||||
container->add_stmt(result);
|
||||
|
||||
// We don't actually use the generated `test' expression
|
||||
delete test;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int draw_while(vhdl_procedural *proc, stmt_container *container,
|
||||
ivl_statement_t stmt)
|
||||
{
|
||||
|
|
@ -685,11 +789,8 @@ int draw_stmt(vhdl_procedural *proc, stmt_container *container,
|
|||
error("disable statement cannot be translated to VHDL");
|
||||
return 1;
|
||||
case IVL_ST_CASEX:
|
||||
error("casex statement cannot be translated to VHDL");
|
||||
return 1;
|
||||
case IVL_ST_CASEZ:
|
||||
error("casez statement cannot be translated to VHDL");
|
||||
return 1;
|
||||
return draw_casezx(proc, container, stmt, is_last);
|
||||
case IVL_ST_FORK:
|
||||
error("fork statement cannot be translated to VHDL");
|
||||
return 1;
|
||||
|
|
|
|||
|
|
@ -664,12 +664,30 @@ vhdl_if_stmt::~vhdl_if_stmt()
|
|||
delete test_;
|
||||
}
|
||||
|
||||
stmt_container *vhdl_if_stmt::add_elsif(vhdl_expr *test)
|
||||
{
|
||||
elsif ef = { test, new stmt_container };
|
||||
elsif_parts_.push_back(ef);
|
||||
return ef.container;
|
||||
}
|
||||
|
||||
void vhdl_if_stmt::emit(std::ostream &of, int level) const
|
||||
{
|
||||
emit_comment(of, level);
|
||||
|
||||
of << "if ";
|
||||
test_->emit(of, level);
|
||||
of << " then";
|
||||
then_part_.emit(of, level);
|
||||
|
||||
std::list<elsif>::const_iterator it;
|
||||
for (it = elsif_parts_.begin(); it != elsif_parts_.end(); ++it) {
|
||||
of << "elsif ";
|
||||
(*it).test->emit(of, level);
|
||||
of << " then";
|
||||
(*it).container->emit(of, level);
|
||||
}
|
||||
|
||||
if (!else_part_.empty()) {
|
||||
of << "else";
|
||||
else_part_.emit(of, level);
|
||||
|
|
|
|||
|
|
@ -427,10 +427,17 @@ public:
|
|||
|
||||
stmt_container *get_then_container() { return &then_part_; }
|
||||
stmt_container *get_else_container() { return &else_part_; }
|
||||
stmt_container *add_elsif(vhdl_expr *test);
|
||||
void emit(std::ostream &of, int level) const;
|
||||
private:
|
||||
struct elsif {
|
||||
vhdl_expr *test;
|
||||
stmt_container *container;
|
||||
};
|
||||
|
||||
vhdl_expr *test_;
|
||||
stmt_container then_part_, else_part_;
|
||||
std::list<elsif> elsif_parts_;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue