From a47b7352b4482aa65e9eb536821df7fa10f4b237 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 14 Oct 2008 20:16:10 +0100 Subject: [PATCH 1/2] Add casex/z support 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. --- tgt-vhdl/stmt.cc | 109 +++++++++++++++++++++++++++++++++++++--- tgt-vhdl/vhdl_syntax.cc | 18 +++++++ tgt-vhdl/vhdl_syntax.hh | 7 +++ 3 files changed, 126 insertions(+), 8 deletions(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 738646ec1..fac0c640e 100644 --- a/tgt-vhdl/stmt.cc +++ b/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(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,92 @@ 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); + } + + 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 +781,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; diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 5ca30e1fc..b40176b85 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -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::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); diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 0c0d9bf25..9b8f1a325 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -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_parts_; }; From 8a3309d79da9fba9971ac981955a91b5fd0db460 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 14 Oct 2008 20:21:19 +0100 Subject: [PATCH 2/2] Add a comment to the output about casex/z translation --- tgt-vhdl/stmt.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index fac0c640e..f5644825e 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -653,6 +653,14 @@ int draw_casezx(vhdl_procedural *proc, stmt_container *container, 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