Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

276 lines (230 sloc) 6.551 kb
/*
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: synth.cc,v 1.4 1999/12/05 02:24:09 steve Exp $"
#endif
/*
* The synth function searches the behavioral description for
* patterns that are known to represent LPM library components. This
* is especially interesting for the sequential components such as
* flip flops and latches. As threads are transformed into components,
* the design is rewritten.
*/
# include "functor.h"
# include "netlist.h"
/*
* This transform recognizes the following patterns:
*
* always @(posedge CLK) Q = D
* always @(negedge CLK) Q = D
*
* always @(posedge CLK) if (CE) Q = D;
* always @(negedge CLK) if (CE) Q = D;
*
* These are memory assignments:
*
* always @(posedge CLK) M[a] = D
* always @(negedge CLK) M[a] = D
*
* always @(posedge CLK) if (CE) M[a] = D;
* always @(negedge CLK) if (CE) M[a] = D;
*
* The r-value of the assignments must be identifiers (i.e. wires or
* registers) and the CE must be single-bit identifiers. The generated
* device will be wide enough to accomodate Q and D.
*/
class match_dff : public proc_match_t {
public:
match_dff(Design*d, NetProcTop*t)
: des_(d), top_(t), pclk_(0), nclk_(0), con_(0), ce_(0),
asn_(0), asm_(0), d_(0)
{ }
~match_dff() { }
void make_it();
private:
void make_dff_();
void make_ram_();
virtual int assign(NetAssign*);
virtual int assign_mem(NetAssignMem*);
virtual int condit(NetCondit*);
virtual int pevent(NetPEvent*);
Design*des_;
NetProcTop*top_;
NetPEvent*pclk_;
NetNEvent*nclk_;
NetCondit *con_;
NetNet*ce_;
NetAssign *asn_;
NetAssignMem*asm_;
NetNet*d_;
};
int match_dff::assign(NetAssign*as)
{
if (!pclk_)
return 0;
if (asn_ || asm_)
return 0;
asn_ = as;
d_ = asn_->rval()->synthesize(des_);
if (d_ == 0)
return 0;
return 1;
}
int match_dff::assign_mem(NetAssignMem*as)
{
if (!pclk_)
return 0;
if (asn_ || asm_)
return 0;
asm_ = as;
d_ = asm_->rval()->synthesize(des_);
if (d_ == 0)
return 0;
return 1;
}
int match_dff::condit(NetCondit*co)
{
if (!pclk_)
return 0;
if (con_ || asn_ || asm_)
return 0;
con_ = co;
if (con_->else_clause())
return 0;
ce_ = con_->expr()->synthesize(des_);
if (ce_ == 0)
return 0;
return con_->if_clause()->match_proc(this);
}
int match_dff::pevent(NetPEvent*pe)
{
if (pclk_ || con_ || asn_ || asm_)
return 0;
pclk_ = pe;
// ... there must be a single event source, ...
svector<class NetNEvent*>*neb = pclk_->back_list();
if (neb == 0)
return 0;
if (neb->count() != 1) {
delete neb;
return 0;
}
nclk_ = (*neb)[0];
delete neb;
return pclk_->statement()->match_proc(this);
}
void match_dff::make_it()
{
if (asn_) {
assert(asm_ == 0);
make_dff_();
} else {
assert(asm_);
make_ram_();
}
}
void match_dff::make_dff_()
{
NetFF*ff = new NetFF(asn_->name(), asn_->pin_count());
for (unsigned idx = 0 ; idx < ff->width() ; idx += 1) {
connect(ff->pin_Data(idx), d_->pin(idx));
connect(ff->pin_Q(idx), asn_->pin(idx));
}
connect(ff->pin_Clock(), nclk_->pin(0));
if (ce_) connect(ff->pin_Enable(), ce_->pin(0));
ff->attribute("LPM_FFType", "DFF");
if (nclk_->type() == NetNEvent::NEGEDGE)
ff->attribute("Clock:LPM_Polarity", "INVERT");
des_->add_node(ff);
}
void match_dff::make_ram_()
{
NetMemory*mem = asm_->memory();
NetNet*adr = asm_->index();
NetRamDq*ram = new NetRamDq(des_->local_symbol(mem->name()), mem,
adr->pin_count());
for (unsigned idx = 0 ; idx < adr->pin_count() ; idx += 1)
connect(adr->pin(idx), ram->pin_Address(idx));
for (unsigned idx = 0 ; idx < ram->width() ; idx += 1)
connect(ram->pin_Data(idx), d_->pin(idx));
if (ce_)
connect(ram->pin_WE(), ce_->pin(0));
assert(nclk_->type() == NetNEvent::POSEDGE);
connect(ram->pin_InClock(), nclk_->pin(0));
ram->absorb_partners();
des_->add_node(ram);
}
class synth_f : public functor_t {
public:
void process(class Design*, class NetProcTop*);
private:
void proc_always_(class Design*);
NetProcTop*top_;
};
/*
* Look at a process, and divide the problem into always and initial
* threads.
*/
void synth_f::process(class Design*des, class NetProcTop*top)
{
switch (top->type()) {
case NetProcTop::KALWAYS:
top_ = top;
proc_always_(des);
break;
}
}
/*
* An "always ..." statement has been found.
*/
void synth_f::proc_always_(class Design*des)
{
match_dff dff_pat(des, top_);
if (top_->statement()->match_proc(&dff_pat)) {
dff_pat.make_it();
des->delete_process(top_);
return;
}
}
void synth(Design*des)
{
synth_f synth_obj;
des->functor(&synth_obj);
}
/*
* $Log: synth.cc,v $
* Revision 1.4 1999/12/05 02:24:09 steve
* Synthesize LPM_RAM_DQ for writes into memories.
*
* Revision 1.3 1999/12/01 06:06:16 steve
* Redo synth to use match_proc_t scanner.
*
* Revision 1.2 1999/11/02 04:55:34 steve
* Add the synthesize method to NetExpr to handle
* synthesis of expressions, and use that method
* to improve r-value handling of LPM_FF synthesis.
*
* Modify the XNF target to handle LPM_FF objects.
*
* Revision 1.1 1999/11/01 02:07:41 steve
* Add the synth functor to do generic synthesis
* and add the LPM_FF device to handle rows of
* flip-flops.
*
*/
Jump to Line
Something went wrong with that request. Please try again.