1 ///////////////////////////////////////////////////////////////////////////////
2 // BSD 3-Clause License
3 //
4 // Copyright (c) 2021, The Regents of the University of California
5 // All rights reserved.
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions are met:
9 //
10 // * Redistributions of source code must retain the above copyright notice, this
11 //   list of conditions and the following disclaimer.
12 //
13 // * Redistributions in binary form must reproduce the above copyright notice,
14 //   this list of conditions and the following disclaimer in the documentation
15 //   and/or other materials provided with the distribution.
16 //
17 // * Neither the name of the copyright holder nor the names of its
18 //   contributors may be used to endorse or promote products derived from
19 //   this software without specific prior written permission.
20 //
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 // ARE
25 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
26 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 ///////////////////////////////////////////////////////////////////////////////
33 
34 #include <algorithm>
35 #include <fstream>
36 #include <iostream>
37 #include <map>
38 #include <random>
39 #include <sstream>
40 #include <string>
41 #include <unordered_map>
42 #include <vector>
43 
44 #include "block_placement.h"
45 #include "mpl2/rtl_mp.h"
46 #include "pin_alignment.h"
47 #include "shape_engine.h"
48 #include "util.h"
49 #include "utl/Logger.h"
50 
51 using utl::PAR;
52 
53 namespace mpl {
54 using block_placement::Block;
55 using shape_engine::Cluster;
56 using shape_engine::Macro;
57 using std::cout;
58 using std::endl;
59 using std::ofstream;
60 using std::string;
61 using std::to_string;
62 using std::unordered_map;
63 using std::vector;
64 using utl::Logger;
65 using utl::MPL;
66 
67 template <class T>
get_param(const unordered_map<string,string> & params,const char * name,T & param,Logger * logger)68 static void get_param(const unordered_map<string, string>& params,
69                       const char* name,
70                       T& param,
71                       Logger* logger)
72 {
73   auto iter = params.find(name);
74   if (iter != params.end()) {
75     std::istringstream s(iter->second);
76     s >> param;
77   }
78   logger->info(MPL, 9, "RTL_MP  Param: {}: {}", name, param);
79 }
80 
rtl_macro_placer(const char * config_file,Logger * logger,const char * report_directory,const char * report_file)81 bool rtl_macro_placer(const char* config_file,
82                       Logger* logger,
83                       const char* report_directory,
84                       const char* report_file)
85 {
86   logger->report("*** In RTLMP ***");
87 
88   string block_file = string(report_directory) + '/' + report_file + ".block";
89   string net_file = string(report_directory) + '/' + report_file + ".net";
90 
91   // parameters defined in config_file
92   // These parameters are related to shape engine
93   float min_aspect_ratio = 0.33;
94   float dead_space = 0.1;
95   float halo_width = 2.0;
96 
97   string region_file = string("macro_blockage.txt");
98 
99   // These parameters are related to multi-start in shape engine
100   int num_thread = 5;
101   int num_run = 5;
102 
103   unsigned seed = 0;
104 
105   // These parameters are related to "Go with the winner"
106   float heat_rate = 0.5;
107   int num_level = 5;
108   int num_worker = 10;
109 
110   // These parameters are related to cost function
111   float alpha = 0.4;                   // weight for area
112   float beta = 0.3;                    // weight for wirelength
113   float gamma = 0.3;                   // weight for outline penalty
114   float boundary_weight = 0.06;        // weight for pushing macros to boundary
115   float macro_blockage_weight = 0.08;  // weight for macro blockage
116 
117   float learning_rate
118       = 0.01;  // learning rate for dynamic weight in cost function
119   float shrink_factor
120       = 0.995;  // shrink factor for soft blocks in simulated annealing
121   float shrink_freq
122       = 0.01;  // shrink frequency for soft blocks in simulated annealing
123 
124   // These parameters are related to action probabilities in each step
125   float resize_prob = 0.4;
126   float pos_swap_prob = 0.2;
127   float neg_swap_prob = 0.2;
128   float double_swap_prob = 0.2;
129 
130   // These parameters are related to fastSA
131   float init_prob = 0.95;
132   float rej_ratio = 0.95;
133   int k = 50;
134   float c = 100;
135   int max_num_step = 300;
136   int perturb_per_step = 3000;
137 
138   unordered_map<string, string> params = ParseConfigFile(config_file);
139 
140   get_param(params, "min_aspect_ratio", min_aspect_ratio, logger);
141   get_param(params, "dead_space", dead_space, logger);
142   get_param(params, "learning_rate", learning_rate, logger);
143   get_param(params, "shrink_factor", shrink_factor, logger);
144   get_param(params, "shrink_freq", shrink_freq, logger);
145   get_param(params, "halo_width", halo_width, logger);
146   get_param(params, "region_file", region_file, logger);
147   get_param(params, "num_thread", num_thread, logger);
148   get_param(params, "num_run", num_run, logger);
149   get_param(params, "heat_rate", heat_rate, logger);
150   get_param(params, "num_level", num_level, logger);
151   get_param(params, "num_worker", num_worker, logger);
152   get_param(params, "alpha", alpha, logger);
153   get_param(params, "beta", beta, logger);
154   get_param(params, "gamma", gamma, logger);
155   get_param(params, "boundary_weight", boundary_weight, logger);
156   get_param(params, "macro_blockage_weight", macro_blockage_weight, logger);
157   get_param(params, "resize_prob", resize_prob, logger);
158   get_param(params, "pos_swap_prob", pos_swap_prob, logger);
159   get_param(params, "neg_swap_prob", neg_swap_prob, logger);
160   get_param(params, "double_swap_prob", double_swap_prob, logger);
161   get_param(params, "init_prob", init_prob, logger);
162   get_param(params, "rej_ratio", rej_ratio, logger);
163   get_param(params, "k", k, logger);
164   get_param(params, "c", c, logger);
165   get_param(params, "max_num_step", max_num_step, logger);
166   get_param(params, "perturb_per_step", perturb_per_step, logger);
167   get_param(params, "seed", seed, logger);
168 
169   float outline_width = 0.0;
170   float outline_height = 0.0;
171   float outline_lx = 0.0;
172   float outline_ly = 0.0;
173 
174   vector<Cluster*> clusters = shape_engine::ShapeEngine(outline_width,
175                                                         outline_height,
176                                                         outline_lx,
177                                                         outline_ly,
178                                                         min_aspect_ratio,
179                                                         dead_space,
180                                                         halo_width,
181                                                         logger,
182                                                         report_directory,
183                                                         block_file,
184                                                         num_thread,
185                                                         num_run,
186                                                         seed);
187 
188   vector<Block> blocks = block_placement::Floorplan(clusters,
189                                                     logger,
190                                                     outline_width,
191                                                     outline_height,
192                                                     net_file,
193                                                     region_file.c_str(),
194                                                     num_level,
195                                                     num_worker,
196                                                     heat_rate,
197                                                     alpha,
198                                                     beta,
199                                                     gamma,
200                                                     boundary_weight,
201                                                     macro_blockage_weight,
202                                                     resize_prob,
203                                                     pos_swap_prob,
204                                                     neg_swap_prob,
205                                                     double_swap_prob,
206                                                     init_prob,
207                                                     rej_ratio,
208                                                     max_num_step,
209                                                     k,
210                                                     c,
211                                                     perturb_per_step,
212                                                     learning_rate,
213                                                     shrink_factor,
214                                                     shrink_freq,
215                                                     seed);
216 
217   unordered_map<string, int> block_map;
218 
219   for (int i = 0; i < clusters.size(); i++)
220     block_map[blocks[i].GetName()] = i;
221 
222   for (int i = 0; i < clusters.size(); i++) {
223     float x = blocks[block_map[clusters[i]->GetName()]].GetX();
224     float y = blocks[block_map[clusters[i]->GetName()]].GetY();
225     float width = blocks[block_map[clusters[i]->GetName()]].GetWidth();
226     float height = blocks[block_map[clusters[i]->GetName()]].GetHeight();
227     clusters[i]->SetPos(x, y);
228     clusters[i]->SetFootprint(width, height);
229   }
230 
231   bool success_flag = pin_alignment::PinAlignment(
232       clusters, logger, report_directory, halo_width, num_thread, num_run, seed);
233 
234   if (success_flag == false) {
235     logger->report("*** RTLMP Failed ***");
236     return false;
237   }
238 
239 
240   string openroad_filename = string("./") + string(report_directory) + "/macro_placement.cfg";
241   ofstream file;
242   file.open(openroad_filename);
243   for (int i = 0; i < clusters.size(); i++) {
244     if (clusters[i]->GetNumMacro() > 0) {
245       float cluster_lx = clusters[i]->GetX();
246       float cluster_ly = clusters[i]->GetY();
247       vector<Macro> macros = clusters[i]->GetMacros();
248       for (int j = 0; j < macros.size(); j++) {
249         string line = macros[j].GetName();
250         float lx = outline_lx + cluster_lx + macros[j].GetX() + halo_width;
251         float ly = outline_ly + cluster_ly + macros[j].GetY() + halo_width;
252         float width = macros[j].GetWidth() - 2 * halo_width;
253         float height = macros[j].GetHeight() - 2 * halo_width;
254         string orientation = macros[j].GetOrientation();
255 
256         if (orientation == string("MX"))
257           line += string("  MX  ") + to_string(lx) + string("   ")
258                   + to_string(ly + height);
259         else if (orientation == string("MY"))
260           line += string("  MY  ") + to_string(lx + width) + string("   ")
261                   + to_string(ly);
262         else if (orientation == string("R180"))
263           line += string("  R180  ") + to_string(lx + width) + string("   ")
264                   + to_string(ly + height);
265         else
266           line += string("  R0 ") + to_string(lx) + string("   ")
267                   + to_string(ly);
268 
269         file << line << endl;
270       }
271     }
272   }
273 
274   file.close();
275 
276   string invs_filename =  string("./") + string(report_directory) + "/macro_placement.txt";
277   file.open(invs_filename);
278   for (int i = 0; i < clusters.size(); i++) {
279     if (clusters[i]->GetNumMacro() > 0) {
280       float cluster_lx = clusters[i]->GetX();
281       float cluster_ly = clusters[i]->GetY();
282       vector<Macro> macros = clusters[i]->GetMacros();
283       for (int j = 0; j < macros.size(); j++) {
284         string line = macros[j].GetName() + string("   ");
285         float lx = outline_lx + cluster_lx + macros[j].GetX() + halo_width;
286         float ly = outline_ly + cluster_ly + macros[j].GetY() + halo_width;
287         float width = macros[j].GetWidth() - 2 * halo_width;
288         float height = macros[j].GetHeight() - 2 * halo_width;
289         line += to_string(lx) + string("   ") + to_string(ly) + string("  ");
290         line += to_string(lx + width) + string("  ") + to_string(ly + height);
291         line += string("   ") + macros[j].GetOrientation();
292         file << line << endl;
293       }
294     }
295   }
296 
297   file.close();
298 
299   // just for quick verification
300   string floorplan_filename = string("./") + string(report_directory) + "/final_floorplan.txt";
301   file.open(floorplan_filename);
302   file << "outline_width:  " << outline_width << endl;
303   file << "outline_height:  " << outline_height << endl;
304   for (int i = 0; i < clusters.size(); i++) {
305     float cluster_lx = clusters[i]->GetX();
306     float cluster_ly = clusters[i]->GetY();
307     float cluster_ux = cluster_lx + clusters[i]->GetWidth();
308     float cluster_uy = cluster_ly + clusters[i]->GetHeight();
309     string cluster_name = clusters[i]->GetName();
310     file << cluster_name << "   ";
311     file << cluster_lx << "    ";
312     file << cluster_ly << "    ";
313     file << cluster_ux << "    ";
314     file << cluster_uy << "    ";
315     file << endl;
316   }
317   file << endl;
318 
319   for (int i = 0; i < clusters.size(); i++) {
320     if (clusters[i]->GetNumMacro() > 0) {
321       float cluster_lx = clusters[i]->GetX();
322       float cluster_ly = clusters[i]->GetY();
323       vector<Macro> macros = clusters[i]->GetMacros();
324       for (int j = 0; j < macros.size(); j++) {
325         string name = macros[j].GetName();
326         float lx = cluster_lx + macros[j].GetX() + halo_width;
327         float ly = cluster_ly + macros[j].GetY() + halo_width;
328         float width = macros[j].GetWidth() - 2 * halo_width;
329         float height = macros[j].GetHeight() - 2 * halo_width;
330         file << name << "    ";
331         file << lx << "   ";
332         file << ly << "   ";
333         file << lx + width << "   ";
334         file << ly + height << "   ";
335         file << endl;
336       }
337     }
338   }
339 
340   file.close();
341 
342   logger->report("*** Exit RTLMP ***");
343 
344   return true;
345 }
346 
init(Logger * logger)347 void MacroPlacer2::init(Logger* logger)
348 {
349   logger_ = logger;
350 }
351 
place(const char * config_file,const char * report_directory,const char * report_file)352 bool MacroPlacer2::place(const char* config_file,
353                          const char* report_directory,
354                          const char* report_file)
355 {
356   return rtl_macro_placer(config_file, logger_, report_directory, report_file);
357 }
358 
359 }  // namespace mpl
360