blob: c8d8d80408c25489c2800a9c798b4a4d5b170c6a [file] [log] [blame]
#include "setup_clocks.h"
#include "globals.h"
#include "expr_eval.h"
#include "vtr_assert.h"
#include "vpr_error.h"
#include "vpr_utils.h"
#include <string>
#include <iostream>
#include <sstream>
static MetalLayer get_metal_layer_from_name(
std::string metal_layer_name,
std::unordered_map<std::string, t_metal_layer> clock_metal_layers,
std::string clock_network_name);
static void setup_clock_network_wires(const t_arch& Arch, std::vector<t_segment_inf>& segment_inf);
static void setup_clock_connections(const t_arch& Arch);
void setup_clock_networks(const t_arch& Arch, std::vector<t_segment_inf>& segment_inf) {
setup_clock_network_wires(Arch, segment_inf);
setup_clock_connections(Arch);
}
/**
* Parses the clock architecture information and modifies the architecture segment
* information.
*/
void setup_clock_network_wires(const t_arch& Arch, std::vector<t_segment_inf>& segment_inf) {
auto& device_ctx = g_vpr_ctx.mutable_device();
auto& clock_networks_device = device_ctx.clock_networks;
auto& grid = device_ctx.grid;
auto& clock_networks_arch = Arch.clock_arch.clock_networks_arch;
auto& clock_metal_layers = Arch.clock_arch.clock_metal_layers;
// TODO: copied over from SetupGrid. Ensure consistency by only assiging in one place
t_formula_data vars;
vars.set_var_value("W", grid.width());
vars.set_var_value("H", grid.height());
for (auto clock_network_arch : clock_networks_arch) {
switch (clock_network_arch.type) {
case e_clock_type::SPINE: {
std::unique_ptr<ClockSpine> spine = std::make_unique<ClockSpine>();
spine->set_clock_name(clock_network_arch.name);
spine->set_num_instance(clock_network_arch.num_inst);
spine->set_metal_layer(get_metal_layer_from_name(
clock_network_arch.metal_layer,
clock_metal_layers,
clock_network_arch.name));
spine->set_initial_wire_location(
parse_formula(clock_network_arch.wire.start, vars),
parse_formula(clock_network_arch.wire.end, vars),
parse_formula(clock_network_arch.wire.position, vars));
spine->set_wire_repeat(
parse_formula(clock_network_arch.repeat.x, vars),
parse_formula(clock_network_arch.repeat.y, vars));
spine->set_drive_location(parse_formula(clock_network_arch.drive.offset, vars));
spine->set_drive_switch(clock_network_arch.drive.arch_switch_idx);
spine->set_drive_name(clock_network_arch.drive.name);
spine->set_tap_locations(
parse_formula(clock_network_arch.tap.offset, vars),
parse_formula(clock_network_arch.tap.increment, vars));
spine->set_tap_name(clock_network_arch.tap.name);
spine->create_segments(segment_inf);
clock_networks_device.push_back(std::move(spine));
break;
}
case e_clock_type::RIB: {
std::unique_ptr<ClockRib> rib = std::make_unique<ClockRib>();
rib->set_clock_name(clock_network_arch.name);
rib->set_num_instance(clock_network_arch.num_inst);
rib->set_metal_layer(get_metal_layer_from_name(
clock_network_arch.metal_layer,
clock_metal_layers,
clock_network_arch.name));
rib->set_initial_wire_location(
parse_formula(clock_network_arch.wire.start, vars),
parse_formula(clock_network_arch.wire.end, vars),
parse_formula(clock_network_arch.wire.position, vars));
rib->set_wire_repeat(
parse_formula(clock_network_arch.repeat.x, vars),
parse_formula(clock_network_arch.repeat.y, vars));
rib->set_drive_location(parse_formula(clock_network_arch.drive.offset, vars));
rib->set_drive_switch(clock_network_arch.drive.arch_switch_idx);
rib->set_drive_name(clock_network_arch.drive.name);
rib->set_tap_locations(
parse_formula(clock_network_arch.tap.offset, vars),
parse_formula(clock_network_arch.tap.increment, vars));
rib->set_tap_name(clock_network_arch.tap.name);
rib->create_segments(segment_inf);
clock_networks_device.push_back(std::move(rib));
break;
}
case e_clock_type::H_TREE: {
VPR_FATAL_ERROR(VPR_ERROR_OTHER, "HTrees not yet supported.\n");
break;
}
default: {
VPR_FATAL_ERROR(VPR_ERROR_OTHER,
"Found unsupported clock network type for '%s' clock network",
clock_network_arch.name.c_str());
}
}
}
clock_networks_device.shrink_to_fit();
}
void setup_clock_connections(const t_arch& Arch) {
auto& device_ctx = g_vpr_ctx.mutable_device();
auto& clock_connections_device = device_ctx.clock_connections;
auto& grid = device_ctx.grid;
auto& clock_connections_arch = Arch.clock_arch.clock_connections_arch;
// TODO: copied over from SetupGrid. Ensure consistency by only assiging in one place
t_formula_data vars;
vars.set_var_value("W", grid.width());
vars.set_var_value("H", grid.height());
for (auto clock_connection_arch : clock_connections_arch) {
if (clock_connection_arch.from == "ROUTING") {
clock_connections_device.emplace_back(new RoutingToClockConnection);
RoutingToClockConnection* routing_to_clock = dynamic_cast<RoutingToClockConnection*>(clock_connections_device.back().get());
//TODO: Add error check to check that clock name and tap name exist and that only
// two names are returned by the below function
auto names = vtr::split(clock_connection_arch.to, ".");
VTR_ASSERT_MSG(names.size() == 2, "Invalid clock name.\n");
routing_to_clock->set_clock_name_to_connect_to(names[0]);
routing_to_clock->set_clock_switch_point_name(names[1]);
routing_to_clock->set_switch_location(
parse_formula(clock_connection_arch.locationx, vars),
parse_formula(clock_connection_arch.locationy, vars));
routing_to_clock->set_switch(clock_connection_arch.arch_switch_idx);
routing_to_clock->set_fc_val(clock_connection_arch.fc);
} else if (clock_connection_arch.to == "CLOCK") {
clock_connections_device.emplace_back(new ClockToPinsConnection);
ClockToPinsConnection* clock_to_pins = dynamic_cast<ClockToPinsConnection*>(clock_connections_device.back().get());
//TODO: Add error check to check that clock name and tap name exist and that only
// two names are returned by the below function
auto names = vtr::split(clock_connection_arch.from, ".");
VTR_ASSERT_MSG(names.size() == 2, "Invalid clock name.\n");
clock_to_pins->set_clock_name_to_connect_from(names[0]);
clock_to_pins->set_clock_switch_point_name(names[1]);
clock_to_pins->set_switch(clock_connection_arch.arch_switch_idx);
clock_to_pins->set_fc_val(clock_connection_arch.fc);
} else {
clock_connections_device.emplace_back(new ClockToClockConneciton);
ClockToClockConneciton* clock_to_clock = dynamic_cast<ClockToClockConneciton*>(clock_connections_device.back().get());
//TODO: Add error check to check that clock name and tap name exist and that only
// two names are returned by the below function
auto to_names = vtr::split(clock_connection_arch.to, ".");
auto from_names = vtr::split(clock_connection_arch.from, ".");
VTR_ASSERT_MSG(to_names.size() == 2, "Invalid clock name.\n");
clock_to_clock->set_to_clock_name(to_names[0]);
clock_to_clock->set_to_clock_switch_point_name(to_names[1]);
clock_to_clock->set_from_clock_name(from_names[0]);
clock_to_clock->set_from_clock_switch_point_name(from_names[1]);
clock_to_clock->set_switch(clock_connection_arch.arch_switch_idx);
clock_to_clock->set_fc_val(clock_connection_arch.fc);
}
}
}
MetalLayer get_metal_layer_from_name(
std::string metal_layer_name,
std::unordered_map<std::string, t_metal_layer> clock_metal_layers,
std::string clock_network_name) {
auto itter = clock_metal_layers.find(metal_layer_name);
if (itter == clock_metal_layers.end()) {
VPR_FATAL_ERROR(VPR_ERROR_OTHER,
"Metal layer '%s' for clock network '%s' not found. Check to make sure that it is"
"included in the clock architecture description",
metal_layer_name.c_str(),
clock_network_name.c_str());
}
// Metal layer was found. Copy over from arch description to proper data type
auto arch_metal_layer = itter->second;
MetalLayer metal_layer;
metal_layer.r_metal = arch_metal_layer.r_metal;
metal_layer.c_metal = arch_metal_layer.c_metal;
return metal_layer;
}