diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 7042dc6d8..62c6cfd1f 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -136,7 +136,7 @@ static vhdl_expr *translate_ulong(ivl_expr_t e) static vhdl_expr *translate_delay(ivl_expr_t e) { - return new vhdl_const_time(ivl_expr_delay_val(e), TIME_UNIT_NS); + return scale_time(get_active_entity(), ivl_expr_delay_val(e)); } static vhdl_expr *translate_reduction(support_function_t f, bool neg, @@ -716,7 +716,7 @@ vhdl_expr *translate_time_expr(ivl_expr_t e) vhdl_type integer(VHDL_TYPE_INTEGER); time = time->cast(&integer); - vhdl_expr *ns1 = new vhdl_const_time(1, TIME_UNIT_NS); + vhdl_expr *ns1 = scale_time(get_active_entity(), 1); return new vhdl_binop_expr(time, VHDL_BINOP_MULT, ns1, vhdl_type::time()); } diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index e98bd9120..fe45e5722 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -839,6 +839,10 @@ static void create_skeleton_entity_for(ivl_scope_t scope, int depth) vhdl_arch *arch = new vhdl_arch(tname, "FromVerilog"); vhdl_entity *ent = new vhdl_entity(tname, arch, depth); + // Calculate the VHDL units to use for time values + ent->set_time_units(ivl_scope_time_units(scope), + ivl_scope_time_precision(scope)); + // Build a comment to add to the entity/architecture ostringstream ss; ss << "Generated from Verilog module " << ivl_scope_tname(scope) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 1c6093099..f0a5efdb2 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -494,7 +494,7 @@ static int draw_delay(vhdl_procedural *proc, stmt_container *container, vhdl_expr *time; if (ivl_statement_type(stmt) == IVL_ST_DELAY) { uint64_t value = ivl_stmt_delay_val(stmt); - time = new vhdl_const_time(value, TIME_UNIT_NS); + time = scale_time(get_active_entity(), value); } else { time = translate_time_expr(ivl_stmt_delay_expr(stmt)); diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index c674e8a0c..cfb181871 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -101,7 +101,8 @@ vhdl_scope *vhdl_scope::get_parent() const } vhdl_entity::vhdl_entity(const string& name, vhdl_arch *arch, int depth__) - : depth(depth__), name_(name), arch_(arch) + : depth(depth__), name_(name), arch_(arch), + time_unit_(TIME_UNIT_NS) { arch->get_scope()->set_parent(&ports_); } @@ -142,6 +143,28 @@ void vhdl_entity::emit(std::ostream &of, int level) const arch_->emit(of, level); } +// Return a VHDL time constant scaled to the correct time scale +// for this entity +vhdl_const_time* scale_time(const vhdl_entity* ent, uint64_t t) +{ + return new vhdl_const_time(t, ent->time_unit_); +} + +// Work out the best VHDL units to use given the Verilog timescale +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) + time_unit_ = TIME_UNIT_US; + else if (vhdl_units >= -9) + time_unit_ = TIME_UNIT_NS; + else + time_unit_ = TIME_UNIT_PS; +} + vhdl_arch::~vhdl_arch() { @@ -652,8 +675,10 @@ void vhdl_const_time::emit(std::ostream &of, int level) const { of << dec << value_; switch (units_) { - case TIME_UNIT_NS: - of << " ns"; + case TIME_UNIT_PS: of << " ps"; break; + case TIME_UNIT_NS: of << " ns"; break; + case TIME_UNIT_US: of << " us"; break; + case TIME_UNIT_MS: of << " ms"; break; } } diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index a7e5dc43f..326f70084 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -203,7 +203,10 @@ private: }; enum time_unit_t { + TIME_UNIT_PS, TIME_UNIT_NS, + TIME_UNIT_US, + TIME_UNIT_MS, }; class vhdl_const_time : public vhdl_expr { @@ -837,6 +840,9 @@ public: const std::string &get_name() const { return name_; } vhdl_scope *get_scope() { return &ports_; } + + 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 @@ -846,6 +852,10 @@ 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_; }; typedef std::list entity_list_t;