@@ -2088,13 +2088,52 @@ struct PopulateNetlist : public TimingPatternInterpretor, public ast::ASTVisitor
20882088
20892089 RTLIL::Cell *cell;
20902090 if (aloads.empty ()) {
2091+ if (clock.edge == ast::EdgeKind::BothEdges) {
2092+ // dual-edge: synthesize via posedge+negedge FFs and mux (ref: https://vlsi-soc.blogspot.com/2013/06/dual-edge-triggered-flip-flop.html)
2093+ for (auto [named_chunk, name] : generate_subfield_names (driven_chunk, type)) {
2094+ std::string var_name = RTLIL::unescape_id (netlist.id (*named_chunk.variable .get_symbol ()));
2095+
2096+ // intermediaries that dont connect directly to output
2097+ std::string pos_wire_name = " $driver$pos$q$" + var_name + name;
2098+ RTLIL::Wire *pos_q = netlist.canvas ->addWire (netlist.canvas ->uniquify (pos_wire_name), named_chunk.bitwidth ());
2099+
2100+ std::string neg_wire_name = " $driver$neg$q$" + var_name + name;
2101+ RTLIL::Wire *neg_q = netlist.canvas ->addWire (netlist.canvas ->uniquify (neg_wire_name), named_chunk.bitwidth ());
2102+
2103+ std::string pos_name = " $driver$pos$" + var_name + name;
2104+ RTLIL::Cell *pos_ff = netlist.canvas ->addDff (netlist.canvas ->uniquify (pos_name),
2105+ timing.triggers [0 ].signal ,
2106+ assigned.extract (named_chunk.base - driven_chunk.base , named_chunk.bitwidth ()),
2107+ pos_q,
2108+ /* edge_polarity=*/ true );
2109+ transfer_attrs (symbol, pos_ff);
2110+
2111+ std::string neg_name = " $driver$neg$" + var_name + name;
2112+ RTLIL::Cell *neg_ff = netlist.canvas ->addDff (netlist.canvas ->uniquify (neg_name),
2113+ timing.triggers [0 ].signal ,
2114+ assigned.extract (named_chunk.base - driven_chunk.base , named_chunk.bitwidth ()),
2115+ neg_q,
2116+ /* edge_polarity=*/ false );
2117+ transfer_attrs (symbol, neg_ff);
2118+
2119+ // mux behavior: A=neg_q (output when clk=0), B=pos_q (output when clk=1), S=clk
2120+ std::string mux_name = " $driver$mux$" + var_name + name;
2121+ RTLIL::Cell *mux = netlist.canvas ->addMux (netlist.canvas ->uniquify (mux_name),
2122+ /* A=*/ neg_q,
2123+ /* B=*/ pos_q,
2124+ /* S=*/ timing.triggers [0 ].signal ,
2125+ /* Y=*/ netlist.convert_static (named_chunk));
2126+ transfer_attrs (symbol, mux);
2127+ }
2128+ } else {
20912129 for (auto [named_chunk, name] : generate_subfield_names (driven_chunk, type)) {
20922130 cell = netlist.canvas ->addDff (netlist.canvas ->uniquify (" $driver$" + RTLIL::unescape_id (netlist.id (*named_chunk.variable .get_symbol ())) + name),
20932131 timing.triggers [0 ].signal ,
20942132 assigned.extract (named_chunk.base - driven_chunk.base , named_chunk.bitwidth ()),
20952133 netlist.convert_static (named_chunk),
20962134 timing.triggers [0 ].edge_polarity );
20972135 transfer_attrs (symbol, cell);
2136+ }
20982137 }
20992138 } else if (aloads.size () == 1 ) {
21002139 VariableBits aldff_q;
@@ -2110,17 +2149,64 @@ struct PopulateNetlist : public TimingPatternInterpretor, public ast::ASTVisitor
21102149 }
21112150
21122151 if (!aldff_q.empty ()) {
2113- for (auto driven_chunk2 : aldff_q.chunks ())
2114- for (auto [named_chunk, name] : generate_subfield_names (driven_chunk2, type)) {
2115- cell = netlist.canvas ->addAldff (netlist.canvas ->uniquify (" $driver$" + RTLIL::unescape_id (netlist.id (*named_chunk.variable .get_symbol ())) + name),
2116- timing.triggers [0 ].signal ,
2117- aloads[0 ].trigger ,
2118- assigned.extract (named_chunk.base - driven_chunk.base , named_chunk.bitwidth ()),
2119- netlist.convert_static (named_chunk),
2120- aloads[0 ].values .evaluate (netlist, named_chunk),
2121- timing.triggers [0 ].edge_polarity ,
2122- aloads[0 ].trigger_polarity );
2123- transfer_attrs (symbol, cell);
2152+ if (clock.edge == ast::EdgeKind::BothEdges) {
2153+ for (auto driven_chunk2 : aldff_q.chunks ())
2154+ for (auto [named_chunk, name] : generate_subfield_names (driven_chunk2, type)) {
2155+ std::string var_name = RTLIL::unescape_id (netlist.id (*named_chunk.variable .get_symbol ()));
2156+
2157+ // intermediaries
2158+ std::string pos_wire_name = " $driver$pos$q$" + var_name + name;
2159+ RTLIL::Wire *pos_q = netlist.canvas ->addWire (netlist.canvas ->uniquify (pos_wire_name), named_chunk.bitwidth ());
2160+
2161+ std::string neg_wire_name = " $driver$neg$q$" + var_name + name;
2162+ RTLIL::Wire *neg_q = netlist.canvas ->addWire (netlist.canvas ->uniquify (neg_wire_name), named_chunk.bitwidth ());
2163+
2164+ // posedge aldff
2165+ std::string pos_name = " $driver$pos$" + var_name + name;
2166+ RTLIL::Cell *pos_ff = netlist.canvas ->addAldff (netlist.canvas ->uniquify (pos_name),
2167+ timing.triggers [0 ].signal ,
2168+ aloads[0 ].trigger ,
2169+ assigned.extract (named_chunk.base - driven_chunk.base , named_chunk.bitwidth ()),
2170+ pos_q,
2171+ aloads[0 ].values .evaluate (netlist, named_chunk),
2172+ /* clk_polarity=*/ true ,
2173+ aloads[0 ].trigger_polarity );
2174+ transfer_attrs (symbol, pos_ff);
2175+
2176+ // negedge aldff
2177+ std::string neg_name = " $driver$neg$" + var_name + name;
2178+ RTLIL::Cell *neg_ff = netlist.canvas ->addAldff (netlist.canvas ->uniquify (neg_name),
2179+ timing.triggers [0 ].signal ,
2180+ aloads[0 ].trigger ,
2181+ assigned.extract (named_chunk.base - driven_chunk.base , named_chunk.bitwidth ()),
2182+ neg_q,
2183+ aloads[0 ].values .evaluate (netlist, named_chunk),
2184+ /* clk_polarity=*/ false ,
2185+ aloads[0 ].trigger_polarity );
2186+ transfer_attrs (symbol, neg_ff);
2187+
2188+ // mux behavior: A=neg_q (output when clk=0), B=pos_q (output when clk=1), S=clk
2189+ std::string mux_name = " $driver$mux$" + var_name + name;
2190+ RTLIL::Cell *mux = netlist.canvas ->addMux (netlist.canvas ->uniquify (mux_name),
2191+ /* A=*/ neg_q,
2192+ /* B=*/ pos_q,
2193+ /* S=*/ timing.triggers [0 ].signal ,
2194+ /* Y=*/ netlist.convert_static (named_chunk));
2195+ transfer_attrs (symbol, mux);
2196+ }
2197+ } else {
2198+ for (auto driven_chunk2 : aldff_q.chunks ())
2199+ for (auto [named_chunk, name] : generate_subfield_names (driven_chunk2, type)) {
2200+ cell = netlist.canvas ->addAldff (netlist.canvas ->uniquify (" $driver$" + RTLIL::unescape_id (netlist.id (*named_chunk.variable .get_symbol ())) + name),
2201+ timing.triggers [0 ].signal ,
2202+ aloads[0 ].trigger ,
2203+ assigned.extract (named_chunk.base - driven_chunk.base , named_chunk.bitwidth ()),
2204+ netlist.convert_static (named_chunk),
2205+ aloads[0 ].values .evaluate (netlist, named_chunk),
2206+ timing.triggers [0 ].edge_polarity ,
2207+ aloads[0 ].trigger_polarity );
2208+ transfer_attrs (symbol, cell);
2209+ }
21242210 }
21252211 }
21262212
0 commit comments