Merge branch 'master' into verilog-ams

This commit is contained in:
Stephen Williams 2008-10-27 09:23:13 -07:00
commit 810686d88e
3 changed files with 134 additions and 8 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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_;
};