From a7cfdc3a876695a7ddaee217e14764a59315091d Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Wed, 11 Jun 2008 14:11:37 +0100 Subject: [PATCH] Add VHDL if statement to AST types --- tgt-vhdl/process.cc | 4 +-- tgt-vhdl/stmt.cc | 75 ++++++++++++++++++++++++++--------------- tgt-vhdl/vhdl_syntax.cc | 41 ++++++++++++++++++---- tgt-vhdl/vhdl_syntax.hh | 34 +++++++++++++++++-- tgt-vhdl/vhdl_target.h | 3 +- 5 files changed, 116 insertions(+), 41 deletions(-) diff --git a/tgt-vhdl/process.cc b/tgt-vhdl/process.cc index 5a650aa0b..b43e0ee64 100644 --- a/tgt-vhdl/process.cc +++ b/tgt-vhdl/process.cc @@ -39,7 +39,7 @@ static int generate_vhdl_process(vhdl_entity *ent, ivl_process_t proc) ent->get_arch()->add_stmt(vhdl_proc); ivl_statement_t stmt = ivl_process_stmt(proc); - int rc = draw_stmt(vhdl_proc, stmt); + int rc = draw_stmt(vhdl_proc, vhdl_proc->get_container(), stmt); if (rc != 0) return rc; @@ -48,7 +48,7 @@ static int generate_vhdl_process(vhdl_entity *ent, ivl_process_t proc) // the end if (ivl_process_type(proc) == IVL_PR_INITIAL) { vhdl_wait_stmt *wait = new vhdl_wait_stmt(); - vhdl_proc->add_stmt(wait); + vhdl_proc->get_container()->add_stmt(wait); } // Add a comment indicating where it came from diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index debd6ec75..a815f8d99 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -37,7 +37,8 @@ * name collision with an existing variable called * `Verilog_Display_Line' -- do something about this? */ -static int draw_stask_display(vhdl_process *proc, ivl_statement_t stmt) +static int draw_stask_display(vhdl_process *proc, stmt_container *container, + ivl_statement_t stmt) { // Add the package requirement to the containing entity proc->get_parent()->get_parent()->requires_package("std.textio"); @@ -87,7 +88,7 @@ static int draw_stask_display(vhdl_process *proc, ivl_statement_t stmt) write->add_expr(ref); write->add_expr(e); - proc->add_stmt(write); + container->add_stmt(write); } // WriteLine(Output, Verilog_Display_Line) @@ -98,7 +99,7 @@ static int draw_stask_display(vhdl_process *proc, ivl_statement_t stmt) vhdl_var_ref *ref = new vhdl_var_ref(display_line, vhdl_type::line()); write_line->add_expr(ref); - proc->add_stmt(write_line); + container->add_stmt(write_line); return 0; } @@ -110,9 +111,10 @@ static int draw_stask_display(vhdl_process *proc, ivl_statement_t stmt) * return a failure exit code when in fact it completed * successfully. */ -static int draw_stask_finish(vhdl_process *proc, ivl_statement_t stmt) +static int draw_stask_finish(vhdl_process *proc, stmt_container *container, + ivl_statement_t stmt) { - proc->add_stmt(new vhdl_assert_stmt("SIMULATION FINISHED")); + container->add_stmt(new vhdl_assert_stmt("SIMULATION FINISHED")); return 0; } @@ -120,14 +122,15 @@ static int draw_stask_finish(vhdl_process *proc, ivl_statement_t stmt) * Generate VHDL for system tasks (like $display). Not all of * these are supported. */ -static int draw_stask(vhdl_process *proc, ivl_statement_t stmt) +static int draw_stask(vhdl_process *proc, stmt_container *container, + ivl_statement_t stmt) { const char *name = ivl_stmt_name(stmt); if (strcmp(name, "$display") == 0) - return draw_stask_display(proc, stmt); + return draw_stask_display(proc, container, stmt); else if (strcmp(name, "$finish") == 0) - return draw_stask_finish(proc, stmt); + return draw_stask_finish(proc, container, stmt); else { error("No VHDL translation for system task %s", name); return 0; @@ -138,13 +141,14 @@ static int draw_stask(vhdl_process *proc, ivl_statement_t stmt) * Generate VHDL for a block of Verilog statements. This doesn't * actually do anything, other than recursively translate the * block's statements and add them to the process. This is OK as - * `begin' and `end process' function like a Verilog block. + * the stmt_container class behaves like a Verilog block. */ -static int draw_block(vhdl_process *proc, ivl_statement_t stmt) +static int draw_block(vhdl_process *proc, stmt_container *container, + ivl_statement_t stmt) { int count = ivl_stmt_block_count(stmt); for (int i = 0; i < count; i++) { - if (draw_stmt(proc, ivl_stmt_block_stmt(stmt, i)) != 0) + if (draw_stmt(proc, container, ivl_stmt_block_stmt(stmt, i)) != 0) return 1; } return 0; @@ -154,9 +158,10 @@ static int draw_block(vhdl_process *proc, ivl_statement_t stmt) * A no-op statement. This corresponds to a `null' statement in * VHDL. */ -static int draw_noop(vhdl_process *proc, ivl_statement_t stmt) +static int draw_noop(vhdl_process *proc, stmt_container *container, + ivl_statement_t stmt) { - proc->add_stmt(new vhdl_null_stmt()); + container->add_stmt(new vhdl_null_stmt()); return 0; } @@ -165,7 +170,8 @@ static int draw_noop(vhdl_process *proc, ivl_statement_t stmt) * this are essentially the same as VHDL's non-blocking signal * assignment. */ -static int draw_nbassign(vhdl_process *proc, ivl_statement_t stmt) +static int draw_nbassign(vhdl_process *proc, stmt_container *container, + ivl_statement_t stmt) { int nlvals = ivl_stmt_lvals(stmt); if (nlvals != 1) { @@ -189,7 +195,7 @@ static int draw_nbassign(vhdl_process *proc, ivl_statement_t stmt) // The type here can be null as it is never actually needed vhdl_var_ref *lval_ref = new vhdl_var_ref(signame, NULL); - proc->add_stmt(new vhdl_nbassign_stmt(lval_ref, rhs)); + container->add_stmt(new vhdl_nbassign_stmt(lval_ref, rhs)); } else { error("Only signals as lvals supported at the moment"); @@ -203,7 +209,8 @@ static int draw_nbassign(vhdl_process *proc, ivl_statement_t stmt) * Delay statements are equivalent to the `wait for' form of the * VHDL wait statement. */ -static int draw_delay(vhdl_process *proc, ivl_statement_t stmt) +static int draw_delay(vhdl_process *proc, stmt_container *container, + ivl_statement_t stmt) { uint64_t value = ivl_stmt_delay_val(stmt); @@ -216,14 +223,14 @@ static int draw_delay(vhdl_process *proc, ivl_statement_t stmt) // the vhdl_process class vhdl_wait_stmt *wait = new vhdl_wait_stmt(VHDL_WAIT_FOR_NS, new vhdl_const_int(value)); - proc->add_stmt(wait); + container->add_stmt(wait); // Expand the sub-statement as well // Often this would result in a useless `null' statement which // is caught here instead ivl_statement_t sub_stmt = ivl_stmt_sub_stmt(stmt); if (ivl_statement_type(sub_stmt) != IVL_ST_NOOP) - draw_stmt(proc, sub_stmt); + draw_stmt(proc, container, sub_stmt); return 0; } @@ -234,7 +241,8 @@ static int draw_delay(vhdl_process *proc, ivl_statement_t stmt) * TODO: This won't yet handle the posedge to rising_edge, etc. * mapping. */ -static int draw_wait(vhdl_process *proc, ivl_statement_t stmt) +static int draw_wait(vhdl_process *proc, stmt_container *container, + ivl_statement_t stmt) { int nevents = ivl_stmt_nevent(stmt); for (int i = 0; i < nevents; i++) { @@ -271,30 +279,41 @@ static int draw_wait(vhdl_process *proc, ivl_statement_t stmt) } ivl_statement_t sub_stmt = ivl_stmt_sub_stmt(stmt); - draw_stmt(proc, sub_stmt); + draw_stmt(proc, container, sub_stmt); return 0; } +static int draw_if(vhdl_process *proc, stmt_container *container, + ivl_statement_t stmt) +{ + return 0; +} + /* * Generate VHDL statements for the given Verilog statement and - * add them to the given VHDL process. + * add them to the given VHDL process. The container is the + * location to add statements: e.g. the process body, a branch + * of an if statement, etc. */ -int draw_stmt(vhdl_process *proc, ivl_statement_t stmt) +int draw_stmt(vhdl_process *proc, stmt_container *container, + ivl_statement_t stmt) { switch (ivl_statement_type(stmt)) { case IVL_ST_STASK: - return draw_stask(proc, stmt); + return draw_stask(proc, container, stmt); case IVL_ST_BLOCK: - return draw_block(proc, stmt); + return draw_block(proc, container, stmt); case IVL_ST_NOOP: - return draw_noop(proc, stmt); + return draw_noop(proc, container, stmt); case IVL_ST_ASSIGN_NB: - return draw_nbassign(proc, stmt); + return draw_nbassign(proc, container, stmt); case IVL_ST_DELAY: - return draw_delay(proc, stmt); + return draw_delay(proc, container, stmt); case IVL_ST_WAIT: - return draw_wait(proc, stmt); + return draw_wait(proc, container, stmt); + case IVL_ST_CONDIT: + return draw_if(proc, container, stmt); default: error("No VHDL translation for statement at %s:%d (type = %d)", ivl_stmt_file(stmt), ivl_stmt_lineno(stmt), diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 076266792..5800fff46 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -193,15 +193,9 @@ vhdl_process::vhdl_process(const char *name) vhdl_process::~vhdl_process() { - delete_children(stmts_); delete_children(decls_); } -void vhdl_process::add_stmt(vhdl_seq_stmt* stmt) -{ - stmts_.push_back(stmt); -} - void vhdl_process::add_decl(vhdl_decl* decl) { decls_.push_back(decl); @@ -244,11 +238,26 @@ void vhdl_process::emit(std::ofstream &of, int level) const of << "is"; emit_children(of, decls_, level); of << "begin"; - emit_children(of, stmts_, level); + stmts_.emit(of, level); of << "end process;"; newline(of, level); } +stmt_container::~stmt_container() +{ + delete_children(stmts_); +} + +void stmt_container::add_stmt(vhdl_seq_stmt *stmt) +{ + stmts_.push_back(stmt); +} + +void stmt_container::emit(std::ofstream &of, int level) const +{ + emit_children(of, stmts_, level); +} + vhdl_comp_inst::vhdl_comp_inst(const char *inst_name, const char *comp_name) : comp_name_(comp_name), inst_name_(inst_name) { @@ -548,6 +557,24 @@ void vhdl_assert_stmt::emit(std::ofstream &of, int level) const of << " report \"" << reason_ << "\" severity failure;"; } +vhdl_if_stmt::~vhdl_if_stmt() +{ + delete test_; +} + +void vhdl_if_stmt::emit(std::ofstream &of, int level) const +{ + of << "if "; + test_->emit(of, level); + of << " then"; + newline(of, level); + then_part_.emit(of, level); + of << "else"; + newline(of, level); + else_part_.emit(of, level); + of << "end if;"; +} + vhdl_unaryop_expr::~vhdl_unaryop_expr() { delete operand_; diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 588d2eeb7..294fe3268 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -204,7 +204,20 @@ public: virtual ~vhdl_seq_stmt() {} }; -typedef std::list seq_stmt_list_t; + +/* + * A list of sequential statements. For example inside a + * process, loop, or if statement. + */ +class stmt_container { +public: + ~stmt_container(); + + void add_stmt(vhdl_seq_stmt *stmt); + void emit(std::ofstream &of, int level) const; +private: + std::list stmts_; +}; /* @@ -262,6 +275,21 @@ private: }; +class vhdl_if_stmt : public vhdl_seq_stmt { +public: + vhdl_if_stmt(vhdl_expr *test) + : test_(test) {} + ~vhdl_if_stmt(); + + stmt_container *get_then_container() { return &then_part_; } + stmt_container *get_else_container() { return &else_part_; } + void emit(std::ofstream &of, int level) const; +private: + vhdl_expr *test_; + stmt_container then_part_, else_part_; +}; + + /* * A procedure call. Which is a statement, unlike a function * call which is an expression. @@ -398,12 +426,12 @@ public: virtual ~vhdl_process(); void emit(std::ofstream &of, int level) const; - void add_stmt(vhdl_seq_stmt *stmt); + stmt_container *get_container() { return &stmts_; } void add_decl(vhdl_decl *decl); void add_sensitivity(const char *name); bool have_declared_var(const std::string &name) const; private: - seq_stmt_list_t stmts_; + stmt_container stmts_; decl_list_t decls_; std::string name_; string_list_t sens_; diff --git a/tgt-vhdl/vhdl_target.h b/tgt-vhdl/vhdl_target.h index b154c5f18..a0fb1f497 100644 --- a/tgt-vhdl/vhdl_target.h +++ b/tgt-vhdl/vhdl_target.h @@ -13,7 +13,8 @@ void error(const char *fmt, ...); int draw_scope(ivl_scope_t scope, void *_parent); int draw_process(ivl_process_t net, void *cd); -int draw_stmt(vhdl_process *proc, ivl_statement_t stmt); +int draw_stmt(vhdl_process *proc, stmt_container *container, + ivl_statement_t stmt); vhdl_expr *translate_expr(ivl_expr_t e);