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.
This commit is contained in:
Stephen Williams 2011-05-30 19:17:40 -07:00
parent da0fb1666f
commit 22ab8e4a76
7 changed files with 176 additions and 3 deletions

View File

@ -145,8 +145,6 @@ int ProcessStatement::rewrite_as_always_edge_(Entity*ent, Architecture*arc)
// And we can convert it to:
// always @(<N>edge <se>) ...
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);

View File

@ -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;

View File

@ -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;

View File

@ -21,7 +21,10 @@
# include "expression.h"
# include "architec.h"
# include "entity.h"
# include "vsignal.h"
# include <iostream>
# include <typeinfo>
# include <cassert>
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;
}

View File

@ -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 <typeinfo>
# include <iostream>
@ -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<const VTypePrimitive*>(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;
}

View File

@ -29,6 +29,8 @@ int IfSequential::elaborate(Entity*ent, Architecture*arc)
{
int errors = 0;
errors += cond_->elaborate_expr(ent, arc, 0);
for (list<SequentialStmt*>::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<Expression*>::iterator cur = waveform_.begin()
; cur != waveform_.end() ; ++cur) {
errors += (*cur)->elaborate_expr(ent, arc, lval_type);
}
return errors;
}

View File

@ -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;