Use yacc based synthesizer.
This commit is contained in:
parent
e5511fd0a7
commit
3c9902d93e
|
|
@ -2,6 +2,7 @@ lexor_keyword.cc
|
||||||
parse.h
|
parse.h
|
||||||
parse.cc
|
parse.cc
|
||||||
parse.cc.output
|
parse.cc.output
|
||||||
|
syn-rules.cc
|
||||||
lexor.cc
|
lexor.cc
|
||||||
ivl
|
ivl
|
||||||
dep
|
dep
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
# 59 Temple Place - Suite 330
|
# 59 Temple Place - Suite 330
|
||||||
# Boston, MA 02111-1307, USA
|
# Boston, MA 02111-1307, USA
|
||||||
#
|
#
|
||||||
#ident "$Id: Makefile.in,v 1.54 2000/05/12 05:23:15 steve Exp $"
|
#ident "$Id: Makefile.in,v 1.55 2000/05/13 20:55:47 steve Exp $"
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
SHELL = /bin/sh
|
SHELL = /bin/sh
|
||||||
|
|
@ -67,7 +67,7 @@ distclean: clean
|
||||||
rm -f Makefile
|
rm -f Makefile
|
||||||
|
|
||||||
TT = t-null.o t-verilog.o t-vvm.o t-xnf.o
|
TT = t-null.o t-verilog.o t-vvm.o t-xnf.o
|
||||||
FF = nodangle.o propinit.o synth.o xnfio.o
|
FF = nodangle.o propinit.o synth.o syn-rules.o xnfio.o
|
||||||
|
|
||||||
O = main.o cprop.o design_dump.o dup_expr.o elaborate.o elab_expr.o \
|
O = main.o cprop.o design_dump.o dup_expr.o elaborate.o elab_expr.o \
|
||||||
elab_net.o elab_pexpr.o elab_scope.o elab_sig.o emit.o eval.o eval_tree.o \
|
elab_net.o elab_pexpr.o elab_scope.o elab_sig.o emit.o eval.o eval_tree.o \
|
||||||
|
|
@ -119,6 +119,9 @@ parse.h parse.cc: $(srcdir)/parse.y
|
||||||
bison --verbose -t -p VL -d $(srcdir)/parse.y -o parse.cc
|
bison --verbose -t -p VL -d $(srcdir)/parse.y -o parse.cc
|
||||||
mv parse.cc.h parse.h
|
mv parse.cc.h parse.h
|
||||||
|
|
||||||
|
syn-rules.cc: $(srcdir)/syn-rules.y
|
||||||
|
bison --verbose -p syn_ -o syn-rules.cc $(srcdir)/syn-rules.y
|
||||||
|
|
||||||
lexor.cc: $(srcdir)/lexor.lex
|
lexor.cc: $(srcdir)/lexor.lex
|
||||||
flex -PVL -s -olexor.cc $(srcdir)/lexor.lex
|
flex -PVL -s -olexor.cc $(srcdir)/lexor.lex
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||||
*/
|
*/
|
||||||
#if !defined(WINNT)
|
#if !defined(WINNT)
|
||||||
#ident "$Id: iverilog.c,v 1.12 2000/05/09 00:02:13 steve Exp $"
|
#ident "$Id: iverilog.c,v 1.13 2000/05/13 20:55:47 steve Exp $"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
@ -96,7 +96,7 @@ static int t_vvm(char*cmd, unsigned ncmd)
|
||||||
|
|
||||||
sprintf(tmp, " | %s/ivl %s -o %s.cc -tvvm -Fcprop %s -Fnodangle"
|
sprintf(tmp, " | %s/ivl %s -o %s.cc -tvvm -Fcprop %s -Fnodangle"
|
||||||
" -fVPI_MODULE_PATH=%s", base, warning_flags, opath,
|
" -fVPI_MODULE_PATH=%s", base, warning_flags, opath,
|
||||||
synth_flag?"-Fsynth":"", base);
|
synth_flag?"-Fsynth -Fsyn-rules":"", base);
|
||||||
|
|
||||||
rc = strlen(tmp);
|
rc = strlen(tmp);
|
||||||
cmd = realloc(cmd, ncmd+rc+1);
|
cmd = realloc(cmd, ncmd+rc+1);
|
||||||
|
|
@ -155,7 +155,7 @@ static int t_xnf(char*cmd, unsigned ncmd)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
sprintf(tmp, " | %s/ivl %s -o %s -txnf -Fcprop -Fsynth "
|
sprintf(tmp, " | %s/ivl %s -o %s -txnf -Fcprop -Fsynth -Fsyn-rules "
|
||||||
"-Fnodangle -Fxnfio", base, warning_flags, opath);
|
"-Fnodangle -Fxnfio", base, warning_flags, opath);
|
||||||
|
|
||||||
rc = strlen(tmp);
|
rc = strlen(tmp);
|
||||||
|
|
@ -355,6 +355,9 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* $Log: iverilog.c,v $
|
* $Log: iverilog.c,v $
|
||||||
|
* Revision 1.13 2000/05/13 20:55:47 steve
|
||||||
|
* Use yacc based synthesizer.
|
||||||
|
*
|
||||||
* Revision 1.12 2000/05/09 00:02:13 steve
|
* Revision 1.12 2000/05/09 00:02:13 steve
|
||||||
* Parameterize LD lib in C++ command line.
|
* Parameterize LD lib in C++ command line.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
7
main.cc
7
main.cc
|
|
@ -19,7 +19,7 @@ const char COPYRIGHT[] =
|
||||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||||
*/
|
*/
|
||||||
#if !defined(WINNT) && !defined(macintosh)
|
#if !defined(WINNT) && !defined(macintosh)
|
||||||
#ident "$Id: main.cc,v 1.33 2000/05/08 05:29:43 steve Exp $"
|
#ident "$Id: main.cc,v 1.34 2000/05/13 20:55:47 steve Exp $"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const char NOTICE[] =
|
const char NOTICE[] =
|
||||||
|
|
@ -89,6 +89,7 @@ extern Design* elaborate(const map<string,Module*>&modules,
|
||||||
extern void cprop(Design*des);
|
extern void cprop(Design*des);
|
||||||
extern void propinit(Design*des);
|
extern void propinit(Design*des);
|
||||||
extern void synth(Design*des);
|
extern void synth(Design*des);
|
||||||
|
extern void syn_rules(Design*des);
|
||||||
extern void nodangle(Design*des);
|
extern void nodangle(Design*des);
|
||||||
extern void xnfio(Design*des);
|
extern void xnfio(Design*des);
|
||||||
|
|
||||||
|
|
@ -101,6 +102,7 @@ static struct net_func_map {
|
||||||
{ "nodangle",&nodangle },
|
{ "nodangle",&nodangle },
|
||||||
{ "propinit",&propinit },
|
{ "propinit",&propinit },
|
||||||
{ "synth", &synth },
|
{ "synth", &synth },
|
||||||
|
{ "syn-rules", &syn_rules },
|
||||||
{ "xnfio", &xnfio },
|
{ "xnfio", &xnfio },
|
||||||
{ 0, 0 }
|
{ 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
@ -303,6 +305,9 @@ int main(int argc, char*argv[])
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* $Log: main.cc,v $
|
* $Log: main.cc,v $
|
||||||
|
* Revision 1.34 2000/05/13 20:55:47 steve
|
||||||
|
* Use yacc based synthesizer.
|
||||||
|
*
|
||||||
* Revision 1.33 2000/05/08 05:29:43 steve
|
* Revision 1.33 2000/05/08 05:29:43 steve
|
||||||
* no need for nobufz functor.
|
* no need for nobufz functor.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,350 @@
|
||||||
|
|
||||||
|
%{
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2000 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) && !defined(macintosh)
|
||||||
|
#ident "$Id: syn-rules.y,v 1.1 2000/05/13 20:55:47 steve Exp $"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file implements synthesys based on matching threads and
|
||||||
|
* converting them to equivilent devices. The trick here is that the
|
||||||
|
* proc_match_t functor can be used to scan a process and generate a
|
||||||
|
* string of tokens. That string of tokens can then be matched by the
|
||||||
|
* rules to determin what kind of device is to be made.
|
||||||
|
*/
|
||||||
|
|
||||||
|
# include "netlist.h"
|
||||||
|
# include "functor.h"
|
||||||
|
|
||||||
|
struct syn_token_t {
|
||||||
|
int token;
|
||||||
|
|
||||||
|
NetAssign*assign;
|
||||||
|
NetAssignMem*assign_mem;
|
||||||
|
NetProcTop*top;
|
||||||
|
NetEvWait*evwait;
|
||||||
|
NetEvent*event;
|
||||||
|
NetExpr*expr;
|
||||||
|
|
||||||
|
syn_token_t*next_;
|
||||||
|
};
|
||||||
|
#define YYSTYPE syn_token_t*
|
||||||
|
|
||||||
|
static int yylex();
|
||||||
|
static void yyerror(const char*);
|
||||||
|
static Design*des_;
|
||||||
|
|
||||||
|
static void make_DFF_CE(Design*des, NetProcTop*top, NetEvWait*wclk,
|
||||||
|
NetEvent*eclk, NetExpr*cexp, NetAssign*asn);
|
||||||
|
static void make_RAM_CE(Design*des, NetProcTop*top, NetEvWait*wclk,
|
||||||
|
NetEvent*eclk, NetExpr*cexp, NetAssignMem*asn);
|
||||||
|
%}
|
||||||
|
|
||||||
|
%token S_ALWAYS S_ASSIGN S_ASSIGN_MEM S_ELSE S_EVENT S_EXPR S_IF S_INITIAL
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
start
|
||||||
|
|
||||||
|
/* These rules match simple DFF devices. Clocked assignments are
|
||||||
|
simply implemented as DFF, and a CE is easily expressed with a
|
||||||
|
conditional statement. The typical Verilog that get these are:
|
||||||
|
|
||||||
|
always @(posedge CLK) Q = D
|
||||||
|
always @(negedge CLK) Q = D
|
||||||
|
|
||||||
|
always @(posedge CLK) if (CE) Q = D;
|
||||||
|
always @(negedge CLK) if (CE) Q = D;
|
||||||
|
|
||||||
|
The width of Q and D cause a wide register to be created. The
|
||||||
|
code generators generally implement that as an array of
|
||||||
|
flip-flops. */
|
||||||
|
|
||||||
|
: S_ALWAYS '@' '(' S_EVENT ')' S_ASSIGN
|
||||||
|
{ make_DFF_CE(des_, $1->top, $2->evwait, $4->event,
|
||||||
|
0, $6->assign);
|
||||||
|
des_->delete_process($1->top);
|
||||||
|
}
|
||||||
|
|
||||||
|
| S_ALWAYS '@' '(' S_EVENT ')' S_IF S_EXPR S_ASSIGN ';'
|
||||||
|
{ make_DFF_CE(des_, $1->top, $2->evwait, $4->event,
|
||||||
|
$7->expr, $8->assign);
|
||||||
|
des_->delete_process($1->top);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* These rules match RAM devices. They are similar to DFF, except
|
||||||
|
that there is an index for the word. The typical Verilog that get
|
||||||
|
these are:
|
||||||
|
|
||||||
|
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 width of Q and D cause a wide register to be created. The
|
||||||
|
code generators generally implement that as an array of
|
||||||
|
flip-flops. */
|
||||||
|
|
||||||
|
| S_ALWAYS '@' '(' S_EVENT ')' S_ASSIGN_MEM ';'
|
||||||
|
{ make_RAM_CE(des_, $1->top, $2->evwait, $4->event,
|
||||||
|
0, $6->assign_mem);
|
||||||
|
des_->delete_process($1->top);
|
||||||
|
}
|
||||||
|
|
||||||
|
| S_ALWAYS '@' '(' S_EVENT ')' S_IF S_EXPR S_ASSIGN_MEM ';' ';'
|
||||||
|
{ make_RAM_CE(des_, $1->top, $2->evwait, $4->event,
|
||||||
|
$7->expr, $8->assign_mem);
|
||||||
|
des_->delete_process($1->top);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
|
||||||
|
/* Various actions. */
|
||||||
|
static void make_DFF_CE(Design*des, NetProcTop*top, NetEvWait*wclk,
|
||||||
|
NetEvent*eclk, NetExpr*cexp, NetAssign*asn)
|
||||||
|
{
|
||||||
|
NetEvProbe*pclk = eclk->probe(0);
|
||||||
|
NetNet*d = asn->rval()->synthesize(des);
|
||||||
|
NetNet*ce = cexp? cexp->synthesize(des) : 0;
|
||||||
|
|
||||||
|
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(), pclk->pin(0));
|
||||||
|
if (ce) connect(ff->pin_Enable(), ce->pin(0));
|
||||||
|
|
||||||
|
ff->attribute("LPM_FFType", "DFF");
|
||||||
|
if (pclk->edge() == NetEvProbe::NEGEDGE)
|
||||||
|
ff->attribute("Clock:LPM_Polarity", "INVERT");
|
||||||
|
|
||||||
|
des->add_node(ff);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void make_RAM_CE(Design*des, NetProcTop*top, NetEvWait*wclk,
|
||||||
|
NetEvent*eclk, NetExpr*cexp, NetAssignMem*asn)
|
||||||
|
{
|
||||||
|
NetMemory*mem = asn->memory();
|
||||||
|
NetNet*adr = asn->index();
|
||||||
|
|
||||||
|
NetEvProbe*pclk = eclk->probe(0);
|
||||||
|
NetNet*d = asn->rval()->synthesize(des);
|
||||||
|
NetNet*ce = cexp? cexp->synthesize(des) : 0;
|
||||||
|
|
||||||
|
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(pclk->edge() == NetEvProbe::POSEDGE);
|
||||||
|
connect(ram->pin_InClock(), pclk->pin(0));
|
||||||
|
|
||||||
|
ram->absorb_partners();
|
||||||
|
des_->add_node(ram);
|
||||||
|
|
||||||
|
des->add_node(ram);
|
||||||
|
}
|
||||||
|
|
||||||
|
static syn_token_t*first_ = 0;
|
||||||
|
static syn_token_t*last_ = 0;
|
||||||
|
static syn_token_t*ptr_ = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The match class is used to take a process and turn it into a stream
|
||||||
|
* of tokens. This stream is used by the yylex function to feed tokens
|
||||||
|
* to the parser.
|
||||||
|
*/
|
||||||
|
struct tokenize : public proc_match_t {
|
||||||
|
tokenize() { }
|
||||||
|
~tokenize() { }
|
||||||
|
|
||||||
|
int assign(NetAssign*dev)
|
||||||
|
{
|
||||||
|
syn_token_t*cur;
|
||||||
|
cur = new syn_token_t;
|
||||||
|
cur->token = S_ASSIGN;
|
||||||
|
cur->assign = dev;
|
||||||
|
cur->next_ = 0;
|
||||||
|
last_->next_ = cur;
|
||||||
|
last_ = cur;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int assign_mem(NetAssignMem*dev)
|
||||||
|
{
|
||||||
|
syn_token_t*cur;
|
||||||
|
cur = new syn_token_t;
|
||||||
|
cur->token = S_ASSIGN_MEM;
|
||||||
|
cur->assign_mem = dev;
|
||||||
|
cur->next_ = 0;
|
||||||
|
last_->next_ = cur;
|
||||||
|
last_ = cur;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int condit(NetCondit*dev)
|
||||||
|
{
|
||||||
|
syn_token_t*cur;
|
||||||
|
|
||||||
|
cur = new syn_token_t;
|
||||||
|
cur->token = S_IF;
|
||||||
|
cur->next_ = 0;
|
||||||
|
last_->next_ = cur;
|
||||||
|
last_ = cur;
|
||||||
|
|
||||||
|
cur = new syn_token_t;
|
||||||
|
cur->token = S_EXPR;
|
||||||
|
cur->expr = dev->expr();
|
||||||
|
cur->next_ = 0;
|
||||||
|
last_->next_ = cur;
|
||||||
|
last_ = cur;
|
||||||
|
|
||||||
|
dev -> if_clause() -> match_proc(this);
|
||||||
|
|
||||||
|
if (dev->else_clause()) {
|
||||||
|
cur = new syn_token_t;
|
||||||
|
cur->token = S_ELSE;
|
||||||
|
cur->next_ = 0;
|
||||||
|
last_->next_ = cur;
|
||||||
|
last_ = cur;
|
||||||
|
|
||||||
|
dev -> else_clause() -> match_proc(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
cur = new syn_token_t;
|
||||||
|
cur->token = ';';
|
||||||
|
cur->next_ = 0;
|
||||||
|
last_->next_ = cur;
|
||||||
|
last_ = cur;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int event_wait(NetEvWait*dev)
|
||||||
|
{
|
||||||
|
syn_token_t*cur;
|
||||||
|
|
||||||
|
cur = new syn_token_t;
|
||||||
|
cur->token = '@';
|
||||||
|
cur->evwait = dev;
|
||||||
|
cur->next_ = 0;
|
||||||
|
last_->next_ = cur;
|
||||||
|
last_ = cur;
|
||||||
|
|
||||||
|
cur = new syn_token_t;
|
||||||
|
cur->token = '(';
|
||||||
|
cur->next_ = 0;
|
||||||
|
last_->next_ = cur;
|
||||||
|
last_ = cur;
|
||||||
|
|
||||||
|
for (unsigned idx = 0; idx < dev->nevents(); idx += 1) {
|
||||||
|
cur = new syn_token_t;
|
||||||
|
cur->token = S_EVENT;
|
||||||
|
cur->event = dev->event(idx);
|
||||||
|
cur->next_ = 0;
|
||||||
|
last_->next_ = cur;
|
||||||
|
last_ = cur;
|
||||||
|
}
|
||||||
|
|
||||||
|
cur = new syn_token_t;
|
||||||
|
cur->token = ')';
|
||||||
|
cur->next_ = 0;
|
||||||
|
last_->next_ = cur;
|
||||||
|
last_ = cur;
|
||||||
|
|
||||||
|
dev -> statement() -> match_proc(this);
|
||||||
|
|
||||||
|
cur = new syn_token_t;
|
||||||
|
cur->token = ';';
|
||||||
|
cur->next_ = 0;
|
||||||
|
last_->next_ = cur;
|
||||||
|
last_ = cur;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static void syn_start_process(NetProcTop*t)
|
||||||
|
{
|
||||||
|
first_ = new syn_token_t;
|
||||||
|
last_ = first_;
|
||||||
|
ptr_ = first_;
|
||||||
|
|
||||||
|
first_->token = (t->type() == NetProcTop::KALWAYS)? S_ALWAYS : S_INITIAL;
|
||||||
|
first_->top = t;
|
||||||
|
first_->next_ = 0;
|
||||||
|
|
||||||
|
tokenize go;
|
||||||
|
t -> statement() -> match_proc(&go);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void syn_done_process()
|
||||||
|
{
|
||||||
|
while (first_) {
|
||||||
|
syn_token_t*cur = first_;
|
||||||
|
first_ = cur->next_;
|
||||||
|
delete cur;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int yylex()
|
||||||
|
{
|
||||||
|
if (ptr_ == 0) {
|
||||||
|
yylval = 0;
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
yylval = ptr_;
|
||||||
|
ptr_ = ptr_->next_;
|
||||||
|
return yylval->token;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct syn_rules_f : public functor_t {
|
||||||
|
~syn_rules_f() { }
|
||||||
|
|
||||||
|
void process(class Design*des, class NetProcTop*top)
|
||||||
|
{
|
||||||
|
syn_start_process(top);
|
||||||
|
yyparse();
|
||||||
|
syn_done_process();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void syn_rules(Design*d)
|
||||||
|
{
|
||||||
|
des_ = d;
|
||||||
|
syn_rules_f obj;
|
||||||
|
des_->functor(&obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void yyerror(const char*)
|
||||||
|
{
|
||||||
|
}
|
||||||
260
synth.cc
260
synth.cc
|
|
@ -17,16 +17,9 @@
|
||||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||||
*/
|
*/
|
||||||
#if !defined(WINNT) && !defined(macintosh)
|
#if !defined(WINNT) && !defined(macintosh)
|
||||||
#ident "$Id: synth.cc,v 1.9 2000/04/16 22:57:34 steve Exp $"
|
#ident "$Id: synth.cc,v 1.10 2000/05/13 20:55:47 steve Exp $"
|
||||||
#endif
|
#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 "functor.h"
|
||||||
# include "netlist.h"
|
# include "netlist.h"
|
||||||
|
|
||||||
|
|
@ -102,194 +95,6 @@ int do_expr::event_wait(NetEvWait*stmt)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* 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), wclk_(0), eclk_(0), pclk_(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 event_wait(NetEvWait*);
|
|
||||||
|
|
||||||
Design*des_;
|
|
||||||
NetProcTop*top_;
|
|
||||||
|
|
||||||
NetEvWait*wclk_;
|
|
||||||
NetEvent *eclk_;
|
|
||||||
NetEvProbe*pclk_;
|
|
||||||
|
|
||||||
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::event_wait(NetEvWait*evw)
|
|
||||||
{
|
|
||||||
if (evw->nevents() != 1)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
wclk_ = evw;
|
|
||||||
eclk_ = evw->event(0);
|
|
||||||
|
|
||||||
if (eclk_->nprobe() != 1)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
pclk_ = eclk_->probe(0);
|
|
||||||
|
|
||||||
return wclk_->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(), pclk_->pin(0));
|
|
||||||
if (ce_) connect(ff->pin_Enable(), ce_->pin(0));
|
|
||||||
|
|
||||||
ff->attribute("LPM_FFType", "DFF");
|
|
||||||
if (pclk_->edge() == NetEvProbe::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(pclk_->edge() == NetEvProbe::POSEDGE);
|
|
||||||
connect(ram->pin_InClock(), pclk_->pin(0));
|
|
||||||
|
|
||||||
ram->absorb_partners();
|
|
||||||
des_->add_node(ram);
|
|
||||||
}
|
|
||||||
|
|
||||||
class match_block : public proc_match_t {
|
|
||||||
|
|
||||||
public:
|
|
||||||
match_block(Design*d, NetProcTop*t)
|
|
||||||
: des_(d), top_(t)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
~match_block() { }
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
Design*des_;
|
|
||||||
NetProcTop*top_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class synth_f : public functor_t {
|
class synth_f : public functor_t {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
@ -297,6 +102,7 @@ class synth_f : public functor_t {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void proc_always_(class Design*);
|
void proc_always_(class Design*);
|
||||||
|
void proc_initial_(class Design*);
|
||||||
|
|
||||||
NetProcTop*top_;
|
NetProcTop*top_;
|
||||||
};
|
};
|
||||||
|
|
@ -308,35 +114,28 @@ class synth_f : public functor_t {
|
||||||
*/
|
*/
|
||||||
void synth_f::process(class Design*des, class NetProcTop*top)
|
void synth_f::process(class Design*des, class NetProcTop*top)
|
||||||
{
|
{
|
||||||
|
top_ = top;
|
||||||
switch (top->type()) {
|
switch (top->type()) {
|
||||||
case NetProcTop::KALWAYS:
|
case NetProcTop::KALWAYS:
|
||||||
top_ = top;
|
|
||||||
proc_always_(des);
|
proc_always_(des);
|
||||||
break;
|
break;
|
||||||
|
case NetProcTop::KINITIAL:
|
||||||
|
proc_initial_(des);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* An "always ..." statement has been found.
|
|
||||||
*/
|
|
||||||
void synth_f::proc_always_(class Design*des)
|
void synth_f::proc_always_(class Design*des)
|
||||||
{
|
{
|
||||||
do_expr expr_pat(des);
|
do_expr expr_pat(des);
|
||||||
top_->statement()->match_proc(&expr_pat);
|
top_->statement()->match_proc(&expr_pat);
|
||||||
|
|
||||||
match_dff dff_pat(des, top_);
|
|
||||||
if (top_->statement()->match_proc(&dff_pat)) {
|
|
||||||
dff_pat.make_it();
|
|
||||||
des->delete_process(top_);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
match_block block_pat(des, top_);
|
|
||||||
if (top_->statement()->match_proc(&block_pat)) {
|
|
||||||
cerr << "XXXX: recurse and return here" << endl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void synth_f::proc_initial_(class Design*des)
|
||||||
|
{
|
||||||
|
do_expr expr_pat(des);
|
||||||
|
top_->statement()->match_proc(&expr_pat);
|
||||||
|
}
|
||||||
|
|
||||||
void synth(Design*des)
|
void synth(Design*des)
|
||||||
{
|
{
|
||||||
|
|
@ -346,41 +145,10 @@ void synth(Design*des)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* $Log: synth.cc,v $
|
* $Log: synth.cc,v $
|
||||||
|
* Revision 1.10 2000/05/13 20:55:47 steve
|
||||||
|
* Use yacc based synthesizer.
|
||||||
|
*
|
||||||
* Revision 1.9 2000/04/16 22:57:34 steve
|
* Revision 1.9 2000/04/16 22:57:34 steve
|
||||||
* Catch expressions that are part of conditionals.
|
* Catch expressions that are part of conditionals.
|
||||||
*
|
|
||||||
* Revision 1.8 2000/04/12 20:02:53 steve
|
|
||||||
* Finally remove the NetNEvent and NetPEvent classes,
|
|
||||||
* Get synthesis working with the NetEvWait class,
|
|
||||||
* and get started supporting multiple events in a
|
|
||||||
* wait in vvm.
|
|
||||||
*
|
|
||||||
* Revision 1.7 2000/04/02 04:26:07 steve
|
|
||||||
* Remove the useless sref template.
|
|
||||||
*
|
|
||||||
* Revision 1.6 2000/02/23 02:56:55 steve
|
|
||||||
* Macintosh compilers do not support ident.
|
|
||||||
*
|
|
||||||
* Revision 1.5 2000/02/13 04:35:43 steve
|
|
||||||
* Include some block matching from Larry.
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue