From 22ab8e4a76d29cfd55a87de414f5e15e075b2648 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Mon, 30 May 2011 19:17:40 -0700 Subject: [PATCH] Elaboration of r-value expressions R-value expressions are more general then L-value expressions, in that the expression type may be a bit more complex. If the R-value expression is part of an assignment, then elaborate with the constrained type from the L-value. In other cases, where the expression type is not as obvious, use expression type probes to figure out the type of the expression and elaborate using that calculated type. --- vhdlpp/architec_elaborate.cc | 2 - vhdlpp/expression.cc | 6 +++ vhdlpp/expression.h | 28 +++++++++++ vhdlpp/expression_elaborate.cc | 88 ++++++++++++++++++++++++++++++++++ vhdlpp/expression_emit.cc | 34 ++++++++++++- vhdlpp/sequential_elaborate.cc | 19 ++++++++ vhdlpp/vsignal.h | 2 + 7 files changed, 176 insertions(+), 3 deletions(-) diff --git a/vhdlpp/architec_elaborate.cc b/vhdlpp/architec_elaborate.cc index 7c1729380..6573ad751 100644 --- a/vhdlpp/architec_elaborate.cc +++ b/vhdlpp/architec_elaborate.cc @@ -145,8 +145,6 @@ int ProcessStatement::rewrite_as_always_edge_(Entity*ent, Architecture*arc) // And we can convert it to: // always @(edge ) ... - cerr << get_fileline() << ": XXXX: Found an always @(posedge) pattern?" << endl; - // Replace the sensitivity expression with an edge expression. ExpEdge*edge = new ExpEdge(op2b->value()=='1'? ExpEdge::POSEDGE : ExpEdge::NEGEDGE, se); assert(sensitivity_list_.size() == 1); diff --git a/vhdlpp/expression.cc b/vhdlpp/expression.cc index 400baef99..912e21a16 100644 --- a/vhdlpp/expression.cc +++ b/vhdlpp/expression.cc @@ -33,6 +33,12 @@ Expression::~Expression() { } +void Expression::set_type(const VType*typ) +{ + assert(type_ == 0); + type_ = typ; +} + bool Expression::evaluate(ScopeBase*, int64_t&) const { return false; diff --git a/vhdlpp/expression.h b/vhdlpp/expression.h index c550005a6..c04b17bfb 100644 --- a/vhdlpp/expression.h +++ b/vhdlpp/expression.h @@ -26,6 +26,7 @@ class Entity; class Architecture; class ScopeBase; +class VType; class ExpName; @@ -47,6 +48,22 @@ class Expression : public LineInfo { // flags needed to indicate their status as writable variables. virtual int elaborate_lval(Entity*ent, Architecture*arc); + // This virtual method probes the expression to get the most + // constrained type for the expression. For a given instance, + // this may be called before the elaborate_expr method. + virtual const VType*probe_type(Entity*ent, Architecture*arc) const; + + // This virtual method elaborates an expression. The ltype is + // the type of the lvalue expression, if known, and can be + // used to calculate the type for the expression being + // elaborated. + virtual int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype); + + // Return the type that this expression would be if it were an + // l-value. This should only be called after elaborate_lval is + // called and only if elaborate_lval succeeded. + inline const VType*peek_type(void) const { return type_; } + // The emit virtual method is called by architecture emit to // output the generated code for the expression. The derived // class fills in the details of what exactly happened. @@ -72,7 +89,11 @@ class Expression : public LineInfo { // Debug dump of the expression. virtual void dump(ostream&out, int indent = 0) const =0; + protected: + void set_type(const VType*); + private: + const VType*type_; private: // Not implemented Expression(const Expression&); @@ -108,6 +129,7 @@ class ExpBinary : public Expression { protected: + int elaborate_exprs(Entity*, Architecture*, const VType*); int emit_operand1(ostream&out, Entity*ent, Architecture*arc); int emit_operand2(ostream&out, Entity*ent, Architecture*arc); @@ -161,6 +183,7 @@ class ExpCharacter : public Expression { ExpCharacter(char val); ~ExpCharacter(); + int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype); int emit(ostream&out, Entity*ent, Architecture*arc); bool is_primary(void) const; void dump(ostream&out, int indent = 0) const; @@ -240,6 +263,8 @@ class ExpName : public Expression { public: // Base methods int elaborate_lval(Entity*ent, Architecture*arc); + const VType* probe_type(Entity*ent, Architecture*arc) const; + int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype); int emit(ostream&out, Entity*ent, Architecture*arc); bool is_primary(void) const; bool evaluate(ScopeBase*scope, int64_t&val) const; @@ -259,6 +284,7 @@ class ExpNameALL : public ExpName { public: int elaborate_lval(Entity*ent, Architecture*arc); + const VType* probe_type(Entity*ent, Architecture*arc) const; void dump(ostream&out, int indent =0) const; }; @@ -273,6 +299,8 @@ class ExpRelation : public ExpBinary { ExpRelation(ExpRelation::fun_t ty, Expression*op1, Expression*op2); ~ExpRelation(); + const VType* probe_type(Entity*ent, Architecture*arc) const; + int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype); int emit(ostream&out, Entity*ent, Architecture*arc); void dump(ostream&out, int indent = 0) const; diff --git a/vhdlpp/expression_elaborate.cc b/vhdlpp/expression_elaborate.cc index 9551a3770..0b3082fff 100644 --- a/vhdlpp/expression_elaborate.cc +++ b/vhdlpp/expression_elaborate.cc @@ -21,7 +21,10 @@ # include "expression.h" # include "architec.h" # include "entity.h" +# include "vsignal.h" # include +# include +# include using namespace std; @@ -31,6 +34,11 @@ int Expression::elaborate_lval(Entity*, Architecture*) return 1; } +const VType* Expression::probe_type(Entity*, Architecture*) const +{ + return 0; +} + int ExpName::elaborate_lval(Entity*ent, Architecture*arc) { int errors = 0; @@ -43,6 +51,7 @@ int ExpName::elaborate_lval(Entity*ent, Architecture*arc) } ent->set_declaration_l_value(name_, true); + set_type(cur->type); return errors; } @@ -53,6 +62,7 @@ int ExpName::elaborate_lval(Entity*ent, Architecture*arc) return errors + 1; } + set_type(sig->peek_type()); return errors; } @@ -60,3 +70,81 @@ int ExpNameALL::elaborate_lval(Entity*ent, Architecture*arc) { return Expression::elaborate_lval(ent, arc); } + +int Expression::elaborate_expr(Entity*, Architecture*, const VType*) +{ + cerr << get_fileline() << ": internal error: I don't know how to elaborate expression type=" << typeid(*this).name() << endl; + return 1; +} + +int ExpBinary::elaborate_exprs(Entity*ent, Architecture*arc, const VType*ltype) +{ + int errors = 0; + + errors += operand1_->elaborate_expr(ent, arc, ltype); + errors += operand2_->elaborate_expr(ent, arc, ltype); + return errors; +} + +int ExpCharacter::elaborate_expr(Entity*, Architecture*, const VType*ltype) +{ + assert(ltype != 0); + set_type(ltype); + return 0; +} + +const VType* ExpName::probe_type(Entity*ent, Architecture*arc) const +{ + if (const InterfacePort*cur = ent->find_port(name_)) + return cur->type; + + if (Signal*sig = arc->find_signal(name_)) + return sig->peek_type(); + + cerr << get_fileline() << ": error: Signal/variable " << name_ + << " not found in this context." << endl; + return 0; +} + +int ExpName::elaborate_expr(Entity*, Architecture*, const VType*ltype) +{ + assert(ltype != 0); + + return 0; +} + +const VType* ExpNameALL::probe_type(Entity*, Architecture*) const +{ + return 0; +} + +const VType* ExpRelation::probe_type(Entity*ent, Architecture*arc) const +{ + const VType*type1 = peek_operand1()->probe_type(ent, arc); + const VType*type2 = peek_operand2()->probe_type(ent, arc); + + if (type1 == type2) + return type1; + + if (type1 && !type2) + return type1; + + if (type2 && !type1) + return type2; + + cerr << get_fileline() << ": error: Type mismatch in relation expression." << endl; + return type1; +} + +int ExpRelation::elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype) +{ + int errors = 0; + + if (ltype == 0) { + ltype = probe_type(ent, arc); + } + + assert(ltype != 0); + errors += elaborate_exprs(ent, arc, ltype); + return errors; +} diff --git a/vhdlpp/expression_emit.cc b/vhdlpp/expression_emit.cc index 0b247398e..545c7df08 100644 --- a/vhdlpp/expression_emit.cc +++ b/vhdlpp/expression_emit.cc @@ -17,7 +17,8 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ -# include "expression.h" +# include "expression.h" +# include "vtype.h" # include # include @@ -109,6 +110,37 @@ int ExpArithmetic::emit(ostream&out, Entity*ent, Architecture*arc) int ExpCharacter::emit(ostream&out, Entity*, Architecture*) { + const VType*etype = peek_type(); + + if (const VTypePrimitive*use_type = dynamic_cast(etype)) { + switch (use_type->type()) { + case VTypePrimitive::BOOLEAN: + case VTypePrimitive::BIT: + switch (value_) { + case '0': + case '1': + out << "1'b" << value_; + return 0; + default: + break; + } + break; + + case VTypePrimitive::STDLOGIC: + switch (value_) { + case '0': + case '1': + out << "1'b" << value_; + return 0; + default: + break; + } + + default: + return 1; + } + } + out << "\"" << value_ << "\""; return 0; } diff --git a/vhdlpp/sequential_elaborate.cc b/vhdlpp/sequential_elaborate.cc index 9515943ae..6bc027f8f 100644 --- a/vhdlpp/sequential_elaborate.cc +++ b/vhdlpp/sequential_elaborate.cc @@ -29,6 +29,8 @@ int IfSequential::elaborate(Entity*ent, Architecture*arc) { int errors = 0; + errors += cond_->elaborate_expr(ent, arc, 0); + for (list::iterator cur = if_.begin() ; cur != if_.end() ; ++cur) { errors += (*cur)->elaborate(ent, arc); @@ -46,7 +48,24 @@ int SignalSeqAssignment::elaborate(Entity*ent, Architecture*arc) { int errors = 0; + // Elaborate the l-value expression. errors += lval_->elaborate_lval(ent, arc); + // The elaborate_lval should have resolved the type of the + // l-value expression. We'll use that type to elaborate the + // r-value. + const VType*lval_type = lval_->peek_type(); + if (lval_type == 0) { + if (errors == 0) errors += 1; + return errors; + } + + // Elaborate the r-value expressions. + for (list::iterator cur = waveform_.begin() + ; cur != waveform_.end() ; ++cur) { + + errors += (*cur)->elaborate_expr(ent, arc, lval_type); + } + return errors; } diff --git a/vhdlpp/vsignal.h b/vhdlpp/vsignal.h index 0a604db6f..8baf7a90f 100644 --- a/vhdlpp/vsignal.h +++ b/vhdlpp/vsignal.h @@ -32,6 +32,8 @@ class Signal : public LineInfo { Signal(perm_string name, const VType*type); ~Signal(); + const VType* peek_type(void) const { return type_; } + int emit(ostream&out, Entity*ent, Architecture*arc); void dump(ostream&out, int indent = 0) const;