From ec49f10e2d00aa8acacf96667547ddac6916e49b Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 2 Oct 2010 11:02:27 -0700 Subject: [PATCH] Revert bad merge from vhdl branch --- Makefile.in | 4 +- discipline.h | 6 +- driver/Makefile.in | 2 +- driver/globals.h | 4 +- driver/iverilog.man.in | 2 +- driver/main.c | 12 +- elab_expr.cc | 68 ++----- elab_lval.cc | 29 +-- elab_net.cc | 8 +- elaborate.cc | 2 +- eval_tree.cc | 28 +-- examples/des.v | 126 ++++++------- examples/pal_reg.v | 8 +- examples/sqrt-virtex.v | 4 +- expr_synth.cc | 4 +- ivl_target.h | 4 +- ivlpp/lexor.lex | 10 +- lexor.lex | 2 +- main.cc | 2 +- mingw.txt | 2 +- net_design.cc | 49 +++-- net_expr.cc | 16 +- net_link.cc | 2 +- net_scope.cc | 4 +- netlist.cc | 2 +- netlist.h | 5 +- netmisc.cc | 163 ++++++++++++++++- netmisc.h | 26 +-- nodangle.cc | 16 +- parse.y | 2 +- parse_misc.h | 2 +- pform.cc | 22 +-- pform.h | 2 +- symbol_search.cc | 2 +- tgt-vhdl/Makefile.in | 4 +- tgt-vhdl/cast.cc | 61 ++---- tgt-vhdl/display.cc | 200 ++++++++++++++++++++ tgt-vhdl/expr.cc | 52 +++--- tgt-vhdl/logic.cc | 30 +-- tgt-vhdl/lpm.cc | 56 +++--- tgt-vhdl/process.cc | 29 +-- tgt-vhdl/scope.cc | 258 ++++++++++++-------------- tgt-vhdl/state.cc | 87 ++------- tgt-vhdl/stmt.cc | 387 ++++++++++++--------------------------- tgt-vhdl/support.cc | 6 +- tgt-vhdl/support.hh | 2 +- tgt-vhdl/vhdl.cc | 6 +- tgt-vhdl/vhdl_element.cc | 23 +-- tgt-vhdl/vhdl_element.hh | 2 +- tgt-vhdl/vhdl_helper.hh | 4 +- tgt-vhdl/vhdl_syntax.cc | 193 ++++++++----------- tgt-vhdl/vhdl_syntax.hh | 98 ++++------ tgt-vhdl/vhdl_target.h | 7 +- tgt-vhdl/vhdl_type.cc | 2 +- tgt-vhdl/vhdl_type.hh | 4 +- tgt-vvp/draw_mux.c | 5 +- tgt-vvp/draw_net_input.c | 20 +- tgt-vvp/draw_ufunc.c | 2 +- tgt-vvp/draw_vpi.c | 3 +- tgt-vvp/eval_expr.c | 22 +-- tgt-vvp/eval_real.c | 2 +- tgt-vvp/modpath.c | 2 +- tgt-vvp/vvp_scope.c | 53 +++++- vpi/fstapi.c | 66 ++++++- vpi/sys_display.c | 3 +- vpi/sys_fileio.c | 5 +- vpi/sys_sdf.c | 3 +- vvp/Makefile.in | 9 +- vvp/array.cc | 3 +- vvp/concat.cc | 2 +- vvp/dff.h | 2 +- vvp/event.cc | 2 +- vvp/examples/vector.vvp | 2 +- vvp/opcodes.txt | 2 +- vvp/schedule.h | 4 +- vvp/vpi_mcd.cc | 2 +- vvp/vpi_vthr_vector.cc | 2 +- vvp/vthread.cc | 4 +- vvp/vvp_island.cc | 2 +- vvp/vvp_net.cc | 6 +- vvp/vvp_net.h | 9 +- vvp/vvp_net_sig.h | 4 +- vvp/words.cc | 2 +- 83 files changed, 1254 insertions(+), 1140 deletions(-) create mode 100644 tgt-vhdl/display.cc diff --git a/Makefile.in b/Makefile.in index 2614e374c..fc291bf98 100644 --- a/Makefile.in +++ b/Makefile.in @@ -30,7 +30,7 @@ SHELL = /bin/sh # The "suffix" is used as an installation suffix. It modifies certain # key install paths/files such that a build and install of Icarus Verilog # with the same $(prefix) but a different $(suffix) will not interfere. -# The normal configuratin leaves suffix empty +# The normal configuration leaves suffix empty suffix = @install_suffix@ prefix = @prefix@ @@ -240,7 +240,7 @@ iverilog-vpi.man: $(srcdir)/iverilog-vpi.man.in version.exe tail -n +2 $(srcdir)/iverilog-vpi.man.in >> $@ iverilog-vpi.ps: iverilog-vpi.man - $(MAN) -t iverilog-vpi.man > iverilog-vpi.ps + $(MAN) -t ./iverilog-vpi.man > iverilog-vpi.ps iverilog-vpi.pdf: iverilog-vpi.ps $(PS2PDF) iverilog-vpi.ps iverilog-vpi.pdf diff --git a/discipline.h b/discipline.h index 9cfc4294b..0726710a9 100644 --- a/discipline.h +++ b/discipline.h @@ -1,7 +1,7 @@ #ifndef __discipline_H #define __discipline_H /* - * Copyright (c) 2008 Stephen Williams (steve@icarus.com) + * Copyright (c) 2008-2010 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -55,8 +55,8 @@ class ivl_discipline_s : public LineInfo { perm_string name() const { return name_; } ivl_dis_domain_t domain() const { return domain_; } - const ivl_nature_t potential() const { return potential_; } - const ivl_nature_t flow() const { return flow_; } + ivl_nature_t potential() const { return potential_; } + ivl_nature_t flow() const { return flow_; } private: perm_string name_; diff --git a/driver/Makefile.in b/driver/Makefile.in index 054c0b1ac..26d6346b7 100644 --- a/driver/Makefile.in +++ b/driver/Makefile.in @@ -89,7 +89,7 @@ iverilog.man: $(srcdir)/iverilog.man.in ../version.exe tail -n +2 $(srcdir)/iverilog.man.in >> $@ iverilog.ps: iverilog.man - $(MAN) -t iverilog.man > iverilog.ps + $(MAN) -t ./iverilog.man > iverilog.ps iverilog.pdf: iverilog.ps $(PS2PDF) iverilog.ps iverilog.pdf diff --git a/driver/globals.h b/driver/globals.h index 22be7a12e..810787f93 100644 --- a/driver/globals.h +++ b/driver/globals.h @@ -40,10 +40,10 @@ extern void process_include_dir(const char*name); /* Add a new -D define. */ extern void process_define(const char*name); - + /* Add a new parameter definition */ extern void process_parameter(const char*name); - + /* Set the default timescale for the simulator. */ extern void process_timescale(const char*ts_string); diff --git a/driver/iverilog.man.in b/driver/iverilog.man.in index a42a89b23..2cb0bc488 100644 --- a/driver/iverilog.man.in +++ b/driver/iverilog.man.in @@ -64,7 +64,7 @@ Verilog source for use by other compilers. .B -g1995\fI|\fP-g2001\fI|\fP-g2001-noconfig\fI|\fP-g2005\fI|\fP-g2009 Select the Verilog language \fIgeneration\fP to support in the compiler. This selects between \fIIEEE1364\-1995\fP, -\fIIEEE1364\-2001\fP, \fIIEEE1364\-2005\fP, or \fIIEEE1800-2009\fP. +\fIIEEE1364\-2001\fP, \fIIEEE1364\-2005\fP, or \fIIEEE1800-2009\fP. Normally, Icarus Verilog defaults to the latest known generation of the language. This flag is most useful to restrict the language to a set supported by tools of specific generations, for compatibility with diff --git a/driver/main.c b/driver/main.c index 51a7c5e74..42505991f 100644 --- a/driver/main.c +++ b/driver/main.c @@ -169,8 +169,8 @@ typedef struct t_command_file { p_command_file cmd_file_head = NULL; /* The FIFO head */ p_command_file cmd_file_tail = NULL; /* The FIFO tail */ -/* Temprarily store parameter definition from command line and - * parse it after we have delt with command file +/* Temporarily store parameter definition from command line and + * parse it after we have dealt with command file */ static const char** defparm_base = 0; static int defparm_size = 0; @@ -777,10 +777,10 @@ int main(int argc, char **argv) turning the last two \ characters to null. Then we append the lib\ivl$(suffix) to finish. */ { char *s; - char basepath[4096], tmp[4096]; - GetModuleFileName(NULL, tmp, sizeof tmp); + char basepath[4096], tmppath[4096]; + GetModuleFileName(NULL, tmppath, sizeof tmppath); /* Convert to a short name to remove any embedded spaces. */ - GetShortPathName(tmp, basepath, sizeof basepath); + GetShortPathName(tmppath, basepath, sizeof basepath); strncpy(ivl_root, basepath, MAXSIZE); ivl_root[MAXSIZE-1] = 0; s = strrchr(ivl_root, sep); @@ -1105,7 +1105,7 @@ int main(int argc, char **argv) /* If we are planning on opening a dependencies file, then open and truncate it here. The other phases of compilation - will append to the file, so this is necessray to make sure + will append to the file, so this is necessary to make sure it starts out empty. */ if (depfile) { FILE*fd = fopen(depfile, "w"); diff --git a/elab_expr.cc b/elab_expr.cc index f772f52c0..4a1e1385f 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -729,7 +729,7 @@ NetExpr* PEBinary::elaborate_expr_base_rshift_(Design*des, return tmp; } - // Falback, handle the general case. + // Fallback, handle the general case. if (expr_wid > 0) lp = pad_to_width(lp, expr_wid, *this); tmp = new NetEBShift(op_, lp, rp); @@ -1011,7 +1011,7 @@ unsigned PEBLeftWidth::test_width(Design*des, NetScope*scope, && wid_left > 0 && wid_left < integer_width) { wid_left = integer_width; - + if (debug_elaborate) cerr << get_fileline() << ": debug: " << "Test width of unsized " << human_readable_op(op_) @@ -1273,7 +1273,7 @@ NetExpr*PECallFunction::cast_to_width_(NetExpr*expr, int wid, bool signed_flag) if (wid < 0) wid = expr->expr_width(); - + if (debug_elaborate) cerr << get_fileline() << ": debug: cast to " << wid << " bits" << endl; @@ -2494,11 +2494,7 @@ NetExpr* PEIdent::elaborate_expr_param_idx_up_(Design*des, NetScope*scope, return result_ex; } - if (par_msv >= par_lsv) { - if (par_lsv != 0) base = make_add_expr(base, -par_lsv); - } else { - base = make_sub_expr(par_lsv-wid+1, base); - } + base = normalize_variable_base(base, par_msv, par_lsv, wid, true); NetExpr*tmp = par->dup_expr(); tmp = new NetESelect(tmp, base, wid); @@ -2578,13 +2574,7 @@ NetExpr* PEIdent::elaborate_expr_param_idx_do_(Design*des, NetScope*scope, return result_ex; } - if (par_msv >= par_lsv) { - if (long offset = par_lsv+wid-1) { - base = make_add_expr(base, -offset); - } - } else { - base = make_sub_expr(par_lsv, base); - } + base = normalize_variable_base(base, par_msv, par_lsv, wid, false); NetExpr*tmp = par->dup_expr(); tmp = new NetESelect(tmp, base, wid); @@ -2610,7 +2600,7 @@ NetExpr* PEIdent::elaborate_expr_param_(Design*des, if (!name_tail.index.empty()) use_sel = name_tail.index.back().sel; - if (par->expr_type() == IVL_VT_REAL && + if (par->expr_type() == IVL_VT_REAL && use_sel != index_component_t::SEL_NONE) { perm_string name = peek_tail_name(path_); cerr << get_fileline() << ": error: " @@ -2742,17 +2732,10 @@ NetExpr* PEIdent::elaborate_expr_param_(Design*des, } else { if (par_me) { - long par_mv = par_me->value().as_long(); - long par_lv = par_le->value().as_long(); - if (par_mv >= par_lv) { - mtmp = par_lv - ? make_add_expr(mtmp, 0-par_lv) - : mtmp; - } else { - if (par_lv != 0) - mtmp = make_add_expr(mtmp, 0-par_mv); - mtmp = make_sub_expr(par_lv-par_mv, mtmp); - } + mtmp = normalize_variable_base(mtmp, + par_me->value().as_long(), + par_le->value().as_long(), + 1, true); } /* The value is constant, but the bit select @@ -2869,7 +2852,8 @@ NetExpr* PEIdent::elaborate_expr_net_word_(Design*des, NetScope*scope, // expression to calculate the canonical address. if (long base = net->array_first()) { - word_index = make_add_expr(word_index, 0-base); + word_index = normalize_variable_array_base( + word_index, base, net->array_count()); eval_expr(word_index); } } @@ -2945,7 +2929,7 @@ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope, cerr << get_fileline() << ": : " "Replacing select with a constant 'bx." << endl; } - + NetEConst*tmp = new NetEConst(verinum(verinum::Vx, 1, false)); tmp->set_line(*this); return tmp; @@ -3053,7 +3037,7 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope, } // Otherwise, make a part select that covers the right // range. - ex = new NetEConst(verinum(net->sig()->sb_to_idx(lsv) + + ex = new NetEConst(verinum(net->sig()->sb_to_idx(lsv) + offset)); if (warn_ob_select) { long rel_base = net->sig()->sb_to_idx(lsv) + offset; @@ -3092,12 +3076,7 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope, return ss; } - if (net->msi() > net->lsi()) { - if (long offset = net->lsi()) - base = make_add_expr(base, -offset); - } else { - base = make_sub_expr(net->lsi()-wid+1, base); - } + base = normalize_variable_base(base, net->msi(), net->lsi(), wid, true); NetESelect*ss = new NetESelect(net, base, wid); ss->set_line(*this); @@ -3184,12 +3163,7 @@ NetExpr* PEIdent::elaborate_expr_net_idx_do_(Design*des, NetScope*scope, return ss; } - if (net->msi() > net->lsi()) { - if (long offset = net->lsi()+wid-1) - base = make_add_expr(base, -offset); - } else { - base = make_sub_expr(net->lsi(), base); - } + base = normalize_variable_base(base, net->msi(), net->lsi(), wid, false); NetESelect*ss = new NetESelect(net, base, wid); ss->set_line(*this); @@ -3294,12 +3268,8 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope, // complicated task because we need to generate // expressions to convert calculated bit select // values to canonical values that are used internally. - - if (net->sig()->msb() < net->sig()->lsb()) { - ex = make_sub_expr(net->sig()->lsb(), ex); - } else { - ex = make_add_expr(ex, - net->sig()->lsb()); - } + ex = normalize_variable_base(ex, net->sig()->msb(), net->sig()->lsb(), + 1, true); NetESelect*ss = new NetESelect(net, ex, 1); ss->set_line(*this); @@ -3537,7 +3507,7 @@ NetExpr*PETernary::elaborate_expr(Design*des, NetScope*scope, // evaluation of ternary expressions, but it doesn't disallow // it. The disadvantage of doing this is that semantic errors // in the unused clause will be missed, but people don't seem - // to mind, and do apreciate the optimization available here. + // to mind, and do appreciate the optimization available here. if (NetEConst*tmp = dynamic_cast (con)) { verinum cval = tmp->value(); ivl_assert(*this, cval.len()==1); diff --git a/elab_lval.cc b/elab_lval.cc index f3ca7d083..cb7bfd2fb 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2009 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2010 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -198,7 +198,7 @@ NetAssign_* PEIdent::elaborate_lval(Design*des, if (reg->array_dimensions() > 0) return elaborate_lval_net_word_(des, scope, reg); - // This must be after the array word elaboration above! + // This must be after the array word elaboration above! if (reg->get_scalar() && use_sel != index_component_t::SEL_NONE) { cerr << get_fileline() << ": error: can not select part of "; @@ -269,7 +269,8 @@ NetAssign_* PEIdent::elaborate_lval_net_word_(Design*des, // expression to calculate the canonical address. if (long base = reg->array_first()) { - word = make_add_expr(word, 0-base); + word = normalize_variable_array_base(word, base, + reg->array_count()); eval_expr(word); } @@ -342,7 +343,6 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des, index_tail.msb->test_width(des, scope, integer_width, integer_width, expr_type_tmp, unsized_flag_tmp); - // Bit selects have a single select expression. Evaluate the // constant value and treat it as a part select with a bit // width of 1. @@ -357,10 +357,7 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des, if (mux) { // Non-constant bit mux. Correct the mux for the range // of the vector, then set the l-value part select expression. - if (reg->msb() < reg->lsb()) - mux = make_sub_expr(reg->lsb(), mux); - else if (reg->lsb() != 0) - mux = make_add_expr(mux, - reg->lsb()); + mux = normalize_variable_base(mux, reg->msb(), reg->lsb(), 1, true); lv->set_part(mux, 1); @@ -535,20 +532,12 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des, } else { /* Correct the mux for the range of the vector. */ if (use_sel == index_component_t::SEL_IDX_UP) { - if (reg->msb() > reg->lsb()) { - if (long offset = reg->lsb()) - base = make_add_expr(base, -offset); - } else { - base = make_sub_expr(reg->lsb()-wid+1, base); - } + base = normalize_variable_base(base, reg->msb(), reg->lsb(), + wid, true); } else { // This is assumed to be a SEL_IDX_DO. - if (reg->msb() > reg->lsb()) { - if (long offset = reg->lsb()+wid-1) - base = make_add_expr(base, -offset); - } else { - base = make_sub_expr(reg->lsb(), base); - } + base = normalize_variable_base(base, reg->msb(), reg->lsb(), + wid, false); } } diff --git a/elab_net.cc b/elab_net.cc index 6cccd5205..06ef24b51 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -497,7 +497,7 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, /* The array has a part/bit select at the end. */ if (name_tail.index.size() > sig->array_dimensions()) { if (sig->get_scalar()) { - cerr << get_fileline() << ": error: " + cerr << get_fileline() << ": error: " << "can not select part of "; if (sig->data_type() == IVL_VT_REAL) cerr << "real"; else cerr << "scalar"; @@ -512,7 +512,7 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, return 0; if (lidx_tmp < 0) { - cerr << get_fileline() << ": sorry: part selects " + cerr << get_fileline() << ": sorry: part selects " "straddling the start of signal (" << path_ << ") are not currently supported." << endl; des->errors += 1; @@ -523,7 +523,7 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, } } else if (!name_tail.index.empty()) { if (sig->get_scalar()) { - cerr << get_fileline() << ": error: " + cerr << get_fileline() << ": error: " << "can not select part of "; if (sig->data_type() == IVL_VT_REAL) cerr << "real: "; else cerr << "scalar: "; @@ -537,7 +537,7 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, return 0; if (lidx_tmp < 0) { - cerr << get_fileline() << ": sorry: part selects " + cerr << get_fileline() << ": sorry: part selects " "straddling the start of signal (" << path_ << ") are not currently supported." << endl; des->errors += 1; diff --git a/elaborate.cc b/elaborate.cc index a53d46733..70fe2a0b5 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -1422,7 +1422,7 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const des->errors += 1; continue; } - + // We do not support real inout ports at all. if (!prts.empty() && (prts[0]->data_type() == IVL_VT_REAL )) { cerr << pins[idx]->get_fileline() << ": error: " diff --git a/eval_tree.cc b/eval_tree.cc index 6f744f452..993025568 100644 --- a/eval_tree.cc +++ b/eval_tree.cc @@ -858,7 +858,7 @@ NetExpr* NetEBDiv::eval_tree(int prune_to_width) eval_expr(right_); if (expr_type() == IVL_VT_REAL) return eval_tree_real_(); - + assert(expr_type() == IVL_VT_LOGIC); NetEConst*lc = dynamic_cast(left_); @@ -1228,6 +1228,12 @@ NetExpr* NetEParam::eval_tree(int prune_to_width) << *this << endl; } + if (solving()) { + cerr << get_fileline() << ": warning: Recursive parameter " + "reference found involving " << *this << "." << endl; + return 0; + } + assert(scope_); perm_string name = (*reference_).first; const NetExpr*expr = (*reference_).second.expr; @@ -1239,35 +1245,35 @@ NetExpr* NetEParam::eval_tree(int prune_to_width) << *this << " cannot be evaluated." << endl; return 0; } -// ivl_assert(*this, expr); - - NetExpr*nexpr = expr->dup_expr(); - assert(nexpr); // If the parameter that I refer to is already evaluated, then // return the constant value. - if (NetEConst*tmp = dynamic_cast(nexpr)) { + if (const NetEConst*tmp = dynamic_cast(expr)) { verinum val = tmp->value(); NetEConstParam*ptmp = new NetEConstParam(scope_, name, val); ptmp->set_line(*this); - delete nexpr; return ptmp; } - if (NetECReal*tmp = dynamic_cast(nexpr)) { + if (const NetECReal*tmp = dynamic_cast(expr)) { verireal val = tmp->value(); NetECRealParam*ptmp = new NetECRealParam(scope_, name, val); ptmp->set_line(*this); - delete nexpr; return ptmp; } // Try to evaluate the expression. If I cannot, then the // expression is not a constant expression and I fail here. + + solving(true); + NetExpr*nexpr = expr->dup_expr(); + assert(nexpr); NetExpr*res = nexpr->eval_tree(); + solving(false); if (res == 0) { - cerr << get_fileline() << ": internal error: Unable to evaluate " - << "parameter " << name << " expression: " + cerr << get_fileline() << ": internal error: Unable to evaluate "; + if (expr_type() == IVL_VT_REAL) cerr << "real "; + cerr << "parameter " << name << " expression: " << *nexpr << endl; delete nexpr; return 0; diff --git a/examples/des.v b/examples/des.v index a0eeff187..59cd0d370 100644 --- a/examples/des.v +++ b/examples/des.v @@ -162,11 +162,11 @@ end endmodule module des(pt, key, ct, clk); -input [1:64] pt; -input [1:64] key; -output [1:64] ct; -input clk; -wire [1:48] k1x,k2x,k3x,k4x,k5x,k6x,k7x,k8x,k9x,k10x,k11x,k12x,k13x,k14x,k15x,k16x; +input [1:64] pt; +input [1:64] key; +output [1:64] ct; +input clk; +wire [1:48] k1x,k2x,k3x,k4x,k5x,k6x,k7x,k8x,k9x,k10x,k11x,k12x,k13x,k14x,k15x,k16x; wire [1:32] l0x,l1x,l2x,l3x,l4x,l5x,l6x,l7x,l8x,l9x,l10x,l11x,l12x,l13x,l14x,l15x,l16x; wire [1:32] r0x,r1x,r2x,r3x,r4x,r5x,r6x,r7x,r8x,r9x,r10x,r11x,r12x,r13x,r14x,r15x,r16x; @@ -194,9 +194,9 @@ endmodule module pc1(key, c0x, d0x); -input [1:64] key; -output [1:28] c0x, d0x; -wire [1:56] XX; +input [1:64] key; +output [1:28] c0x, d0x; +wire [1:56] XX; assign XX[1]=key[57]; assign XX[2]=key[49]; assign XX[3]=key[41]; assign XX[4]=key[33]; assign XX[5]=key[25]; assign XX[6]=key[17]; assign XX[7]=key[9]; assign XX[8]=key[1]; assign XX[9]=key[58]; assign XX[10]=key[50]; assign XX[11]=key[42]; assign XX[12]=key[34]; assign XX[13]=key[26]; assign XX[14]=key[18]; @@ -213,9 +213,9 @@ endmodule module pc2(c,d,k); -input [1:28] c,d; -output [1:48] k; -wire [1:56] YY; +input [1:28] c,d; +output [1:48] k; +wire [1:56] YY; assign YY[1:28]=c; assign YY[29:56]=d; @@ -231,7 +231,7 @@ endmodule module rol1(o, i); -output [1:28] o; +output [1:28] o; input [1:28] i; assign o={i[2:28],i[1]}; @@ -240,7 +240,7 @@ endmodule module rol2(o, i); -output [1:28] o; +output [1:28] o; input [1:28] i; assign o={i[3:28],i[1:2]}; @@ -248,10 +248,10 @@ endmodule module keysched(key,k1x,k2x,k3x,k4x,k5x,k6x,k7x,k8x,k9x,k10x,k11x,k12x,k13x,k14x,k15x,k16x); -input [1:64] key; -output [1:48] k1x,k2x,k3x,k4x,k5x,k6x,k7x,k8x,k9x,k10x,k11x,k12x,k13x,k14x,k15x,k16x; -wire [1:28] c0x,c1x,c2x,c3x,c4x,c5x,c6x,c7x,c8x,c9x,c10x,c11x,c12x,c13x,c14x,c15x,c16x; -wire [1:28] d0x,d1x,d2x,d3x,d4x,d5x,d6x,d7x,d8x,d9x,d10x,d11x,d12x,d13x,d14x,d15x,d16x; +input [1:64] key; +output [1:48] k1x,k2x,k3x,k4x,k5x,k6x,k7x,k8x,k9x,k10x,k11x,k12x,k13x,k14x,k15x,k16x; +wire [1:28] c0x,c1x,c2x,c3x,c4x,c5x,c6x,c7x,c8x,c9x,c10x,c11x,c12x,c13x,c14x,c15x,c16x; +wire [1:28] d0x,d1x,d2x,d3x,d4x,d5x,d6x,d7x,d8x,d9x,d10x,d11x,d12x,d13x,d14x,d15x,d16x; pc1 pc1(key, c0x, d0x); @@ -294,10 +294,10 @@ endmodule module s1(clk, b, so); -input clk; -input [1:6] b; -output [1:4] so; -reg [1:4] so; +input clk; +input [1:6] b; +output [1:4] so; +reg [1:4] so; always @(posedge clk) casex(b) @@ -370,10 +370,10 @@ endmodule module s2(clk, b, so); -input clk; -input [1:6] b; -output [1:4] so; -reg [1:4] so; +input clk; +input [1:6] b; +output [1:4] so; +reg [1:4] so; always @(posedge clk) casex(b) @@ -446,10 +446,10 @@ endmodule module s3(clk, b, so); -input clk; -input [1:6] b; -output [1:4] so; -reg [1:4] so; +input clk; +input [1:6] b; +output [1:4] so; +reg [1:4] so; always @(posedge clk) casex(b) @@ -522,10 +522,10 @@ endmodule module s4(clk, b, so); -input clk; -input [1:6] b; -output [1:4] so; -reg [1:4] so; +input clk; +input [1:6] b; +output [1:4] so; +reg [1:4] so; always @(posedge clk) casex(b) @@ -598,10 +598,10 @@ endmodule module s5(clk, b, so); -input clk; -input [1:6] b; -output [1:4] so; -reg [1:4] so; +input clk; +input [1:6] b; +output [1:4] so; +reg [1:4] so; always @(posedge clk) casex(b) @@ -674,10 +674,10 @@ endmodule module s6(clk, b, so); -input clk; -input [1:6] b; -output [1:4] so; -reg [1:4] so; +input clk; +input [1:6] b; +output [1:4] so; +reg [1:4] so; always @(posedge clk) casex(b) @@ -750,10 +750,10 @@ endmodule module s7(clk, b, so); -input clk; -input [1:6] b; -output [1:4] so; -reg [1:4] so; +input clk; +input [1:6] b; +output [1:4] so; +reg [1:4] so; always @(posedge clk) casex(b) @@ -826,10 +826,10 @@ endmodule module s8(clk, b, so); -input clk; -input [1:6] b; -output [1:4] so; -reg [1:4] so; +input clk; +input [1:6] b; +output [1:4] so; +reg [1:4] so; always @(posedge clk) casex(b) @@ -902,8 +902,8 @@ endmodule module ip(pt, l0x, r0x); -input [1:64] pt; -output [1:32] l0x, r0x; +input [1:64] pt; +output [1:32] l0x, r0x; assign l0x[1]=pt[58]; assign l0x[2]=pt[50]; assign l0x[3]=pt[42]; assign l0x[4]=pt[34]; assign l0x[5]=pt[26]; assign l0x[6]=pt[18]; assign l0x[7]=pt[10]; assign l0x[8]=pt[2]; @@ -941,10 +941,10 @@ endmodule module desxor1(e,b1x,b2x,b3x,b4x,b5x,b6x,b7x,b8x,k); -input [1:48] e; -output [1:6] b1x,b2x,b3x,b4x,b5x,b6x,b7x,b8x; -input [1:48] k; -wire [1:48] XX; +input [1:48] e; +output [1:6] b1x,b2x,b3x,b4x,b5x,b6x,b7x,b8x; +input [1:48] k; +wire [1:48] XX; assign XX = k ^ e; assign b1x = XX[1:6]; @@ -960,9 +960,9 @@ endmodule module pp(so1x,so2x,so3x,so4x,so5x,so6x,so7x,so8x,ppo); -input [1:4] so1x,so2x,so3x,so4x,so5x,so6x,so7x,so8x; -output [1:32] ppo; -wire [1:32] XX; +input [1:4] so1x,so2x,so3x,so4x,so5x,so6x,so7x,so8x; +output [1:32] ppo; +wire [1:32] XX; assign XX[1:4]=so1x; assign XX[5:8]=so2x; assign XX[9:12]=so3x; assign XX[13:16]=so4x; assign XX[17:20]=so5x; assign XX[21:24]=so6x; assign XX[25:28]=so7x; assign XX[29:32]=so8x; @@ -980,8 +980,8 @@ endmodule module desxor2(d,l,q); -input [1:32] d,l; -output [1:32] q; +input [1:32] d,l; +output [1:32] q; assign q = d ^ l; @@ -994,10 +994,10 @@ input [1:32] li, ri; input [1:48] k; output [1:32] lo, ro; -wire [1:48] e; +wire [1:48] e; wire [1:6] b1x,b2x,b3x,b4x,b5x,b6x,b7x,b8x; wire [1:4] so1x,so2x,so3x,so4x,so5x,so6x,so7x,so8x; -wire [1:32] ppo; +wire [1:32] ppo; xp xp(ri, e); desxor1 desxor1(e, b1x, b2x, b3x, b4x, b5x, b6x, b7x, b8x, k); @@ -1018,7 +1018,7 @@ endmodule module fp(l,r,ct); -input [1:32] l,r; +input [1:32] l,r; output [1:64] ct; assign ct[1]=r[8]; assign ct[2]=l[8]; assign ct[3]=r[16]; assign ct[4]=l[16]; assign ct[5]=r[24]; assign ct[6]=l[24]; assign ct[7]=r[32]; assign ct[8]=l[32]; diff --git a/examples/pal_reg.v b/examples/pal_reg.v index f959a6e1b..2207c88a1 100644 --- a/examples/pal_reg.v +++ b/examples/pal_reg.v @@ -55,12 +55,12 @@ module register (out, val, clk, oe); output [7:0] out; - input [7:0] val; - input clk, oe; + input [7:0] val; + input clk, oe; - reg [7:0] Q; + reg [7:0] Q; - wire [7:0] out; + wire [7:0] out; bufif0 drv[7:0](out, Q, oe); diff --git a/examples/sqrt-virtex.v b/examples/sqrt-virtex.v index bc95d4939..ad532eab3 100644 --- a/examples/sqrt-virtex.v +++ b/examples/sqrt-virtex.v @@ -252,7 +252,7 @@ endmodule // sqrt32 module main; reg [31:0] x; - reg clk, reset; + reg clk, reset; wire [15:0] y; wire rdy; @@ -354,7 +354,7 @@ module chip_root(clk, rdy, reset, x, y); input [31:0] x; output [15:0] y; - wire clk_int; + wire clk_int; (* cellref="BUFG:O,I" *) buf gbuf (clk_int, clk); diff --git a/expr_synth.cc b/expr_synth.cc index e58c2b30d..c4d0c39c9 100644 --- a/expr_synth.cc +++ b/expr_synth.cc @@ -907,7 +907,7 @@ NetNet* NetEUnary::synthesize(Design*des, NetScope*scope, NetExpr*root) return sig; } - cerr << get_fileline() << ": iternal error: " + cerr << get_fileline() << ": internal error: " << "NetEUnary::synthesize cannot handle op_=" << op_ << endl; des->errors += 1; return expr_->synthesize(des, scope, root); @@ -1328,7 +1328,7 @@ static NetEvWait* make_func_trigger(Design*des, NetScope*scope, NetExpr*root) delete nset; return trigger; -} +} NetNet* NetESFunc::synthesize(Design*des, NetScope*scope, NetExpr*root) { diff --git a/ivl_target.h b/ivl_target.h index 35946e776..c63531697 100644 --- a/ivl_target.h +++ b/ivl_target.h @@ -607,7 +607,7 @@ extern double ivl_const_real(ivl_net_const_t net); * * The discipline domain will not be IVL_DIS_NONE. The "none" domain * is a place-holder internally for incomplete parsing, and is also - * available for code generaters to use. + * available for code generators to use. */ extern const char*ivl_discipline_name(ivl_discipline_t net); extern ivl_dis_domain_t ivl_discipline_domain(ivl_discipline_t net); @@ -1696,7 +1696,7 @@ extern int ivl_scope_time_units(ivl_scope_t net); * * ivl_signal_discipline * If the signal has been declared with a domain (Verilog-AMS) then - * this function wil return a non-nil ivl_discipline_t. + * this function will return a non-nil ivl_discipline_t. * * ivl_signal_msb * ivl_signal_lsb diff --git a/ivlpp/lexor.lex b/ivlpp/lexor.lex index 365678674..0dc93a8ed 100644 --- a/ivlpp/lexor.lex +++ b/ivlpp/lexor.lex @@ -1394,19 +1394,19 @@ static void do_expand(int use_args) str_buf[idx+1] = '0'; str_buf[idx+2] = '4'; str_buf[idx+3] = '2'; - idx += 4; - continue; + idx += 4; + continue; } if (*cp == '\\') { str_buf[idx] = '\\'; str_buf[idx+1] = '1'; str_buf[idx+2] = '3'; str_buf[idx+3] = '4'; - idx += 4; - continue; + idx += 4; + continue; } str_buf[idx] = *cp; - idx += 1; + idx += 1; } str_buf[idx] = 0; idx += 1; diff --git a/lexor.lex b/lexor.lex index 00e8dc96c..ff96863c4 100644 --- a/lexor.lex +++ b/lexor.lex @@ -1179,7 +1179,7 @@ static void process_ucdrive(const char*txt) cp += strspn(cp, " \t"); if (strncmp(cp, "//", 2) != 0 && (size_t)(cp-yytext) != strlen(yytext)) { - VLerror(yylloc, "Invalid `unconnected_dirve directive (extra " + VLerror(yylloc, "Invalid `unconnected_drive directive (extra " "garbage after precision)."); return; } diff --git a/main.cc b/main.cc index 0bfcd0a1f..ff5ee6f48 100644 --- a/main.cc +++ b/main.cc @@ -872,7 +872,7 @@ int main(int argc, char*argv[]) if (gn_cadence_types_flag) lexor_keyword_mask |= GN_KEYWORDS_ICARUS; - + if (gn_verilog_ams_flag) lexor_keyword_mask |= GN_KEYWORDS_VAMS_2_3; diff --git a/mingw.txt b/mingw.txt index c8a2ee063..af1c61489 100644 --- a/mingw.txt +++ b/mingw.txt @@ -84,7 +84,7 @@ Download the msys-1.x.x.exe and msysdtc-1.x.x.exe binaries. These are self-installing packages. Install msys first, and then msysDTC. Most likely, you want to install them in c:/msys. (The msysDTK is installed in the same location, as it is an add-on.) - + This install should be easy and reliable. The installation will leave an "msys" icon on your desktop and in the diff --git a/net_design.cc b/net_design.cc index 84c4a55a1..055e620ed 100644 --- a/net_design.cc +++ b/net_design.cc @@ -341,8 +341,7 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur) eval_expr((*cur).second.msb); if (! eval_as_long(msb, (*cur).second.msb)) { cerr << (*cur).second.expr->get_fileline() - << ": internal error: " - << "unable to evaluate msb expression " + << ": error: Unable to evaluate msb expression " << "for parameter " << (*cur).first << ": " << *(*cur).second.msb << endl; des->errors += 1; @@ -357,8 +356,7 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur) eval_expr((*cur).second.lsb); if (! eval_as_long(lsb, (*cur).second.lsb)) { cerr << (*cur).second.expr->get_fileline() - << ": internal error: " - << "unable to evaluate lsb expression " + << ": error: Unable to evaluate lsb expression " << "for parameter " << (*cur).first << ": " << *(*cur).second.lsb << endl; des->errors += 1; @@ -384,10 +382,10 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur) case IVL_VT_REAL: if (! dynamic_cast(expr)) { cerr << expr->get_fileline() - << ": internal error: " - << "unable to evaluate real parameter value: " - << *expr << endl; + << ": error: Unable to evaluate real parameter " + << (*cur).first << " value: " << *expr << endl; des->errors += 1; + (*cur).second.expr = NULL; return; } break; @@ -396,11 +394,10 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur) case IVL_VT_BOOL: if (! dynamic_cast(expr)) { cerr << expr->get_fileline() - << ": internal error: " - << "unable to evaluate parameter " - << (*cur).first - << " value: " << *expr << endl; + << ": error: Unable to evaluate parameter " + << (*cur).first << " value: " << *expr << endl; des->errors += 1; + (*cur).second.expr = NULL; return; } break; @@ -408,8 +405,9 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur) default: cerr << expr->get_fileline() << ": internal error: " - << "unhandled expression type?" << endl; + << "Unhandled expression type?" << endl; des->errors += 1; + (*cur).second.expr = NULL; return; } @@ -522,7 +520,13 @@ void NetScope::evaluate_parameter_real_(Design*des, param_ref_t cur) if (NetECReal*tmp = dynamic_cast(expr)) { res = tmp; } else { - ivl_assert(*expr, 0); + cerr << expr->get_fileline() + << ": error: " + << "Unable to evaluate real parameter " + << (*cur).first << " value: " << *expr << endl; + des->errors += 1; + (*cur).second.expr = NULL; + return; } break; @@ -533,12 +537,23 @@ void NetScope::evaluate_parameter_real_(Design*des, param_ref_t cur) res = new NetECReal(val); res->set_line(*tmp); } else { - ivl_assert(*expr, 0); + cerr << expr->get_fileline() + << ": error: " + << "Unable to evaluate parameter " + << (*cur).first << " value: " << *expr << endl; + des->errors += 1; + (*cur).second.expr = NULL; + return; } break; default: - ivl_assert(*expr, 0); + cerr << expr->get_fileline() + << ": internal error: " + << "Unhandled expression type?" << endl; + des->errors += 1; + (*cur).second.expr = NULL; + return; break; } @@ -586,7 +601,7 @@ void NetScope::evaluate_parameter_real_(Design*des, param_ref_t cur) if (! from_flag) { cerr << res->get_fileline() << ": error: " << "Parameter value " << value - << " is out of range for parameter " << (*cur).first + << " is out of range for real parameter " << (*cur).first << "." << endl; des->errors += 1; } @@ -612,7 +627,7 @@ void NetScope::evaluate_parameters(Design*des) // Resolve the expression type (signed/unsigned) if the // expression is present. It is possible to not be - // present if there are earlier errors en elaboration. + // present if there are earlier errors in elaboration. if (cur->second.expr) cur->second.expr->resolve_pexpr_type(); diff --git a/net_expr.cc b/net_expr.cc index 3b5890caa..1dc1c3cb1 100644 --- a/net_expr.cc +++ b/net_expr.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2009 Stephen Williams (steve@icarus.com) + * Copyright (c) 2002-2010 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -488,18 +488,21 @@ const NetScope* NetECRealParam::scope() const NetEParam::NetEParam() : des_(0), scope_(0) { + solving_ = false; } NetEParam::NetEParam(Design*d, NetScope*s, perm_string n) : des_(d), scope_(s), reference_(scope_->find_parameter(n)) { cast_signed_base_(reference_->second.signed_flag); + solving_ = false; } NetEParam::NetEParam(Design*d, NetScope*s, ref_t ref) : des_(d), scope_(s), reference_(ref) { cast_signed_base_(reference_->second.signed_flag); + solving_ = false; } NetEParam::~NetEParam() @@ -519,10 +522,21 @@ ivl_variable_type_t NetEParam::expr_type() const NetEParam* NetEParam::dup_expr() const { NetEParam*tmp = new NetEParam(des_, scope_, reference_); + tmp->solving(solving_); tmp->set_line(*this); return tmp; } +void NetEParam::solving(bool arg) +{ + solving_ = arg; +} + +bool NetEParam::solving() const +{ + return solving_; +} + NetESelect::NetESelect(NetExpr*exp, NetExpr*base, unsigned wid) : expr_(exp), base_(base) { diff --git a/net_link.cc b/net_link.cc index 2bf71302c..e53f9da6a 100644 --- a/net_link.cc +++ b/net_link.cc @@ -382,7 +382,7 @@ void Nexus::unlink(Link*that) } // If the link I'm removing was a driver for this nexus, then - // cancel my guess of the driven value. + // cancel my guess of the driven value. if (that->get_dir() != Link::INPUT) driven_ = NO_GUESS; diff --git a/net_scope.cc b/net_scope.cc index c9760cd0c..ae84b6e39 100644 --- a/net_scope.cc +++ b/net_scope.cc @@ -251,14 +251,14 @@ void NetScope::print_type(ostream&stream) const break; case FORK_JOIN: stream << "parallel block"; - break; + break; case FUNC: stream << "function"; break; case MODULE: stream << "module <" << (module_name_ ? module_name_.str() : "") << "> instance"; - break; + break; case TASK: stream << "task"; break; diff --git a/netlist.cc b/netlist.cc index 264196863..12d776f58 100644 --- a/netlist.cc +++ b/netlist.cc @@ -227,7 +227,7 @@ bool NetPins::is_linked(void) NetObj::NetObj(NetScope*s, perm_string n, unsigned np) : NetPins(np), scope_(s), name_(n), delay1_(0), delay2_(0), delay3_(0) { - /* Don't + /* Don't ivl_assert(*this, np > 0); * because it would happen before we get to print a useful * message in the NetNet constructor diff --git a/netlist.h b/netlist.h index 04ef95a06..e2c165d92 100644 --- a/netlist.h +++ b/netlist.h @@ -1829,7 +1829,7 @@ class NetPartSelect : public NetNode { * that makes sense for the technology. * * A NetBUFZ is transparent if strengths are passed through it without - * change. A NetBUFZ is non-transparent if values other then HiZ are + * change. A NetBUFZ is non-transparent if values other than HiZ are * converted to the strength of the output. */ class NetBUFZ : public NetNode { @@ -3574,6 +3574,8 @@ class NetEParam : public NetExpr { virtual ivl_variable_type_t expr_type() const; virtual NetExpr* eval_tree(int prune_to_width = -1); virtual NetEParam* dup_expr() const; + void solving(bool arg); + bool solving() const; virtual void dump(ostream&) const; @@ -3582,6 +3584,7 @@ class NetEParam : public NetExpr { NetScope*scope_; typedef map::iterator ref_t; ref_t reference_; + bool solving_; NetEParam(class Design*des, NetScope*scope, ref_t ref); }; diff --git a/netmisc.cc b/netmisc.cc index f2644cc56..9fa1a0e95 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -161,7 +161,7 @@ NetNet* cast_to_real(Design*des, NetScope*scope, NetNet*src) * NetEBAdd node that has the input expression and an expression made * from the constant value. */ -NetExpr* make_add_expr(NetExpr*expr, long val) +static NetExpr* make_add_expr(NetExpr*expr, long val) { if (val == 0) return expr; @@ -190,10 +190,14 @@ NetExpr* make_add_expr(NetExpr*expr, long val) return res; } -NetExpr* make_sub_expr(long val, NetExpr*expr) +/* + * Subtract an existing expression from a signed constant. + */ +static NetExpr* make_sub_expr(long val, NetExpr*expr) { verinum val_v (val, expr->expr_width()); val_v.has_sign(true); + NetEConst*val_c = new NetEConst(val_v); val_c->set_line(*expr); @@ -203,6 +207,150 @@ NetExpr* make_sub_expr(long val, NetExpr*expr) return res; } +/* + * This routine is used to calculate the number of bits needed to + * contain the given number. + */ +static unsigned num_bits(long arg) +{ + unsigned res = 0; + + /* For a negative value we have room for one extra value, but + * we have a signed result so we need an extra bit for this. */ + if (arg < 0) { + arg = -arg - 1; + res += 1; + } + + /* Calculate the number of bits needed here. */ + while (arg) { + res += 1; + arg >>= 1; + } + + return res; +} + +/* + * This routine generates the normalization expression needed for a variable + * bit select or a variable base expression for an indexed part select. + */ +NetExpr *normalize_variable_base(NetExpr *base, long msb, long lsb, + unsigned long wid, bool is_up) +{ + long offset = lsb; + + if (msb < lsb) { + /* Correct the offset if needed. */ + if (is_up) offset -= wid - 1; + /* Calculate the space needed for the offset. */ + unsigned min_wid = num_bits(offset); + /* We need enough space for the larger of the offset or the + * base expression. */ + if (min_wid < base->expr_width()) min_wid = base->expr_width(); + /* Now that we have the minimum needed width increase it by + * one to make room for the normalization calculation. */ + min_wid += 1; + /* Pad the base expression to the correct width. */ + base = pad_to_width(base, min_wid, *base); + /* If the base expression is unsigned and either the lsb + * is negative or it does not fill the width of the base + * expression then we could generate negative normalized + * values so cast the expression to signed to get the + * math correct. */ + if ((lsb < 0 || num_bits(lsb+1) <= base->expr_width()) && + ! base->has_sign()) { + /* We need this extra select to hide the signed + * property from the padding above. It will be + * removed automatically during code generation. */ + NetESelect *tmp = new NetESelect(base, 0 , min_wid); + tmp->set_line(*base); + tmp->cast_signed(true); + base = tmp; + } + /* Normalize the expression. */ + base = make_sub_expr(offset, base); + } else { + /* Correct the offset if needed. */ + if (!is_up) offset += wid - 1; + /* If the offset is zero then just return the base (index) + * expression. */ + if (offset == 0) return base; + /* Calculate the space needed for the offset. */ + unsigned min_wid = num_bits(-offset); + /* We need enough space for the larger of the offset or the + * base expression. */ + if (min_wid < base->expr_width()) min_wid = base->expr_width(); + /* Now that we have the minimum needed width increase it by + * one to make room for the normalization calculation. */ + min_wid += 1; + /* Pad the base expression to the correct width. */ + base = pad_to_width(base, min_wid, *base); + /* If the offset is greater than zero then we need to do + * signed math to get the location value correct. */ + if (offset > 0 && ! base->has_sign()) { + /* We need this extra select to hide the signed + * property from the padding above. It will be + * removed automatically during code generation. */ + NetESelect *tmp = new NetESelect(base, 0 , min_wid); + tmp->set_line(*base); + tmp->cast_signed(true); + base = tmp; + } + /* Normalize the expression. */ + base = make_add_expr(base, -offset); + } + + return base; +} + +/* + * This routine generates the normalization expression needed for a variable + * array word select. + */ +NetExpr *normalize_variable_array_base(NetExpr *base, long offset, + unsigned count) +{ + assert(offset != 0); + /* Calculate the space needed for the offset. */ + unsigned min_wid = num_bits(-offset); + /* We need enough space for the larger of the offset or the base + * expression. */ + if (min_wid < base->expr_width()) min_wid = base->expr_width(); + /* Now that we have the minimum needed width increase it by one + * to make room for the normalization calculation. */ + min_wid += 1; + /* Pad the base expression to the correct width. */ + base = pad_to_width(base, min_wid, *base); + /* If the offset is greater than zero then we need to do signed + * math to get the location value correct. */ + if (offset > 0 && ! base->has_sign()) { + /* We need this extra select to hide the signed property + * from the padding above. It will be removed automatically + * during code generation. */ + NetESelect *tmp = new NetESelect(base, 0 , min_wid); + tmp->set_line(*base); + tmp->cast_signed(true); + base = tmp; + } + /* Normalize the expression. */ + base = make_add_expr(base, -offset); + + /* We should not need to do this, but .array/port does not + * handle a small signed index correctly and it is a major + * effort to fix it. For now we will just pad the expression + * enough so that any negative value when converted to + * unsigned is larger than the maximum array word. */ + if (base->has_sign()) { + unsigned range_wid = num_bits(count-1) + 1; + if (min_wid < range_wid) { + base = pad_to_width(base, range_wid, *base); + } + } + + return base; +} + NetEConst* make_const_x(unsigned long wid) { verinum xxx (verinum::Vx, wid); @@ -289,8 +437,15 @@ NetExpr* elab_and_eval(Design*des, NetScope*scope, void eval_expr(NetExpr*&expr, int prune_width) { assert(expr); - if (dynamic_cast(expr)) return; if (dynamic_cast(expr)) return; + /* Resize a constant if allowed and needed. */ + if (NetEConst *tmp = dynamic_cast(expr)) { + if (prune_width <= 0) return; + if (tmp->has_width()) return; + if ((unsigned)prune_width <= tmp->expr_width()) return; + expr = pad_to_width(expr, (unsigned)prune_width, *expr); + return; + } NetExpr*tmp = expr->eval_tree(prune_width); if (tmp != 0) { @@ -423,7 +578,7 @@ const char *human_readable_op(const char op, bool unary) case '>': type = ">"; break; case 'L': type = "<="; break; case 'G': type = ">="; break; - + case '^': type = "^"; break; // XOR case 'X': type = "~^"; break; // XNOR case '&': type = "&"; break; // Bitwise AND diff --git a/netmisc.h b/netmisc.h index 31d97def7..6992faea0 100644 --- a/netmisc.h +++ b/netmisc.h @@ -91,6 +91,15 @@ extern NetExpr*condition_reduce(NetExpr*expr); */ extern NetNet*crop_to_width(Design*des, NetNet*n, unsigned w); +/* + * These functions generate an equation to normalize an expression using + * the provided vector/array information. + */ +extern NetExpr*normalize_variable_base(NetExpr *base, long msb, long lsb, + unsigned long wid, bool is_up); +extern NetExpr*normalize_variable_array_base(NetExpr *base, long offset, + unsigned count); + /* * This function takes as input a NetNet signal and adds a constant * value to it. If the val is 0, then simply return sig. Otherwise, @@ -99,23 +108,6 @@ extern NetNet*crop_to_width(Design*des, NetNet*n, unsigned w); extern NetNet*add_to_net(Design*des, NetNet*sig, long val); extern NetNet*sub_net_from(Design*des, NetScope*scope, long val, NetNet*sig); -/* - * These functions make various sorts of expressions, given operands - * of certain type. The order of the operands is preserved in cases - * where order matters. - * - * make_add_expr - * Make a NetEBAdd expression with the first argument and - * the second. This may get turned into a subtract if is - * less than zero. If val is exactly zero, then return as is. - * - * make_sub_expr - * Make a NetEBAdd(subtract) node that subtracts the given - * expression from the integer value. - */ -extern NetExpr*make_add_expr(NetExpr*expr, long val); -extern NetExpr*make_sub_expr(long val, NetExpr*expr); - /* * Make a NetEConst object that contains only X bits. */ diff --git a/nodangle.cc b/nodangle.cc index 5ce442dac..68c2118ee 100644 --- a/nodangle.cc +++ b/nodangle.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2009 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2010 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -131,14 +131,12 @@ void nodangle_f::signal(Design*des, NetNet*sig) if (sig->get_refs() > 0) return; - /* Cannot delete the ports of tasks or functions. There are - too many places where they are referenced. */ - if ((sig->port_type() != NetNet::NOT_A_PORT) - && (sig->scope()->type() == NetScope::TASK)) - return; - - if ((sig->port_type() != NetNet::NOT_A_PORT) - && (sig->scope()->type() == NetScope::FUNC)) + /* Cannot delete the ports of tasks, functions or modules. There + are too many places where they are referenced. */ + if ((sig->port_type() != NetNet::NOT_A_PORT) && + ((sig->scope()->type() == NetScope::TASK) || + (sig->scope()->type() == NetScope::FUNC) || + (sig->scope()->type() == NetScope::MODULE))) return; /* Can't delete ports of cells. */ diff --git a/parse.y b/parse.y index a9a5bfc3f..fe87b00e7 100644 --- a/parse.y +++ b/parse.y @@ -2052,7 +2052,7 @@ local_timeunit_prec_decl module : attribute_list_opt module_start IDENTIFIER { pform_startmodule($3, @2.text, @2.first_line, $1); } module_parameter_port_list_opt - module_port_list_opt + module_port_list_opt module_attribute_foreign ';' { pform_module_set_ports($6); } local_timeunit_prec_decl_opt diff --git a/parse_misc.h b/parse_misc.h index 40efbfffa..f3b5dfc9b 100644 --- a/parse_misc.h +++ b/parse_misc.h @@ -78,7 +78,7 @@ extern bool have_timeunit_decl; extern bool have_timeprec_decl; /* - * Export there functions because we have to generate PENumber class + * Export these functions because we have to generate PENumber class * in pform.cc for user defparam definition from command file. */ extern verinum*make_unsized_dec(const char*txt); diff --git a/pform.cc b/pform.cc index 973f52c70..7b5566018 100644 --- a/pform.cc +++ b/pform.cc @@ -62,10 +62,10 @@ void parm_to_defparam_list(const string¶m) key = strdup(param.substr(0, off).c_str()); value = strdup(param.substr(off+1).c_str()); } - + // Resolve hierarchical name for defparam. Remember // to deal with bit select for generate scopes. Bit - // select expression should be constant interger. + // select expression should be constant integer. pform_name_t name; char *nkey = key; char *ptr = strchr(key, '.'); @@ -109,7 +109,7 @@ void parm_to_defparam_list(const string¶m) ptr = strchr(nkey, '.'); } name.push_back(name_component_t(lex_strings.make(nkey))); - + // Resolve value to PExpr class. Should support all kind of constant // format including based number, dec number, real number and string. if (*value == '"') { // string type @@ -127,13 +127,13 @@ void parm_to_defparam_list(const string¶m) cerr << ": error: missing close quote of string for defparam: " << name << endl; else if (*(buf_ptr+1) != 0) { // '"' appears within string with no escape cerr << buf_ptr << endl; - cerr << ": error: \'\"\' appears within string value for defparam: " << name + cerr << ": error: \'\"\' appears within string value for defparam: " << name << ". Ignore characters after \'\"\'" << endl; } - + *buf_ptr = '\0'; buf_ptr = buf+1; - // Remember to use 'new' to allocate string for PEString + // Remember to use 'new' to allocate string for PEString // because 'delete' is used by its destructor. char *nchar = strcpy(new char [strlen(buf_ptr)+1], buf_ptr); PExpr* ndec = new PEString(nchar); @@ -144,7 +144,7 @@ void parm_to_defparam_list(const string¶m) char *num = strchr(value, '\''); if (num != 0) { verinum *val; - // BASED_NUMBER, somthing like - scope.parameter='b11 + // BASED_NUMBER, something like - scope.parameter='b11 // make sure to check 'h' first because 'b'&'d' may be included // in hex format if (strchr(num, 'h') || strchr(num, 'H')) @@ -165,17 +165,17 @@ void parm_to_defparam_list(const string¶m) free(value); return; } - + // BASED_NUMBER with size, something like - scope.parameter=2'b11 if (num != value) { *num = 0; verinum *siz = make_unsized_dec(value); val = pform_verinum_with_size(siz, val, "", 0); } - + PExpr* ndec = new PENumber(val); Module::user_defparms.push_back( make_pair(name, ndec) ); - + } else { // REALTIME, something like - scope.parameter=1.22 or scope.parameter=1e2 @@ -799,7 +799,7 @@ void pform_endmodule(const char*name, bool inside_celldefine, tp_local_flag = false; } -static void pform_add_genvar(const struct vlltype&li, const perm_string&name, +static void pform_add_genvar(const struct vlltype&li, const perm_string&name, map&genvars) { LineInfo*lni = new LineInfo(); diff --git a/pform.h b/pform.h index 4d611ad8d..ea50b318a 100644 --- a/pform.h +++ b/pform.h @@ -418,7 +418,7 @@ extern PExpr* pform_make_branch_probe_expression(const struct vlltype&loc, extern PExpr* pform_make_branch_probe_expression(const struct vlltype&loc, char*name, char*branch); -/* +/* * Parse configuration file with format =, where key * is the hierarchical name of a valid parameter name and value * is the value user wants to assign to. The value should be constant. diff --git a/symbol_search.cc b/symbol_search.cc index f6ed3f527..8b8cadbfa 100644 --- a/symbol_search.cc +++ b/symbol_search.cc @@ -61,7 +61,7 @@ NetScope*symbol_search(const LineInfo*li, Design*des, NetScope*scope, cerr << li->get_fileline() << ": error: Hierarchical " "reference to automatically allocated item " "`" << key << "' in path `" << path << "'" << endl; - des->errors += 1; + des->errors += 1; } hier_path = true; diff --git a/tgt-vhdl/Makefile.in b/tgt-vhdl/Makefile.in index ef1e54de0..ea04ee9a1 100644 --- a/tgt-vhdl/Makefile.in +++ b/tgt-vhdl/Makefile.in @@ -50,7 +50,7 @@ dep: mv $*.d dep O = vhdl.o state.o vhdl_element.o vhdl_type.o vhdl_syntax.o scope.o process.o \ - stmt.o expr.o lpm.o support.o cast.o logic.o + stmt.o expr.o lpm.o display.o support.o cast.o logic.o ifeq (@WIN32@,yes) TGTLDFLAGS=-L.. -livl @@ -72,7 +72,7 @@ stamp-vhdl_config-h: $(srcdir)/vhdl_config.h.in ../config.status vhdl_config.h: stamp-vhdl_config-h clean: - rm -rf $(O) dep vhdl.tgt + rm -rf $(O) dep vhdl.tgt distclean: clean rm -f Makefile config.log diff --git a/tgt-vhdl/cast.cc b/tgt-vhdl/cast.cc index e1568929f..07540f71d 100644 --- a/tgt-vhdl/cast.cc +++ b/tgt-vhdl/cast.cc @@ -39,7 +39,7 @@ vhdl_expr *vhdl_expr::cast(const vhdl_type *to) // we can't generate any type conversion code if (NULL == type_) return this; - + if (to->get_name() == type_->get_name()) { if (to->get_width() == type_->get_width()) return this; // Identical @@ -58,8 +58,6 @@ vhdl_expr *vhdl_expr::cast(const vhdl_type *to) return to_vector(to->get_name(), to->get_width()); case VHDL_TYPE_STD_LOGIC: return to_std_logic(); - case VHDL_TYPE_STRING: - return to_string(); case VHDL_TYPE_STD_ULOGIC: return to_std_ulogic(); default: @@ -81,7 +79,7 @@ vhdl_expr *vhdl_expr::to_vector(vhdl_type_name_t name, int w) vhdl_bit_spec_expr *bs = new vhdl_bit_spec_expr(new vhdl_type(name, w - 1, 0), others); bs->add_bit(0, this); - + return bs; } else { @@ -91,11 +89,11 @@ vhdl_expr *vhdl_expr::to_vector(vhdl_type_name_t name, int w) vhdl_type *t = new vhdl_type(name, w - 1, 0); vhdl_fcall *conv = new vhdl_fcall(t->get_string().c_str(), t); conv->add_expr(this); - + if (w != type_->get_width()) return conv->resize(w); else - return conv; + return conv; } } @@ -112,29 +110,10 @@ vhdl_expr *vhdl_expr::to_integer() } else conv = new vhdl_fcall("To_Integer", vhdl_type::integer()); - - conv->add_expr(this); - - return conv; -} -vhdl_expr *vhdl_expr::to_string() -{ - bool numeric = type_->get_name() == VHDL_TYPE_UNSIGNED - || type_->get_name() == VHDL_TYPE_SIGNED; - - if (numeric) { - vhdl_fcall *image = new vhdl_fcall("integer'image", vhdl_type::string()); - image->add_expr(this->cast(vhdl_type::integer())); - return image; - } - else { - // Assume type'image exists - vhdl_fcall *image = new vhdl_fcall(type_->get_string() + "'image", - vhdl_type::string()); - image->add_expr(this); - return image; - } + conv->add_expr(this); + + return conv; } /* @@ -151,7 +130,7 @@ vhdl_expr *vhdl_expr::to_boolean() else if (type_->get_name() == VHDL_TYPE_UNSIGNED) { // Need to use a support function for this conversion require_support_function(SF_UNSIGNED_TO_BOOLEAN); - + vhdl_fcall *conv = new vhdl_fcall(support_function::function_name(SF_UNSIGNED_TO_BOOLEAN), vhdl_type::boolean()); @@ -160,7 +139,7 @@ vhdl_expr *vhdl_expr::to_boolean() } else if (type_->get_name() == VHDL_TYPE_SIGNED) { require_support_function(SF_SIGNED_TO_BOOLEAN); - + vhdl_fcall *conv = new vhdl_fcall(support_function::function_name(SF_SIGNED_TO_BOOLEAN), vhdl_type::boolean()); @@ -178,12 +157,12 @@ vhdl_expr *vhdl_expr::to_std_logic() { if (type_->get_name() == VHDL_TYPE_BOOLEAN) { require_support_function(SF_BOOLEAN_TO_LOGIC); - + vhdl_fcall *ah = new vhdl_fcall(support_function::function_name(SF_BOOLEAN_TO_LOGIC), vhdl_type::std_logic()); ah->add_expr(this); - + return ah; } else if (type_->get_name() == VHDL_TYPE_SIGNED) { @@ -217,7 +196,7 @@ vhdl_expr *vhdl_expr::to_std_ulogic() f->add_expr(this); return f; } - else + else assert(false); } @@ -240,11 +219,11 @@ vhdl_expr *vhdl_expr::resize(int newwidth) vhdl_binop_expr* concat = new vhdl_binop_expr(zeros, VHDL_BINOP_CONCAT, this, vhdl_type::nunsigned(newwidth)); - return concat; + return concat; } else return this; // Doesn't make sense to resize non-vector type - + vhdl_fcall *resizef = new vhdl_fcall("Resize", rtype); resizef->add_expr(this); resizef->add_expr(new vhdl_const_int(newwidth)); @@ -288,10 +267,10 @@ vhdl_expr *vhdl_const_bits::to_std_logic() // VHDL won't let us cast directly between a vector and // a scalar type // But we don't need to here as we have the bits available - + // Take the least significant bit char lsb = value_[0]; - + return new vhdl_const_bit(lsb); } @@ -301,14 +280,14 @@ char vhdl_const_bits::sign_bit() const } vhdl_expr *vhdl_const_bits::to_vector(vhdl_type_name_t name, int w) -{ +{ if (name == VHDL_TYPE_STD_LOGIC_VECTOR) { // Don't need to do anything return this; } else if (name == VHDL_TYPE_SIGNED || name == VHDL_TYPE_UNSIGNED) { // Extend with sign bit - value_.resize(w, sign_bit()); + value_.resize(w, sign_bit()); return this; } assert(false); @@ -325,8 +304,8 @@ vhdl_expr *vhdl_const_bits::resize(int w) // Rather than generating a call to Resize, when can just sign-extend // the bits here. As well as looking better, this avoids any ambiguity // between which of the signed/unsigned versions of Resize to use. - - value_.resize(w, sign_bit()); + + value_.resize(w, sign_bit()); return this; } diff --git a/tgt-vhdl/display.cc b/tgt-vhdl/display.cc new file mode 100644 index 000000000..1f95365ec --- /dev/null +++ b/tgt-vhdl/display.cc @@ -0,0 +1,200 @@ +/* + * VHDL implementation of $display. + * + * Copyright (C) 2008-2009 Nick Gasson (nick@nickg.me.uk) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "vhdl_target.h" + +#include +#include +#include +#include +#include + +static const char *DISPLAY_LINE = "Verilog_Display_Line"; + +/* + * Write a VHDL expression into the current display line. + */ +static void display_write(stmt_container *container, vhdl_expr *expr) +{ + vhdl_pcall_stmt *write = new vhdl_pcall_stmt("Write"); + vhdl_var_ref *ref = + new vhdl_var_ref(DISPLAY_LINE, vhdl_type::line()); + write->add_expr(ref); + + vhdl_type_name_t type = expr->get_type()->get_name(); + if (type == VHDL_TYPE_SIGNED || type == VHDL_TYPE_UNSIGNED) { + vhdl_type integer(VHDL_TYPE_INTEGER); + write->add_expr(expr->cast(&integer)); + } + else if (type != VHDL_TYPE_STRING) { + // Need to add a call to Type'Image for types not + // supported by std.textio + std::string name(expr->get_type()->get_string()); + name += "'Image"; + + vhdl_fcall *cast + = new vhdl_fcall(name.c_str(), vhdl_type::string()); + cast->add_expr(expr); + + write->add_expr(cast); + } + else + write->add_expr(expr); + + container->add_stmt(write); +} + +/* + * Write the value of DISPLAY_LINE to the output. + */ +static void display_line(stmt_container *container) +{ + vhdl_pcall_stmt *write_line = new vhdl_pcall_stmt("WriteLine"); + vhdl_var_ref *output_ref = + new vhdl_var_ref("std.textio.Output", new vhdl_type(VHDL_TYPE_FILE)); + write_line->add_expr(output_ref); + vhdl_var_ref *ref = + new vhdl_var_ref(DISPLAY_LINE, vhdl_type::line()); + write_line->add_expr(ref); + container->add_stmt(write_line); +} + +/* + * Parse an octal escape sequence. + */ +static char parse_octal(const char *p) +{ + assert(*p && *(p+1) && *(p+2)); + assert(isdigit(*p) && isdigit(*(p+1)) && isdigit(*(p+1))); + + return (*p - '0') * 64 + + (*(p+1) - '0') * 8 + + (*(p+2) - '0') * 1; +} + +static void flush_string(std::ostringstream &ss, stmt_container *container) +{ + display_write(container, new vhdl_const_string(ss.str().c_str())); + + // Clear the stream + ss.str(""); +} + +// This should display the hierarchical module name, but we don't support +// this in VHDL. So just emit a warning. +static void display_m(stmt_container* container) +{ + cerr << "Warning: no VHDL translation for %m format code" << endl; +} + +/* + * Generate VHDL for the $display system task. + * This is implemented using the functions in std.textio. Each + * parameter is written to a line variable in the process and + * then the line is written to the special variable `Output' + * (which represents the console). Subsequent $displays will + * use the same line variable. + * + * It's possible, although quite unlikely, that there will be + * name collision with an existing variable called + * `Verilog_Display_Line' -- do something about this? + */ +int draw_stask_display(vhdl_procedural *proc, stmt_container *container, + ivl_statement_t stmt, bool newline) +{ + if (!proc->get_scope()->have_declared(DISPLAY_LINE)) { + vhdl_var_decl *line_var = + new vhdl_var_decl(DISPLAY_LINE, vhdl_type::line()); + line_var->set_comment("For generating $display output"); + proc->get_scope()->add_decl(line_var); + } + + // Write the data into the line + int count = ivl_stmt_parm_count(stmt), i = 0; + while (i < count) { + // $display may have an empty parameter, in which case + // the expression will be null + // The behaviour here seems to be to output a space + ivl_expr_t net = ivl_stmt_parm(stmt, i++); + if (net == NULL) { + display_write(container, new vhdl_const_string(" ")); + continue; + } + + if (ivl_expr_type(net) == IVL_EX_STRING) { + ostringstream ss; + for (const char *p = ivl_expr_string(net); *p; p++) { + if (*p == '\\') { + // Octal escape + char ch = parse_octal(p+1); + if (ch == '\n') { + flush_string(ss, container); + display_line(container); + } + else + ss << ch; + p += 3; + } + else if (*p == '%' && *(++p) != '%') { + flush_string(ss, container); + + // Skip over width for now + while (isdigit(*p)) ++p; + + switch (*p) { + case 'm': + display_m(container); + break; + default: + { + assert(i < count); + ivl_expr_t netp = ivl_stmt_parm(stmt, i++); + assert(netp); + + vhdl_expr *base = translate_expr(netp); + if (NULL == base) + return 1; + + display_write(container, base); + } + } + } + else + ss << *p; + } + + // Call Write on any non-empty string data left in the buffer + if (!ss.str().empty()) + display_write(container, new vhdl_const_string(ss.str().c_str())); + } + else { + vhdl_expr *base = translate_expr(net); + if (NULL == base) + return 1; + + display_write(container, base); + } + } + + if (newline) + display_line(container); + + return 0; +} diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 78ce66882..a382fb8f6 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -35,7 +35,7 @@ static vhdl_expr *change_signedness(vhdl_expr *e, bool issigned) int msb = e->get_type()->get_msb(); int lsb = e->get_type()->get_lsb(); vhdl_type u(issigned ? VHDL_TYPE_SIGNED : VHDL_TYPE_UNSIGNED, msb, lsb); - + return e->cast(&u); } @@ -44,9 +44,9 @@ static vhdl_expr *change_signedness(vhdl_expr *e, bool issigned) * same signedness as the Verilog expression vl_e. */ static vhdl_expr *correct_signedness(vhdl_expr *vhd_e, ivl_expr_t vl_e) -{ +{ bool should_be_signed = ivl_expr_signed(vl_e) != 0; - + if (vhd_e->get_type()->get_name() == VHDL_TYPE_UNSIGNED && should_be_signed) { //operand->print(); @@ -69,7 +69,7 @@ static vhdl_expr *correct_signedness(vhdl_expr *vhd_e, ivl_expr_t vl_e) * Convert a constant Verilog string to a constant VHDL string. */ static vhdl_expr *translate_string(ivl_expr_t e) -{ +{ // TODO: May need to inspect or escape parts of this const char *str = ivl_expr_string(e); return new vhdl_const_string(str); @@ -82,12 +82,12 @@ static vhdl_expr *translate_string(ivl_expr_t e) static vhdl_var_ref *translate_signal(ivl_expr_t e) { ivl_signal_t sig = ivl_expr_signal(e); - + const vhdl_scope *scope = find_scope_for_signal(sig); assert(scope); const char *renamed = get_renamed_signal(sig).c_str(); - + vhdl_decl *decl = scope->get_decl(renamed); assert(decl); @@ -102,7 +102,7 @@ static vhdl_var_ref *translate_signal(ivl_expr_t e) vhdl_var_ref *ref = new vhdl_var_ref(renamed, new vhdl_type(*decl->get_type())); - + ivl_expr_t off; if (ivl_signal_array_count(sig) > 0 && (off = ivl_expr_oper1(e))) { // Select from an array @@ -152,7 +152,7 @@ static vhdl_expr *translate_reduction(support_function_t f, bool neg, vhdl_fcall *fcall = new vhdl_fcall(support_function::function_name(f), vhdl_type::std_logic()); - + vhdl_type std_logic_vector(VHDL_TYPE_STD_LOGIC_VECTOR); fcall->add_expr(operand->cast(&std_logic_vector)); @@ -173,7 +173,7 @@ static vhdl_expr *translate_unary(ivl_expr_t e) return NULL; operand = correct_signedness(operand, e); - + char opcode = ivl_expr_opcode(e); switch (opcode) { case '!': @@ -234,7 +234,7 @@ static vhdl_expr *translate_relation(vhdl_expr *lhs, vhdl_expr *rhs, // Generate any necessary casts // Arbitrarily, the RHS is casted to the type of the LHS vhdl_expr *r_cast = rhs->cast(lhs->get_type()); - + return new vhdl_binop_expr(lhs, op, r_cast, vhdl_type::boolean()); } @@ -311,7 +311,7 @@ static vhdl_expr *translate_binary(ivl_expr_t e) vhdl_expr *lhs = translate_expr(ivl_expr_oper1(e)); if (NULL == lhs) return NULL; - + vhdl_expr *rhs = translate_expr(ivl_expr_oper2(e)); if (NULL == rhs) return NULL; @@ -319,7 +319,7 @@ static vhdl_expr *translate_binary(ivl_expr_t e) int lwidth = lhs->get_type()->get_width(); int rwidth = rhs->get_type()->get_width(); int result_width = ivl_expr_width(e); - + // For === and !== we need to compare std_logic_vectors // rather than signeds vhdl_type std_logic_vector(VHDL_TYPE_STD_LOGIC_VECTOR, result_width-1, 0); @@ -328,7 +328,7 @@ static vhdl_expr *translate_binary(ivl_expr_t e) bool vectorop = (ltype == VHDL_TYPE_SIGNED || ltype == VHDL_TYPE_UNSIGNED) && (rtype == VHDL_TYPE_SIGNED || rtype == VHDL_TYPE_UNSIGNED); - + // May need to resize the left or right hand side or change the // signedness if (vectorop) { @@ -425,7 +425,7 @@ static vhdl_expr *translate_binary(ivl_expr_t e) result = translate_shift(lhs, rhs, VHDL_BINOP_SRA); else result = translate_shift(lhs, rhs, VHDL_BINOP_SR); - break; + break; case '^': result = translate_numeric(lhs, rhs, VHDL_BINOP_XOR); break; @@ -463,7 +463,7 @@ static vhdl_expr *translate_select(ivl_expr_t e) return NULL; ivl_expr_t o2 = ivl_expr_oper2(e); - if (o2) { + if (o2) { vhdl_expr *base = translate_expr(ivl_expr_oper2(e)); if (NULL == base) return NULL; @@ -477,7 +477,7 @@ static vhdl_expr *translate_select(ivl_expr_t e) new vhdl_type(*from->get_type())); } else if (from_var_ref->get_type()->get_name() != VHDL_TYPE_STD_LOGIC) { - // We can use the more idomatic VHDL slice notation on a + // We can use the more idiomatic VHDL slice notation on a // single variable reference vhdl_type integer(VHDL_TYPE_INTEGER); from_var_ref->set_slice(base->cast(&integer), ivl_expr_width(e) - 1); @@ -528,7 +528,7 @@ static vhdl_expr *translate_ufunc(ivl_expr_t e) const char *funcname = ivl_scope_tname(defscope); - vhdl_type *rettype = + vhdl_type *rettype = vhdl_type::type_for(ivl_expr_width(e), ivl_expr_signed(e) != 0); vhdl_fcall *fcall = new vhdl_fcall(funcname, rettype); @@ -539,18 +539,18 @@ static vhdl_expr *translate_ufunc(ivl_expr_t e) delete fcall; return NULL; } - + // Ensure the parameter has the correct VHDL type // Parameter number is i + 1 since 0th parameter is return value ivl_signal_t param_sig = ivl_scope_port(defscope, i + 1); vhdl_type *param_type = vhdl_type::type_for(ivl_signal_width(param_sig), ivl_signal_signed(param_sig) != 0); - + fcall->add_expr(param->cast(param_type)); delete param_type; } - + return fcall; } @@ -565,7 +565,7 @@ static vhdl_expr *translate_ternary(ivl_expr_t e) sf = SF_TERNARY_SIGNED; else sf = SF_TERNARY_UNSIGNED; - + require_support_function(sf); vhdl_expr *test = translate_expr(ivl_expr_oper1(e)); @@ -576,20 +576,20 @@ static vhdl_expr *translate_ternary(ivl_expr_t e) vhdl_type boolean(VHDL_TYPE_BOOLEAN); test = test->cast(&boolean); - + vhdl_fcall *fcall = new vhdl_fcall(support_function::function_name(sf), vhdl_type::type_for(width, issigned)); fcall->add_expr(test); fcall->add_expr(true_part); fcall->add_expr(false_part); - + return fcall; } static vhdl_expr *translate_concat(ivl_expr_t e) { - vhdl_type *rtype = + vhdl_type *rtype = vhdl_type::type_for(ivl_expr_width(e), ivl_expr_signed(e) != 0); vhdl_binop_expr *concat = new vhdl_binop_expr(VHDL_BINOP_CONCAT, rtype); @@ -716,11 +716,11 @@ vhdl_expr *translate_time_expr(ivl_expr_t e) if (time->get_type()->get_name() != VHDL_TYPE_TIME) { vhdl_type integer(VHDL_TYPE_INTEGER); time = time->cast(&integer); - + vhdl_expr *ns1 = scale_time(get_active_entity(), 1); return new vhdl_binop_expr(time, VHDL_BINOP_MULT, ns1, vhdl_type::time()); } else // Translating IVL_EX_DELAY will always return a time type - return time; + return time; } diff --git a/tgt-vhdl/logic.cc b/tgt-vhdl/logic.cc index b27f69ce2..4efe3cc33 100644 --- a/tgt-vhdl/logic.cc +++ b/tgt-vhdl/logic.cc @@ -36,11 +36,11 @@ static vhdl_expr *inputs_to_expr(vhdl_scope *scope, vhdl_binop_t op, // the program has already been type checked vhdl_binop_expr *gate = new vhdl_binop_expr(op, vhdl_type::std_logic()); - + int npins = ivl_logic_pins(log); for (int i = 1; i < npins; i++) { ivl_nexus_t input = ivl_logic_pin(log, i); - + gate->add_expr(readable_ref(scope, input)); } @@ -57,7 +57,7 @@ static vhdl_expr *input_to_expr(vhdl_scope *scope, vhdl_unaryop_t op, assert(input); vhdl_expr *operand = readable_ref(scope, input); - return new vhdl_unaryop_expr(op, operand, vhdl_type::std_logic()); + return new vhdl_unaryop_expr(op, operand, vhdl_type::std_logic()); } static void bufif_logic(vhdl_arch *arch, ivl_net_logic_t log, bool if0) @@ -65,7 +65,7 @@ static void bufif_logic(vhdl_arch *arch, ivl_net_logic_t log, bool if0) ivl_nexus_t output = ivl_logic_pin(log, 0); vhdl_var_ref *lhs = nexus_to_var_ref(arch->get_scope(), output); assert(lhs); - + vhdl_expr *val = readable_ref(arch->get_scope(), ivl_logic_pin(log, 1)); vhdl_expr *sel = readable_ref(arch->get_scope(), ivl_logic_pin(log, 2)); @@ -80,7 +80,7 @@ static void bufif_logic(vhdl_arch *arch, ivl_net_logic_t log, bool if0) vhdl_binop_t op = if0 ? VHDL_BINOP_EQ : VHDL_BINOP_NEQ; cmp = new vhdl_binop_expr(sel, op, zero, NULL); } - + ivl_signal_t sig = find_signal_named(lhs->get_name(), arch->get_scope()); char zbit; switch (ivl_signal_type(sig)) { @@ -107,12 +107,12 @@ static void bufif_logic(vhdl_arch *arch, ivl_net_logic_t log, bool if0) static void comb_udp_logic(vhdl_arch *arch, ivl_net_logic_t log) { ivl_udp_t udp = ivl_logic_udp(log); - + // As with regular case statements, the expression in a // `with .. select' statement must be "locally static". // This is achieved by first combining the inputs into // a temporary - + ostringstream ss; ss << ivl_logic_basename(log) << "_Tmp"; int msb = ivl_udp_nin(udp) - 1; @@ -149,11 +149,11 @@ static void comb_udp_logic(vhdl_arch *arch, ivl_net_logic_t log) // Ensure the select statement completely covers the input space // or some strict VHDL compilers will complain ws->add_default(new vhdl_const_bit('X')); - + int nrows = ivl_udp_rows(udp); for (int i = 0; i < nrows; i++) { const char *row = ivl_udp_row(udp, i); - + vhdl_expr *value = new vhdl_const_bit(row[nin]); vhdl_expr *cond = new vhdl_const_bits(row, nin, false); @@ -189,11 +189,11 @@ static void seq_udp_logic(vhdl_arch *arch, ivl_net_logic_t log) int msb = ivl_udp_nin(udp) - 1; vhdl_type *tmp_type = vhdl_type::std_logic_vector(msb, 0); proc->get_scope()->add_decl(new vhdl_var_decl("UDP_Inputs", tmp_type)); - + // Concatenate the inputs into a single expression that can be // used as the test in a case statement (this can't be inserted // directly into the case statement due to the requirement that - // the test expression be "locally static") + // the test expression be "locally static") int nin = ivl_udp_nin(udp); vhdl_expr *tmp_rhs = NULL; if (nin == 1) { @@ -217,7 +217,7 @@ static void seq_udp_logic(vhdl_arch *arch, ivl_net_logic_t log) proc->get_container()->add_stmt (new vhdl_assign_stmt(new vhdl_var_ref("UDP_Inputs", NULL), tmp_rhs)); - + arch->add_stmt(proc); } @@ -273,18 +273,18 @@ void draw_logic(vhdl_arch *arch, ivl_net_logic_t log) udp_logic(arch, log); break; default: - { + { // The output is always pin zero ivl_nexus_t output = ivl_logic_pin(log, 0); vhdl_var_ref *lhs = nexus_to_var_ref(arch->get_scope(), output); vhdl_expr *rhs = translate_logic_inputs(arch->get_scope(), log); vhdl_cassign_stmt *ass = new vhdl_cassign_stmt(lhs, rhs); - + ivl_expr_t delay = ivl_logic_delay(log, 1); if (delay) ass->set_after(translate_time_expr(delay)); - + arch->add_stmt(ass); } } diff --git a/tgt-vhdl/lpm.cc b/tgt-vhdl/lpm.cc index 67c09d569..c68d6bebe 100644 --- a/tgt-vhdl/lpm.cc +++ b/tgt-vhdl/lpm.cc @@ -47,7 +47,7 @@ static vhdl_expr *concat_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) vhdl_type::type_for(ivl_lpm_width(lpm), ivl_lpm_signed(lpm) != 0); vhdl_binop_expr *expr = new vhdl_binop_expr(VHDL_BINOP_CONCAT, result_type); - + for (int i = ivl_lpm_size(lpm) - 1; i >= 0; i--) { vhdl_expr *e = readable_ref(scope, ivl_lpm_data(lpm, i)); if (NULL == e) { @@ -67,7 +67,7 @@ static vhdl_expr *binop_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm, vhdl_binop vhdl_type *result_type = vhdl_type::type_for(out_width, ivl_lpm_signed(lpm) != 0); vhdl_binop_expr *expr = new vhdl_binop_expr(op, result_type); - + for (int i = 0; i < 2; i++) { vhdl_expr *e = readable_ref(scope, ivl_lpm_data(lpm, i)); if (NULL == e) { @@ -77,16 +77,16 @@ static vhdl_expr *binop_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm, vhdl_binop expr->add_expr(e->cast(result_type)); } - + if (op == VHDL_BINOP_MULT) { // Need to resize the output to the desired size, // as this does not happen automatically in VHDL - + vhdl_fcall *resize = new vhdl_fcall("Resize", vhdl_type::nsigned(out_width)); resize->add_expr(expr); resize->add_expr(new vhdl_const_int(out_width)); - + return resize; } else @@ -106,7 +106,7 @@ static vhdl_expr *rel_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm, vhdl_binop_t delete lhs; return NULL; } - + // Ensure LHS and RHS are the same type if (lhs->get_type() != rhs->get_type()) rhs = rhs->cast(lhs->get_type()); @@ -122,20 +122,20 @@ static vhdl_expr *part_select_vp_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) vhdl_var_ref *selfrom = readable_ref(scope, ivl_lpm_data(lpm, 0)); if (NULL == selfrom) return NULL; - + vhdl_expr *off = part_select_base(scope, lpm);; if (NULL == off) return NULL; if (selfrom->get_type()->get_width() > 1) selfrom->set_slice(off, ivl_lpm_width(lpm) - 1); - + return selfrom; } static vhdl_expr *part_select_pv_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) -{ +{ return readable_ref(scope, ivl_lpm_data(lpm, 0)); } @@ -171,13 +171,13 @@ static vhdl_expr *reduction_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm, require_support_function(f); vhdl_fcall *fcall = new vhdl_fcall(support_function::function_name(f), vhdl_type::std_logic()); - - vhdl_type std_logic_vector(VHDL_TYPE_STD_LOGIC_VECTOR); + + vhdl_type std_logic_vector(VHDL_TYPE_STD_LOGIC_VECTOR); fcall->add_expr(ref->cast(&std_logic_vector)); - + result = fcall; - } - + } + if (invert) return new vhdl_unaryop_expr (VHDL_UNARYOP_NOT, result, vhdl_type::std_logic()); @@ -199,12 +199,12 @@ static vhdl_expr *array_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) ivl_signal_t array = ivl_lpm_array(lpm); if (!seen_signal_before(array)) return NULL; - + const char *renamed = get_renamed_signal(array).c_str(); - + vhdl_decl *adecl = scope->get_decl(renamed); assert(adecl); - + vhdl_type *atype = new vhdl_type(*adecl->get_type()); vhdl_expr *select = readable_ref(scope, ivl_lpm_select(lpm)); @@ -212,11 +212,11 @@ static vhdl_expr *array_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) delete atype; return NULL; } - + vhdl_var_ref *ref = new vhdl_var_ref(renamed, atype); vhdl_type integer(VHDL_TYPE_INTEGER); ref->set_slice(select->cast(&integer)); - + return ref; } @@ -226,8 +226,8 @@ static vhdl_expr *shift_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm, vhdl_expr *lhs = readable_ref(scope, ivl_lpm_data(lpm, 0)); vhdl_expr *rhs = readable_ref(scope, ivl_lpm_data(lpm, 1)); if (!lhs || !rhs) - return NULL; - + return NULL; + // The RHS must be an integer vhdl_type integer(VHDL_TYPE_INTEGER); vhdl_expr *r_cast = rhs->cast(&integer); @@ -311,7 +311,7 @@ static int draw_mux_lpm(vhdl_arch *arch, ivl_lpm_t lpm) } vhdl_scope *scope = arch->get_scope(); - + vhdl_expr *s0 = readable_ref(scope, ivl_lpm_data(lpm, 0)); vhdl_expr *s1 = readable_ref(scope, ivl_lpm_data(lpm, 1)); @@ -319,7 +319,7 @@ static int draw_mux_lpm(vhdl_arch *arch, ivl_lpm_t lpm) vhdl_expr *b1 = new vhdl_const_bit('1'); vhdl_expr *t1 = new vhdl_binop_expr(sel, VHDL_BINOP_EQ, b1, vhdl_type::boolean()); - + vhdl_var_ref *out = nexus_to_var_ref(scope, ivl_lpm_q(lpm)); // Make sure s0 and s1 have the same type as the output @@ -337,11 +337,11 @@ int draw_lpm(vhdl_arch *arch, ivl_lpm_t lpm) { if (ivl_lpm_type(lpm) == IVL_LPM_MUX) return draw_mux_lpm(arch, lpm); - + vhdl_expr *f = lpm_to_expr(arch->get_scope(), lpm); if (NULL == f) return 1; - + vhdl_var_ref *out = nexus_to_var_ref(arch->get_scope(), ivl_lpm_q(lpm)); if (ivl_lpm_type(lpm) == IVL_LPM_PART_PV) { vhdl_expr *off = part_select_base(arch->get_scope(), lpm); @@ -357,16 +357,16 @@ int draw_lpm(vhdl_arch *arch, ivl_lpm_t lpm) bool bool_to_logic = out->get_type()->get_name() == VHDL_TYPE_STD_LOGIC && f->get_type()->get_name() == VHDL_TYPE_BOOLEAN; - + if (bool_to_logic) { vhdl_cassign_stmt* s = new vhdl_cassign_stmt(out, new vhdl_const_bit('0')); s->add_condition(new vhdl_const_bit('1'), f); arch->add_stmt(s); } - else + else arch->add_stmt(new vhdl_cassign_stmt(out, f->cast(out->get_type()))); - + return 0; } diff --git a/tgt-vhdl/process.cc b/tgt-vhdl/process.cc index 93e2fba8f..4660ea98b 100644 --- a/tgt-vhdl/process.cc +++ b/tgt-vhdl/process.cc @@ -33,7 +33,7 @@ static int generate_vhdl_process(vhdl_entity *ent, ivl_process_t proc) { set_active_entity(ent); - + // Create a new process and store it in the entity's // architecture. This needs to be done first or the // parent link won't be valid (and draw_stmt needs this @@ -45,7 +45,7 @@ static int generate_vhdl_process(vhdl_entity *ent, ivl_process_t proc) // into the declarations vhdl_proc->get_scope()->set_initializing (ivl_process_type(proc) == IVL_PR_INITIAL); - + ivl_statement_t stmt = ivl_process_stmt(proc); int rc = draw_stmt(vhdl_proc, vhdl_proc->get_container(), stmt); if (rc != 0) @@ -57,14 +57,17 @@ static int generate_vhdl_process(vhdl_entity *ent, ivl_process_t proc) // However, if no statements were added to the container // by draw_stmt, don't bother adding a wait as `emit' // will optimise the process out of the output - bool is_initial = ivl_process_type(proc) == IVL_PR_INITIAL; - bool is_empty = vhdl_proc->get_container()->empty(); - - if (is_initial && !is_empty) { - vhdl_wait_stmt *wait = new vhdl_wait_stmt(); - vhdl_proc->get_container()->add_stmt(wait); + if (ivl_process_type(proc) == IVL_PR_INITIAL) { + // Get rid of any useless `wait for 0 ns's at the end of the process + prune_wait_for_0(vhdl_proc->get_container()); + + // The above pruning might have removed all logic from the process + if (!vhdl_proc->get_container()->empty()) { + vhdl_wait_stmt *wait = new vhdl_wait_stmt(); + vhdl_proc->get_container()->add_stmt(wait); + } } - + // Add a comment indicating where it came from ivl_scope_t scope = ivl_process_scope(proc); const char *type = ivl_process_type(proc) == IVL_PR_INITIAL @@ -87,21 +90,21 @@ extern "C" int draw_process(ivl_process_t proc, void *cd) if (!is_default_scope_instance(scope)) return 0; // Ignore this process at it's not in a scope that // we're using to generate code - + debug_msg("Translating process in scope type %s (%s:%d)", ivl_scope_tname(scope), ivl_process_file(proc), ivl_process_lineno(proc)); - + // Skip over any generate and begin scopes until we find // the module that contains them - this is where we will // generate the process while (ivl_scope_type(scope) == IVL_SCT_GENERATE || ivl_scope_type(scope) == IVL_SCT_BEGIN) scope = ivl_scope_parent(scope); - + assert(ivl_scope_type(scope) == IVL_SCT_MODULE); vhdl_entity *ent = find_entity(scope); assert(ent != NULL); - + return generate_vhdl_process(ent, proc); } diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index c7caa9716..1cd47f91e 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -42,7 +42,7 @@ struct scope_nexus_t { string tmpname; // A new temporary signal list connect; // Other signals to wire together }; - + /* * This structure is stored in the private part of each nexus. * It stores a scope_nexus_t for each VHDL scope which is @@ -76,11 +76,11 @@ static scope_nexus_t *visible_nexus(nexus_private_t *priv, vhdl_scope *scope) */ static void link_scope_to_nexus_signal(nexus_private_t *priv, vhdl_scope *scope, ivl_signal_t sig, unsigned pin) -{ +{ scope_nexus_t *sn; if ((sn = visible_nexus(priv, scope))) { assert(sn->tmpname == ""); - + // Remember to connect this signal up later // If one of the signals is a input, make sure the input is not being driven if (ivl_signal_port(sn->sig) == IVL_SIP_INPUT) @@ -126,16 +126,16 @@ static ivl_signal_type_t signal_type_of_nexus(ivl_nexus_t nex, int &width) { ivl_signal_type_t out = IVL_SIT_TRI; width = 0; - + for (unsigned idx = 0; idx < ivl_nexus_ptrs(nex); idx += 1) { ivl_signal_type_t stype; ivl_nexus_ptr_t ptr = ivl_nexus_ptr(nex, idx); ivl_signal_t sig = ivl_nexus_ptr_sig(ptr); if (sig == 0) continue; - + width = ivl_signal_width(sig); - + stype = ivl_signal_type(sig); if (stype == IVL_SIT_TRI) continue; @@ -143,7 +143,7 @@ static ivl_signal_type_t signal_type_of_nexus(ivl_nexus_t nex, int &width) continue; out = stype; } - + return out; } @@ -151,11 +151,11 @@ static ivl_signal_type_t signal_type_of_nexus(ivl_nexus_t nex, int &width) * Generates VHDL code to fully represent a nexus. */ void draw_nexus(ivl_nexus_t nexus) -{ +{ nexus_private_t *priv = new nexus_private_t; int nexus_signal_width = -1; priv->const_driver = NULL; - + int nptrs = ivl_nexus_ptrs(nexus); // Number of drivers for this nexus @@ -164,9 +164,9 @@ void draw_nexus(ivl_nexus_t nexus) // First pass through connect all the signals up for (int i = 0; i < nptrs; i++) { ivl_nexus_ptr_t nexus_ptr = ivl_nexus_ptr(nexus, i); - + ivl_signal_t sig; - if ((sig = ivl_nexus_ptr_sig(nexus_ptr))) { + if ((sig = ivl_nexus_ptr_sig(nexus_ptr))) { vhdl_scope *scope = find_scope_for_signal(sig); if (scope) { unsigned pin = ivl_nexus_ptr_pin(nexus_ptr); @@ -181,7 +181,7 @@ void draw_nexus(ivl_nexus_t nexus) // inputs and outputs for (int i = 0; i < nptrs; i++) { ivl_nexus_ptr_t nexus_ptr = ivl_nexus_ptr(nexus, i); - + ivl_net_logic_t log; ivl_lpm_t lpm; ivl_net_const_t con; @@ -189,10 +189,10 @@ void draw_nexus(ivl_nexus_t nexus) ivl_scope_t log_scope = ivl_logic_scope(log); if (!is_default_scope_instance(log_scope)) continue; - + vhdl_entity *ent = find_entity(log_scope); assert(ent); - + vhdl_scope *vhdl_scope = ent->get_arch()->get_scope(); if (visible_nexus(priv, vhdl_scope)) { // Already seen this signal in vhdl_scope @@ -201,7 +201,7 @@ void draw_nexus(ivl_nexus_t nexus) // Create a temporary signal to connect it to the nexus vhdl_type *type = vhdl_type::type_for(ivl_logic_width(log), false); - + ostringstream ss; ss << "LO" << ivl_logic_basename(log); vhdl_scope->add_decl(new vhdl_signal_decl(ss.str().c_str(), type)); @@ -218,7 +218,7 @@ void draw_nexus(ivl_nexus_t nexus) ivl_scope_t lpm_scope = ivl_lpm_scope(lpm); vhdl_entity *ent = find_entity(lpm_scope); assert(ent); - + vhdl_scope *vhdl_scope = ent->get_arch()->get_scope(); if (visible_nexus(priv, vhdl_scope)) { // Already seen this signal in vhdl_scope @@ -235,7 +235,7 @@ void draw_nexus(ivl_nexus_t nexus) lpm_temp_width = nexus_signal_width; else lpm_temp_width = ivl_lpm_width(lpm); - + vhdl_type *type = vhdl_type::type_for(lpm_temp_width, ivl_lpm_signed(lpm) != 0); ostringstream ss; @@ -243,7 +243,7 @@ void draw_nexus(ivl_nexus_t nexus) if (!vhdl_scope->have_declared(ss.str())) vhdl_scope->add_decl(new vhdl_signal_decl(ss.str().c_str(), type)); - + link_scope_to_nexus_tmp(priv, vhdl_scope, ss.str()); } @@ -274,7 +274,7 @@ void draw_nexus(ivl_nexus_t nexus) if (ndrivers == 0) { char def = 0; int width; - + switch (signal_type_of_nexus(nexus, width)) { case IVL_SIT_TRI: case IVL_SIT_UWIRE: @@ -305,7 +305,7 @@ void draw_nexus(ivl_nexus_t nexus) priv->const_driver = new vhdl_const_bit(def); } } - + // Save the private data in the nexus ivl_nexus_set_private(nexus, priv); } @@ -316,10 +316,10 @@ void draw_nexus(ivl_nexus_t nexus) */ static void seen_nexus(ivl_nexus_t nexus) { - if (ivl_nexus_get_private(nexus) == NULL) + if (ivl_nexus_get_private(nexus) == NULL) draw_nexus(nexus); } - + /* * Translate a nexus to a variable reference. Given a nexus and a * scope, this function returns a reference to a signal that is @@ -332,18 +332,18 @@ static void seen_nexus(ivl_nexus_t nexus) vhdl_var_ref *nexus_to_var_ref(vhdl_scope *scope, ivl_nexus_t nexus) { seen_nexus(nexus); - + nexus_private_t *priv = static_cast(ivl_nexus_get_private(nexus)); unsigned pin; string renamed(visible_nexus_signal_name(priv, scope, &pin)); - + vhdl_decl *decl = scope->get_decl(renamed); assert(decl); vhdl_type *type = new vhdl_type(*(decl->get_type())); vhdl_var_ref *ref = new vhdl_var_ref(renamed.c_str(), type); - + if (decl->get_type()->get_name() == VHDL_TYPE_ARRAY) ref->set_slice(new vhdl_const_int(pin), 0); @@ -355,7 +355,7 @@ vhdl_var_ref *nexus_to_var_ref(vhdl_scope *scope, ivl_nexus_t nexus) vhdl_var_ref* readable_ref(vhdl_scope* scope, ivl_nexus_t nex) { vhdl_var_ref* ref = nexus_to_var_ref(scope, nex); - + vhdl_decl* decl = scope->get_decl(ref->get_name()); decl->ensure_readable(); @@ -369,10 +369,10 @@ vhdl_var_ref* readable_ref(vhdl_scope* scope, ivl_nexus_t nex) static void declare_logic(vhdl_arch *arch, ivl_scope_t scope) { debug_msg("Declaring logic in scope type %s", ivl_scope_tname(scope)); - + int nlogs = ivl_scope_logs(scope); for (int i = 0; i < nlogs; i++) - draw_logic(arch, ivl_scope_log(scope, i)); + draw_logic(arch, ivl_scope_log(scope, i)); } // Replace consecutive underscores with a single underscore @@ -422,7 +422,7 @@ static string valid_entity_name(const string& module_name) name = "module" + name; if (*name.rbegin() == '_') name += "module"; - + if (is_vhdl_reserved_word(name)) name += "_module"; @@ -434,7 +434,7 @@ static string valid_entity_name(const string& module_name) ss.str(""); ss << name << i++; } - + return ss.str(); } @@ -445,7 +445,7 @@ string make_safe_name(ivl_signal_t sig) if (ivl_signal_local(sig)) base = "tmp" + base; - + if (base[0] == '_') base = "sig" + base; @@ -454,14 +454,14 @@ string make_safe_name(ivl_signal_t sig) // Can't have two consecutive underscores replace_consecutive_underscores(base); - + // A signal name may not be the same as a component name if (find_entity(base) != NULL) base += "_sig"; if (is_vhdl_reserved_word(base)) base += "_sig"; - + return base; } @@ -478,7 +478,7 @@ static void avoid_name_collision(string& name, vhdl_scope* scope) ss.str(""); ss << name << i++; } while (scope->name_collides(ss.str())); - + name = ss.str(); } } @@ -495,24 +495,24 @@ static string genvar_unique_suffix(ivl_scope_t scope) for (unsigned i = 0; i < ivl_scope_params(scope); i++) { ivl_parameter_t param = ivl_scope_param(scope, i); ivl_expr_t e = ivl_parameter_expr(param); - + if (ivl_expr_type(e) == IVL_EX_NUMBER) { vhdl_expr* value = translate_expr(e); assert(value); - + value = value->cast(vhdl_type::integer()); - + suffix << "_" << ivl_parameter_basename(param); value->emit(suffix, 0); - + delete value; } else { error("Only numeric genvars supported at the moment"); return "_ERROR"; // Never used - } + } } - + scope = ivl_scope_parent(scope); } @@ -528,33 +528,33 @@ static void declare_one_signal(vhdl_entity *ent, ivl_signal_t sig, string name(make_safe_name(sig)); name += genvar_unique_suffix(scope); avoid_name_collision(name, ent->get_arch()->get_scope()); - + rename_signal(sig, name); - + vhdl_type *sig_type; unsigned dimensions = ivl_signal_dimensions(sig); if (dimensions > 0) { // Arrays are implemented by generating a separate type // declaration for each array, and then declaring a // signal of that type - + if (dimensions > 1) { error("> 1 dimension arrays not implemented yet"); return; } - + string type_name = name + "_Type"; vhdl_type *base_type = vhdl_type::type_for(ivl_signal_width(sig), ivl_signal_signed(sig) != 0); - + int lsb = ivl_signal_array_base(sig); int msb = lsb + ivl_signal_array_count(sig) - 1; - + vhdl_type *array_type = vhdl_type::array_of(base_type, type_name, msb, lsb); vhdl_decl *array_decl = new vhdl_type_decl(type_name.c_str(), array_type); ent->get_arch()->get_scope()->add_decl(array_decl); - + sig_type = new vhdl_type(*array_type); } else { @@ -562,15 +562,15 @@ static void declare_one_signal(vhdl_entity *ent, ivl_signal_t sig, ivl_signal_signed(sig) != 0, 0, ivl_signal_type(sig) == IVL_SIT_UWIRE); - + } - + ivl_signal_port_t mode = ivl_signal_port(sig); switch (mode) { case IVL_SIP_NONE: { vhdl_decl *decl = new vhdl_signal_decl(name.c_str(), sig_type); - + ostringstream ss; if (ivl_signal_local(sig)) { ss << "Temporary created at " << ivl_signal_file(sig) << ":" @@ -580,7 +580,7 @@ static void declare_one_signal(vhdl_entity *ent, ivl_signal_t sig, << ivl_signal_lineno(sig); } decl->set_comment(ss.str().c_str()); - + ent->get_arch()->get_scope()->add_decl(decl); } break; @@ -591,10 +591,10 @@ static void declare_one_signal(vhdl_entity *ent, ivl_signal_t sig, case IVL_SIP_OUTPUT: { vhdl_port_decl *decl = - new vhdl_port_decl(name.c_str(), sig_type, VHDL_PORT_OUT); + new vhdl_port_decl(name.c_str(), sig_type, VHDL_PORT_OUT); ent->get_scope()->add_decl(decl); } - + if (ivl_signal_type(sig) == IVL_SIT_REG) { // A registered output // In Verilog the output and reg can have the @@ -604,11 +604,11 @@ static void declare_one_signal(vhdl_entity *ent, ivl_signal_t sig, std::string newname(name); newname += "_Reg"; rename_signal(sig, newname.c_str()); - + vhdl_type *reg_type = new vhdl_type(*sig_type); ent->get_arch()->get_scope()->add_decl (new vhdl_signal_decl(newname.c_str(), reg_type)); - + // Create a concurrent assignment statement to // connect the register to the output ent->get_arch()->add_stmt @@ -633,17 +633,17 @@ static void declare_one_signal(vhdl_entity *ent, ivl_signal_t sig, static void declare_signals(vhdl_entity *ent, ivl_scope_t scope) { debug_msg("Declaring signals in scope type %s", ivl_scope_tname(scope)); - + int nsigs = ivl_scope_sigs(scope); for (int i = 0; i < nsigs; i++) { - ivl_signal_t sig = ivl_scope_sig(scope, i); + ivl_signal_t sig = ivl_scope_sig(scope, i); if (ivl_signal_port(sig) != IVL_SIP_NONE) declare_one_signal(ent, sig, scope); } - + for (int i = 0; i < nsigs; i++) { - ivl_signal_t sig = ivl_scope_sig(scope, i); + ivl_signal_t sig = ivl_scope_sig(scope, i); if (ivl_signal_port(sig) == IVL_SIP_NONE) declare_one_signal(ent, sig, scope); @@ -669,7 +669,7 @@ static void declare_lpm(vhdl_arch *arch, ivl_scope_t scope) */ static void map_signal(ivl_signal_t to, vhdl_entity *parent, vhdl_comp_inst *inst) -{ +{ // TODO: Work for multiple words ivl_nexus_t nexus = ivl_signal_nex(to, 0); seen_nexus(nexus); @@ -699,14 +699,14 @@ static void map_signal(ivl_signal_t to, vhdl_entity *parent, && !arch_scope->have_declared(name + "_Readable")) { vhdl_decl* tmp_decl = new vhdl_signal_decl(name + "_Readable", ref->get_type()); - + // Add a comment to explain what this is for tmp_decl->set_comment("Needed to connect outputs"); - + arch_scope->add_decl(tmp_decl); parent->get_arch()->add_stmt (new vhdl_cassign_stmt(from_decl->make_ref(), tmp_decl->make_ref())); - + map_to = tmp_decl->make_ref(); } else @@ -719,7 +719,7 @@ static void map_signal(ivl_signal_t to, vhdl_entity *parent, else { // This nexus isn't attached to anything in the parent return; - } + } inst->map_port(name, map_to); } @@ -734,7 +734,7 @@ static void port_map(ivl_scope_t scope, vhdl_entity *parent, int nsigs = ivl_scope_sigs(scope); for (int i = 0; i < nsigs; i++) { ivl_signal_t sig = ivl_scope_sig(scope, i); - + ivl_signal_port_t mode = ivl_signal_port(sig); switch (mode) { case IVL_SIP_NONE: @@ -744,10 +744,10 @@ static void port_map(ivl_scope_t scope, vhdl_entity *parent, case IVL_SIP_OUTPUT: case IVL_SIP_INOUT: map_signal(sig, parent, inst); - break; + break; default: assert(false); - } + } } } @@ -788,9 +788,9 @@ static int draw_function(ivl_scope_t scope, ivl_scope_t parent) vhdl_type *sigtype = vhdl_type::type_for(ivl_signal_width(sig), ivl_signal_signed(sig) != 0); - + string signame(make_safe_name(sig)); - + switch (ivl_signal_port(sig)) { case IVL_SIP_INPUT: func->add_param(new vhdl_param_decl(signame.c_str(), sigtype)); @@ -807,30 +807,30 @@ static int draw_function(ivl_scope_t scope, ivl_scope_t parent) // Only expecting inputs and outputs assert(false); } - + remember_signal(sig, func->get_scope()); rename_signal(sig, signame); } - + int nsigs = ivl_scope_sigs(scope); for (int i = 0; i < nsigs; i++) { - ivl_signal_t sig = ivl_scope_sig(scope, i); + ivl_signal_t sig = ivl_scope_sig(scope, i); if (ivl_signal_port(sig) == IVL_SIP_NONE) { vhdl_type *sigtype = vhdl_type::type_for( ivl_signal_width(sig), ivl_signal_signed(sig) != 0); - + string signame(make_safe_name(sig)); func->get_scope()->add_decl( new vhdl_var_decl(signame, sigtype)); - + remember_signal(sig, func->get_scope()); rename_signal(sig, signame); } } - + // Non-blocking assignment not allowed in functions func->get_scope()->set_allow_signal_assignment(false); @@ -849,8 +849,8 @@ static int draw_function(ivl_scope_t scope, ivl_scope_t parent) ss << "Generated from function " << funcname << " at " << ivl_scope_def_file(scope) << ":" << ivl_scope_def_lineno(scope); func->set_comment(ss.str().c_str()); - - ent->get_arch()->get_scope()->add_decl(func); + + ent->get_arch()->get_scope()->add_decl(func); return 0; } @@ -867,14 +867,14 @@ static int draw_task(ivl_scope_t scope, ivl_scope_t parent) assert(ent); const char *taskname = ivl_scope_tname(scope); - + int nsigs = ivl_scope_sigs(scope); for (int i = 0; i < nsigs; i++) { - ivl_signal_t sig = ivl_scope_sig(scope, i); + ivl_signal_t sig = ivl_scope_sig(scope, i); vhdl_type *sigtype = vhdl_type::type_for(ivl_signal_width(sig), ivl_signal_signed(sig) != 0); - + string signame(make_safe_name(sig)); // Check this signal isn't declared in the outer scope @@ -889,13 +889,13 @@ static int draw_task(ivl_scope_t scope, ivl_scope_t parent) ss << "Declared at " << ivl_signal_file(sig) << ":" << ivl_signal_lineno(sig) << " (in task " << taskname << ")"; decl->set_comment(ss.str().c_str()); - - ent->get_arch()->get_scope()->add_decl(decl); - + + ent->get_arch()->get_scope()->add_decl(decl); + remember_signal(sig, ent->get_arch()->get_scope()); rename_signal(sig, signame); } - + return 0; } @@ -908,7 +908,7 @@ static void create_skeleton_entity_for(ivl_scope_t scope, int depth) // The type name will become the entity name const string tname = valid_entity_name(ivl_scope_tname(scope)); - + // Verilog does not have the entity/architecture distinction // so we always create a pair and associate the architecture // with the entity for convenience (this also means that we @@ -926,29 +926,9 @@ static void create_skeleton_entity_for(ivl_scope_t scope, int depth) << " (" << ivl_scope_def_file(scope) << ":" << ivl_scope_def_lineno(scope) << ")"; - unsigned nparams = ivl_scope_params(scope); - for (unsigned i = 0; i < nparams; i++) { - ivl_parameter_t param = ivl_scope_param(scope, i); - ss << "\n " << ivl_parameter_basename(param) << " = "; - - ivl_expr_t value = ivl_parameter_expr(param); - switch (ivl_expr_type(value)) { - case IVL_EX_STRING: - ss << "\"" << ivl_expr_string(value) << "\""; - break; - - case IVL_EX_NUMBER: - ss << ivl_expr_uvalue(value); - break; - - default: - assert(false); - } - } - arch->set_comment(ss.str()); ent->set_comment(ss.str()); - + remember_entity(ent, scope); } @@ -962,10 +942,10 @@ extern "C" int draw_skeleton_scope(ivl_scope_t scope, void *_unused) if (seen_this_scope_type(scope)) return 0; // Already generated a skeleton for this scope type - + debug_msg("Initial visit to scope type %s at depth %d", ivl_scope_tname(scope), depth); - + switch (ivl_scope_type(scope)) { case IVL_SCT_MODULE: create_skeleton_entity_for(scope, depth); @@ -988,7 +968,7 @@ extern "C" int draw_all_signals(ivl_scope_t scope, void *_parent) { if (!is_default_scope_instance(scope)) return 0; // Not interested in this instance - + if (ivl_scope_type(scope) == IVL_SCT_MODULE) { vhdl_entity *ent = find_entity(scope); assert(ent); @@ -1003,7 +983,7 @@ extern "C" int draw_all_signals(ivl_scope_t scope, void *_parent) ivl_scope_t parent = ivl_scope_parent(scope); while (ivl_scope_type(parent) == IVL_SCT_GENERATE) parent = ivl_scope_parent(scope); - + vhdl_entity* ent = find_entity(parent); assert(ent); @@ -1020,7 +1000,7 @@ extern "C" int draw_functions(ivl_scope_t scope, void *_parent) { if (!is_default_scope_instance(scope)) return 0; // Not interested in this instance - + ivl_scope_t parent = static_cast(_parent); if (ivl_scope_type(scope) == IVL_SCT_FUNCTION) { if (draw_function(scope, parent) != 0) @@ -1044,9 +1024,9 @@ extern "C" int draw_constant_drivers(ivl_scope_t scope, void *_parent) { if (!is_default_scope_instance(scope)) return 0; // Not interested in this instance - + ivl_scope_children(scope, draw_constant_drivers, scope); - + if (ivl_scope_type(scope) == IVL_SCT_MODULE) { vhdl_entity *ent = find_entity(scope); assert(ent); @@ -1054,7 +1034,7 @@ extern "C" int draw_constant_drivers(ivl_scope_t scope, void *_parent) int nsigs = ivl_scope_sigs(scope); for (int i = 0; i < nsigs; i++) { ivl_signal_t sig = ivl_scope_sig(scope, i); - + for (unsigned j = ivl_signal_array_base(sig); j < ivl_signal_array_count(sig); j++) { @@ -1062,7 +1042,7 @@ extern "C" int draw_constant_drivers(ivl_scope_t scope, void *_parent) ivl_nexus_t nex = ivl_signal_nex(sig, j); if (!nex) continue; // skip virtual pins seen_nexus(nex); - + nexus_private_t *priv = static_cast(ivl_nexus_get_private(nex)); assert(priv); @@ -1072,9 +1052,9 @@ extern "C" int draw_constant_drivers(ivl_scope_t scope, void *_parent) if (priv->const_driver && ivl_signal_port(sig) != IVL_SIP_INPUT) { // Don't drive inputs assert(j == 0); // TODO: Make work for more words - + vhdl_var_ref *ref = nexus_to_var_ref(arch_scope, nex); - + ent->get_arch()->add_stmt (new vhdl_cassign_stmt(ref, priv->const_driver)); priv->const_driver = NULL; @@ -1085,7 +1065,7 @@ extern "C" int draw_constant_drivers(ivl_scope_t scope, void *_parent) scope_nexus_t *sn = visible_nexus(priv, arch_scope); // Make sure we don't drive inputs - if (ivl_signal_port(sn->sig) != IVL_SIP_INPUT) { + if (ivl_signal_port(sn->sig) != IVL_SIP_INPUT) { for (list::const_iterator it = sn->connect.begin(); it != sn->connect.end(); ++it) { @@ -1095,20 +1075,20 @@ extern "C" int draw_constant_drivers(ivl_scope_t scope, void *_parent) vhdl_type* ltype = vhdl_type::type_for(ivl_signal_width(*it), ivl_signal_signed(*it)); - + vhdl_var_ref *rref = new vhdl_var_ref(get_renamed_signal(sn->sig).c_str(), rtype); vhdl_var_ref *lref = new vhdl_var_ref(get_renamed_signal(*it).c_str(), ltype); - + // Make sure the LHS and RHS have the same type vhdl_expr* rhs = rref->cast(lref->get_type()); - + ent->get_arch()->add_stmt(new vhdl_cassign_stmt(lref, rhs)); } } - sn->connect.clear(); - } + sn->connect.clear(); + } } } @@ -1119,7 +1099,7 @@ extern "C" int draw_all_logic_and_lpm(ivl_scope_t scope, void *_parent) { if (!is_default_scope_instance(scope)) return 0; // Not interested in this instance - + if (ivl_scope_type(scope) == IVL_SCT_MODULE) { vhdl_entity *ent = find_entity(scope); assert(ent); @@ -1130,40 +1110,40 @@ extern "C" int draw_all_logic_and_lpm(ivl_scope_t scope, void *_parent) declare_lpm(ent->get_arch(), scope); } set_active_entity(NULL); - } + } return ivl_scope_children(scope, draw_all_logic_and_lpm, scope); } extern "C" int draw_hierarchy(ivl_scope_t scope, void *_parent) -{ +{ if (ivl_scope_type(scope) == IVL_SCT_MODULE && _parent) { ivl_scope_t parent = static_cast(_parent); // Skip over any containing generate scopes while (ivl_scope_type(parent) == IVL_SCT_GENERATE) parent = ivl_scope_parent(parent); - + if (!is_default_scope_instance(parent)) return 0; // Not generating code for the parent instance so // don't generate for the child - + vhdl_entity *ent = find_entity(scope); assert(ent); - + vhdl_entity *parent_ent = find_entity(parent); assert(parent_ent); vhdl_arch *parent_arch = parent_ent->get_arch(); assert(parent_arch != NULL); - + // Create a forward declaration for it vhdl_scope *parent_scope = parent_arch->get_scope(); if (!parent_scope->have_declared(ent->get_name())) { vhdl_decl *comp_decl = vhdl_component_decl::component_decl_for(ent); parent_arch->get_scope()->add_decl(comp_decl); } - + // And an instantiation statement string inst_name(ivl_scope_basename(scope)); inst_name += genvar_unique_suffix(ivl_scope_parent(scope)); @@ -1174,13 +1154,13 @@ extern "C" int draw_hierarchy(ivl_scope_t scope, void *_parent) // Would produce an invalid instance name inst_name += "_inst"; } - + // Need to replace any [ and ] characters that result // from generate statements string::size_type loc = inst_name.find('[', 0); if (loc != string::npos) inst_name.erase(loc, 1); - + loc = inst_name.find(']', 0); if (loc != string::npos) inst_name.erase(loc, 1); @@ -1197,7 +1177,7 @@ extern "C" int draw_hierarchy(ivl_scope_t scope, void *_parent) // Make sure the name doesn't collide with anything we've // already declared avoid_name_collision(inst_name, parent_arch->get_scope()); - + vhdl_comp_inst *inst = new vhdl_comp_inst(inst_name.c_str(), ent->get_name().c_str()); port_map(scope, parent_ent, inst); @@ -1206,15 +1186,15 @@ extern "C" int draw_hierarchy(ivl_scope_t scope, void *_parent) ss << "Generated from instantiation at " << ivl_scope_file(scope) << ":" << ivl_scope_lineno(scope); inst->set_comment(ss.str().c_str()); - + parent_arch->add_stmt(inst); - } + } return ivl_scope_children(scope, draw_hierarchy, scope); } int draw_scope(ivl_scope_t scope, void *_parent) -{ +{ int rc = draw_skeleton_scope(scope, _parent); if (rc != 0) return rc; @@ -1225,7 +1205,7 @@ int draw_scope(ivl_scope_t scope, void *_parent) rc = draw_all_logic_and_lpm(scope, _parent); if (rc != 0) - return rc; + return rc; rc = draw_hierarchy(scope, _parent); if (rc != 0) @@ -1238,7 +1218,7 @@ int draw_scope(ivl_scope_t scope, void *_parent) rc = draw_constant_drivers(scope, _parent); if (rc != 0) return rc; - + return 0; } diff --git a/tgt-vhdl/state.cc b/tgt-vhdl/state.cc index e03c201e1..8de2f33d0 100644 --- a/tgt-vhdl/state.cc +++ b/tgt-vhdl/state.cc @@ -25,9 +25,8 @@ #include #include #include -#include +#include #include -#include using namespace std; @@ -54,7 +53,7 @@ using namespace std; * provides a mechanism for renaming signals -- i.e. when * an output has the same name as register: valid in Verilog * but not in VHDL, so two separate signals need to be - * defined. + * defined. */ struct signal_defn_t { std::string renamed; // The name of the VHDL signal @@ -65,10 +64,10 @@ struct signal_defn_t { // These are stored in a list rather than a set so the first // entity added will correspond to the first (top) Verilog module // encountered and hence it will appear first in the output file. -static entity_list_t g_entities; +static entity_list_t g_entities; // Store the mapping of ivl scope names to entity names -typedef map scope_name_map_t; +typedef map scope_name_map_t; static scope_name_map_t g_scope_names; typedef std::map signal_defn_map_t; @@ -78,9 +77,10 @@ static vhdl_entity *g_active_entity = NULL; // Set of scopes that are treated as the default examples of // that type. Any other scopes of the same type are ignored. -typedef vector default_scopes_t; +typedef set default_scopes_t; static default_scopes_t g_default_scopes; + // True if signal `sig' has already been encountered by the code // generator. This means we have already assigned it to a VHDL code // object and possibly renamed it. @@ -145,7 +145,7 @@ ivl_signal_t find_signal_named(const std::string &name, const vhdl_scope *scope) // Compare the name of an entity against a string struct cmp_ent_name { cmp_ent_name(const string& n) : name_(n) {} - + bool operator()(const vhdl_entity* ent) const { return ent->get_name() == name_; @@ -156,7 +156,7 @@ struct cmp_ent_name { // Find an entity given its name. vhdl_entity* find_entity(const string& name) -{ +{ entity_list_t::const_iterator it = find_if(g_entities.begin(), g_entities.end(), cmp_ent_name(name)); @@ -176,34 +176,21 @@ vhdl_entity* find_entity(ivl_scope_t scope) // Skip over generate scopes while (ivl_scope_type(scope) == IVL_SCT_GENERATE) scope = ivl_scope_parent(scope); - + assert(ivl_scope_type(scope) == IVL_SCT_MODULE); - if (is_default_scope_instance(scope)) { - scope_name_map_t::iterator it = g_scope_names.find(scope); - if (it != g_scope_names.end()) - return find_entity((*it).second); - else - return NULL; - } - else { - const char *tname = ivl_scope_tname(scope); - - for (scope_name_map_t::iterator it = g_scope_names.begin(); - it != g_scope_names.end(); ++it) { - if (strcmp(tname, ivl_scope_tname((*it).first)) == 0) - return find_entity((*it).second); - } - + scope_name_map_t::iterator it = g_scope_names.find(ivl_scope_tname(scope)); + if (it != g_scope_names.end()) + return find_entity((*it).second); + else return NULL; - } } // Add an entity/architecture pair to the list of entities to emit. void remember_entity(vhdl_entity* ent, ivl_scope_t scope) { g_entities.push_back(ent); - g_scope_names[scope] = ent->get_name(); + g_scope_names[ivl_scope_tname(scope)] = ent->get_name(); } // Print all VHDL entities, in order, to the specified output stream. @@ -226,7 +213,7 @@ void free_all_vhdl_objects() size_t total = vhdl_element::total_allocated(); debug_msg("%d total bytes used for VHDL syntax objects", total); - + g_entities.clear(); } @@ -241,52 +228,12 @@ void set_active_entity(vhdl_entity *ent) { g_active_entity = ent; } - /* * True if two scopes have the same type name. */ static bool same_scope_type_name(ivl_scope_t a, ivl_scope_t b) { - if (strcmp(ivl_scope_tname(a), ivl_scope_tname(b)) != 0) - return false; - - unsigned nparams_a = ivl_scope_params(a); - unsigned nparams_b = ivl_scope_params(b); - - if (nparams_a != nparams_b) - return false; - - for (unsigned i = 0; i < nparams_a; i++) { - ivl_parameter_t param_a = ivl_scope_param(a, i); - ivl_parameter_t param_b = ivl_scope_param(b, i); - - if (strcmp(ivl_parameter_basename(param_a), - ivl_parameter_basename(param_b)) != 0) - return false; - - ivl_expr_t value_a = ivl_parameter_expr(param_a); - ivl_expr_t value_b = ivl_parameter_expr(param_b); - - if (ivl_expr_type(value_a) != ivl_expr_type(value_b)) - return false; - - switch (ivl_expr_type(value_a)) { - case IVL_EX_STRING: - if (strcmp(ivl_expr_string(value_a), ivl_expr_string(value_b)) != 0) - return false; - break; - - case IVL_EX_NUMBER: - if (ivl_expr_uvalue(value_a) != ivl_expr_uvalue(value_b)) - return false; - break; - - default: - assert(false); - } - } - - return true; + return strcmp(ivl_scope_tname(a), ivl_scope_tname(b)) == 0; } /* @@ -299,7 +246,7 @@ bool seen_this_scope_type(ivl_scope_t s) if (find_if(g_default_scopes.begin(), g_default_scopes.end(), bind1st(ptr_fun(same_scope_type_name), s)) == g_default_scopes.end()) { - g_default_scopes.push_back(s); + g_default_scopes.insert(s); return false; } else diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 1fcc44fae..7d217eb09 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -1,7 +1,7 @@ /* * VHDL code generation for statements. * - * Copyright (C) 2008-2010 Nick Gasson (nick@nickg.me.uk) + * Copyright (C) 2008-2009 Nick Gasson (nick@nickg.me.uk) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,9 +30,6 @@ #include #include -static void emit_wait_for_0(vhdl_procedural *proc, stmt_container *container, - ivl_statement_t stmt, vhdl_expr *expr); - /* * VHDL has no real equivalent of Verilog's $finish task. The * current solution is to use `assert false ...' to terminate @@ -43,7 +40,7 @@ static void emit_wait_for_0(vhdl_procedural *proc, stmt_container *container, * An alternative is to use the VHPI interface supported by * some VHDL simulators and implement the $finish functionality * in C. This function can be enabled with the flag - * -puse-vhpi-finish=1. + * -puse-vhpi-finish=1. */ static int draw_stask_finish(vhdl_procedural *proc, stmt_container *container, ivl_statement_t stmt) @@ -54,111 +51,9 @@ static int draw_stask_finish(vhdl_procedural *proc, stmt_container *container, container->add_stmt(new vhdl_pcall_stmt("work.Verilog_Support.Finish")); } else { - container->add_stmt( - new vhdl_report_stmt(new vhdl_const_string("SIMULATION FINISHED"), - SEVERITY_FAILURE)); - } - - return 0; -} - -static char parse_octal(const char *p) -{ - assert(*p && *(p+1) && *(p+2)); - assert(isdigit(*p) && isdigit(*(p+1)) && isdigit(*(p+1))); - - return (*p - '0') * 64 - + (*(p+1) - '0') * 8 - + (*(p+2) - '0') * 1; -} - -// Generate VHDL report statements for Verilog $display/$write -static int draw_stask_display(vhdl_procedural *proc, - stmt_container *container, - ivl_statement_t stmt) -{ - vhdl_binop_expr *text = new vhdl_binop_expr(VHDL_BINOP_CONCAT, - vhdl_type::string()); - - const int count = ivl_stmt_parm_count(stmt); - int i = 0; - while (i < count) { - // $display may have an empty parameter, in which case - // the expression will be null - // The behaviour here seems to be to output a space - ivl_expr_t net = ivl_stmt_parm(stmt, i++); - if (net == NULL) { - text->add_expr(new vhdl_const_string(" ")); - continue; - } - - if (ivl_expr_type(net) == IVL_EX_STRING) { - ostringstream ss; - for (const char *p = ivl_expr_string(net); *p; p++) { - if (*p == '\\') { - // Octal escape - char ch = parse_octal(p+1); - if (ch == '\n') { - // Is there a better way of handling newlines? - // Maybe generate another report statement - } - else - ss << ch; - p += 3; - } - else if (*p == '%' && *(++p) != '%') { - // Flush the output string up to this point - text->add_expr(new vhdl_const_string(ss.str())); - ss.str(""); - - // Skip over width for now - while (isdigit(*p)) ++p; - - switch (*p) { - case 'm': - // TOOD: we can get the module name via attributes - cerr << "Warning: no VHDL translation for %m format code" - << endl; - break; - default: - { - assert(i < count); - ivl_expr_t netp = ivl_stmt_parm(stmt, i++); - assert(netp); - - vhdl_expr *base = translate_expr(netp); - if (NULL == base) - return 1; - - emit_wait_for_0(proc, container, stmt, base); - - text->add_expr(base->cast(text->get_type())); - } - } - } - else - ss << *p; - } - - // Emit any non-empty string data left in the buffer - if (!ss.str().empty()) - text->add_expr(new vhdl_const_string(ss.str())); - } - else { - vhdl_expr *base = translate_expr(net); - if (NULL == base) - return 1; - - emit_wait_for_0(proc, container, stmt, base); - - text->add_expr(base->cast(text->get_type())); - } + container->add_stmt(new vhdl_assert_stmt("SIMULATION FINISHED")); } - if (count == 0) - text->add_expr(new vhdl_const_string("")); - - container->add_stmt(new vhdl_report_stmt(text)); return 0; } @@ -172,9 +67,9 @@ static int draw_stask(vhdl_procedural *proc, stmt_container *container, const char *name = ivl_stmt_name(stmt); if (strcmp(name, "$display") == 0) - return draw_stask_display(proc, container, stmt); + return draw_stask_display(proc, container, stmt, true); else if (strcmp(name, "$write") == 0) - return draw_stask_display(proc, container, stmt); + return draw_stask_display(proc, container, stmt, false); else if (strcmp(name, "$finish") == 0) return draw_stask_finish(proc, container, stmt); else { @@ -198,7 +93,7 @@ static int draw_stask(vhdl_procedural *proc, stmt_container *container, * * If this block has its own scope with local variables then these * are added to the process as local variables and the statements - * are generated as above. + * are generated as above. */ static int draw_block(vhdl_procedural *proc, stmt_container *container, ivl_statement_t stmt, bool is_last) @@ -216,7 +111,7 @@ static int draw_block(vhdl_procedural *proc, stmt_container *container, (new vhdl_var_decl(make_safe_name(sig), type)); } } - + int count = ivl_stmt_block_count(stmt); for (int i = 0; i < count; i++) { ivl_statement_t stmt_i = ivl_stmt_block_stmt(stmt, i); @@ -236,6 +131,27 @@ static int draw_noop(vhdl_procedural *proc, stmt_container *container, return 0; } +/* + * The VHDL code generator inserts `wait for 0 ns' after each + * not-last-in-block blocking assignment. + * If this is immediately followed by another `wait for ...' then + * we might as well not emit the first zero-time wait. + */ +void prune_wait_for_0(stmt_container *container) +{ + vhdl_wait_stmt *wait0; + stmt_container::stmt_list_t &stmts = container->get_stmts(); + while (stmts.size() > 0 + && (wait0 = dynamic_cast(stmts.back()))) { + if (wait0->get_type() == VHDL_WAIT_FOR0) { + delete wait0; + stmts.pop_back(); + } + else + break; + } +} + static vhdl_var_ref *make_assign_lhs(ivl_lval_t lval, vhdl_scope *scope) { ivl_signal_t sig = ivl_lval_sig(lval); @@ -251,13 +167,13 @@ static vhdl_var_ref *make_assign_lhs(ivl_lval_t lval, vhdl_scope *scope) if (e_off) { if ((base = translate_expr(e_off)) == NULL) return NULL; - + vhdl_type integer(VHDL_TYPE_INTEGER); base = base->cast(&integer); } - + unsigned lval_width = ivl_lval_width(lval); - + string signame(get_renamed_signal(sig)); vhdl_decl *decl = scope->get_decl(signame); assert(decl); @@ -281,7 +197,7 @@ static vhdl_var_ref *make_assign_lhs(ivl_lval_t lval, vhdl_scope *scope) // ...and use this new variable as the assignment LHS decl = shadow_decl; } - + vhdl_type *ltype = new vhdl_type(*decl->get_type()); vhdl_var_ref *lval_ref = new vhdl_var_ref(decl->get_name(), ltype); if (base) { @@ -305,7 +221,7 @@ static bool assignment_lvals(ivl_statement_t stmt, vhdl_procedural *proc, return false; lvals.push_back(lhs); - } + } return true; } @@ -323,7 +239,7 @@ assign_for(vhdl_decl::assign_type_t atype, vhdl_var_ref *lhs, vhdl_expr *rhs) return new vhdl_assign_stmt(lhs, rhs); case vhdl_decl::ASSIGN_NONBLOCK: return new vhdl_nbassign_stmt(lhs, rhs); - } + } assert(false); return NULL; } @@ -347,68 +263,12 @@ bool check_valid_assignment(vhdl_decl::assign_type_t atype, vhdl_procedural *pro return true; } -// Generate a "wait for 0 ns" statement to emulate the behaviour of -// Verilog blocking assignment using VHDL signals. This is only generated -// if we read from the target of a blocking assignment in the same -// process (i.e. it is only generated when required, not for every -// blocking assignment). An example: -// -// begin -// x = 5; -// if (x == 2) -// y = 7; -// end -// -// Becomes: -// -// x <= 5; -// wait for 0 ns; -- Required to implement assignment semantics -// if x = 2 then -// y <= 7; -- No need for wait here, not read -// end if; -// -static void emit_wait_for_0(vhdl_procedural *proc, - stmt_container *container, - ivl_statement_t stmt, - vhdl_expr *expr) -{ - vhdl_var_set_t read; - expr->find_vars(read); - - bool need_wait_for_0 = false; - for (vhdl_var_set_t::const_iterator it = read.begin(); - it != read.end(); ++it) { - if (proc->is_blocking_target(*it)) - need_wait_for_0 = true; - } - - stmt_container::stmt_list_t &stmts = container->get_stmts(); - bool last_was_wait = - !stmts.empty() && dynamic_cast(stmts.back()); - - if (need_wait_for_0 && !last_was_wait) { - debug_msg("Generated wait-for-0 for %s:%d", - ivl_stmt_file(stmt), ivl_stmt_lineno(stmt)); - - vhdl_seq_stmt *wait = new vhdl_wait_stmt(VHDL_WAIT_FOR0); - - ostringstream ss; - ss << "Read target of blocking assignment (" - << ivl_stmt_file(stmt) - << ":" << ivl_stmt_lineno(stmt) << ")"; - wait->set_comment(ss.str()); - - container->add_stmt(wait); - proc->added_wait_stmt(); - } -} - // Generate an assignment of type T for the Verilog statement stmt. // If a statement was generated then `assign_type' will contain the // type of assignment that was generated; this should be initialised // to some sensible default. void make_assignment(vhdl_procedural *proc, stmt_container *container, - ivl_statement_t stmt, bool emul_blocking, + ivl_statement_t stmt, bool blocking, vhdl_decl::assign_type_t& assign_type) { list lvals; @@ -426,23 +286,14 @@ void make_assignment(vhdl_procedural *proc, stmt_container *container, if (rhs == NULL) return; - emit_wait_for_0(proc, container, stmt, rhs); - if (rhs2) - emit_wait_for_0(proc, container, stmt, rhs2); - if (lvals.size() == 1) { vhdl_var_ref *lhs = lvals.front(); rhs = rhs->cast(lhs->get_type()); - + ivl_expr_t i_delay; vhdl_expr *after = NULL; - if ((i_delay = ivl_stmt_delay_expr(stmt)) != NULL) { + if ((i_delay = ivl_stmt_delay_expr(stmt)) != NULL) after = translate_time_expr(i_delay); - if (after == NULL) - return; - - emit_wait_for_0(proc, container, stmt, after); - } // Find the declaration of the LHS so we know what type // of assignment statement to generate (is it a signal, @@ -450,9 +301,6 @@ void make_assignment(vhdl_procedural *proc, stmt_container *container, vhdl_decl *decl = proc->get_scope()->get_decl(lhs->get_name()); assign_type = decl->assignment_type(); - if (assign_type == vhdl_decl::ASSIGN_NONBLOCK && emul_blocking) - proc->add_blocking_target(lhs); - // A small optimisation is to expand ternary RHSs into an // if statement (eliminates a function call and produces // more idiomatic code) @@ -460,13 +308,11 @@ void make_assignment(vhdl_procedural *proc, stmt_container *container, rhs2 = rhs2->cast(lhs->get_type()); vhdl_var_ref *lhs2 = make_assign_lhs(ivl_stmt_lval(stmt, 0), proc->get_scope()); - + vhdl_expr *test = translate_expr(ivl_expr_oper1(rval)); if (NULL == test) return; - emit_wait_for_0(proc, container, stmt, test); - if (!check_valid_assignment(decl->assignment_type(), proc, stmt)) return; @@ -498,7 +344,7 @@ void make_assignment(vhdl_procedural *proc, stmt_container *container, // declaration as initialisers. This optimisation is only // performed on assignments of constant values to prevent // ordering problems. - + // This also has another application: If this is an `initial' // process and we haven't yet generated a `wait' statement then // moving the assignment to the initialization preserves the @@ -514,7 +360,7 @@ void make_assignment(vhdl_procedural *proc, stmt_container *container, && !decl->has_initial() && rhs->constant() && decl->get_type()->get_name() != VHDL_TYPE_ARRAY) { - + // If this assignment is not in the top-level container // it will not be made on all paths through the code // This precludes any future extraction of an initialiser @@ -522,7 +368,6 @@ void make_assignment(vhdl_procedural *proc, stmt_container *container, decl->set_initial(NULL); // Default initial value else { decl->set_initial(rhs); - proc->get_scope()->hoisted_initialiser(true); delete lhs; return; } @@ -534,8 +379,8 @@ void make_assignment(vhdl_procedural *proc, stmt_container *container, vhdl_abstract_assign_stmt *a = assign_for(decl->assignment_type(), lhs, rhs); container->add_stmt(a); - - if (after != NULL) + + if (after != NULL) a->set_after(after); } else { @@ -551,25 +396,20 @@ void make_assignment(vhdl_procedural *proc, stmt_container *container, proc->get_scope()->add_decl(tmp_decl); container->add_stmt(new vhdl_assign_stmt(tmp_decl->make_ref(), rhs)); - + list::iterator it; int width_so_far = 0; for (it = lvals.begin(); it != lvals.end(); ++it) { vhdl_var_ref *tmp_rhs = tmp_decl->make_ref(); - + int lval_width = (*it)->get_type()->get_width(); vhdl_expr *slice_base = new vhdl_const_int(width_so_far); tmp_rhs->set_slice(slice_base, lval_width - 1); - + ivl_expr_t i_delay; vhdl_expr *after = NULL; - if ((i_delay = ivl_stmt_delay_expr(stmt)) != NULL) { + if ((i_delay = ivl_stmt_delay_expr(stmt)) != NULL) after = translate_time_expr(i_delay); - if (after == NULL) - return; - - emit_wait_for_0(proc, container, stmt, after); - } // Find the declaration of the LHS so we know what type // of assignment statement to generate (is it a signal, @@ -579,7 +419,7 @@ void make_assignment(vhdl_procedural *proc, stmt_container *container, if (!check_valid_assignment(decl->assignment_type(), proc, stmt)) return; - + vhdl_abstract_assign_stmt *a = assign_for(decl->assignment_type(), *it, tmp_rhs); if (after) @@ -588,11 +428,10 @@ void make_assignment(vhdl_procedural *proc, stmt_container *container, container->add_stmt(a); width_so_far += lval_width; - - if (assign_type == vhdl_decl::ASSIGN_NONBLOCK && emul_blocking) - proc->add_blocking_target(*it); } } + + return; } /* @@ -615,10 +454,26 @@ static int draw_assign(vhdl_procedural *proc, stmt_container *container, ivl_statement_t stmt, bool is_last) { vhdl_decl::assign_type_t assign_type = vhdl_decl::ASSIGN_NONBLOCK; - bool emulate_blocking = proc->get_scope()->allow_signal_assignment(); - - make_assignment(proc, container, stmt, emulate_blocking, assign_type); - + if (proc->get_scope()->allow_signal_assignment()) { + // Blocking assignment is implemented as non-blocking assignment + // followed by a zero-time wait + // This follows the Verilog semantics fairly closely. + + make_assignment(proc, container, stmt, false, assign_type); + + // Don't generate a zero-wait if either: + // a) this is the last statement in the process + // c) a blocking assignment was generated + if (!is_last && assign_type == vhdl_decl::ASSIGN_NONBLOCK) { + prune_wait_for_0(container); + container->add_stmt + (new vhdl_wait_stmt(VHDL_WAIT_FOR0)); + proc->added_wait_stmt(); + } + } + else + make_assignment(proc, container, stmt, true, assign_type); + return 0; } @@ -646,7 +501,9 @@ static int draw_delay(vhdl_procedural *proc, stmt_container *container, if (NULL == time) return 1; } - + + prune_wait_for_0(container); + ivl_statement_t sub_stmt = ivl_stmt_sub_stmt(stmt); vhdl_wait_stmt *wait = new vhdl_wait_stmt(VHDL_WAIT_FOR, time); @@ -654,7 +511,7 @@ static int draw_delay(vhdl_procedural *proc, stmt_container *container, // Remember that we needed a wait statement so if this is // a process it cannot have a sensitivity list proc->added_wait_stmt(); - + container->add_stmt(wait); // Expand the sub-statement as well @@ -662,12 +519,12 @@ static int draw_delay(vhdl_procedural *proc, stmt_container *container, // is caught here instead if (ivl_statement_type(sub_stmt) != IVL_ST_NOOP) draw_stmt(proc, container, sub_stmt); - + // Any further assignments occur after simulation time 0 // so they cannot be used to initialise signal declarations // (if this scope is an initial process) - proc->get_scope()->set_initializing(false); - + proc->get_scope()->set_initializing(false); + return 0; } @@ -725,19 +582,19 @@ static bool draw_synthesisable_wait(vhdl_process *proc, stmt_container *containe { // At the moment this only detects FFs with an asynchronous reset // All other code will fall back on the default draw_wait - + // Store a set of the edge triggered signals // The second item is true if this is positive-edge set edge_triggered; - + const int nevents = ivl_stmt_nevent(stmt); - + for (int i = 0; i < nevents; i++) { ivl_event_t event = ivl_stmt_events(stmt, i); if (ivl_event_nany(event) > 0) return false; - + int npos = ivl_event_npos(event); for (int j = 0; j < npos; j++) edge_triggered.insert(ivl_event_pos(event, j)); @@ -804,13 +661,13 @@ static bool draw_synthesisable_wait(vhdl_process *proc, stmt_container *containe edge = new vhdl_fcall("falling_edge", vhdl_type::boolean()); } assert(edge); - + edge->add_expr(nexus_to_var_ref(proc->get_scope(), *clock_net.begin())); // Draw the clocked branch // For an asynchronous reset we just want this around the else branch, stmt_container *else_container = body->add_elsif(edge); - + draw_stmt(proc, else_container, ivl_stmt_cond_false(sub_stmt)); if (proc->contains_wait_stmt()) { @@ -850,7 +707,7 @@ static bool draw_synthesisable_wait(vhdl_process *proc, stmt_container *containe * The difficulty stems from VHDL's restriction that a process with * a sensitivity list may not contain any `wait' statements: we need * to generate these to accurately model some Verilog statements. - * + * * The steps followed are: * 1) Determine whether this is the top-level statement in the process * 2) If this is top-level, call draw_synthesisable_wait to see if the @@ -886,20 +743,17 @@ static int draw_wait(vhdl_procedural *_proc, stmt_container *container, // If this container is the top-level statement (i.e. it is the // first thing inside a process) then we can extract these - // events out into the sensitivity list as long as we haven't - // promoted any preceding assignments to initialisers - bool is_top_level = - container == proc->get_container() - && container->empty() - && !proc->get_scope()->hoisted_initialiser(); + // events out into the sensitivity list + bool is_top_level = container == proc->get_container() + && container->empty(); - // See if this can be implemented in a more idomatic way before we + // See if this can be implemented in a more idiomatic way before we // fall back on the generic translation if (is_top_level && draw_synthesisable_wait(proc, container, stmt)) return 0; int nevents = ivl_stmt_nevent(stmt); - + bool combinatorial = true; // True if no negedge/posedge events for (int i = 0; i < nevents; i++) { ivl_event_t event = ivl_stmt_events(stmt, i); @@ -916,11 +770,11 @@ static int draw_wait(vhdl_procedural *_proc, stmt_container *container, vhdl_wait_stmt *wait = NULL; if (proc->contains_wait_stmt() || !is_top_level) - wait = new vhdl_wait_stmt(VHDL_WAIT_ON); - + wait = new vhdl_wait_stmt(VHDL_WAIT_ON); + for (int i = 0; i < nevents; i++) { ivl_event_t event = ivl_stmt_events(stmt, i); - + int nany = ivl_event_nany(event); for (int j = 0; j < nany; j++) { ivl_nexus_t nexus = ivl_event_any(event, j); @@ -949,22 +803,22 @@ static int draw_wait(vhdl_procedural *_proc, stmt_container *container, stmt_container tmp_container; draw_stmt(proc, &tmp_container, ivl_stmt_sub_stmt(stmt), true); - + for (int i = 0; i < nevents; i++) { ivl_event_t event = ivl_stmt_events(stmt, i); - + int nany = ivl_event_nany(event); for (int j = 0; j < nany; j++) { ivl_nexus_t nexus = ivl_event_any(event, j); vhdl_var_ref *ref = nexus_to_var_ref(proc->get_scope(), nexus); - + ref->set_name(ref->get_name() + "'Event"); test->add_expr(ref); if (!proc->contains_wait_stmt() && is_top_level) proc->add_sensitivity(ref->get_name()); } - + int nneg = ivl_event_nneg(event); for (int j = 0; j < nneg; j++) { ivl_nexus_t nexus = ivl_event_neg(event, j); @@ -972,13 +826,13 @@ static int draw_wait(vhdl_procedural *_proc, stmt_container *container, vhdl_fcall *detect = new vhdl_fcall("falling_edge", vhdl_type::boolean()); detect->add_expr(ref); - + test->add_expr(detect); if (!proc->contains_wait_stmt() && is_top_level) proc->add_sensitivity(ref->get_name()); } - + int npos = ivl_event_npos(event); for (int j = 0; j < npos; j++) { ivl_nexus_t nexus = ivl_event_pos(event, j); @@ -986,14 +840,14 @@ static int draw_wait(vhdl_procedural *_proc, stmt_container *container, vhdl_fcall *detect = new vhdl_fcall("rising_edge", vhdl_type::boolean()); detect->add_expr(ref); - + test->add_expr(detect); if (!proc->contains_wait_stmt() && is_top_level) proc->add_sensitivity(ref->get_name()); } } - + if (proc->contains_wait_stmt() || !is_top_level) { container->add_stmt(new vhdl_wait_stmt(VHDL_WAIT_UNTIL, test)); container->move_stmts_from(&tmp_container); @@ -1009,9 +863,9 @@ static int draw_wait(vhdl_procedural *_proc, stmt_container *container, container->add_stmt(edge_detect); } - + } - + return 0; } @@ -1022,11 +876,8 @@ static int draw_if(vhdl_procedural *proc, stmt_container *container, if (NULL == test) return 1; - emit_wait_for_0(proc, container, stmt, test); - vhdl_if_stmt *vhdif = new vhdl_if_stmt(test); - container->add_stmt(vhdif); - + ivl_statement_t cond_true_stmt = ivl_stmt_cond_true(stmt); if (cond_true_stmt) draw_stmt(proc, vhdif->get_then_container(), cond_true_stmt, is_last); @@ -1035,6 +886,8 @@ static int draw_if(vhdl_procedural *proc, stmt_container *container, if (cond_false_stmt) draw_stmt(proc, vhdif->get_else_container(), cond_false_stmt, is_last); + container->add_stmt(vhdif); + return 0; } @@ -1051,7 +904,7 @@ static vhdl_var_ref *draw_case_test(vhdl_procedural *proc, stmt_container *conta if (typeid(*test) != typeid(vhdl_var_ref)) { const char *tmp_name = "Verilog_Case_Ex"; vhdl_type *test_type = new vhdl_type(*test->get_type()); - + if (!proc->get_scope()->have_declared(tmp_name)) { proc->get_scope()->add_decl (new vhdl_var_decl(tmp_name, new vhdl_type(*test_type))); @@ -1072,7 +925,7 @@ static int draw_case(vhdl_procedural *proc, stmt_container *container, 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); @@ -1080,7 +933,7 @@ static int draw_case(vhdl_procedural *proc, stmt_container *container, // possible case. So make sure we add an 'others' branch // if there isn't a default one. bool have_others = false; - + int nbranches = ivl_stmt_case_count(stmt); for (int i = 0; i < nbranches; i++) { vhdl_expr *when; @@ -1094,7 +947,7 @@ static int draw_case(vhdl_procedural *proc, stmt_container *container, when = new vhdl_var_ref("others", NULL); have_others = true; } - + vhdl_case_branch *branch = new vhdl_case_branch(when); vhdlcase->add_branch(branch); @@ -1107,8 +960,8 @@ static int draw_case(vhdl_procedural *proc, stmt_container *container, new vhdl_case_branch(new vhdl_var_ref("others", NULL)); others->get_container()->add_stmt(new vhdl_null_stmt()); vhdlcase->add_branch(others); - } - + } + return 0; } @@ -1472,12 +1325,12 @@ int draw_casezx(vhdl_procedural *proc, stmt_container *container, return 1; vhdl_if_stmt *result = NULL; - + int nbranches = ivl_stmt_case_count(stmt); bool is_casez = ivl_statement_type(stmt) == IVL_ST_CASEZ; for (int i = 0; i < nbranches; i++) { stmt_container *where = NULL; - + ivl_expr_t net = ivl_stmt_case_expr(stmt, i); if (net) { vhdl_binop_expr *all = @@ -1524,7 +1377,7 @@ int draw_casezx(vhdl_procedural *proc, stmt_container *container, // We don't actually use the generated `test' expression delete test; - + return 0; } @@ -1540,7 +1393,7 @@ int draw_while(vhdl_procedural *proc, stmt_container *container, int rc = draw_stmt(proc, &tmp_container, ivl_stmt_sub_stmt(stmt)); if (rc != 0) return 1; - + vhdl_expr *test = translate_expr(ivl_stmt_cond_expr(stmt)); if (NULL == test) return 1; @@ -1550,13 +1403,9 @@ int draw_while(vhdl_procedural *proc, stmt_container *container, vhdl_type boolean(VHDL_TYPE_BOOLEAN); test = test->cast(&boolean); - emit_wait_for_0(proc, container, stmt, test); - vhdl_while_stmt *loop = new vhdl_while_stmt(test); draw_stmt(proc, loop->get_container(), ivl_stmt_sub_stmt(stmt)); - emit_wait_for_0(proc, loop->get_container(), stmt, test); - container->add_stmt(loop); return 0; } @@ -1588,7 +1437,7 @@ int draw_repeat(vhdl_procedural *proc, stmt_container *container, container->add_stmt(loop); draw_stmt(proc, loop->get_container(), ivl_stmt_sub_stmt(stmt)); - + return 0; } @@ -1606,7 +1455,7 @@ int draw_utask(vhdl_procedural *proc, stmt_container *container, // TOOD: this completely ignores parameters! draw_stmt(proc, container, ivl_scope_def(tscope), false); - + return 0; } @@ -1624,7 +1473,7 @@ int draw_stmt(vhdl_procedural *proc, stmt_container *container, ivl_statement_t stmt, bool is_last) { assert(stmt); - + switch (ivl_statement_type(stmt)) { case IVL_ST_STASK: return draw_stask(proc, container, stmt); @@ -1674,6 +1523,6 @@ int draw_stmt(vhdl_procedural *proc, stmt_container *container, error("No VHDL translation for statement at %s:%d (type = %d)", ivl_stmt_file(stmt), ivl_stmt_lineno(stmt), ivl_statement_type(stmt)); - return 1; + return 1; } } diff --git a/tgt-vhdl/support.cc b/tgt-vhdl/support.cc index 5001d5bc8..6f16ba762 100644 --- a/tgt-vhdl/support.cc +++ b/tgt-vhdl/support.cc @@ -92,7 +92,7 @@ void support_function::emit_reduction(std::ostream &of, int level, // Emit a VHDL function emulating a Verilog reduction operator // Where op is the corresponding VHDL operator and unit is the // right-unit of the operator - + of << "(X : std_logic_vector) return std_logic is" << nl_string(indent(level)) << "variable R : std_logic := '" << unit << "';" << nl_string(level) @@ -106,7 +106,7 @@ void support_function::emit_reduction(std::ostream &of, int level, void support_function::emit(std::ostream &of, int level) const { of << nl_string(level) << "function " << function_name(type_); - + switch (type_) { case SF_UNSIGNED_TO_BOOLEAN: of << "(X : unsigned) return Boolean is" << nl_string(level) @@ -169,6 +169,6 @@ void support_function::emit(std::ostream &of, int level) const default: assert(false); } - + of << nl_string(level) << "end function;"; } diff --git a/tgt-vhdl/support.hh b/tgt-vhdl/support.hh index 1487cb036..063234be1 100644 --- a/tgt-vhdl/support.hh +++ b/tgt-vhdl/support.hh @@ -52,7 +52,7 @@ private: void emit_ternary(std::ostream &of, int level) const; void emit_reduction(std::ostream &of, int level, const char *op, char unit) const; - + support_function_t type_; }; diff --git a/tgt-vhdl/vhdl.cc b/tgt-vhdl/vhdl.cc index 9c025a3c2..9437517f2 100644 --- a/tgt-vhdl/vhdl.cc +++ b/tgt-vhdl/vhdl.cc @@ -80,7 +80,7 @@ void debug_msg(const char *fmt, ...) va_start(args, fmt); if (std::strcmp(ivl_design_flag(g_design, "debug"), "")) { - std::fputs("[DEBUG] ", stdout); + std::fputs("[DEBUG] ", stdout); std::vprintf(fmt, args); std::putchar('\n'); } @@ -127,10 +127,10 @@ extern "C" int target_design(ivl_design_t des) emit_all_entities(outfile, max_depth); } - + // Clean up free_all_vhdl_objects(); - + return g_errors; } diff --git a/tgt-vhdl/vhdl_element.cc b/tgt-vhdl/vhdl_element.cc index 06b97c784..21478c952 100644 --- a/tgt-vhdl/vhdl_element.cc +++ b/tgt-vhdl/vhdl_element.cc @@ -40,7 +40,7 @@ std::string nl_string(int level) { std::ostringstream ss; newline(ss, level); - return ss.str(); + return ss.str(); } /* @@ -81,21 +81,10 @@ void vhdl_element::emit_comment(std::ostream &of, int level, { if (comment_.size() > 0) { if (end_of_line) - of << " -- " << comment_; - else { - // Comment may contain embedded newlines - of << "-- "; - for (string::const_iterator it = comment_.begin(); - it != comment_.end(); ++it) { - if (*it == '\n') { - newline(of, level); - of << "-- "; - } - else - of << *it; - } + of << " "; + of << "-- " << comment_; + if (!end_of_line) newline(of, level); - } } } @@ -109,7 +98,7 @@ void vhdl_element::print() const // This records the pointer allocated in a static field of vhdl_element // so we can delete it just before the code generator exits. void* vhdl_element::operator new(size_t size) throw (bad_alloc) -{ +{ // Let the default new handle the allocation void* ptr = ::operator new(size); @@ -126,7 +115,7 @@ void* vhdl_element::operator new(size_t size) throw (bad_alloc) // This just sets the corresponding pointer in vhdl_element::allocated_ // to NULL (since it's safe to delete a NULL pointer). void vhdl_element::operator delete(void* ptr) -{ +{ // Let the default delete handle the deallocation ::operator delete(ptr); diff --git a/tgt-vhdl/vhdl_element.hh b/tgt-vhdl/vhdl_element.hh index 01f15d48d..a324e227d 100644 --- a/tgt-vhdl/vhdl_element.hh +++ b/tgt-vhdl/vhdl_element.hh @@ -48,7 +48,7 @@ public: void* operator new(size_t size) throw (std::bad_alloc); void operator delete(void* ptr); - + virtual void emit(std::ostream &of, int level=0) const = 0; void print() const; diff --git a/tgt-vhdl/vhdl_helper.hh b/tgt-vhdl/vhdl_helper.hh index fb4b5848c..814c5369d 100644 --- a/tgt-vhdl/vhdl_helper.hh +++ b/tgt-vhdl/vhdl_helper.hh @@ -29,8 +29,8 @@ template void emit_children(std::ostream &of, const std::list &children, int level, const char *delim = "", - bool trailing_newline = true) -{ + bool trailing_newline = true) +{ // Don't indent if there are no children if (children.empty()) newline(of, level); diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index e944abe1f..363a04736 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -1,7 +1,7 @@ /* * VHDL abstract syntax elements. * - * Copyright (C) 2008-2010 Nick Gasson (nick@nickg.me.uk) + * Copyright (C) 2008 Nick Gasson (nick@nickg.me.uk) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -31,15 +31,14 @@ using namespace std; vhdl_scope::vhdl_scope() - : parent_(NULL), init_(false), sig_assign_(true), - hoisted_init_(false) + : parent_(NULL), init_(false), sig_assign_(true) { - + } vhdl_scope::~vhdl_scope() { - + } void vhdl_scope::set_initializing(bool i) @@ -101,16 +100,6 @@ vhdl_scope *vhdl_scope::get_parent() const return parent_; } -bool vhdl_scope::hoisted_initialiser() const -{ - return hoisted_init_; -} - -void vhdl_scope::hoisted_initialiser(bool h) -{ - hoisted_init_ = h; -} - vhdl_entity::vhdl_entity(const string& name, vhdl_arch *arch, int depth__) : depth(depth__), name_(name), arch_(arch), time_unit_(TIME_UNIT_NS) @@ -120,7 +109,7 @@ vhdl_entity::vhdl_entity(const string& name, vhdl_arch *arch, int depth__) vhdl_entity::~vhdl_entity() { - + } void vhdl_entity::add_port(vhdl_port_decl *decl) @@ -135,8 +124,9 @@ void vhdl_entity::emit(std::ostream &of, int level) const of << "library ieee;" << std::endl; of << "use ieee.std_logic_1164.all;" << std::endl; of << "use ieee.numeric_std.all;" << std::endl; + of << "use std.textio.all;" << std::endl; of << std::endl; - + emit_comment(of, level); of << "entity " << name_ << " is"; @@ -146,7 +136,7 @@ void vhdl_entity::emit(std::ostream &of, int level) const emit_children(of, ports_.get_decls(), indent(level), ";"); of << ");"; } - + newline(of, level); of << "end entity; "; blank_line(of, level); // Extra blank line after entities @@ -164,7 +154,7 @@ vhdl_const_time* scale_time(const vhdl_entity* ent, uint64_t t) void vhdl_entity::set_time_units(int units, int precision) { int vhdl_units = std::min(units, precision); - + if (vhdl_units >= -3) time_unit_ = TIME_UNIT_MS; else if (vhdl_units >= -6) @@ -177,7 +167,7 @@ void vhdl_entity::set_time_units(int units, int precision) vhdl_arch::~vhdl_arch() { - + } void vhdl_arch::add_stmt(vhdl_process *proc) @@ -203,16 +193,6 @@ void vhdl_arch::emit(std::ostream &of, int level) const blank_line(of, level); // Extra blank line after architectures; } -void vhdl_procedural::add_blocking_target(vhdl_var_ref* ref) -{ - blocking_targets_.insert(ref->get_name()); -} - -bool vhdl_procedural::is_blocking_target(vhdl_var_ref* ref) const -{ - return blocking_targets_.find(ref->get_name()) != blocking_targets_.end(); -} - void vhdl_process::add_sensitivity(const std::string &name) { sens_.push_back(name); @@ -233,7 +213,7 @@ void vhdl_process::emit(std::ostream &of, int level) const if (name_.size() > 0) of << name_ << ": "; of << "process "; - + int num_sens = sens_.size(); if (num_sens > 0) { of << "("; @@ -255,7 +235,7 @@ void vhdl_process::emit(std::ostream &of, int level) const stmt_container::~stmt_container() { - + } void stmt_container::add_stmt(vhdl_seq_stmt *stmt) @@ -288,18 +268,18 @@ void stmt_container::find_vars(vhdl_var_set_t& read, void stmt_container::emit(std::ostream &of, int level, bool newline) const { - emit_children(of, stmts_, level, "", newline); + emit_children(of, stmts_, level, "", newline); } vhdl_comp_inst::vhdl_comp_inst(const char *inst_name, const char *comp_name) : comp_name_(comp_name), inst_name_(inst_name) { - + } vhdl_comp_inst::~vhdl_comp_inst() { - + } void vhdl_comp_inst::map_port(const string& name, vhdl_expr *expr) @@ -331,7 +311,7 @@ void vhdl_comp_inst::emit(std::ostream &of, int level) const newline(of, indent(level)); of << ")"; } - + of << ";"; } @@ -352,7 +332,7 @@ vhdl_component_decl *vhdl_component_decl::component_decl_for(vhdl_entity *ent) (ent->get_name().c_str()); decl->ports_ = ent->get_scope()->get_decls(); - + return decl; } @@ -368,14 +348,14 @@ void vhdl_component_decl::emit(std::ostream &of, int level) const emit_children(of, ports_, indent(level), ";"); of << ");"; } - + newline(of, level); of << "end component;"; } vhdl_wait_stmt::~vhdl_wait_stmt() { - + } void vhdl_wait_stmt::find_vars(vhdl_var_set_t& read, @@ -417,14 +397,13 @@ void vhdl_wait_stmt::emit(std::ostream &of, int level) const } break; } - + of << ";"; - emit_comment(of, level, true); } vhdl_decl::~vhdl_decl() { - + } // Make a reference object to this declaration @@ -440,7 +419,7 @@ const vhdl_type *vhdl_decl::get_type() const } void vhdl_decl::set_initial(vhdl_expr *initial) -{ +{ if (!has_initial_) { assert(initial_ == NULL); initial_ = initial; @@ -451,7 +430,7 @@ void vhdl_decl::set_initial(vhdl_expr *initial) void vhdl_port_decl::emit(std::ostream &of, int level) const { of << name_ << " : "; - + switch (mode_) { case VHDL_PORT_IN: of << "in "; @@ -466,7 +445,7 @@ void vhdl_port_decl::emit(std::ostream &of, int level) const of << "buffer "; break; } - + type_->emit(of, level); } @@ -490,12 +469,12 @@ void vhdl_var_decl::emit(std::ostream &of, int level) const { of << "variable " << name_ << " : "; type_->emit(of, level); - + if (initial_) { of << " := "; initial_->emit(of, level); } - + of << ";"; emit_comment(of, level, true); } @@ -504,12 +483,12 @@ void vhdl_signal_decl::emit(std::ostream &of, int level) const { of << "signal " << name_ << " : "; type_->emit(of, level); - + if (initial_) { of << " := "; initial_->emit(of, level); } - + of << ";"; emit_comment(of, level, true); } @@ -523,7 +502,7 @@ void vhdl_type_decl::emit(std::ostream &of, int level) const vhdl_expr::~vhdl_expr() { - + } void vhdl_expr_list::add_expr(vhdl_expr *e) @@ -533,7 +512,7 @@ void vhdl_expr_list::add_expr(vhdl_expr *e) vhdl_expr_list::~vhdl_expr_list() { - + } void vhdl_expr_list::find_vars(vhdl_var_set_t& read) @@ -546,7 +525,7 @@ void vhdl_expr_list::find_vars(vhdl_var_set_t& read) void vhdl_expr_list::emit(std::ostream &of, int level) const { of << "("; - + int size = exprs_.size(); std::list::const_iterator it; for (it = exprs_.begin(); it != exprs_.end(); ++it) { @@ -574,7 +553,7 @@ void vhdl_pcall_stmt::find_vars(vhdl_var_set_t& read, vhdl_var_ref::~vhdl_var_ref() { - + } void vhdl_var_ref::set_slice(vhdl_expr *s, int w) @@ -583,18 +562,18 @@ void vhdl_var_ref::set_slice(vhdl_expr *s, int w) slice_ = s; slice_width_ = w; - + vhdl_type_name_t tname = type_->get_name(); if (tname == VHDL_TYPE_ARRAY) { type_ = type_->get_base(); } else { assert(tname == VHDL_TYPE_UNSIGNED || tname == VHDL_TYPE_SIGNED); - + if (w > 0) type_ = new vhdl_type(tname, w); else - type_ = vhdl_type::std_logic(); + type_ = vhdl_type::std_logic(); } } @@ -619,7 +598,11 @@ void vhdl_var_ref::emit(std::ostream &of, int level) const void vhdl_const_string::emit(std::ostream &of, int level) const { - of << "\"" << value_ << "\""; + // In some instances a string literal can be ambiguous between + // a String type and some other types (e.g. std_logic_vector) + // The explicit cast to String removes this ambiguity (although + // isn't always strictly necessary) + of << "String'(\"" << value_ << "\")"; } void vhdl_null_stmt::emit(std::ostream &of, int level) const @@ -641,13 +624,13 @@ void vhdl_fcall::emit(std::ostream &of, int level) const vhdl_abstract_assign_stmt::~vhdl_abstract_assign_stmt() { - + } void vhdl_abstract_assign_stmt::find_vars(vhdl_var_set_t& read, vhdl_var_set_t& write) { - lhs_->find_vars(write); + write.insert(lhs_); rhs_->find_vars(read); } @@ -661,7 +644,7 @@ void vhdl_nbassign_stmt::emit(std::ostream &of, int level) const of << " after "; after_->emit(of, level); } - + of << ";"; } @@ -674,12 +657,12 @@ void vhdl_assign_stmt::emit(std::ostream &of, int level) const } vhdl_const_bits::vhdl_const_bits(const char *value, int width, bool issigned, - bool qualify) + bool qualify) : vhdl_expr(issigned ? vhdl_type::nsigned(width) : vhdl_type::nunsigned(width), true), qualified_(qualify), signed_(issigned) -{ +{ // Can't rely on value being NULL-terminated while (width--) value_.push_back(*value++); @@ -709,9 +692,9 @@ void vhdl_const_bits::emit(std::ostream &of, int level) const && !has_meta_bits() && bits <= 64 && bits % 4 == 0) { of << "X\"" << hex << setfill('0') << setw(bits / 4) << ival; } - else { + else { of << "\""; - + std::string::const_reverse_iterator it; for (it = value_.rbegin(); it != value_.rend(); ++it) of << vl_to_vhdl_bit(*it); @@ -749,7 +732,7 @@ void vhdl_const_time::emit(std::ostream &of, int level) const vhdl_cassign_stmt::~vhdl_cassign_stmt() { - + } void vhdl_cassign_stmt::add_condition(vhdl_expr *value, vhdl_expr *cond) @@ -774,51 +757,19 @@ void vhdl_cassign_stmt::emit(std::ostream &of, int level) const of << "else "; } rhs_->emit(of, level); - + if (after_) { of << " after "; after_->emit(of, level); } - + of << ";"; } -vhdl_report_stmt::vhdl_report_stmt(vhdl_expr *text, - vhdl_severity_t severity) - : severity_(severity), - text_(text) -{ - -} - -void vhdl_report_stmt::emit(ostream& of, int level) const -{ - of << "report "; - text_->emit(of, level); - - if (severity_ != SEVERITY_NOTE) { - const char *levels[] = { "note", "warning", "error", "failure" }; - of << " severity " << levels[severity_]; - } - - of << ";"; -} - -void vhdl_report_stmt::find_vars(vhdl_var_set_t& read, vhdl_var_set_t& write) -{ - text_->find_vars(read); -} - -vhdl_assert_stmt::vhdl_assert_stmt(const char *reason) - : vhdl_report_stmt(new vhdl_const_string(reason), SEVERITY_FAILURE) -{ - -} - void vhdl_assert_stmt::emit(std::ostream &of, int level) const { - of << "assert false "; // TODO: Allow arbitrary expression - vhdl_report_stmt::emit(of, level); + of << "assert false"; // TODO: Allow arbitrary expression + of << " report \"" << reason_ << "\" severity failure;"; } vhdl_if_stmt::vhdl_if_stmt(vhdl_expr *test) @@ -830,7 +781,7 @@ vhdl_if_stmt::vhdl_if_stmt(vhdl_expr *test) vhdl_if_stmt::~vhdl_if_stmt() { - + } stmt_container *vhdl_if_stmt::add_elsif(vhdl_expr *test) @@ -843,7 +794,7 @@ stmt_container *vhdl_if_stmt::add_elsif(vhdl_expr *test) void vhdl_if_stmt::emit(std::ostream &of, int level) const { emit_comment(of, level); - + of << "if "; test_->emit(of, level); of << " then"; @@ -856,7 +807,7 @@ void vhdl_if_stmt::emit(std::ostream &of, int level) const of << " then"; (*it).container->emit(of, level); } - + if (!else_part_.empty()) { of << "else"; else_part_.emit(of, level); @@ -897,7 +848,7 @@ void vhdl_expr::close_parens(std::ostream& of) vhdl_unaryop_expr::~vhdl_unaryop_expr() { - + } void vhdl_unaryop_expr::find_vars(vhdl_var_set_t& read) @@ -932,7 +883,7 @@ vhdl_binop_expr::vhdl_binop_expr(vhdl_expr *left, vhdl_binop_t op, vhdl_binop_expr::~vhdl_binop_expr() { - + } void vhdl_binop_expr::add_expr(vhdl_expr *e) @@ -951,7 +902,7 @@ void vhdl_binop_expr::emit(std::ostream &of, int level) const { open_parens(of); - assert(operands_.size() > 0); + assert(operands_.size() > 0); std::list::const_iterator it = operands_.begin(); (*it)->emit(of, level); @@ -965,14 +916,14 @@ void vhdl_binop_expr::emit(std::ostream &of, int level) const of << " " << ops[op_] << " "; (*it)->emit(of, level); - } + } close_parens(of); } vhdl_bit_spec_expr::~vhdl_bit_spec_expr() { - + } void vhdl_bit_spec_expr::add_bit(int bit, vhdl_expr *e) @@ -984,7 +935,7 @@ void vhdl_bit_spec_expr::add_bit(int bit, vhdl_expr *e) void vhdl_bit_spec_expr::emit(std::ostream &of, int level) const { of << "("; - + std::list::const_iterator it; it = bits_.begin(); while (it != bits_.end()) { @@ -998,13 +949,13 @@ void vhdl_bit_spec_expr::emit(std::ostream &of, int level) const of << (bits_.empty() ? "" : ", ") << "others => "; others_->emit(of, level); } - + of << ")"; } vhdl_case_branch::~vhdl_case_branch() { - + } void vhdl_case_branch::emit(std::ostream &of, int level) const @@ -1017,7 +968,7 @@ void vhdl_case_branch::emit(std::ostream &of, int level) const vhdl_case_stmt::~vhdl_case_stmt() { - + } void vhdl_case_stmt::find_vars(vhdl_var_set_t& read, @@ -1048,13 +999,13 @@ void vhdl_case_stmt::emit(std::ostream &of, int level) const else newline(of, level); } - + of << "end case;"; } vhdl_while_stmt::~vhdl_while_stmt() { - + } void vhdl_while_stmt::find_vars(vhdl_var_set_t& read, @@ -1088,7 +1039,7 @@ void vhdl_loop_stmt::emit(std::ostream &of, int level) const vhdl_for_stmt::~vhdl_for_stmt() { - + } @@ -1156,7 +1107,7 @@ void vhdl_param_decl::emit(std::ostream &of, int level) const vhdl_with_select_stmt::~vhdl_with_select_stmt() { - + } void vhdl_with_select_stmt::emit(std::ostream &of, int level) const @@ -1164,12 +1115,12 @@ void vhdl_with_select_stmt::emit(std::ostream &of, int level) const of << "with "; test_->emit(of, level); of << " select"; - emit_comment(of, level, true); + emit_comment(of, level, true); newline(of, indent(level)); out_->emit(of, level); - of << " <= "; - + of << " <= "; + when_list_t::const_iterator it = whens_.begin(); while (it != whens_.end()) { (*it).value->emit(of, level); @@ -1179,7 +1130,7 @@ void vhdl_with_select_stmt::emit(std::ostream &of, int level) const } of << " when "; (*it).cond->emit(of, level); - + if (++it != whens_.end() || others_ != NULL) { of << ","; newline(of, indent(level)); diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 80076f1c1..ea7b7de3f 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -44,7 +44,7 @@ public: const vhdl_type *get_type() const { return type_; } bool constant() const { return isconst_; } - + vhdl_expr *cast(const vhdl_type *to); virtual vhdl_expr *resize(int newwidth); virtual vhdl_expr *to_boolean(); @@ -52,8 +52,7 @@ public: virtual vhdl_expr *to_std_logic(); virtual vhdl_expr *to_std_ulogic(); virtual vhdl_expr *to_vector(vhdl_type_name_t name, int w); - virtual vhdl_expr *to_string(); - virtual void find_vars(vhdl_var_set_t& read) {} + virtual void find_vars(vhdl_var_set_t& read) const {} protected: static void open_parens(ostream& of); @@ -74,7 +73,7 @@ public: vhdl_expr *slice = NULL) : vhdl_expr(type), name_(name), slice_(slice), slice_width_(0) {} ~vhdl_var_ref(); - + void emit(std::ostream &of, int level) const; const std::string &get_name() const { return name_; } void set_name(const std::string &name) { name_ = name; } @@ -177,7 +176,7 @@ private: class vhdl_const_string : public vhdl_expr { public: - vhdl_const_string(const string& value) + vhdl_const_string(const char *value) : vhdl_expr(vhdl_type::string(), true), value_(value) {} void emit(std::ostream &of, int level) const; @@ -199,7 +198,7 @@ private: int64_t bits_to_int() const; char sign_bit() const; bool has_meta_bits() const; - + std::string value_; bool qualified_, signed_; }; @@ -256,7 +255,7 @@ private: class vhdl_expr_list : public vhdl_element { public: ~vhdl_expr_list(); - + void emit(std::ostream &of, int level) const; bool empty() const { return exprs_.empty(); } void add_expr(vhdl_expr *e); @@ -271,7 +270,7 @@ private: */ class vhdl_fcall : public vhdl_expr { public: - vhdl_fcall(const string& name, vhdl_type *rtype) + vhdl_fcall(const char *name, vhdl_type *rtype) : vhdl_expr(rtype), name_(name) {}; ~vhdl_fcall() {} @@ -330,7 +329,7 @@ public: vhdl_with_select_stmt(vhdl_expr *test, vhdl_var_ref *out) : test_(test), out_(out), others_(NULL) {} ~vhdl_with_select_stmt(); - + void emit(std::ostream &of, int level) const; void add_condition(vhdl_expr *value, vhdl_expr *cond, vhdl_expr *delay=NULL); void add_default(vhdl_expr* value); @@ -364,7 +363,7 @@ public: class stmt_container { public: ~stmt_container(); - + void add_stmt(vhdl_seq_stmt *stmt); void move_stmts_from(stmt_container *other); void emit(std::ostream &of, int level, bool newline=true) const; @@ -392,7 +391,7 @@ public: protected: vhdl_var_ref *lhs_; vhdl_expr *rhs_, *after_; -}; +}; /* @@ -403,7 +402,7 @@ class vhdl_nbassign_stmt : public vhdl_abstract_assign_stmt { public: vhdl_nbassign_stmt(vhdl_var_ref *lhs, vhdl_expr *rhs) : vhdl_abstract_assign_stmt(lhs, rhs) {} - + void emit(std::ostream &of, int level) const; }; @@ -435,7 +434,7 @@ public: vhdl_expr *expr = NULL) : type_(type), expr_(expr) {} ~vhdl_wait_stmt(); - + void emit(std::ostream &of, int level) const; void add_sensitivity(const std::string &s) { sensitivity_.push_back(s); } vhdl_wait_type_t get_type() const { return type_; } @@ -454,32 +453,15 @@ public: }; -enum vhdl_severity_t { - SEVERITY_NOTE, - SEVERITY_WARNING, - SEVERITY_ERROR, - SEVERITY_FAILURE -}; - -class vhdl_report_stmt : public vhdl_seq_stmt { +class vhdl_assert_stmt : public vhdl_seq_stmt { public: - vhdl_report_stmt(vhdl_expr *text, - vhdl_severity_t severity = SEVERITY_NOTE); - virtual ~vhdl_report_stmt() {} + vhdl_assert_stmt(const char *reason) + : reason_(reason) {} - virtual void emit(ostream& of, int level) const; - void find_vars(vhdl_var_set_t& read, vhdl_var_set_t& write); + void emit(std::ostream &of, int level) const; + void find_vars(vhdl_var_set_t& read, vhdl_var_set_t& write) {} private: - vhdl_severity_t severity_; - vhdl_expr *text_; -}; - - -class vhdl_assert_stmt : public vhdl_report_stmt { -public: - vhdl_assert_stmt(const char *reason); - - void emit(ostream &of, int level) const; + std::string reason_; }; @@ -498,7 +480,7 @@ private: vhdl_expr *test; stmt_container *container; }; - + vhdl_expr *test_; stmt_container then_part_, else_part_; std::list elsif_parts_; @@ -541,7 +523,7 @@ private: class vhdl_loop_stmt : public vhdl_seq_stmt { public: virtual ~vhdl_loop_stmt() {} - + stmt_container *get_container() { return &stmts_; } void emit(std::ostream &of, int level) const; virtual void find_vars(vhdl_var_set_t& read, @@ -568,7 +550,7 @@ public: vhdl_for_stmt(const char *lname, vhdl_expr *from, vhdl_expr *to) : lname_(lname), from_(from), to_(to) {} ~vhdl_for_stmt(); - + void emit(std::ostream &of, int level) const; void find_vars(vhdl_var_set_t& read, vhdl_var_set_t& write); private: @@ -584,7 +566,7 @@ private: class vhdl_pcall_stmt : public vhdl_seq_stmt { public: vhdl_pcall_stmt(const char *name) : name_(name) {} - + void emit(std::ostream &of, int level) const; void add_expr(vhdl_expr *e) { exprs_.add_expr(e); } void find_vars(vhdl_var_set_t& read, vhdl_var_set_t& write); @@ -615,14 +597,14 @@ public: // Return a new reference to this declaration vhdl_var_ref* make_ref() const; - + // The different sorts of assignment statement // ASSIGN_CONST is used to generate a variable to shadow a // constant that cannot be assigned to (e.g. a function parameter) enum assign_type_t { ASSIGN_BLOCK, ASSIGN_NONBLOCK, ASSIGN_CONST }; - + // Get the sort of assignment statement to generate for - // assignemnts to this declaration + // assignments to this declaration // For some sorts of declarations it doesn't make sense // to assign to it so calling assignment_type just raises // an assertion failure @@ -631,7 +613,7 @@ public: // True if this declaration can be read from virtual bool is_readable() const { return true; } - + // Modify this declaration so it can be read from // This does nothing for most declaration types virtual void ensure_readable() {} @@ -643,7 +625,7 @@ protected: }; typedef std::list decl_list_t; - + /* * A forward declaration of a component. At the moment it is assumed @@ -773,7 +755,7 @@ class vhdl_scope { public: vhdl_scope(); ~vhdl_scope(); - + void add_decl(vhdl_decl *decl); void add_forward_decl(vhdl_decl *decl); vhdl_decl *get_decl(const std::string &name) const; @@ -781,15 +763,13 @@ public: bool name_collides(const string& name) const; bool contained_within(const vhdl_scope *other) const; vhdl_scope *get_parent() const; - + bool empty() const { return decls_.empty(); } const decl_list_t &get_decls() const { return decls_; } void set_parent(vhdl_scope *p) { parent_ = p; } bool initializing() const { return init_; } void set_initializing(bool i); - bool hoisted_initialiser() const; - void hoisted_initialiser(bool h); void set_allow_signal_assignment(bool b) { sig_assign_ = b; } bool allow_signal_assignment() const { return sig_assign_; } @@ -797,7 +777,6 @@ private: decl_list_t decls_; vhdl_scope *parent_; bool init_, sig_assign_; - bool hoisted_init_; }; @@ -810,30 +789,21 @@ class vhdl_procedural { public: vhdl_procedural() : contains_wait_stmt_(false) {} virtual ~vhdl_procedural() {} - + virtual stmt_container *get_container() { return &stmts_; } virtual vhdl_scope *get_scope() { return &scope_; } void added_wait_stmt() { contains_wait_stmt_ = true; } bool contains_wait_stmt() const { return contains_wait_stmt_; } - - // Managing set of blocking assignment targets in this block - void add_blocking_target(vhdl_var_ref* ref); - bool is_blocking_target(vhdl_var_ref* ref) const; - protected: stmt_container stmts_; vhdl_scope scope_; // If this is true then the body contains a `wait' statement // embedded in it somewhere - // If this is the case then we can't use a sensitvity list for + // If this is the case then we can't use a sensitivity list for // the process bool contains_wait_stmt_; - - // The set of variable we have performed a blocking - // assignment to - set blocking_targets_; }; @@ -841,7 +811,7 @@ class vhdl_function : public vhdl_decl, public vhdl_procedural { friend class vhdl_forward_fdecl; public: vhdl_function(const char *name, vhdl_type *ret_type); - + virtual void emit(std::ostream &of, int level) const; vhdl_scope *get_scope() { return &variables_; } void add_param(vhdl_param_decl *p) { scope_.add_decl(p); } @@ -911,7 +881,7 @@ public: void set_time_units(int units, int precision); friend vhdl_const_time* scale_time(const vhdl_entity* ent, uint64_t t); - + // Each entity has an associated depth which is how deep in // the Verilog module hierarchy it was found // This is used to limit the maximum depth of modules emitted @@ -920,7 +890,7 @@ private: std::string name_; vhdl_arch *arch_; // Entity may only have a single architecture vhdl_scope ports_; - + // Entities have an associated VHDL time unit // This is used to implement the Verilog timescale directive time_unit_t time_unit_; diff --git a/tgt-vhdl/vhdl_target.h b/tgt-vhdl/vhdl_target.h index 60510f83a..3a4aad72a 100644 --- a/tgt-vhdl/vhdl_target.h +++ b/tgt-vhdl/vhdl_target.h @@ -1,4 +1,3 @@ -// -*- mode: c++ -*- #ifndef INC_VHDL_TARGET_H #define INC_VHDL_TARGET_H @@ -29,8 +28,10 @@ ivl_design_t get_vhdl_design(); vhdl_var_ref *nexus_to_var_ref(vhdl_scope *arch_scope, ivl_nexus_t nexus); vhdl_var_ref* readable_ref(vhdl_scope* scope, ivl_nexus_t nex); string make_safe_name(ivl_signal_t sig); - + +int draw_stask_display(vhdl_procedural *proc, stmt_container *container, + ivl_statement_t stmt, bool newline = true); +void prune_wait_for_0(stmt_container *container); void require_support_function(support_function_t f); #endif /* #ifndef INC_VHDL_TARGET_H */ - diff --git a/tgt-vhdl/vhdl_type.cc b/tgt-vhdl/vhdl_type.cc index c448f6a5e..c53e8e7aa 100644 --- a/tgt-vhdl/vhdl_type.cc +++ b/tgt-vhdl/vhdl_type.cc @@ -86,7 +86,7 @@ std::string vhdl_type::get_string() const case VHDL_TYPE_STD_ULOGIC: return std::string("std_ulogic"); case VHDL_TYPE_STD_LOGIC_VECTOR: - return std::string("std_logic_vector"); + return std::string("std_logic_vector"); case VHDL_TYPE_STRING: return std::string("String"); case VHDL_TYPE_LINE: diff --git a/tgt-vhdl/vhdl_type.hh b/tgt-vhdl/vhdl_type.hh index 9786ab9ad..c374584a7 100644 --- a/tgt-vhdl/vhdl_type.hh +++ b/tgt-vhdl/vhdl_type.hh @@ -57,7 +57,7 @@ public: // Copy constructor vhdl_type(const vhdl_type &other); - + virtual ~vhdl_type(); void emit(std::ostream &of, int level) const; @@ -69,7 +69,7 @@ public: int get_width() const { return msb_ - lsb_ + 1; } int get_msb() const { return msb_; } int get_lsb() const { return lsb_; } - + // Common types static vhdl_type *std_logic(); static vhdl_type *std_ulogic(); diff --git a/tgt-vvp/draw_mux.c b/tgt-vvp/draw_mux.c index 68ae8cf2b..234834900 100644 --- a/tgt-vvp/draw_mux.c +++ b/tgt-vvp/draw_mux.c @@ -105,12 +105,13 @@ static void draw_lpm_mux_ab(ivl_lpm_t net, const char*muxz) static void draw_lpm_mux_nest(ivl_lpm_t net, const char*muxz) { - int idx, level; + unsigned idx, level; unsigned width = ivl_lpm_width(net); unsigned swidth = ivl_lpm_selects(net); char*select_input; - assert(ivl_lpm_size(net) == (1 << swidth)); + assert(swidth < sizeof(unsigned)); + assert(ivl_lpm_size(net) == (1U << swidth)); select_input = strdup(draw_net_input(ivl_lpm_select(net))); diff --git a/tgt-vvp/draw_net_input.c b/tgt-vvp/draw_net_input.c index d0bdbfcbb..a915820b4 100644 --- a/tgt-vvp/draw_net_input.c +++ b/tgt-vvp/draw_net_input.c @@ -94,7 +94,8 @@ static char* draw_C4_to_string(ivl_net_const_t cptr) for (idx = 0 ; idx < ivl_const_width(cptr) ; idx += 1) { char bitchar = bits[ivl_const_width(cptr)-idx-1]; *dp++ = bitchar; - assert((dp - result) < result_len); + assert(dp >= result); + assert((unsigned)(dp - result) < result_len); } strcpy(dp, ">"); @@ -144,7 +145,8 @@ static char* draw_C8_to_string(ivl_net_const_t cptr, assert(0); break; } - assert(dp - result < nresult); + assert(dp >= result); + assert((unsigned)(dp - result) < nresult); } strcpy(dp, ">"); @@ -260,7 +262,8 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr) dp += ivl_logic_width(lptr); *dp++ = '>'; *dp = 0; - assert((dp-result) <= result_len); + assert(dp >= result); + assert((unsigned)(dp - result) <= result_len); return result; } else { char val[4]; @@ -279,7 +282,8 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr) dp += 3*ivl_logic_width(lptr); *dp++ = '>'; *dp = 0; - assert((dp-result) <= result_len); + assert(dp >= result); + assert((unsigned)(dp - result) <= result_len); return result; } } @@ -297,7 +301,8 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr) dp += ivl_logic_width(lptr); *dp++ = '>'; *dp = 0; - assert((dp-result) <= result_len); + assert(dp >= result); + assert((unsigned)(dp - result) <= result_len); } else { char val[4]; @@ -316,7 +321,8 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr) dp += 3*ivl_logic_width(lptr); *dp++ = '>'; *dp = 0; - assert((dp-result) <= result_len); + assert(dp >= result); + assert((unsigned)(dp - result) <= result_len); } @@ -705,7 +711,7 @@ static void draw_net_input_x(ivl_nexus_t nex, if (res == IVL_SIT_UWIRE) { if (ndrivers > 1) { unsigned uidx; - ivl_signal_t usig; + ivl_signal_t usig = 0; /* Find the uwire signal. */ for (uidx = 0 ; uidx < ivl_nexus_ptrs(nex) ; uidx += 1) { ivl_nexus_ptr_t ptr = ivl_nexus_ptr(nex, uidx); diff --git a/tgt-vvp/draw_ufunc.c b/tgt-vvp/draw_ufunc.c index 1b30e9039..8e0f8fcfa 100644 --- a/tgt-vvp/draw_ufunc.c +++ b/tgt-vvp/draw_ufunc.c @@ -156,7 +156,7 @@ int draw_ufunc_real(ivl_expr_t expr) ivl_scope_t def = ivl_expr_def(expr); ivl_signal_t retval = ivl_scope_port(def, 0); int res = 0; - int idx; + unsigned idx; /* If this is an automatic function, allocate the local storage. */ if (ivl_scope_is_auto(def)) { diff --git a/tgt-vvp/draw_vpi.c b/tgt-vvp/draw_vpi.c index 0a2543cc0..ccf4db9da 100644 --- a/tgt-vvp/draw_vpi.c +++ b/tgt-vvp/draw_vpi.c @@ -282,7 +282,8 @@ static void draw_vpi_taskfunc_args(const char*call_string, for (bit = wid ; bit > 0 ; bit -= 1) *dp++ = bits[bit-1]; *dp++ = 0; - assert(dp - buffer <= sizeof buffer); + assert(dp >= buffer); + assert((unsigned)(dp - buffer) <= sizeof buffer); } args[idx].text = strdup(buffer); continue; diff --git a/tgt-vvp/eval_expr.c b/tgt-vvp/eval_expr.c index 5907e3189..cf3847614 100644 --- a/tgt-vvp/eval_expr.c +++ b/tgt-vvp/eval_expr.c @@ -929,9 +929,9 @@ static struct vector_info draw_binary_expr_le(ivl_expr_t expr, case 'G': rv = draw_eval_expr_wid(re, owid, STUFF_OK_XZ); if (number_is_immediate(le,16,0) && !number_is_unknown(le)) { - unsigned imm = get_number_immediate(le); + long imm = get_number_immediate(le); assert(imm >= 0); - fprintf(vvp_out, " %%cmpi/%c %u, %u, %u;\n", s_flag, + fprintf(vvp_out, " %%cmpi/%c %u, %ld, %u;\n", s_flag, rv.base, imm, rv.wid); } else { lv = draw_eval_expr_wid(le, owid, STUFF_OK_XZ); @@ -945,9 +945,9 @@ static struct vector_info draw_binary_expr_le(ivl_expr_t expr, case 'L': lv = draw_eval_expr_wid(le, owid, STUFF_OK_XZ); if (number_is_immediate(re,16,0) && !number_is_unknown(re)) { - unsigned imm = get_number_immediate(re); + long imm = get_number_immediate(re); assert(imm >= 0); - fprintf(vvp_out, " %%cmpi/%c %u, %u, %u;\n", s_flag, + fprintf(vvp_out, " %%cmpi/%c %u, %ld, %u;\n", s_flag, lv.base, imm, lv.wid); } else { rv = draw_eval_expr_wid(re, owid, STUFF_OK_XZ); @@ -961,9 +961,9 @@ static struct vector_info draw_binary_expr_le(ivl_expr_t expr, case '<': lv = draw_eval_expr_wid(le, owid, STUFF_OK_XZ); if (number_is_immediate(re,16,0) && !number_is_unknown(re)) { - unsigned imm = get_number_immediate(re); + long imm = get_number_immediate(re); assert(imm >= 0); - fprintf(vvp_out, " %%cmpi/%c %u, %u, %u;\n", s_flag, + fprintf(vvp_out, " %%cmpi/%c %u, %ld, %u;\n", s_flag, lv.base, imm, lv.wid); } else { rv = draw_eval_expr_wid(re, owid, STUFF_OK_XZ); @@ -976,9 +976,9 @@ static struct vector_info draw_binary_expr_le(ivl_expr_t expr, case '>': rv = draw_eval_expr_wid(re, owid, STUFF_OK_XZ); if (number_is_immediate(le,16,0) && !number_is_unknown(le)) { - unsigned imm = get_number_immediate(le); + long imm = get_number_immediate(le); assert(imm >= 0); - fprintf(vvp_out, " %%cmpi/%c %u, %u, %u;\n", s_flag, + fprintf(vvp_out, " %%cmpi/%c %u, %ld, %u;\n", s_flag, rv.base, imm, rv.wid); } else { lv = draw_eval_expr_wid(le, owid, STUFF_OK_XZ); @@ -1942,7 +1942,7 @@ static struct vector_info draw_number_expr(ivl_expr_t expr, unsigned wid) /* * This little helper function generates the instructions to pad a * vector in place. It is assumed that the calling function has set up - * the first sub_sidth bits of the dest vector, and the signed_flag is + * the first sub_width bits of the dest vector, and the signed_flag is * true if the extension is to be signed. */ static void pad_in_place(struct vector_info dest, unsigned sub_width, int signed_flag) @@ -2589,7 +2589,7 @@ static struct vector_info draw_select_unsized_literal(ivl_expr_t expr, /* If we have an undefined index then just produce a 'bx result. */ fprintf(vvp_out, " %%jmp/1 T_%d.%d, 4;\n", thread_count, lab_x); - /* If the subv result is a magic constant, then make a copy in + /* If the subv result is a magic constant, then make a copy in writable vector space and work from there instead. */ if (subv.base < 4) { res.base = allocate_vector(subv.wid); @@ -2609,7 +2609,7 @@ static struct vector_info draw_select_unsized_literal(ivl_expr_t expr, fprintf(vvp_out, " %%mov %u, %u, %u; Pad sub-expression to match width\n", res.base, subv.base, subv.wid); if (ivl_expr_signed(sube)) { - int idx; + unsigned idx; for (idx = subv.wid ; idx < res.wid ; idx += 1) { fprintf(vvp_out, " %%mov %u, %u, 1;\n", res.base+idx, subv.base+subv.wid-1); diff --git a/tgt-vvp/eval_real.c b/tgt-vvp/eval_real.c index 76c3934e7..eeb8abfc1 100644 --- a/tgt-vvp/eval_real.c +++ b/tgt-vvp/eval_real.c @@ -166,7 +166,7 @@ static int draw_number_real(ivl_expr_t expr) /* If this is a negative number, then arrange for the 2's complement to be calculated as we scan through the value. Real values are sign-magnitude, and this negation - gets us a magnitide. */ + gets us a magnitude. */ int negate = 0; int carry = 0; diff --git a/tgt-vvp/modpath.c b/tgt-vvp/modpath.c index c26087e5e..e65f629e0 100644 --- a/tgt-vvp/modpath.c +++ b/tgt-vvp/modpath.c @@ -28,7 +28,7 @@ static ivl_signal_t find_path_source_port(ivl_delaypath_t path) { - int idx; + unsigned idx; ivl_nexus_t nex = ivl_path_source(path); ivl_scope_t path_scope = ivl_path_scope(path); diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index aed28c035..2c1836c83 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.c @@ -260,9 +260,43 @@ const char*drive_string(ivl_drive_t drive) * on. The last net is selected as the output of the nexus. */ +/* + * When checking if we can elide a buffer we need to keep the buffer + * if both the input and output for the buffer are connected only + * to netlist signals. This routine performs this check on the + * given nexus. + */ +static unsigned is_netlist_signal(ivl_net_logic_t net, ivl_nexus_t nex) +{ + unsigned idx, rtn; + + /* Assume that this is a netlist signal. */ + rtn = 1; + + for (idx = 0; idx < ivl_nexus_ptrs(nex); idx += 1) { + ivl_nexus_ptr_t nptr; + ivl_signal_t sptr; + + nptr = ivl_nexus_ptr(nex, idx); + + /* Skip a pointer to the buffer we're checking. */ + if (ivl_nexus_ptr_log(nptr) == net) continue; + + /* Check to see if this is a netlist signal. */ + sptr = ivl_nexus_ptr_sig(nptr); + if (sptr && !ivl_signal_local(sptr)) continue; + + /* If we get here then this is not just a netlist signal. */ + rtn = 0; + break; + } + + return rtn; +} + /* * This tests a bufz device against an output receiver, and determines - * if the device can be skipped. If this function returns true, then a + * if the device can be skipped. If this function returns false, then a * gate will be generated for this node. Otherwise, the code generator * will connect its input to its output and skip the gate. */ @@ -311,6 +345,14 @@ int can_elide_bufz(ivl_net_logic_t net, ivl_nexus_ptr_t nptr) if (drive_count != 1) return 0; + /* If both the input and output are netlist signal then we cannot + elide a BUFZ since it represents a continuous assignment. */ + if (is_netlist_signal(net, ivl_logic_pin(net, 0)) && + is_netlist_signal(net, ivl_logic_pin(net, 1)) && + (ivl_logic_type(net) == IVL_LO_BUFZ)) { + return 0; + } + return 1; } @@ -887,14 +929,15 @@ static void draw_logic_in_scope(ivl_net_logic_t lptr) /* Get all the input label that I will use for parameters to the functor that I create later. */ ninp = ivl_logic_pins(lptr) - 1; + assert(ninp >= 0); input_strings = calloc(ninp, sizeof(char*)); - for (pdx = 0 ; pdx < ninp ; pdx += 1) + for (pdx = 0 ; pdx < (unsigned)ninp ; pdx += 1) input_strings[pdx] = draw_net_input(ivl_logic_pin(lptr, pdx+1)); level = 0; while (ninp) { - int inst; - for (inst = 0; inst < ninp; inst += 4) { + unsigned inst; + for (inst = 0; inst < (unsigned)ninp; inst += 4) { if (ninp > 4) fprintf(vvp_out, "L_%p/%d/%d .functor %s %u", lptr, level, inst, lcasc, vector_width); @@ -907,7 +950,7 @@ static void draw_logic_in_scope(ivl_net_logic_t lptr) fprintf(vvp_out, " [%u %u]", str0, str1); } - for (pdx = inst; pdx < ninp && pdx < inst+4 ; pdx += 1) { + for (pdx = inst; pdx < (unsigned)ninp && pdx < inst+4 ; pdx += 1) { if (level) { fprintf(vvp_out, ", L_%p/%d/%d", lptr, level - 1, pdx*4); diff --git a/vpi/fstapi.c b/vpi/fstapi.c index bbb32e737..59211b772 100644 --- a/vpi/fstapi.c +++ b/vpi/fstapi.c @@ -42,6 +42,10 @@ #define FST_MACOSX #endif +#if defined(__CYGWIN__) && defined(__GNUC__) +#define FST_USE_FWRITE_COMBINING +#endif + /***********************/ /*** ***/ @@ -375,7 +379,7 @@ return(rc); static int fstWriterVarint(FILE *handle, uint64_t v) { uint64_t nxt; -unsigned char buf[32]; +unsigned char buf[10]; /* ceil(64/7) = 10 */ unsigned char *pnt = buf; int len; @@ -391,6 +395,50 @@ fstFwrite(buf, len, 1, handle); return(len); } +#ifndef FST_USE_FWRITE_COMBINING +static int fstWriterUint32WithVarint(FILE *handle, uint32_t *u, uint64_t v) +{ +uint64_t nxt; +unsigned char buf[10 + sizeof(uint32_t)]; +unsigned char *pnt = buf + sizeof(uint32_t); +int len; + +memcpy(buf, u, sizeof(uint32_t)); + +while((nxt = v>>7)) + { + *(pnt++) = (v&0x7f) | 0x80; + v = nxt; + } +*(pnt++) = (v&0x7f); + +len = pnt-buf; +fstFwrite(buf, len, 1, handle); +return(len); +} +#else +static int fstWriterUint32WithVarint(FILE *handle, uint32_t *u, uint64_t v, const void *dbuf, size_t siz) +{ +uint64_t nxt; +unsigned char buf[10 + sizeof(uint32_t) + siz]; /* gcc extension ok for cygwin */ +unsigned char *pnt = buf + sizeof(uint32_t); +int len; + +memcpy(buf, u, sizeof(uint32_t)); + +while((nxt = v>>7)) + { + *(pnt++) = (v&0x7f) | 0x80; + v = nxt; + } +*(pnt++) = (v&0x7f); +memcpy(pnt, dbuf, siz); + +len = pnt-buf + siz; +fstFwrite(buf, len, 1, handle); +return(len); +} +#endif /***********************/ /*** ***/ @@ -1555,7 +1603,6 @@ size_t len; if((xc) && (handle <= xc->maxhandle)) { - uint32_t prev_chg; uint32_t fpos; uint32_t *vm4ip; @@ -1573,14 +1620,15 @@ if((xc) && (handle <= xc->maxhandle)) if(!xc->is_initial_time) { - prev_chg = vm4ip[2]; fpos = xc->vchn_siz; - - fstFwrite(&prev_chg, 1, sizeof(uint32_t), xc->vchn_handle); - xc->vchn_siz += 4; - xc->vchn_siz += fstWriterVarint(xc->vchn_handle, xc->tchn_idx - vm4ip[3]); - fstFwrite(buf, len, 1, xc->vchn_handle); - xc->vchn_siz += len; + /* cygwin runs faster if these writes are combined, so the new fstWriterUint32WithVarint function, but should help with regular */ +#ifndef FST_USE_FWRITE_COMBINING + xc->vchn_siz += fstWriterUint32WithVarint(xc->vchn_handle, &vm4ip[2], xc->tchn_idx - vm4ip[3]); /* prev_chg is vm4ip[2] */ + fstFwrite(buf, len, 1, xc->vchn_handle); + xc->vchn_siz += len; +#else + xc->vchn_siz += fstWriterUint32WithVarint(xc->vchn_handle, &vm4ip[2], xc->tchn_idx - vm4ip[3], buf, len); /* do one fwrite op only */ +#endif vm4ip[3] = xc->tchn_idx; vm4ip[2] = fpos; } diff --git a/vpi/sys_display.c b/vpi/sys_display.c index 227edbc22..b8b4a317b 100644 --- a/vpi/sys_display.c +++ b/vpi/sys_display.c @@ -265,7 +265,8 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus, unsigned int ini_size = 512; /* The initial size of the buffer. */ /* Make sure the width fits in the initial buffer. */ - if (width+1 > ini_size) ini_size = width + 1; + assert(width >= -1); + if ((unsigned int)(width+1) > ini_size) ini_size = width + 1; /* The default return value is the full format. */ result = malloc(ini_size*sizeof(char)); diff --git a/vpi/sys_fileio.c b/vpi/sys_fileio.c index eaf688663..0b13f4bb8 100644 --- a/vpi/sys_fileio.c +++ b/vpi/sys_fileio.c @@ -545,7 +545,7 @@ static unsigned fread_word(FILE *fp, vpiHandle word, * my local vector. */ val.format = vpiVectorVal; vpi_get_value(word, &val); - for (bidx = 0; bidx < words; bidx += 1) { + for (bidx = 0; (unsigned)bidx < words; bidx += 1) { vector[bidx].aval = val.value.vector[bidx].aval; vector[bidx].bval = val.value.vector[bidx].bval; } @@ -682,10 +682,11 @@ static PLI_INT32 sys_fread_calltf(PLI_BYTE8*name) vector = calloc(words, sizeof(s_vpi_vecval)); bpe = (width+7)/8; + assert(count >= 0); if (is_mem) { unsigned idx; rtn = 0; - for (idx = 0; idx < count; idx += 1) { + for (idx = 0; idx < (unsigned)count; idx += 1) { vpiHandle word; word = vpi_handle_by_index(mem_reg, start+(signed)idx); rtn += fread_word(fp, word, words, bpe, vector); diff --git a/vpi/sys_sdf.c b/vpi/sys_sdf.c index 048c16046..0c8c02760 100644 --- a/vpi/sys_sdf.c +++ b/vpi/sys_sdf.c @@ -71,7 +71,8 @@ void sdf_select_instance(const char*celltype, const char*cellinst) const char*src = cellinst; const char*dp; while ( (dp=strchr(src, '.')) ) { - int len = dp - src; + unsigned len = dp - src; + assert(dp >= src); assert(len < sizeof buffer); strncpy(buffer, src, len); buffer[len] = 0; diff --git a/vvp/Makefile.in b/vvp/Makefile.in index bf55273c1..b68832fdb 100644 --- a/vvp/Makefile.in +++ b/vvp/Makefile.in @@ -59,7 +59,7 @@ all: dep vvp@EXEEXT@ libvpi.a vvp.man clean: rm -f *.o *~ parse.cc parse.h lexor.cc tables.cc - rm -rf dep vvp@EXEEXT@ libvpi.a parse.output vvp.man vvp.pdf vvp.exp + rm -rf dep vvp@EXEEXT@ libvpi.a parse.output vvp.man vvp.ps vvp.pdf vvp.exp distclean: clean rm -f Makefile config.log @@ -152,8 +152,11 @@ vvp.man: $(srcdir)/vvp.man.in ../version.exe ../version.exe `head -1 $(srcdir)/vvp.man.in`'\n' > $@ tail -n +2 $(srcdir)/vvp.man.in >> $@ -vvp.pdf: vvp.man - $(MAN) -t $(srcdir)/vvp.man | $(PS2PDF) - vvp.pdf +vvp.ps: vvp.man + $(MAN) -t ./vvp.man > vvp.ps + +vvp.pdf: vvp.ps + $(PS2PDF) vvp.ps vvp.pdf ifeq (@MINGW32@,yes) ifeq ($(MAN),none) diff --git a/vvp/array.cc b/vvp/array.cc index be0c86ed6..0258a948f 100644 --- a/vvp/array.cc +++ b/vvp/array.cc @@ -769,7 +769,7 @@ static unsigned vpi_array_is_real(vvp_array_t arr) assert(arr->array_count > 0); struct __vpiRealVar*rsig = vpip_realvar_from_handle(arr->nets[0]); if (rsig) { - struct __vpiSignal*vsig = vpip_signal_from_handle(arr->nets[0]); + struct __vpiSignal*vsig = vpip_signal_from_handle(arr->nets[0]); assert(vsig == 0); return 1U; } @@ -1503,7 +1503,6 @@ void vpip_array_word_change(struct __vpiCallback*cb, vpiHandle obj) void vpip_array_change(struct __vpiCallback*cb, vpiHandle obj) { - struct __vpiArray*arr = ARRAY_HANDLE(obj); cb->extra_data = -1; // This is a callback for every element. cb->next = arr->vpi_callbacks; diff --git a/vvp/concat.cc b/vvp/concat.cc index 76a05715c..a2498536d 100644 --- a/vvp/concat.cc +++ b/vvp/concat.cc @@ -69,7 +69,7 @@ void vvp_fun_concat::recv_vec4_pv(vvp_net_ptr_t port, const vvp_vector4_t&bit, vvp_context_t) { assert(bit.size() == wid); - + unsigned pdx = port.port(); if (vwid != wid_[pdx]) { diff --git a/vvp/dff.h b/vvp/dff.h index 2915ee960..3f6372b0d 100644 --- a/vvp/dff.h +++ b/vvp/dff.h @@ -30,7 +30,7 @@ * * port-0: D input * port-1: Clock input - * port-2: Clock Enagle input + * port-2: Clock Enable input * port-3: Asynchronous D input. */ class vvp_dff : public vvp_net_fun_t { diff --git a/vvp/event.cc b/vvp/event.cc index 570755c3e..ca4027fa8 100644 --- a/vvp/event.cc +++ b/vvp/event.cc @@ -51,7 +51,7 @@ void waitable_hooks_s::run_waiting_threads_(vthread_t&threads) vthread_t tmp = threads; if (tmp == 0) return; threads = 0; - + vthread_schedule_list(tmp); } diff --git a/vvp/examples/vector.vvp b/vvp/examples/vector.vvp index dd8071e79..8e249d098 100644 --- a/vvp/examples/vector.vvp +++ b/vvp/examples/vector.vvp @@ -2,7 +2,7 @@ main .scope module, "main"; -T0 %vpi_call 0 0 "$display", "Display the number: %b", 5'b0zx1; +T0 %vpi_call 0 0 "$display", "Display the number: %b", 5'b0zx1; %end; .thread T0; :file_names 2; diff --git a/vvp/opcodes.txt b/vvp/opcodes.txt index 6a2351fae..7ea27d598 100644 --- a/vvp/opcodes.txt +++ b/vvp/opcodes.txt @@ -373,7 +373,7 @@ register to read the repetition count from (signed or unsigned). %evctl/i sets the repetition to an immediate unsigned value. %evctl/c clears the event control information. This is needed if a -%assign/e may be skiped since the %assign/e statements clear the +%assign/e may be skipped since the %assign/e statements clear the event control information and the other %evctl statements assert that this information has been cleared. You can get an assert if this information is not managed correctly. diff --git a/vvp/schedule.h b/vvp/schedule.h index 966a9ee7e..11628ca13 100644 --- a/vvp/schedule.h +++ b/vvp/schedule.h @@ -65,9 +65,9 @@ extern void schedule_assign_array_word(vvp_array_t mem, * Create an event to propagate the output of a net. */ extern void schedule_propagate_plucked_vector(vvp_net_t*ptr, - vvp_time64_t delay, + vvp_time64_t delay, const vvp_vector4_t&val, - unsigned adr, unsigned wid); + unsigned adr, unsigned wid); /* * This is very similar to schedule_assign_vector, but generates an diff --git a/vvp/vpi_mcd.cc b/vvp/vpi_mcd.cc index c6ebb24f8..bf8ced53a 100644 --- a/vvp/vpi_mcd.cc +++ b/vvp/vpi_mcd.cc @@ -65,7 +65,7 @@ void vpip_mcd_init(FILE *log) fd_table[idx].fp = NULL; fd_table[idx].filename = NULL; } - + mcd_table[0].fp = stdout; mcd_table[0].filename = strdup("stdout"); diff --git a/vvp/vpi_vthr_vector.cc b/vvp/vpi_vthr_vector.cc index add5b8321..f65d2de97 100644 --- a/vvp/vpi_vthr_vector.cc +++ b/vvp/vpi_vthr_vector.cc @@ -318,7 +318,7 @@ static void vthr_vec_get_value(vpiHandle ref, s_vpi_value*vp) break; case vpiObjTypeVal: - vp->format = vpiVectorVal; + vp->format = vpiVectorVal; case vpiVectorVal: vp->value.vector = (s_vpi_vecval*) need_result_buf((wid+31)/32*sizeof(s_vpi_vecval), RBUF_VAL); diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 5bc2326fd..e70a366e2 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -972,7 +972,7 @@ bool of_ASSIGN_V0(vthread_t thr, vvp_code_t cp) vvp_net_ptr_t ptr (cp->net, 0); if (bit >= 4) { // If the vector is not a synthetic one, then have the - // scheduler pluck it direcly out of my vector space. + // scheduler pluck it directly out of my vector space. schedule_assign_plucked_vector(ptr, delay, thr->bits4, bit, wid); } else { vvp_vector4_t value = vthread_bits_to_vector(thr, bit, wid); @@ -2078,7 +2078,7 @@ static unsigned long* divide_bits(unsigned long*ap, unsigned long*bp, unsigned w ap[cur_ptr+btop+1]); } - // cur_res is a guestimate of the result this far. It + // cur_res is a guesstimate of the result this far. It // may be 1 too big. (But it will also be >0) Try it, // and if the difference comes out negative, then adjust. diff --git a/vvp/vvp_island.cc b/vvp/vvp_island.cc index b4166d147..1b79d932e 100644 --- a/vvp/vvp_island.cc +++ b/vvp/vvp_island.cc @@ -291,7 +291,7 @@ vvp_island* compile_find_island(const char*island) * * The is a label in the domain outside the island, and the *