Skip to content

Commit 9e2b66b

Browse files
mtdudekacomodi
andcommitted
vpr: interchange: add device data reading
This PR adds basic support for the architecture reading: - Device - Layout - Switches Signed-off-by: Alessandro Comodi <[email protected]> Co-authored-by: Maciej Dudek <[email protected]> Co-authored-by: Alessandro Comodi <[email protected]>
1 parent f92cfeb commit 9e2b66b

File tree

2 files changed

+309
-0
lines changed

2 files changed

+309
-0
lines changed

libs/libarchfpga/src/read_fpga_interchange_arch.cpp

Lines changed: 283 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,72 @@ using namespace DeviceResources;
3434
using namespace LogicalNetlist;
3535
using namespace capnp;
3636

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+
37103
struct ArchReader {
38104
public:
39105
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 {
47113

48114
void read_arch() {
49115
process_models();
116+
process_device();
117+
118+
process_layout();
119+
process_switches();
120+
process_segments();
50121
}
51122

52123
private:
@@ -163,6 +234,218 @@ struct ArchReader {
163234
}
164235
}
165236
}
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+
}
166449
};
167450

168451
void FPGAInterchangeReadArch(const char* FPGAInterchangeDeviceFile,

vpr/test/test_interchange_device.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,30 @@ TEST_CASE("read_interchange_models", "[vpr]") {
4141
REQUIRE(lib_models.size() == 0);
4242
}
4343

44+
TEST_CASE("read_interchange_layout", "[vpr]") {
45+
t_arch arch;
46+
std::vector<t_physical_tile_type> physical_tile_types;
47+
std::vector<t_logical_block_type> logical_block_types;
48+
49+
FPGAInterchangeReadArch(kArchFile, /*timing_enabled=*/true, &arch, physical_tile_types, logical_block_types);
50+
51+
auto& gd = arch.grid_layouts[0];
52+
REQUIRE(gd.grid_type == GridDefType::FIXED);
53+
REQUIRE(gd.height == 10);
54+
REQUIRE(gd.width == 10);
55+
56+
std::unordered_map<std::string, bool> tile_types({{"NULL", false}, {"PWR", false}, {"IOB", false}, {"CLB", false}});
57+
for (auto& loc : gd.loc_defs) {
58+
auto ret = tile_types.find(loc.block_type);
59+
REQUIRE(ret != tile_types.end());
60+
REQUIRE(loc.priority == 1);
61+
62+
ret->second = true;
63+
}
64+
65+
for (auto type : tile_types) {
66+
CHECK(type.second);
67+
}
68+
}
69+
4470
} // namespace

0 commit comments

Comments
 (0)