10
10
#include < memory>
11
11
#include < unordered_set>
12
12
#include < cmath>
13
+ #include < regex>
13
14
14
15
#include " vtr_assert.h"
15
16
#include " vtr_util.h"
@@ -2099,6 +2100,186 @@ class NetlistWriterVisitor : public NetlistVisitor {
2099
2100
struct t_analysis_opts opts_;
2100
2101
};
2101
2102
2103
+ /* *
2104
+ * @brief A class which writes post-synthesis merged netlists (Verilog)
2105
+ *
2106
+ * It implements the NetlistVisitor interface used by NetlistWalker (see netlist_walker.h)
2107
+ */
2108
+ class MergedNetlistWriterVisitor : public NetlistWriterVisitor {
2109
+ public: // Public interface
2110
+ MergedNetlistWriterVisitor (std::ostream& verilog_os, // /<Output stream for verilog netlist
2111
+ std::ostream& blif_os, // /<Output stream for blif netlist
2112
+ std::ostream& sdf_os, // /<Output stream for SDF
2113
+ std::shared_ptr<const AnalysisDelayCalculator> delay_calc)
2114
+ : NetlistWriterVisitor(verilog_os, blif_os, sdf_os, delay_calc) {}
2115
+
2116
+ std::map<std::string, int > portmap;
2117
+
2118
+ void visit_atom_impl (const t_pb* atom) override {
2119
+ auto & atom_ctx = g_vpr_ctx.atom ();
2120
+
2121
+ auto atom_pb = atom_ctx.lookup .pb_atom (atom);
2122
+ if (atom_pb == AtomBlockId::INVALID ()) {
2123
+ return ;
2124
+ }
2125
+ const t_model* model = atom_ctx.nlist .block_model (atom_pb);
2126
+
2127
+ if (model->name == std::string (MODEL_INPUT)) {
2128
+ auto merged_io_name = make_io (atom, PortType::INPUT);
2129
+ if (merged_io_name != " " )
2130
+ inputs_.emplace_back (merged_io_name);
2131
+ } else if (model->name == std::string (MODEL_OUTPUT)) {
2132
+ auto merged_io_name = make_io (atom, PortType::OUTPUT);
2133
+ if (merged_io_name != " " )
2134
+ outputs_.emplace_back (merged_io_name);
2135
+ } else if (model->name == std::string (MODEL_NAMES)) {
2136
+ cell_instances_.push_back (make_lut_instance (atom));
2137
+ } else if (model->name == std::string (MODEL_LATCH)) {
2138
+ cell_instances_.push_back (make_latch_instance (atom));
2139
+ } else if (model->name == std::string (" single_port_ram" )) {
2140
+ cell_instances_.push_back (make_ram_instance (atom));
2141
+ } else if (model->name == std::string (" dual_port_ram" )) {
2142
+ cell_instances_.push_back (make_ram_instance (atom));
2143
+ } else if (model->name == std::string (" multiply" )) {
2144
+ cell_instances_.push_back (make_multiply_instance (atom));
2145
+ } else if (model->name == std::string (" adder" )) {
2146
+ cell_instances_.push_back (make_adder_instance (atom));
2147
+ } else {
2148
+ cell_instances_.push_back (make_blackbox_instance (atom));
2149
+ }
2150
+ }
2151
+
2152
+ /* *
2153
+ * @brief Returns the name of circuit-level Input/Output ports with multi-bit
2154
+ * ports merged into one.
2155
+ *
2156
+ * The I/O is recorded and instantiated by the top level output routines
2157
+ * @param atom The implementation primitive representing the I/O
2158
+ * @param dir The IO direction
2159
+ * @param portmap Map for keeping port names and width
2160
+ */
2161
+ std::string make_io (const t_pb* atom,
2162
+ PortType dir) {
2163
+ const t_pb_graph_node* pb_graph_node = atom->pb_graph_node ;
2164
+
2165
+ std::string io_name;
2166
+ std::string indexed_io_name;
2167
+ int cluster_pin_idx = -1 ;
2168
+ // regex for matching 3 groups:
2169
+ // * 'out:' - optional
2170
+ // * verilog identifier - mandatory
2171
+ // * index - optional
2172
+ std::string rgx = " (out:)?([a-zA-Z$_]+[a-zA-Z0-9$_]*)(\\ [[0-9]+\\ ])?$" ;
2173
+ std::string name (atom->name );
2174
+ std::regex regex (rgx);
2175
+ std::smatch matches;
2176
+
2177
+ if (dir == PortType::INPUT) {
2178
+ VTR_ASSERT (pb_graph_node->num_output_ports == 1 ); // One output port
2179
+ VTR_ASSERT (pb_graph_node->num_output_pins [0 ] == 1 ); // One output pin
2180
+ cluster_pin_idx = pb_graph_node->output_pins [0 ][0 ].pin_count_in_cluster ; // Unique pin index in cluster
2181
+
2182
+ io_name = " " ;
2183
+ indexed_io_name = atom->name ;
2184
+
2185
+ if (std::regex_match (name, matches, regex)) {
2186
+ if (std::find (inputs_.begin (), inputs_.end (), matches[2 ]) == inputs_.end ()) { // Skip already existing multi-bit port names
2187
+ io_name = matches[2 ];
2188
+ portmap[matches[2 ]] = 0 ;
2189
+ } else {
2190
+ portmap[matches[2 ]]++;
2191
+ }
2192
+ }
2193
+
2194
+ } else {
2195
+ VTR_ASSERT (pb_graph_node->num_input_ports == 1 ); // One input port
2196
+ VTR_ASSERT (pb_graph_node->num_input_pins [0 ] == 1 ); // One input pin
2197
+ cluster_pin_idx = pb_graph_node->input_pins [0 ][0 ].pin_count_in_cluster ; // Unique pin index in cluster
2198
+
2199
+ // Strip off the starting 'out:' that vpr adds to uniqify outputs
2200
+ // this makes the port names match the input blif file
2201
+
2202
+ io_name = " " ;
2203
+ indexed_io_name = atom->name + 4 ;
2204
+
2205
+ if (std::regex_search (name, matches, regex)) {
2206
+ if (std::find (outputs_.begin (), outputs_.end (), matches[2 ]) == outputs_.end ()) { // Skip already existing multi-bit port names
2207
+ portmap[matches[2 ]] = 0 ;
2208
+ io_name = matches[2 ];
2209
+ } else {
2210
+ portmap[matches[2 ]]++;
2211
+ }
2212
+ }
2213
+ }
2214
+
2215
+ const auto & top_pb_route = find_top_pb_route (atom);
2216
+
2217
+ if (top_pb_route.count (cluster_pin_idx)) {
2218
+ // Net exists
2219
+ auto atom_net_id = top_pb_route[cluster_pin_idx].atom_net_id ; // Connected net in atom netlist
2220
+
2221
+ // Port direction is inverted (inputs drive internal nets, outputs sink internal nets)
2222
+ PortType wire_dir = (dir == PortType::INPUT) ? PortType::OUTPUT : PortType::INPUT;
2223
+
2224
+ // Look up the tnode associated with this pin (used for delay calculation)
2225
+ tatum::NodeId tnode_id = find_tnode (atom, cluster_pin_idx);
2226
+
2227
+ auto wire_name = make_inst_wire (atom_net_id, tnode_id, indexed_io_name, wire_dir, 0 , 0 );
2228
+
2229
+ // Connect the wires to to I/Os with assign statements
2230
+ if (wire_dir == PortType::INPUT) {
2231
+ assignments_.emplace_back (indexed_io_name, escape_verilog_identifier (wire_name));
2232
+ } else {
2233
+ assignments_.emplace_back (escape_verilog_identifier (wire_name), indexed_io_name);
2234
+ }
2235
+ }
2236
+
2237
+ return io_name;
2238
+ }
2239
+
2240
+ void print_primary_io (int depth) {
2241
+ // Primary Inputs
2242
+ for (auto iter = inputs_.begin (); iter != inputs_.end (); ++iter) {
2243
+ // verilog_os_ << indent(depth + 1) << "input " << escape_verilog_identifier(*iter);
2244
+ std::string range;
2245
+ if (portmap[*iter] > 0 )
2246
+ verilog_os_ << indent (depth + 1 ) << " input [" << portmap[*iter] << " :0] " << *iter;
2247
+ else
2248
+ verilog_os_ << indent (depth + 1 ) << " input " << *iter;
2249
+ if (iter + 1 != inputs_.end () || outputs_.size () > 0 ) {
2250
+ verilog_os_ << " ," ;
2251
+ }
2252
+ verilog_os_ << " \n " ;
2253
+ }
2254
+
2255
+ // Primary Outputs
2256
+ for (auto iter = outputs_.begin (); iter != outputs_.end (); ++iter) {
2257
+ std::string range;
2258
+ if (portmap[*iter] > 0 )
2259
+ verilog_os_ << indent (depth + 1 ) << " output [" << portmap[*iter] << " :0] " << *iter;
2260
+ else
2261
+ verilog_os_ << indent (depth + 1 ) << " output " << *iter;
2262
+ if (iter + 1 != outputs_.end ()) {
2263
+ verilog_os_ << " ," ;
2264
+ }
2265
+ verilog_os_ << " \n " ;
2266
+ }
2267
+ }
2268
+
2269
+ void print_assignments (int depth) {
2270
+ verilog_os_ << " \n " ;
2271
+ verilog_os_ << indent (depth + 1 ) << " //IO assignments\n " ;
2272
+ for (auto & assign : assignments_) {
2273
+ assign.print_merged_verilog (verilog_os_, indent (depth + 1 ));
2274
+ }
2275
+ }
2276
+
2277
+ void finish_impl () override {
2278
+ // Don't write to blif and sdf streams
2279
+ print_verilog ();
2280
+ }
2281
+ };
2282
+
2102
2283
//
2103
2284
// Externally Accessible Functions
2104
2285
//
@@ -2124,6 +2305,23 @@ void netlist_writer(const std::string basename, std::shared_ptr<const AnalysisDe
2124
2305
nl_walker.walk ();
2125
2306
}
2126
2307
2308
+ // /@brief Main routing for this file. See netlist_writer.h for details.
2309
+ void merged_netlist_writer (const std::string basename, std::shared_ptr<const AnalysisDelayCalculator> delay_calc) {
2310
+ std::string verilog_filename = basename + " _merged_post_synthesis.v" ;
2311
+
2312
+ VTR_LOG (" Writing Implementation Netlist: %s\n " , verilog_filename.c_str ());
2313
+
2314
+ std::ofstream verilog_os (verilog_filename);
2315
+ // Don't write blif and sdf, pass dummy streams
2316
+ std::ofstream blif_os;
2317
+ std::ofstream sdf_os;
2318
+
2319
+ MergedNetlistWriterVisitor visitor (verilog_os, blif_os, sdf_os, delay_calc);
2320
+
2321
+ NetlistWalker nl_walker (visitor);
2322
+
2323
+ nl_walker.walk ();
2324
+ }
2127
2325
//
2128
2326
// File-scope function implementations
2129
2327
//
0 commit comments