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 void dump(ostream&out, int indent =0) const;
|
||||
|
||||
private:
|
||||
int rewrite_as_always_edge_(Entity*ent, Architecture*arc);
|
||||
|
||||
private:
|
||||
perm_string iname_;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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_
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
|
|
|
|||
Loading…
Reference in New Issue