@@ -34,6 +34,72 @@ using namespace DeviceResources;
34
34
using namespace LogicalNetlist ;
35
35
using namespace capnp ;
36
36
37
+ static float get_corner_value (Device::CornerModel::Reader model, const char * speed_model, const char * value) {
38
+ bool slow_model = std::string (speed_model) == std::string (" slow" );
39
+ bool fast_model = std::string (speed_model) == std::string (" fast" );
40
+
41
+ bool min_corner = std::string (value) == std::string (" min" );
42
+ bool typ_corner = std::string (value) == std::string (" typ" );
43
+ bool max_corner = std::string (value) == std::string (" max" );
44
+
45
+ if (!slow_model && !fast_model) {
46
+ archfpga_throw (" " , __LINE__,
47
+ " Wrong speed model `%s`. Expected `slow` or `fast`\n " , speed_model);
48
+ }
49
+
50
+ if (!min_corner && !typ_corner && !max_corner) {
51
+ archfpga_throw (" " , __LINE__,
52
+ " Wrong corner model `%s`. Expected `min`, `typ` or `max`\n " , value);
53
+ }
54
+
55
+ bool has_fast = model.getFast ().hasFast ();
56
+ bool has_slow = model.getSlow ().hasSlow ();
57
+
58
+ if (slow_model && has_slow) {
59
+ auto half = model.getSlow ().getSlow ();
60
+ if (min_corner && half.getMin ().isMin ()) {
61
+ return half.getMin ().getMin ();
62
+ } else if (typ_corner && half.getTyp ().isTyp ()) {
63
+ return half.getTyp ().getTyp ();
64
+ } else if (max_corner && half.getMax ().isMax ()) {
65
+ return half.getMax ().getMax ();
66
+ } else {
67
+ if (half.getMin ().isMin ()) {
68
+ return half.getMin ().getMin ();
69
+ } else if (half.getTyp ().isTyp ()) {
70
+ return half.getTyp ().getTyp ();
71
+ } else if (half.getMax ().isMax ()) {
72
+ return half.getMax ().getMax ();
73
+ } else {
74
+ archfpga_throw (" " , __LINE__,
75
+ " Invalid speed model %s. No value found!\n " , speed_model);
76
+ }
77
+ }
78
+ } else if (fast_model && has_fast) {
79
+ auto half = model.getFast ().getFast ();
80
+ if (min_corner && half.getMin ().isMin ()) {
81
+ return half.getMin ().getMin ();
82
+ } else if (typ_corner && half.getTyp ().isTyp ()) {
83
+ return half.getTyp ().getTyp ();
84
+ } else if (max_corner && half.getMax ().isMax ()) {
85
+ return half.getMax ().getMax ();
86
+ } else {
87
+ if (half.getMin ().isMin ()) {
88
+ return half.getMin ().getMin ();
89
+ } else if (half.getTyp ().isTyp ()) {
90
+ return half.getTyp ().getTyp ();
91
+ } else if (half.getMax ().isMax ()) {
92
+ return half.getMax ().getMax ();
93
+ } else {
94
+ archfpga_throw (" " , __LINE__,
95
+ " Invalid speed model %s. No value found!\n " , speed_model);
96
+ }
97
+ }
98
+ }
99
+
100
+ return 0 .;
101
+ }
102
+
37
103
struct ArchReader {
38
104
public:
39
105
ArchReader (t_arch* arch, Device::Reader& arch_reader, const char * arch_file, std::vector<t_physical_tile_type>& phys_types, std::vector<t_logical_block_type>& logical_types)
@@ -47,6 +113,11 @@ struct ArchReader {
47
113
48
114
void read_arch () {
49
115
process_models ();
116
+ process_device ();
117
+
118
+ process_layout ();
119
+ process_switches ();
120
+ process_segments ();
50
121
}
51
122
52
123
private:
@@ -163,6 +234,218 @@ struct ArchReader {
163
234
}
164
235
}
165
236
}
237
+
238
+ // Layout Processing
239
+ void process_layout () {
240
+ auto strList = ar_.getStrList ();
241
+ auto tileList = ar_.getTileList ();
242
+ auto tileTypeList = ar_.getTileTypeList ();
243
+ t_grid_def grid_def;
244
+
245
+ grid_def.width = grid_def.height = 0 ;
246
+ for (auto tile : tileList) {
247
+ grid_def.width = std::max (grid_def.width , tile.getCol () + 1 );
248
+ grid_def.height = std::max (grid_def.height , tile.getRow () + 1 );
249
+ }
250
+
251
+ grid_def.grid_type = GridDefType::FIXED;
252
+ std::string name = std::string (ar_.getName ());
253
+ if (name == " auto" ) {
254
+ archfpga_throw (arch_file_, __LINE__,
255
+ " The name auto is reserved for auto-size layouts; please choose another name" );
256
+ }
257
+ grid_def.name = name;
258
+ for (auto tile : tileList) {
259
+ t_metadata_dict data;
260
+ std::string tile_prefix (strList[tile.getName ()].cStr ());
261
+ auto tileType = tileTypeList[tile.getType ()];
262
+ std::string tile_type (strList[tileType.getName ()].cStr ());
263
+
264
+ size_t pos = tile_prefix.find (tile_type);
265
+ if (pos != std::string::npos && pos == 0 )
266
+ tile_prefix.erase (pos, tile_type.length () + 1 );
267
+ data.add (arch_->strings .intern_string (vtr::string_view (" fasm_prefix" )),
268
+ arch_->strings .intern_string (vtr::string_view (tile_prefix.c_str ())));
269
+ t_grid_loc_def single (tile_type, 1 );
270
+ single.x .start_expr = tile.getCol ();
271
+ single.y .start_expr = tile.getRow ();
272
+ single.x .end_expr = single.x .start_expr + " + w - 1" ;
273
+ single.y .end_expr = single.y .start_expr + " + h - 1" ;
274
+ single.owned_meta = std::make_unique<t_metadata_dict>(data);
275
+ single.meta = single.owned_meta .get ();
276
+ grid_def.loc_defs .emplace_back (std::move (single));
277
+ }
278
+
279
+ arch_->grid_layouts .emplace_back (std::move (grid_def));
280
+ }
281
+
282
+ void process_device () {
283
+ /*
284
+ * The generic architecture data is not currently available in the interchange format
285
+ * therefore, for a very initial implementation, the values are taken from the ones
286
+ * used primarly in the Xilinx series7 devices, generated using SymbiFlow.
287
+ *
288
+ * As the interchange format develops further, with possibly more details, this function can
289
+ * become dynamic, allowing for different parameters for the different architectures.
290
+ */
291
+ arch_->R_minW_nmos = 6065.520020 ;
292
+ arch_->R_minW_pmos = 18138.500000 ;
293
+ arch_->grid_logic_tile_area = 14813.392 ;
294
+ arch_->Chans .chan_x_dist .type = UNIFORM;
295
+ arch_->Chans .chan_x_dist .peak = 1 ;
296
+ arch_->Chans .chan_x_dist .width = 0 ;
297
+ arch_->Chans .chan_x_dist .xpeak = 0 ;
298
+ arch_->Chans .chan_x_dist .dc = 0 ;
299
+ arch_->Chans .chan_y_dist .type = UNIFORM;
300
+ arch_->Chans .chan_y_dist .peak = 1 ;
301
+ arch_->Chans .chan_y_dist .width = 0 ;
302
+ arch_->Chans .chan_y_dist .xpeak = 0 ;
303
+ arch_->Chans .chan_y_dist .dc = 0 ;
304
+ arch_->ipin_cblock_switch_name = std::string (" generic" );
305
+ arch_->SBType = WILTON;
306
+ arch_->Fs = 3 ;
307
+ default_fc_.specified = true ;
308
+ default_fc_.in_value_type = e_fc_value_type::FRACTIONAL;
309
+ default_fc_.in_value = 1.0 ;
310
+ default_fc_.out_value_type = e_fc_value_type::FRACTIONAL;
311
+ default_fc_.out_value = 1.0 ;
312
+ }
313
+
314
+ void process_switches () {
315
+ std::set<std::pair<bool , uint32_t >> pip_timing_models;
316
+ for (auto tile_type : ar_.getTileTypeList ()) {
317
+ for (auto pip : tile_type.getPips ()) {
318
+ pip_timing_models.insert (std::pair<bool , uint32_t >(pip.getBuffered21 (), pip.getTiming ()));
319
+ if (!pip.getDirectional ())
320
+ pip_timing_models.insert (std::pair<bool , uint32_t >(pip.getBuffered20 (), pip.getTiming ()));
321
+ }
322
+ }
323
+
324
+ auto timing_data = ar_.getPipTimings ();
325
+
326
+ std::vector<std::pair<bool , uint32_t >> pip_timing_models_list;
327
+ pip_timing_models_list.reserve (pip_timing_models.size ());
328
+
329
+ for (auto entry : pip_timing_models) {
330
+ pip_timing_models_list.push_back (entry);
331
+ }
332
+
333
+ auto num_switches = pip_timing_models.size () + 2 ;
334
+ std::string switch_name;
335
+
336
+ arch_->num_switches = num_switches;
337
+ auto * switches = arch_->Switches ;
338
+
339
+ if (num_switches > 0 ) {
340
+ switches = new t_arch_switch_inf[num_switches];
341
+ }
342
+
343
+ float R, Cin, Cint, Cout, Tdel;
344
+ for (int i = 0 ; i < (int )num_switches; ++i) {
345
+ t_arch_switch_inf& as = switches[i];
346
+
347
+ R = Cin = Cint = Cout = Tdel = 0.0 ;
348
+ SwitchType type;
349
+
350
+ if (i == 0 ) {
351
+ switch_name = " short" ;
352
+ type = SwitchType::SHORT;
353
+ R = 0.0 ;
354
+ } else if (i == 1 ) {
355
+ switch_name = " generic" ;
356
+ type = SwitchType::MUX;
357
+ R = 0.0 ;
358
+ } else {
359
+ auto entry = pip_timing_models_list[i - 2 ];
360
+ auto model = timing_data[entry.second ];
361
+ std::stringstream name;
362
+ std::string mux_type_string = entry.first ? " mux_" : " passGate_" ;
363
+ name << mux_type_string;
364
+
365
+ R = get_corner_value (model.getOutputResistance (), " slow" , " min" );
366
+ name << " R" << std::scientific << R;
367
+
368
+ Cin = get_corner_value (model.getInputCapacitance (), " slow" , " min" );
369
+ name << " Cin" << std::scientific << Cin;
370
+
371
+ Cout = get_corner_value (model.getOutputCapacitance (), " slow" , " min" );
372
+ name << " Cout" << std::scientific << Cout;
373
+
374
+ if (entry.first ) {
375
+ Cint = get_corner_value (model.getInternalCapacitance (), " slow" , " min" );
376
+ name << " Cinternal" << std::scientific << Cint;
377
+ }
378
+
379
+ Tdel = get_corner_value (model.getInternalDelay (), " slow" , " min" );
380
+ name << " Tdel" << std::scientific << Tdel;
381
+
382
+ switch_name = name.str ();
383
+ type = entry.first ? SwitchType::MUX : SwitchType::PASS_GATE;
384
+ }
385
+
386
+ /* Should never happen */
387
+ if (switch_name == std::string (VPR_DELAYLESS_SWITCH_NAME)) {
388
+ archfpga_throw (arch_file_, __LINE__,
389
+ " Switch name '%s' is a reserved name for VPR internal usage!" , switch_name.c_str ());
390
+ }
391
+
392
+ as.name = vtr::strdup (switch_name.c_str ());
393
+ as.set_type (type);
394
+ as.mux_trans_size = as.type () == SwitchType::MUX ? 1 : 0 ;
395
+
396
+ as.R = R;
397
+ as.Cin = Cin;
398
+ as.Cout = Cout;
399
+ as.Cinternal = Cint;
400
+ as.set_Tdel (t_arch_switch_inf::UNDEFINED_FANIN, Tdel);
401
+
402
+ if (as.type () == SwitchType::SHORT || as.type () == SwitchType::PASS_GATE) {
403
+ as.buf_size_type = BufferSize::ABSOLUTE;
404
+ as.buf_size = 0 ;
405
+ as.power_buffer_type = POWER_BUFFER_TYPE_ABSOLUTE_SIZE;
406
+ as.power_buffer_size = 0 .;
407
+ } else {
408
+ as.buf_size_type = BufferSize::AUTO;
409
+ as.buf_size = 0 .;
410
+ as.power_buffer_type = POWER_BUFFER_TYPE_AUTO;
411
+ }
412
+ }
413
+ }
414
+
415
+ void process_segments () {
416
+ // Segment names will be taken from wires connected to pips
417
+ // They are good representation for nodes
418
+ std::set<uint32_t > wire_names;
419
+ for (auto tile_type : ar_.getTileTypeList ()) {
420
+ auto wires = tile_type.getWires ();
421
+ for (auto pip : tile_type.getPips ()) {
422
+ wire_names.insert (wires[pip.getWire0 ()]);
423
+ wire_names.insert (wires[pip.getWire1 ()]);
424
+ }
425
+ }
426
+ int numSeg = wire_names.size ();
427
+ arch_->Segments .resize (numSeg);
428
+ uint32_t index = 0 ;
429
+ for (auto i : wire_names) {
430
+ // Use default values as we will populate rr_graph with correct values
431
+ // This segments are just declaration of future use
432
+ arch_->Segments [index ].name = str (i);
433
+ arch_->Segments [index ].length = 1 ;
434
+ arch_->Segments [index ].frequency = 1 ;
435
+ arch_->Segments [index ].Rmetal = 0 ;
436
+ arch_->Segments [index ].Cmetal = 0 ;
437
+ arch_->Segments [index ].parallel_axis = BOTH_AXIS;
438
+ arch_->Segments [index ].directionality = BI_DIRECTIONAL;
439
+ arch_->Segments [index ].arch_wire_switch = 1 ;
440
+ arch_->Segments [index ].arch_opin_switch = 1 ;
441
+ arch_->Segments [index ].cb .resize (1 );
442
+ arch_->Segments [index ].cb [0 ] = true ;
443
+ arch_->Segments [index ].sb .resize (2 );
444
+ arch_->Segments [index ].sb [0 ] = true ;
445
+ arch_->Segments [index ].sb [1 ] = true ;
446
+ ++index ;
447
+ }
448
+ }
166
449
};
167
450
168
451
void FPGAInterchangeReadArch (const char * FPGAInterchangeDeviceFile,
0 commit comments