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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int draw_case(vhdl_procedural *proc, stmt_container *container,
|
static vhdl_var_ref *draw_case_test(vhdl_procedural *proc, stmt_container *container,
|
||||||
ivl_statement_t stmt, bool is_last)
|
ivl_statement_t stmt)
|
||||||
{
|
{
|
||||||
vhdl_expr *test = translate_expr(ivl_stmt_cond_expr(stmt));
|
vhdl_expr *test = translate_expr(ivl_stmt_cond_expr(stmt));
|
||||||
if (NULL == test)
|
if (NULL == test)
|
||||||
return 1;
|
return NULL;
|
||||||
|
|
||||||
// VHDL case expressions are required to be quite simple: variable
|
// VHDL case expressions are required to be quite simple: variable
|
||||||
// references or slices. So we may need to create a temporary
|
// 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);
|
vhdl_var_ref *tmp_ref = new vhdl_var_ref(tmp_name, NULL);
|
||||||
container->add_stmt(new vhdl_assign_stmt(tmp_ref, test));
|
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);
|
vhdl_case_stmt *vhdlcase = new vhdl_case_stmt(test);
|
||||||
container->add_stmt(vhdlcase);
|
container->add_stmt(vhdlcase);
|
||||||
|
|
@ -565,6 +575,100 @@ static int draw_case(vhdl_procedural *proc, stmt_container *container,
|
||||||
return 0;
|
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,
|
int draw_while(vhdl_procedural *proc, stmt_container *container,
|
||||||
ivl_statement_t stmt)
|
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");
|
error("disable statement cannot be translated to VHDL");
|
||||||
return 1;
|
return 1;
|
||||||
case IVL_ST_CASEX:
|
case IVL_ST_CASEX:
|
||||||
error("casex statement cannot be translated to VHDL");
|
|
||||||
return 1;
|
|
||||||
case IVL_ST_CASEZ:
|
case IVL_ST_CASEZ:
|
||||||
error("casez statement cannot be translated to VHDL");
|
return draw_casezx(proc, container, stmt, is_last);
|
||||||
return 1;
|
|
||||||
case IVL_ST_FORK:
|
case IVL_ST_FORK:
|
||||||
error("fork statement cannot be translated to VHDL");
|
error("fork statement cannot be translated to VHDL");
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
||||||
|
|
@ -664,12 +664,30 @@ vhdl_if_stmt::~vhdl_if_stmt()
|
||||||
delete test_;
|
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
|
void vhdl_if_stmt::emit(std::ostream &of, int level) const
|
||||||
{
|
{
|
||||||
|
emit_comment(of, level);
|
||||||
|
|
||||||
of << "if ";
|
of << "if ";
|
||||||
test_->emit(of, level);
|
test_->emit(of, level);
|
||||||
of << " then";
|
of << " then";
|
||||||
then_part_.emit(of, level);
|
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()) {
|
if (!else_part_.empty()) {
|
||||||
of << "else";
|
of << "else";
|
||||||
else_part_.emit(of, level);
|
else_part_.emit(of, level);
|
||||||
|
|
|
||||||
|
|
@ -427,10 +427,17 @@ public:
|
||||||
|
|
||||||
stmt_container *get_then_container() { return &then_part_; }
|
stmt_container *get_then_container() { return &then_part_; }
|
||||||
stmt_container *get_else_container() { return &else_part_; }
|
stmt_container *get_else_container() { return &else_part_; }
|
||||||
|
stmt_container *add_elsif(vhdl_expr *test);
|
||||||
void emit(std::ostream &of, int level) const;
|
void emit(std::ostream &of, int level) const;
|
||||||
private:
|
private:
|
||||||
|
struct elsif {
|
||||||
|
vhdl_expr *test;
|
||||||
|
stmt_container *container;
|
||||||
|
};
|
||||||
|
|
||||||
vhdl_expr *test_;
|
vhdl_expr *test_;
|
||||||
stmt_container then_part_, else_part_;
|
stmt_container then_part_, else_part_;
|
||||||
|
std::list<elsif> elsif_parts_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue