Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Use yacc based synthesizer.

  • Loading branch information...
commit 3c9902d93e431c987cb407d96d0ff3045b6ad2f9 1 parent e5511fd
steve authored
View
1  .cvsignore
@@ -2,6 +2,7 @@ lexor_keyword.cc
parse.h
parse.cc
parse.cc.output
+syn-rules.cc
lexor.cc
ivl
dep
View
7 Makefile.in
@@ -18,7 +18,7 @@
# 59 Temple Place - Suite 330
# 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
@@ -67,7 +67,7 @@ distclean: clean
rm -f Makefile
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 \
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
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
flex -PVL -s -olexor.cc $(srcdir)/lexor.lex
View
9 iverilog.c
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#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
#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"
" -fVPI_MODULE_PATH=%s", base, warning_flags, opath,
- synth_flag?"-Fsynth":"", base);
+ synth_flag?"-Fsynth -Fsyn-rules":"", base);
rc = strlen(tmp);
cmd = realloc(cmd, ncmd+rc+1);
@@ -155,7 +155,7 @@ static int t_xnf(char*cmd, unsigned ncmd)
{
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);
rc = strlen(tmp);
@@ -355,6 +355,9 @@ int main(int argc, char **argv)
/*
* $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
* Parameterize LD lib in C++ command line.
*
View
7 main.cc
@@ -19,7 +19,7 @@ const char COPYRIGHT[] =
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#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
const char NOTICE[] =
@@ -89,6 +89,7 @@ extern Design* elaborate(const map<string,Module*>&modules,
extern void cprop(Design*des);
extern void propinit(Design*des);
extern void synth(Design*des);
+extern void syn_rules(Design*des);
extern void nodangle(Design*des);
extern void xnfio(Design*des);
@@ -101,6 +102,7 @@ static struct net_func_map {
{ "nodangle",&nodangle },
{ "propinit",&propinit },
{ "synth", &synth },
+ { "syn-rules", &syn_rules },
{ "xnfio", &xnfio },
{ 0, 0 }
};
@@ -303,6 +305,9 @@ int main(int argc, char*argv[])
/*
* $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
* no need for nobufz functor.
*
View
350 syn-rules.y
@@ -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*)
+{
+}
View
260 synth.cc
@@ -17,16 +17,9 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#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
-/*
- * 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"
@@ -102,194 +95,6 @@ int do_expr::event_wait(NetEvWait*stmt)
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 {
public:
@@ -297,6 +102,7 @@ class synth_f : public functor_t {
private:
void proc_always_(class Design*);
+ void proc_initial_(class Design*);
NetProcTop*top_;
};
@@ -308,35 +114,28 @@ class synth_f : public functor_t {
*/
void synth_f::process(class Design*des, class NetProcTop*top)
{
+ top_ = top;
switch (top->type()) {
case NetProcTop::KALWAYS:
- top_ = top;
proc_always_(des);
break;
+ case NetProcTop::KINITIAL:
+ proc_initial_(des);
+ break;
}
}
-/*
- * An "always ..." statement has been found.
- */
void synth_f::proc_always_(class Design*des)
{
do_expr expr_pat(des);
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)
{
@@ -346,41 +145,10 @@ void synth(Design*des)
/*
* $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
* 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.
- *
*/
Please sign in to comment.
Something went wrong with that request. Please try again.