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:
parent
a53082176d
commit
da0fb1666f
|
|
@ -135,6 +135,9 @@ class ProcessStatement : public Architecture::Statement {
|
||||||
virtual int emit(ostream&out, Entity*entity, Architecture*arc);
|
virtual int emit(ostream&out, Entity*entity, Architecture*arc);
|
||||||
virtual void dump(ostream&out, int indent =0) const;
|
virtual void dump(ostream&out, int indent =0) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int rewrite_as_always_edge_(Entity*ent, Architecture*arc);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
perm_string iname_;
|
perm_string iname_;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -70,10 +70,109 @@ int ComponentInstantiation::elaborate(Entity*ent, Architecture*arc)
|
||||||
return errors;
|
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 ProcessStatement::elaborate(Entity*ent, Architecture*arc)
|
||||||
{
|
{
|
||||||
int errors = 0;
|
int errors = 0;
|
||||||
|
|
||||||
|
rewrite_as_always_edge_(ent, arc);
|
||||||
|
|
||||||
for (list<SequentialStmt*>::iterator cur = statements_list_.begin()
|
for (list<SequentialStmt*>::iterator cur = statements_list_.begin()
|
||||||
; cur != statements_list_.end() ; ++cur) {
|
; cur != statements_list_.end() ; ++cur) {
|
||||||
errors += (*cur)->elaborate(ent, arc);
|
errors += (*cur)->elaborate(ent, arc);
|
||||||
|
|
|
||||||
|
|
@ -189,6 +189,23 @@ void ExpCharacter::dump(ostream&out, int indent) const
|
||||||
<< " at " << get_fileline() << endl;
|
<< " 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
|
void ExpInteger::dump(ostream&out, int indent) const
|
||||||
{
|
{
|
||||||
out << setw(indent) << "" << "Integer " << value_
|
out << setw(indent) << "" << "Integer " << value_
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,8 @@
|
||||||
# include "expression.h"
|
# include "expression.h"
|
||||||
# include "scope.h"
|
# include "scope.h"
|
||||||
# include <iostream>
|
# include <iostream>
|
||||||
|
# include <typeinfo>
|
||||||
|
# include <cassert>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
|
@ -36,6 +38,36 @@ bool Expression::evaluate(ScopeBase*, int64_t&) const
|
||||||
return false;
|
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)
|
ExpAttribute::ExpAttribute(ExpName*bas, perm_string nam)
|
||||||
: base_(bas), name_(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)
|
ExpInteger::ExpInteger(int64_t val)
|
||||||
: value_(val)
|
: value_(val)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,10 @@ class Expression : public LineInfo {
|
||||||
// cannot be done.
|
// cannot be done.
|
||||||
virtual bool evaluate(ScopeBase*scope, int64_t&val) const;
|
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
|
// This method returns true if the drawn Verilog for this
|
||||||
// expression is a primary. A containing expression can use
|
// expression is a primary. A containing expression can use
|
||||||
// this method to know if it needs to wrap parentheses. This
|
// this method to know if it needs to wrap parentheses. This
|
||||||
|
|
@ -79,7 +83,7 @@ class ExpUnary : public Expression {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ExpUnary(Expression*op1);
|
ExpUnary(Expression*op1);
|
||||||
~ExpUnary();
|
virtual ~ExpUnary() =0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int emit_operand1(ostream&out, Entity*ent, Architecture*arc);
|
int emit_operand1(ostream&out, Entity*ent, Architecture*arc);
|
||||||
|
|
@ -97,7 +101,10 @@ class ExpBinary : public Expression {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ExpBinary(Expression*op1, Expression*op2);
|
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:
|
protected:
|
||||||
|
|
||||||
|
|
@ -137,6 +144,9 @@ class ExpAttribute : public Expression {
|
||||||
ExpAttribute(ExpName*base, perm_string name);
|
ExpAttribute(ExpName*base, perm_string name);
|
||||||
~ExpAttribute();
|
~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);
|
int emit(ostream&out, Entity*ent, Architecture*arc);
|
||||||
void dump(ostream&out, int indent = 0) const;
|
void dump(ostream&out, int indent = 0) const;
|
||||||
|
|
||||||
|
|
@ -155,10 +165,34 @@ class ExpCharacter : public Expression {
|
||||||
bool is_primary(void) const;
|
bool is_primary(void) const;
|
||||||
void dump(ostream&out, int indent = 0) const;
|
void dump(ostream&out, int indent = 0) const;
|
||||||
|
|
||||||
|
char value() const { return value_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
char value_;
|
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 {
|
class ExpInteger : public Expression {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
@ -183,6 +217,8 @@ class ExpLogical : public ExpBinary {
|
||||||
ExpLogical(ExpLogical::fun_t ty, Expression*op1, Expression*op2);
|
ExpLogical(ExpLogical::fun_t ty, Expression*op1, Expression*op2);
|
||||||
~ExpLogical();
|
~ExpLogical();
|
||||||
|
|
||||||
|
inline fun_t logic_fun() const { return fun_; }
|
||||||
|
|
||||||
int emit(ostream&out, Entity*ent, Architecture*arc);
|
int emit(ostream&out, Entity*ent, Architecture*arc);
|
||||||
void dump(ostream&out, int indent = 0) const;
|
void dump(ostream&out, int indent = 0) const;
|
||||||
|
|
||||||
|
|
@ -207,6 +243,7 @@ class ExpName : public Expression {
|
||||||
int emit(ostream&out, Entity*ent, Architecture*arc);
|
int emit(ostream&out, Entity*ent, Architecture*arc);
|
||||||
bool is_primary(void) const;
|
bool is_primary(void) const;
|
||||||
bool evaluate(ScopeBase*scope, int64_t&val) const;
|
bool evaluate(ScopeBase*scope, int64_t&val) const;
|
||||||
|
bool symbolic_compare(const Expression*that) const;
|
||||||
void dump(ostream&out, int indent = 0) const;
|
void dump(ostream&out, int indent = 0) const;
|
||||||
const char* name() const;
|
const char* name() const;
|
||||||
|
|
||||||
|
|
@ -230,6 +267,8 @@ class ExpRelation : public ExpBinary {
|
||||||
public:
|
public:
|
||||||
enum fun_t { EQ, LT, GT, NEQ, LE, GE };
|
enum fun_t { EQ, LT, GT, NEQ, LE, GE };
|
||||||
|
|
||||||
|
inline fun_t relation_fun(void) const { return fun_; }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ExpRelation(ExpRelation::fun_t ty, Expression*op1, Expression*op2);
|
ExpRelation(ExpRelation::fun_t ty, Expression*op1, Expression*op2);
|
||||||
~ExpRelation();
|
~ExpRelation();
|
||||||
|
|
|
||||||
|
|
@ -118,6 +118,25 @@ bool ExpCharacter::is_primary(void) const
|
||||||
return true;
|
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*)
|
int ExpInteger::emit(ostream&out, Entity*, Architecture*)
|
||||||
{
|
{
|
||||||
out << value_;
|
out << value_;
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,33 @@ IfSequential::IfSequential(Expression*cond, std::list<SequentialStmt*>*tr,
|
||||||
IfSequential::~IfSequential()
|
IfSequential::~IfSequential()
|
||||||
{
|
{
|
||||||
delete cond_;
|
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)
|
SignalSeqAssignment::SignalSeqAssignment(Expression*sig, std::list<Expression*>*wav)
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,13 @@ class IfSequential : public SequentialStmt {
|
||||||
int emit(ostream&out, Entity*entity, Architecture*arc);
|
int emit(ostream&out, Entity*entity, Architecture*arc);
|
||||||
void dump(ostream&out, int indent) const;
|
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:
|
private:
|
||||||
Expression*cond_;
|
Expression*cond_;
|
||||||
std::list<SequentialStmt*> if_;
|
std::list<SequentialStmt*> if_;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue