Detect always @edge patterns

VHDL doesn't have a direct way to express "always @(posedge...)"
statements, but we do want to detect common paradigms that naturally
translate. This makes for a better translation.
This commit is contained in:
Stephen Williams 2011-05-28 10:49:33 -07:00
parent a53082176d
commit da0fb1666f
8 changed files with 254 additions and 2 deletions

View File

@ -135,6 +135,9 @@ class ProcessStatement : public Architecture::Statement {
virtual int emit(ostream&out, Entity*entity, Architecture*arc);
virtual void dump(ostream&out, int indent =0) const;
private:
int rewrite_as_always_edge_(Entity*ent, Architecture*arc);
private:
perm_string iname_;

View File

@ -70,10 +70,109 @@ int ComponentInstantiation::elaborate(Entity*ent, Architecture*arc)
return errors;
}
/*
* This method attempts to rewrite the process content as an
* always-@(n-edge <expr>) version of the same statement. This makes
* for a more natural translation to verilog, if it comes to that.
*/
int ProcessStatement::rewrite_as_always_edge_(Entity*ent, Architecture*arc)
{
// If thare are multiple sensitivity expressions, I give up.
if (sensitivity_list_.size() != 1)
return -1;
// If there are multiple statements, I give up.
if (statements_list_.size() != 1)
return -1;
Expression*se = sensitivity_list_.front();
SequentialStmt*stmt_raw = statements_list_.front();
// If the statement is not an if-statement, I give up.
IfSequential*stmt = dynamic_cast<IfSequential*> (stmt_raw);
if (stmt == 0)
return -1;
const Expression*ce_raw = stmt->peek_condition();
// We expect the condition to be <name>'event AND <name>='1'.
// If it's not a logical AND, I give up.
const ExpLogical*ce = dynamic_cast<const ExpLogical*> (ce_raw);
if (ce == 0)
return -1;
if (ce->logic_fun() != ExpLogical::AND)
return -1;
const Expression*op1_raw = ce->peek_operand1();
const Expression*op2_raw = ce->peek_operand2();
if (dynamic_cast<const ExpAttribute*>(op2_raw)) {
const Expression*tmp = op1_raw;
op1_raw = op2_raw;
op2_raw = tmp;
}
// If operand1 is not an 'event attribute, I give up.
const ExpAttribute*op1 = dynamic_cast<const ExpAttribute*>(op1_raw);
if (op1 == 0)
return -1;
if (op1->peek_attribute() != "event")
return -1;
const ExpRelation*op2 = dynamic_cast<const ExpRelation*>(op2_raw);
if (op2 == 0)
return -1;
if (op2->relation_fun() != ExpRelation::EQ)
return -1;
const Expression*op2a_raw = op2->peek_operand1();
const Expression*op2b_raw = op2->peek_operand2();
if (dynamic_cast<const ExpCharacter*>(op2a_raw)) {
const Expression*tmp = op2b_raw;
op2b_raw = op2a_raw;
op2a_raw = tmp;
}
if (! se->symbolic_compare(op1->peek_base()))
return -1;
const ExpCharacter*op2b = dynamic_cast<const ExpCharacter*>(op2b_raw);
if (op2b->value() != '1' && op2b->value() != '0')
return -1;
// We've matched this pattern:
// process (<se>) if (<se>'event and <se> = <op2b>) then ...
// 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);
sensitivity_list_.pop_front();
sensitivity_list_.push_front(edge);
assert(statements_list_.size() == 1);
statements_list_.pop_front();
stmt->extract_true(statements_list_);
std::list<SequentialStmt*> tmp;
stmt->extract_false(tmp);
assert(tmp.size() == 0);
delete stmt;
return 0;
}
int ProcessStatement::elaborate(Entity*ent, Architecture*arc)
{
int errors = 0;
rewrite_as_always_edge_(ent, arc);
for (list<SequentialStmt*>::iterator cur = statements_list_.begin()
; cur != statements_list_.end() ; ++cur) {
errors += (*cur)->elaborate(ent, arc);

View File

@ -189,6 +189,23 @@ void ExpCharacter::dump(ostream&out, int indent) const
<< " at " << get_fileline() << endl;
}
void ExpEdge::dump(ostream&out, int indent) const
{
out << setw(indent) << "";
switch (fun_) {
case NEGEDGE:
out << "negedge ";
break;
case ANYEDGE:
out << "ANYedge ";
break;
case POSEDGE:
out << "posedge ";
}
out << "at " << get_fileline() << endl;
dump_operand1(out, indent+3);
}
void ExpInteger::dump(ostream&out, int indent) const
{
out << setw(indent) << "" << "Integer " << value_

View File

@ -20,6 +20,8 @@
# include "expression.h"
# include "scope.h"
# include <iostream>
# include <typeinfo>
# include <cassert>
using namespace std;
@ -36,6 +38,36 @@ bool Expression::evaluate(ScopeBase*, int64_t&) const
return false;
}
bool Expression::symbolic_compare(const Expression*) const
{
cerr << get_fileline() << ": internal error: "
<< "symbolic_compare() method not implemented "
<< "for " << typeid(*this).name() << endl;
return false;
}
bool ExpName::symbolic_compare(const Expression*that) const
{
const ExpName*that_name = dynamic_cast<const ExpName*> (that);
if (that_name == 0)
return false;
if (name_ != that_name->name_)
return false;
if (that_name->index_ && !index_)
return false;
if (index_ && !that_name->index_)
return false;
if (index_) {
assert(that_name->index_);
return index_->symbolic_compare(that_name->index_);
}
return true;
}
ExpAttribute::ExpAttribute(ExpName*bas, perm_string nam)
: base_(bas), name_(nam)
{
@ -137,6 +169,15 @@ ExpCharacter::~ExpCharacter()
{
}
ExpEdge::ExpEdge(ExpEdge::fun_t typ, Expression*op)
: ExpUnary(op), fun_(typ)
{
}
ExpEdge::~ExpEdge()
{
}
ExpInteger::ExpInteger(int64_t val)
: value_(val)
{

View File

@ -58,6 +58,10 @@ class Expression : public LineInfo {
// cannot be done.
virtual bool evaluate(ScopeBase*scope, int64_t&val) const;
// The symbolic compare returns true if the two expressions
// are equal without actually calculating the value.
virtual bool symbolic_compare(const Expression*that) const;
// This method returns true if the drawn Verilog for this
// expression is a primary. A containing expression can use
// this method to know if it needs to wrap parentheses. This
@ -79,7 +83,7 @@ class ExpUnary : public Expression {
public:
ExpUnary(Expression*op1);
~ExpUnary();
virtual ~ExpUnary() =0;
protected:
int emit_operand1(ostream&out, Entity*ent, Architecture*arc);
@ -97,7 +101,10 @@ class ExpBinary : public Expression {
public:
ExpBinary(Expression*op1, Expression*op2);
~ExpBinary();
virtual ~ExpBinary() =0;
const Expression* peek_operand1(void) const { return operand1_; }
const Expression* peek_operand2(void) const { return operand2_; }
protected:
@ -137,6 +144,9 @@ class ExpAttribute : public Expression {
ExpAttribute(ExpName*base, perm_string name);
~ExpAttribute();
inline perm_string peek_attribute() const { return name_; }
inline const ExpName* peek_base() const { return base_; }
int emit(ostream&out, Entity*ent, Architecture*arc);
void dump(ostream&out, int indent = 0) const;
@ -155,10 +165,34 @@ class ExpCharacter : public Expression {
bool is_primary(void) const;
void dump(ostream&out, int indent = 0) const;
char value() const { return value_; }
private:
char value_;
};
/*
* This is a special expression type that represents posedge/negedge
* expressions in sensitivity lists.
*/
class ExpEdge : public ExpUnary {
public:
enum fun_t { NEGEDGE, ANYEDGE, POSEDGE };
public:
explicit ExpEdge(ExpEdge::fun_t ty, Expression*op);
~ExpEdge();
inline fun_t edge_fun() const { return fun_; }
int emit(ostream&out, Entity*ent, Architecture*arc);
void dump(ostream&out, int indent = 0) const;
private:
fun_t fun_;
};
class ExpInteger : public Expression {
public:
@ -183,6 +217,8 @@ class ExpLogical : public ExpBinary {
ExpLogical(ExpLogical::fun_t ty, Expression*op1, Expression*op2);
~ExpLogical();
inline fun_t logic_fun() const { return fun_; }
int emit(ostream&out, Entity*ent, Architecture*arc);
void dump(ostream&out, int indent = 0) const;
@ -207,6 +243,7 @@ class ExpName : public Expression {
int emit(ostream&out, Entity*ent, Architecture*arc);
bool is_primary(void) const;
bool evaluate(ScopeBase*scope, int64_t&val) const;
bool symbolic_compare(const Expression*that) const;
void dump(ostream&out, int indent = 0) const;
const char* name() const;
@ -230,6 +267,8 @@ class ExpRelation : public ExpBinary {
public:
enum fun_t { EQ, LT, GT, NEQ, LE, GE };
inline fun_t relation_fun(void) const { return fun_; }
public:
ExpRelation(ExpRelation::fun_t ty, Expression*op1, Expression*op2);
~ExpRelation();

View File

@ -118,6 +118,25 @@ bool ExpCharacter::is_primary(void) const
return true;
}
int ExpEdge::emit(ostream&out, Entity*ent, Architecture*arc)
{
int errors = 0;
switch (fun_) {
case NEGEDGE:
out << "negedge ";
break;
case POSEDGE:
out << "posedge ";
break;
default:
out << "INVALIDedge ";
errors += 1;
break;
}
errors += emit_operand1(out, ent, arc);
return errors;
}
int ExpInteger::emit(ostream&out, Entity*, Architecture*)
{
out << value_;

View File

@ -39,6 +39,33 @@ IfSequential::IfSequential(Expression*cond, std::list<SequentialStmt*>*tr,
IfSequential::~IfSequential()
{
delete cond_;
while (if_.size() > 0) {
SequentialStmt*cur = if_.front();
if_.pop_front();
delete cur;
}
while (else_.size() > 0) {
SequentialStmt*cur = else_.front();
else_.pop_front();
delete cur;
}
}
void IfSequential::extract_true(std::list<SequentialStmt*>&that)
{
while (if_.size() > 0) {
that.push_back(if_.front());
if_.pop_front();
}
}
void IfSequential::extract_false(std::list<SequentialStmt*>&that)
{
while (else_.size() > 0) {
that.push_back(else_.front());
else_.pop_front();
}
}
SignalSeqAssignment::SignalSeqAssignment(Expression*sig, std::list<Expression*>*wav)

View File

@ -50,6 +50,13 @@ class IfSequential : public SequentialStmt {
int emit(ostream&out, Entity*entity, Architecture*arc);
void dump(ostream&out, int indent) const;
const Expression*peek_condition() const { return cond_; }
// These method extract (and remove) the sub-statements from
// the true or false clause.
void extract_true(std::list<SequentialStmt*>&that);
void extract_false(std::list<SequentialStmt*>&that);
private:
Expression*cond_;
std::list<SequentialStmt*> if_;