Merge branch 'master' of gitlab.com:SymbioticEDA/nextpnr into chipdbng
This commit is contained in:
commit
c0a2f0b89f
@ -2,6 +2,7 @@
|
|||||||
* nextpnr -- Next Generation Place and Route
|
* nextpnr -- Next Generation Place and Route
|
||||||
*
|
*
|
||||||
* Copyright (C) 2018 Clifford Wolf <clifford@clifford.at>
|
* Copyright (C) 2018 Clifford Wolf <clifford@clifford.at>
|
||||||
|
* Copyright (C) 2018 David Shah <david@symbioticeda.com>
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for any
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
@ -18,7 +19,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "design_utils.h"
|
#include "design_utils.h"
|
||||||
|
#include <map>
|
||||||
|
#include "log.h"
|
||||||
|
#include "util.h"
|
||||||
NEXTPNR_NAMESPACE_BEGIN
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
void replace_port(CellInfo *old_cell, IdString old_name, CellInfo *rep_cell,
|
void replace_port(CellInfo *old_cell, IdString old_name, CellInfo *rep_cell,
|
||||||
@ -49,4 +52,23 @@ void replace_port(CellInfo *old_cell, IdString old_name, CellInfo *rep_cell,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Print utilisation of a design
|
||||||
|
void print_utilisation(const Design *design)
|
||||||
|
{
|
||||||
|
// Sort by Bel type
|
||||||
|
std::map<BelType, int> used_types;
|
||||||
|
for (auto cell : design->cells) {
|
||||||
|
used_types[belTypeFromId(cell.second->type)]++;
|
||||||
|
}
|
||||||
|
std::map<BelType, int> available_types;
|
||||||
|
for (auto bel : design->chip.getBels()) {
|
||||||
|
available_types[design->chip.getBelType(bel)]++;
|
||||||
|
}
|
||||||
|
log("\nDesign utilisation:\n");
|
||||||
|
for (auto type : available_types) {
|
||||||
|
log("\t%20s: %5d/%5d\n", belTypeToId(type.first).c_str(),
|
||||||
|
get_or_default(used_types, type.first, 0), type.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
* nextpnr -- Next Generation Place and Route
|
* nextpnr -- Next Generation Place and Route
|
||||||
*
|
*
|
||||||
* Copyright (C) 2018 Clifford Wolf <clifford@clifford.at>
|
* Copyright (C) 2018 Clifford Wolf <clifford@clifford.at>
|
||||||
|
* Copyright (C) 2018 David Shah <david@symbioticeda.com>
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for any
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
@ -83,6 +84,8 @@ CellInfo *net_driven_by(const NetInfo *net, F1 cell_pred, IdString port)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void print_utilisation(const Design *design);
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -2,6 +2,10 @@
|
|||||||
* nextpnr -- Next Generation Place and Route
|
* nextpnr -- Next Generation Place and Route
|
||||||
*
|
*
|
||||||
* Copyright (C) 2018 Clifford Wolf <clifford@clifford.at>
|
* Copyright (C) 2018 Clifford Wolf <clifford@clifford.at>
|
||||||
|
* Copyright (C) 2018 David Shah <david@symbioticeda.com>
|
||||||
|
*
|
||||||
|
* Simulated annealing implementation based on arachne-pnr
|
||||||
|
* Copyright (C) 2015-2018 Cotton Seed
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for any
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
@ -17,7 +21,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "place.h"
|
#include "place_sa.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@ -107,6 +111,7 @@ struct SAState
|
|||||||
int n_move, n_accept;
|
int n_move, n_accept;
|
||||||
int diameter = 35;
|
int diameter = 35;
|
||||||
std::vector<std::vector<std::vector<std::vector<BelId>>>> fast_bels;
|
std::vector<std::vector<std::vector<std::vector<BelId>>>> fast_bels;
|
||||||
|
std::unordered_set<BelId> locked_bels;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get the total estimated wirelength for a net
|
// Get the total estimated wirelength for a net
|
||||||
@ -122,6 +127,8 @@ static float get_wirelength(Chip *chip, NetInfo *net)
|
|||||||
return 0;
|
return 0;
|
||||||
consider_driver =
|
consider_driver =
|
||||||
chip->estimatePosition(driver_cell->bel, driver_x, driver_y);
|
chip->estimatePosition(driver_cell->bel, driver_x, driver_y);
|
||||||
|
WireId drv_wire = chip->getWireBelPin(driver_cell->bel,
|
||||||
|
portPinFromId(net->driver.port));
|
||||||
if (!consider_driver)
|
if (!consider_driver)
|
||||||
return 0;
|
return 0;
|
||||||
for (auto load : net->users) {
|
for (auto load : net->users) {
|
||||||
@ -131,8 +138,12 @@ static float get_wirelength(Chip *chip, NetInfo *net)
|
|||||||
int load_x = 0, load_y = 0;
|
int load_x = 0, load_y = 0;
|
||||||
if (load_cell->bel == BelId())
|
if (load_cell->bel == BelId())
|
||||||
continue;
|
continue;
|
||||||
chip->estimatePosition(load_cell->bel, load_x, load_y);
|
// chip->estimatePosition(load_cell->bel, load_x, load_y);
|
||||||
wirelength += std::abs(load_x - driver_x) + std::abs(load_y - driver_y);
|
WireId user_wire =
|
||||||
|
chip->getWireBelPin(load_cell->bel, portPinFromId(load.port));
|
||||||
|
// wirelength += std::abs(load_x - driver_x) + std::abs(load_y -
|
||||||
|
// driver_y);
|
||||||
|
wirelength += chip->estimateDelay(drv_wire, user_wire);
|
||||||
}
|
}
|
||||||
return wirelength;
|
return wirelength;
|
||||||
}
|
}
|
||||||
@ -171,13 +182,17 @@ static bool try_swap_position(Design *design, CellInfo *cell, BelId newBel,
|
|||||||
}
|
}
|
||||||
|
|
||||||
chip.bindBel(newBel, cell->name);
|
chip.bindBel(newBel, cell->name);
|
||||||
|
|
||||||
if (other != IdString()) {
|
if (other != IdString()) {
|
||||||
if (!isValidBelForCell(design, other_cell, oldBel)) {
|
chip.bindBel(oldBel, other_cell->name);
|
||||||
chip.unbindBel(newBel);
|
}
|
||||||
goto swap_fail;
|
|
||||||
} else {
|
if (!isBelLocationValid(design, newBel) ||
|
||||||
chip.bindBel(oldBel, other_cell->name);
|
((other != IdString() && !isBelLocationValid(design, oldBel)))) {
|
||||||
}
|
chip.unbindBel(newBel);
|
||||||
|
if (other != IdString())
|
||||||
|
chip.unbindBel(oldBel);
|
||||||
|
goto swap_fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
cell->bel = newBel;
|
cell->bel = newBel;
|
||||||
@ -246,12 +261,17 @@ BelId random_bel_for_cell(Design *design, CellInfo *cell, SAState &state,
|
|||||||
const auto &fb = state.fast_bels.at(int(targetType)).at(nx).at(ny);
|
const auto &fb = state.fast_bels.at(int(targetType)).at(nx).at(ny);
|
||||||
if (fb.size() == 0)
|
if (fb.size() == 0)
|
||||||
continue;
|
continue;
|
||||||
return fb.at(random_int_between(rnd, 0, fb.size()));
|
BelId bel = fb.at(random_int_between(rnd, 0, fb.size()));
|
||||||
|
if (state.locked_bels.find(bel) != state.locked_bels.end())
|
||||||
|
continue;
|
||||||
|
return bel;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void place_design_sa(Design *design)
|
void place_design_sa(Design *design)
|
||||||
{
|
{
|
||||||
|
SAState state;
|
||||||
|
|
||||||
size_t total_cells = design->cells.size(), placed_cells = 0;
|
size_t total_cells = design->cells.size(), placed_cells = 0;
|
||||||
std::queue<CellInfo *> visit_cells;
|
std::queue<CellInfo *> visit_cells;
|
||||||
// Initial constraints placer
|
// Initial constraints placer
|
||||||
@ -277,6 +297,7 @@ void place_design_sa(Design *design)
|
|||||||
|
|
||||||
cell->bel = bel;
|
cell->bel = bel;
|
||||||
design->chip.bindBel(bel, cell->name);
|
design->chip.bindBel(bel, cell->name);
|
||||||
|
state.locked_bels.insert(bel);
|
||||||
placed_cells++;
|
placed_cells++;
|
||||||
visit_cells.push(cell);
|
visit_cells.push(cell);
|
||||||
}
|
}
|
||||||
@ -285,16 +306,19 @@ void place_design_sa(Design *design)
|
|||||||
rnd_state rnd;
|
rnd_state rnd;
|
||||||
rnd.state = 1;
|
rnd.state = 1;
|
||||||
std::vector<CellInfo *> autoplaced;
|
std::vector<CellInfo *> autoplaced;
|
||||||
SAState state;
|
// Sort to-place cells for deterministic initial placement
|
||||||
// Place cells randomly initially
|
|
||||||
for (auto cell : design->cells) {
|
for (auto cell : design->cells) {
|
||||||
CellInfo *ci = cell.second;
|
CellInfo *ci = cell.second;
|
||||||
if (ci->bel == BelId()) {
|
if (ci->bel == BelId()) {
|
||||||
place_initial(design, ci, rnd);
|
|
||||||
autoplaced.push_back(cell.second);
|
autoplaced.push_back(cell.second);
|
||||||
placed_cells++;
|
|
||||||
}
|
}
|
||||||
log_info("placed %d/%d\n", int(placed_cells), int(total_cells));
|
}
|
||||||
|
std::sort(autoplaced.begin(), autoplaced.end(),
|
||||||
|
[](CellInfo *a, CellInfo *b) { return a->name < b->name; });
|
||||||
|
// Place cells randomly initially
|
||||||
|
for (auto cell : autoplaced) {
|
||||||
|
place_initial(design, cell, rnd);
|
||||||
|
placed_cells++;
|
||||||
}
|
}
|
||||||
// Build up a fast position/type to Bel lookup table
|
// Build up a fast position/type to Bel lookup table
|
||||||
int max_x = 0, max_y = 0;
|
int max_x = 0, max_y = 0;
|
||||||
@ -330,9 +354,9 @@ void place_design_sa(Design *design)
|
|||||||
state.n_move = state.n_accept = 0;
|
state.n_move = state.n_accept = 0;
|
||||||
state.improved = false;
|
state.improved = false;
|
||||||
|
|
||||||
// if (iter % 50 == 0)
|
if (iter % 5 == 0)
|
||||||
log(" at iteration #%d: temp = %f, wire length = %f\n", iter,
|
log(" at iteration #%d: temp = %f, wire length = %f\n", iter,
|
||||||
state.temp, state.curr_wirelength);
|
state.temp, state.curr_wirelength);
|
||||||
|
|
||||||
for (int m = 0; m < 15; ++m) {
|
for (int m = 0; m < 15; ++m) {
|
||||||
// Loop through all automatically placed cells
|
// Loop through all automatically placed cells
|
||||||
@ -382,6 +406,16 @@ void place_design_sa(Design *design)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (auto bel : design->chip.getBels()) {
|
||||||
|
if (!isBelLocationValid(design, bel)) {
|
||||||
|
std::string cell_text = "no cell";
|
||||||
|
IdString cell = design->chip.getBelCell(bel, false);
|
||||||
|
if (cell != IdString())
|
||||||
|
cell_text = std::string("cell '") + cell.str() + "'";
|
||||||
|
log_error("post-placement validity check failed for Bel '%s' (%s)",
|
||||||
|
design->chip.getBelName(bel).c_str(), cell_text.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
@ -2,7 +2,7 @@
|
|||||||
* nextpnr -- Next Generation Place and Route
|
* nextpnr -- Next Generation Place and Route
|
||||||
*
|
*
|
||||||
* Copyright (C) 2018 Clifford Wolf <clifford@clifford.at>
|
* Copyright (C) 2018 Clifford Wolf <clifford@clifford.at>
|
||||||
* Copyright (C) 2018 David Shah <dave@ds0.me>
|
* Copyright (C) 2018 David Shah <david@symbioticeda.com>
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for any
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
* nextpnr -- Next Generation Place and Route
|
* nextpnr -- Next Generation Place and Route
|
||||||
*
|
*
|
||||||
* Copyright (C) 2018 Clifford Wolf <clifford@clifford.at>
|
* Copyright (C) 2018 Clifford Wolf <clifford@clifford.at>
|
||||||
* Copyright (C) 2018 David Shah <dave@ds0.me>
|
* Copyright (C) 2018 David Shah <david@symbioticeda.com>
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for any
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
* nextpnr -- Next Generation Place and Route
|
* nextpnr -- Next Generation Place and Route
|
||||||
*
|
*
|
||||||
* Copyright (C) 2018 Clifford Wolf <clifford@clifford.at>
|
* Copyright (C) 2018 Clifford Wolf <clifford@clifford.at>
|
||||||
* Copyright (C) 2018 David Shah <dave@ds0.me>
|
* Copyright (C) 2018 David Shah <david@symbioticeda.com>
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for any
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -440,8 +440,8 @@ void route_design(Design *design, bool verbose)
|
|||||||
"routing.\n",
|
"routing.\n",
|
||||||
int(netsQueue.size()));
|
int(netsQueue.size()));
|
||||||
|
|
||||||
ripup_pip_penalty *= 1.5;
|
ripup_pip_penalty += 5;
|
||||||
ripup_wire_penalty *= 1.5;
|
ripup_wire_penalty += 5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
61
common/util.h
Normal file
61
common/util.h
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* nextpnr -- Next Generation Place and Route
|
||||||
|
*
|
||||||
|
* Copyright (C) 2018 David Shah <david@symbioticeda.com>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef UTIL_H
|
||||||
|
#define UTIL_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include "nextpnr.h"
|
||||||
|
|
||||||
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
// Get a value from a map-style container, returning default if value is not
|
||||||
|
// found
|
||||||
|
template <typename Container, typename KeyType, typename ValueType>
|
||||||
|
ValueType get_or_default(const Container &ct, const KeyType &key,
|
||||||
|
ValueType def = ValueType())
|
||||||
|
{
|
||||||
|
auto found = ct.find(key);
|
||||||
|
if (found == ct.end())
|
||||||
|
return def;
|
||||||
|
else
|
||||||
|
return found->second;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get a value from a map-style container, converting to int, and returning
|
||||||
|
// default if value is not found
|
||||||
|
template <typename Container, typename KeyType>
|
||||||
|
int int_or_default(const Container &ct, const KeyType &key, int def = 0)
|
||||||
|
{
|
||||||
|
auto found = ct.find(key);
|
||||||
|
if (found == ct.end())
|
||||||
|
return def;
|
||||||
|
else
|
||||||
|
return std::stoi(found->second);
|
||||||
|
};
|
||||||
|
|
||||||
|
// As above, but convert to bool
|
||||||
|
template <typename Container, typename KeyType>
|
||||||
|
bool bool_or_default(const Container &ct, const KeyType &key, bool def = false)
|
||||||
|
{
|
||||||
|
return bool(int_or_default(ct, key, int(def)));
|
||||||
|
};
|
||||||
|
NEXTPNR_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif
|
@ -345,6 +345,7 @@ static int const_net_idx = 0;
|
|||||||
|
|
||||||
template <typename F>
|
template <typename F>
|
||||||
void json_import_ports(Design *design, const string &modname,
|
void json_import_ports(Design *design, const string &modname,
|
||||||
|
const std::vector<IdString> &netnames,
|
||||||
const string &obj_name, const string &port_name,
|
const string &obj_name, const string &port_name,
|
||||||
JsonNode *dir_node, JsonNode *wire_group_node, F visitor)
|
JsonNode *dir_node, JsonNode *wire_group_node, F visitor)
|
||||||
{
|
{
|
||||||
@ -432,7 +433,10 @@ void json_import_ports(Design *design, const string &modname,
|
|||||||
|
|
||||||
// A simple net, specified by a number
|
// A simple net, specified by a number
|
||||||
net_num = wire_node->data_number;
|
net_num = wire_node->data_number;
|
||||||
net_id = std::to_string(net_num);
|
if (net_num < netnames.size())
|
||||||
|
net_id = netnames.at(net_num);
|
||||||
|
else
|
||||||
|
net_id = std::to_string(net_num);
|
||||||
if (design->nets.count(net_id) == 0) {
|
if (design->nets.count(net_id) == 0) {
|
||||||
// The net doesn't exist in the design (yet)
|
// The net doesn't exist in the design (yet)
|
||||||
// Create in now
|
// Create in now
|
||||||
@ -511,8 +515,9 @@ void json_import_ports(Design *design, const string &modname,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void json_import_cell(Design *design, string modname, JsonNode *cell_node,
|
void json_import_cell(Design *design, string modname,
|
||||||
string cell_name)
|
const std::vector<IdString> &netnames,
|
||||||
|
JsonNode *cell_node, string cell_name)
|
||||||
{
|
{
|
||||||
JsonNode *cell_type, *param_node, *attr_node;
|
JsonNode *cell_type, *param_node, *attr_node;
|
||||||
|
|
||||||
@ -616,7 +621,7 @@ void json_import_cell(Design *design, string modname, JsonNode *cell_node,
|
|||||||
wire_group_node = connections->data_dict.at(port_name);
|
wire_group_node = connections->data_dict.at(port_name);
|
||||||
|
|
||||||
json_import_ports(
|
json_import_ports(
|
||||||
design, modname, cell->name, port_name, dir_node,
|
design, modname, netnames, cell->name, port_name, dir_node,
|
||||||
wire_group_node,
|
wire_group_node,
|
||||||
[cell](PortType type, const std::string &name, NetInfo *net) {
|
[cell](PortType type, const std::string &name, NetInfo *net) {
|
||||||
cell->ports[name] = PortInfo{name, net, type};
|
cell->ports[name] = PortInfo{name, net, type};
|
||||||
@ -696,12 +701,14 @@ static void insert_iobuf(Design *design, NetInfo *net, PortType type,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void json_import_toplevel_port(Design *design, const string &modname,
|
void json_import_toplevel_port(Design *design, const string &modname,
|
||||||
|
const std::vector<IdString> &netnames,
|
||||||
const string &portname, JsonNode *node)
|
const string &portname, JsonNode *node)
|
||||||
{
|
{
|
||||||
JsonNode *dir_node = node->data_dict.at("direction");
|
JsonNode *dir_node = node->data_dict.at("direction");
|
||||||
JsonNode *nets_node = node->data_dict.at("bits");
|
JsonNode *nets_node = node->data_dict.at("bits");
|
||||||
json_import_ports(
|
json_import_ports(
|
||||||
design, modname, "Top Level IO", portname, dir_node, nets_node,
|
design, modname, netnames, "Top Level IO", portname, dir_node,
|
||||||
|
nets_node,
|
||||||
[design](PortType type, const std::string &name, NetInfo *net) {
|
[design](PortType type, const std::string &name, NetInfo *net) {
|
||||||
insert_iobuf(design, net, type, name);
|
insert_iobuf(design, net, type, name);
|
||||||
});
|
});
|
||||||
@ -714,6 +721,35 @@ void json_import(Design *design, string modname, JsonNode *node)
|
|||||||
|
|
||||||
log_info("Importing module %s\n", modname.c_str());
|
log_info("Importing module %s\n", modname.c_str());
|
||||||
|
|
||||||
|
// Import netnames
|
||||||
|
std::vector<IdString> netnames;
|
||||||
|
if (node->data_dict.count("netnames")) {
|
||||||
|
JsonNode *cell_parent = node->data_dict.at("netnames");
|
||||||
|
for (int nnid = 0; nnid < GetSize(cell_parent->data_dict_keys);
|
||||||
|
nnid++) {
|
||||||
|
JsonNode *here;
|
||||||
|
|
||||||
|
here = cell_parent->data_dict.at(cell_parent->data_dict_keys[nnid]);
|
||||||
|
std::string basename = cell_parent->data_dict_keys[nnid];
|
||||||
|
if (here->data_dict.count("bits")) {
|
||||||
|
JsonNode *bits = here->data_dict.at("bits");
|
||||||
|
assert(bits->type == 'A');
|
||||||
|
size_t num_bits = bits->data_array.size();
|
||||||
|
for (size_t i = 0; i < num_bits; i++) {
|
||||||
|
int netid = bits->data_array.at(i)->data_number;
|
||||||
|
if (netid >= netnames.size())
|
||||||
|
netnames.resize(netid + 1);
|
||||||
|
netnames.at(netid) =
|
||||||
|
basename +
|
||||||
|
(num_bits == 1
|
||||||
|
? ""
|
||||||
|
: std::string("[") + std::to_string(i) +
|
||||||
|
std::string("]"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (node->data_dict.count("cells")) {
|
if (node->data_dict.count("cells")) {
|
||||||
JsonNode *cell_parent = node->data_dict.at("cells");
|
JsonNode *cell_parent = node->data_dict.at("cells");
|
||||||
//
|
//
|
||||||
@ -727,7 +763,7 @@ void json_import(Design *design, string modname, JsonNode *node)
|
|||||||
|
|
||||||
here = cell_parent->data_dict.at(
|
here = cell_parent->data_dict.at(
|
||||||
cell_parent->data_dict_keys[cellid]);
|
cell_parent->data_dict_keys[cellid]);
|
||||||
json_import_cell(design, modname, here,
|
json_import_cell(design, modname, netnames, here,
|
||||||
cell_parent->data_dict_keys[cellid]);
|
cell_parent->data_dict_keys[cellid]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -744,7 +780,7 @@ void json_import(Design *design, string modname, JsonNode *node)
|
|||||||
|
|
||||||
here = ports_parent->data_dict.at(
|
here = ports_parent->data_dict.at(
|
||||||
ports_parent->data_dict_keys[portid]);
|
ports_parent->data_dict_keys[portid]);
|
||||||
json_import_toplevel_port(design, modname,
|
json_import_toplevel_port(design, modname, netnames,
|
||||||
ports_parent->data_dict_keys[portid],
|
ports_parent->data_dict_keys[portid],
|
||||||
here);
|
here);
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
* nextpnr -- Next Generation Place and Route
|
* nextpnr -- Next Generation Place and Route
|
||||||
*
|
*
|
||||||
* Copyright (C) 2018 Clifford Wolf <clifford@clifford.at>
|
* Copyright (C) 2018 Clifford Wolf <clifford@clifford.at>
|
||||||
|
* Copyright (C) 2018 David Shah <david@symbioticeda.com>
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for any
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
@ -19,6 +20,7 @@
|
|||||||
|
|
||||||
#include "arch_place.h"
|
#include "arch_place.h"
|
||||||
#include "cells.h"
|
#include "cells.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_BEGIN
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
@ -39,7 +41,7 @@ static bool logicCellsCompatible(const std::vector<const CellInfo *> &cells)
|
|||||||
std::unordered_set<const NetInfo *> locals;
|
std::unordered_set<const NetInfo *> locals;
|
||||||
|
|
||||||
for (auto cell : cells) {
|
for (auto cell : cells) {
|
||||||
if (std::stoi(cell->params.at("DFF_ENABLE"))) {
|
if (bool_or_default(cell->params, "DFF_ENABLE")) {
|
||||||
if (!dffs_exist) {
|
if (!dffs_exist) {
|
||||||
dffs_exist = true;
|
dffs_exist = true;
|
||||||
cen = get_net_or_nullptr(cell, "CEN");
|
cen = get_net_or_nullptr(cell, "CEN");
|
||||||
@ -53,7 +55,7 @@ static bool logicCellsCompatible(const std::vector<const CellInfo *> &cells)
|
|||||||
if (!is_global_net(sr))
|
if (!is_global_net(sr))
|
||||||
locals.insert(sr);
|
locals.insert(sr);
|
||||||
|
|
||||||
if (std::stoi(cell->params.at("NEG_CLK"))) {
|
if (bool_or_default(cell->params, "NEG_CLK")) {
|
||||||
dffs_neg = true;
|
dffs_neg = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -63,7 +65,7 @@ static bool logicCellsCompatible(const std::vector<const CellInfo *> &cells)
|
|||||||
return false;
|
return false;
|
||||||
if (sr != get_net_or_nullptr(cell, "SR"))
|
if (sr != get_net_or_nullptr(cell, "SR"))
|
||||||
return false;
|
return false;
|
||||||
if (dffs_neg != bool(std::stoi(cell->params.at("NEG_CLK"))))
|
if (dffs_neg != bool_or_default(cell->params, "NEG_CLK"))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -79,6 +81,28 @@ static bool logicCellsCompatible(const std::vector<const CellInfo *> &cells)
|
|||||||
return locals.size() <= 32;
|
return locals.size() <= 32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isBelLocationValid(Design *design, BelId bel)
|
||||||
|
{
|
||||||
|
const Chip &chip = design->chip;
|
||||||
|
if (chip.getBelType(bel) == TYPE_ICESTORM_LC) {
|
||||||
|
std::vector<const CellInfo *> cells;
|
||||||
|
for (auto bel_other : chip.getBelsAtSameTile(bel)) {
|
||||||
|
IdString cell_other = chip.getBelCell(bel_other, false);
|
||||||
|
if (cell_other != IdString()) {
|
||||||
|
const CellInfo *ci_other = design->cells[cell_other];
|
||||||
|
cells.push_back(ci_other);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return logicCellsCompatible(cells);
|
||||||
|
} else {
|
||||||
|
IdString cellId = chip.getBelCell(bel, false);
|
||||||
|
if (cellId == IdString())
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return isValidBelForCell(design, design->cells.at(cellId), bel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool isValidBelForCell(Design *design, CellInfo *cell, BelId bel)
|
bool isValidBelForCell(Design *design, CellInfo *cell, BelId bel)
|
||||||
{
|
{
|
||||||
const Chip &chip = design->chip;
|
const Chip &chip = design->chip;
|
||||||
@ -99,6 +123,26 @@ bool isValidBelForCell(Design *design, CellInfo *cell, BelId bel)
|
|||||||
return logicCellsCompatible(cells);
|
return logicCellsCompatible(cells);
|
||||||
} else if (cell->type == "SB_IO") {
|
} else if (cell->type == "SB_IO") {
|
||||||
return design->chip.getBelPackagePin(bel) != "";
|
return design->chip.getBelPackagePin(bel) != "";
|
||||||
|
} else if (cell->type == "SB_GB") {
|
||||||
|
bool is_reset = false, is_cen = false;
|
||||||
|
assert(cell->ports.at("GLOBAL_BUFFER_OUTPUT").net != nullptr);
|
||||||
|
for (auto user : cell->ports.at("GLOBAL_BUFFER_OUTPUT").net->users) {
|
||||||
|
if (is_reset_port(user))
|
||||||
|
is_reset = true;
|
||||||
|
if (is_enable_port(user))
|
||||||
|
is_cen = true;
|
||||||
|
}
|
||||||
|
IdString glb_net = chip.getWireName(
|
||||||
|
chip.getWireBelPin(bel, PIN_GLOBAL_BUFFER_OUTPUT));
|
||||||
|
int glb_id = std::stoi(std::string("") + glb_net.str().back());
|
||||||
|
if (is_reset && is_cen)
|
||||||
|
return false;
|
||||||
|
else if (is_reset)
|
||||||
|
return (glb_id % 2) == 0;
|
||||||
|
else if (is_cen)
|
||||||
|
return (glb_id % 2) == 1;
|
||||||
|
else
|
||||||
|
return true;
|
||||||
} else {
|
} else {
|
||||||
// TODO: IO cell clock checks
|
// TODO: IO cell clock checks
|
||||||
return true;
|
return true;
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
* nextpnr -- Next Generation Place and Route
|
* nextpnr -- Next Generation Place and Route
|
||||||
*
|
*
|
||||||
* Copyright (C) 2018 Clifford Wolf <clifford@clifford.at>
|
* Copyright (C) 2018 Clifford Wolf <clifford@clifford.at>
|
||||||
|
* Copyright (C) 2018 David Shah <david@symbioticeda.com>
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for any
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
@ -12,7 +13,7 @@
|
|||||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
* ACTION OF CONTRACT, NeEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@ -30,6 +31,9 @@ NEXTPNR_NAMESPACE_BEGIN
|
|||||||
// such as conflicting set/reset signals, etc
|
// such as conflicting set/reset signals, etc
|
||||||
bool isValidBelForCell(Design *design, CellInfo *cell, BelId bel);
|
bool isValidBelForCell(Design *design, CellInfo *cell, BelId bel);
|
||||||
|
|
||||||
|
// Return true whether all Bels at a given location are valid
|
||||||
|
bool isBelLocationValid(Design *design, BelId bel);
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
* nextpnr -- Next Generation Place and Route
|
* nextpnr -- Next Generation Place and Route
|
||||||
*
|
*
|
||||||
* Copyright (C) 2018 Clifford Wolf <clifford@clifford.at>
|
* Copyright (C) 2018 Clifford Wolf <clifford@clifford.at>
|
||||||
* Copyright (C) 2018 David Shah <dave@ds0.me>
|
* Copyright (C) 2018 David Shah <david@symbioticeda.com>
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for any
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
@ -287,12 +287,6 @@ void write_asc(const Design &design, std::ostream &out)
|
|||||||
TileType tile = tile_at(chip, x, y);
|
TileType tile = tile_at(chip, x, y);
|
||||||
TileInfoPOD &ti = bi.tiles_nonrouting[tile];
|
TileInfoPOD &ti = bi.tiles_nonrouting[tile];
|
||||||
|
|
||||||
// disable RAM to stop icebox_vlog crashing (FIXME)
|
|
||||||
if ((tile == TILE_RAMB) && (chip.args.type == ChipArgs::LP1K ||
|
|
||||||
chip.args.type == ChipArgs::HX1K)) {
|
|
||||||
set_config(ti, config.at(y).at(x), "RamConfig.PowerUp", true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// set all ColBufCtrl bits (FIXME)
|
// set all ColBufCtrl bits (FIXME)
|
||||||
bool setColBufCtrl = true;
|
bool setColBufCtrl = true;
|
||||||
if (chip.args.type == ChipArgs::LP1K ||
|
if (chip.args.type == ChipArgs::LP1K ||
|
||||||
@ -398,6 +392,14 @@ void write_asc(const Design &design, std::ostream &out)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Write symbols
|
||||||
|
const bool write_symbols = 1;
|
||||||
|
for (auto wire : chip.getWires()) {
|
||||||
|
IdString net = chip.getWireNet(wire, false);
|
||||||
|
if (net != IdString())
|
||||||
|
out << ".sym " << wire.index << " " << net << std::endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
* nextpnr -- Next Generation Place and Route
|
* nextpnr -- Next Generation Place and Route
|
||||||
*
|
*
|
||||||
* Copyright (C) 2018 Clifford Wolf <clifford@clifford.at>
|
* Copyright (C) 2018 Clifford Wolf <clifford@clifford.at>
|
||||||
|
* Copyright (C) 2018 David Shah <david@symbioticeda.com>
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for any
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
* nextpnr -- Next Generation Place and Route
|
* nextpnr -- Next Generation Place and Route
|
||||||
*
|
*
|
||||||
* Copyright (C) 2018 Clifford Wolf <clifford@clifford.at>
|
* Copyright (C) 2018 Clifford Wolf <clifford@clifford.at>
|
||||||
|
* Copyright (C) 2018 David Shah <david@symbioticeda.com>
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for any
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
@ -190,6 +191,41 @@ void nxio_to_sb(CellInfo *nxio, CellInfo *sbio)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_clock_port(const PortRef &port)
|
||||||
|
{
|
||||||
|
if (port.cell == nullptr)
|
||||||
|
return false;
|
||||||
|
if (is_ff(port.cell))
|
||||||
|
return port.port == "C";
|
||||||
|
if (port.cell->type == "ICESTORM_LC")
|
||||||
|
return port.port == "CLK";
|
||||||
|
if (is_ram(port.cell) || port.cell->type == "ICESTORM_RAM")
|
||||||
|
return port.port == "RCLK" || port.port == "WCLK";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_reset_port(const PortRef &port)
|
||||||
|
{
|
||||||
|
if (port.cell == nullptr)
|
||||||
|
return false;
|
||||||
|
if (is_ff(port.cell))
|
||||||
|
return port.port == "R" || port.port == "S";
|
||||||
|
if (port.cell->type == "ICESTORM_LC")
|
||||||
|
return port.port == "SR";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_enable_port(const PortRef &port)
|
||||||
|
{
|
||||||
|
if (port.cell == nullptr)
|
||||||
|
return false;
|
||||||
|
if (is_ff(port.cell))
|
||||||
|
return port.port == "E";
|
||||||
|
if (port.cell->type == "ICESTORM_LC")
|
||||||
|
return port.port == "CEN";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool is_global_net(const NetInfo *net)
|
bool is_global_net(const NetInfo *net)
|
||||||
{
|
{
|
||||||
return bool(net_driven_by(net, is_gbuf, "GLOBAL_BUFFER_OUTPUT"));
|
return bool(net_driven_by(net, is_gbuf, "GLOBAL_BUFFER_OUTPUT"));
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
* nextpnr -- Next Generation Place and Route
|
* nextpnr -- Next Generation Place and Route
|
||||||
*
|
*
|
||||||
* Copyright (C) 2018 Clifford Wolf <clifford@clifford.at>
|
* Copyright (C) 2018 Clifford Wolf <clifford@clifford.at>
|
||||||
|
* Copyright (C) 2018 David Shah <david@symbioticeda.com>
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for any
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
@ -77,6 +78,15 @@ void nxio_to_sb(CellInfo *nxio, CellInfo *sbio);
|
|||||||
// Return true if a net is a global net
|
// Return true if a net is a global net
|
||||||
bool is_global_net(const NetInfo *net);
|
bool is_global_net(const NetInfo *net);
|
||||||
|
|
||||||
|
// Return true if a port is a clock port
|
||||||
|
bool is_clock_port(const PortRef &port);
|
||||||
|
|
||||||
|
// Return true if a port is a reset port
|
||||||
|
bool is_reset_port(const PortRef &port);
|
||||||
|
|
||||||
|
// Return true if a port is a clock enable port
|
||||||
|
bool is_enable_port(const PortRef &port);
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -25,13 +25,14 @@
|
|||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "bitstream.h"
|
#include "bitstream.h"
|
||||||
|
#include "design_utils.h"
|
||||||
#include "jsonparse.h"
|
#include "jsonparse.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "nextpnr.h"
|
#include "nextpnr.h"
|
||||||
#include "pack.h"
|
#include "pack.h"
|
||||||
#include "pcf.h"
|
#include "pcf.h"
|
||||||
#include "place.h"
|
#include "place_sa.h"
|
||||||
#include "pybindings.h"
|
#include "pybindings.h"
|
||||||
#include "route.h"
|
#include "route.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
@ -221,6 +222,7 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
pack_design(&design);
|
pack_design(&design);
|
||||||
|
print_utilisation(&design);
|
||||||
if (!vm.count("pack-only")) {
|
if (!vm.count("pack-only")) {
|
||||||
place_design_sa(&design);
|
place_design_sa(&design);
|
||||||
route_design(&design, verbose);
|
route_design(&design, verbose);
|
||||||
|
123
ice40/pack.cc
123
ice40/pack.cc
@ -2,7 +2,7 @@
|
|||||||
* nextpnr -- Next Generation Place and Route
|
* nextpnr -- Next Generation Place and Route
|
||||||
*
|
*
|
||||||
* Copyright (C) 2018 Clifford Wolf <clifford@clifford.at>
|
* Copyright (C) 2018 Clifford Wolf <clifford@clifford.at>
|
||||||
* Copyright (C) 2018 David Shah <dave@ds0.me>
|
* Copyright (C) 2018 David Shah <david@symbioticeda.com>
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for any
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
@ -276,15 +276,36 @@ static void pack_io(Design *design)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool is_clock_port(const PortRef &port)
|
static void insert_global(Design *design, NetInfo *net, bool is_reset,
|
||||||
|
bool is_cen)
|
||||||
{
|
{
|
||||||
if (port.cell == nullptr)
|
CellInfo *gb = create_ice_cell(design, "SB_GB");
|
||||||
return false;
|
gb->ports["USER_SIGNAL_TO_GLOBAL_BUFFER"].net = net;
|
||||||
if (is_ff(port.cell))
|
PortRef pr;
|
||||||
return port.port == "C";
|
pr.cell = gb;
|
||||||
if (is_ram(port.cell))
|
pr.port = "USER_SIGNAL_TO_GLOBAL_BUFFER";
|
||||||
return port.port == "RCLK" || port.port == "WCLK";
|
net->users.push_back(pr);
|
||||||
return false;
|
|
||||||
|
pr.cell = gb;
|
||||||
|
pr.port = "GLOBAL_BUFFER_OUTPUT";
|
||||||
|
NetInfo *glbnet = new NetInfo();
|
||||||
|
glbnet->name = net->name.str() + std::string("_glb_") +
|
||||||
|
(is_reset ? "sr" : (is_cen ? "ce" : "clk"));
|
||||||
|
glbnet->driver = pr;
|
||||||
|
design->nets[glbnet->name] = glbnet;
|
||||||
|
gb->ports["GLOBAL_BUFFER_OUTPUT"].net = glbnet;
|
||||||
|
std::vector<PortRef> keep_users;
|
||||||
|
for (auto user : net->users) {
|
||||||
|
if (is_clock_port(user) || (is_reset && is_reset_port(user)) ||
|
||||||
|
(is_cen && is_enable_port(user))) {
|
||||||
|
user.cell->ports[user.port].net = glbnet;
|
||||||
|
glbnet->users.push_back(user);
|
||||||
|
} else {
|
||||||
|
keep_users.push_back(user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
net->users = keep_users;
|
||||||
|
design->cells[gb->name] = gb;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Simple global promoter (clock only)
|
// Simple global promoter (clock only)
|
||||||
@ -292,48 +313,72 @@ static void promote_globals(Design *design)
|
|||||||
{
|
{
|
||||||
log_info("Promoting globals..\n");
|
log_info("Promoting globals..\n");
|
||||||
|
|
||||||
std::unordered_map<IdString, int> clock_count;
|
std::unordered_map<IdString, int> clock_count, reset_count, cen_count;
|
||||||
for (auto net : design->nets) {
|
for (auto net : design->nets) {
|
||||||
NetInfo *ni = net.second;
|
NetInfo *ni = net.second;
|
||||||
if (ni->driver.cell != nullptr && !is_global_net(ni)) {
|
if (ni->driver.cell != nullptr && !is_global_net(ni)) {
|
||||||
clock_count[net.first] = 0;
|
clock_count[net.first] = 0;
|
||||||
|
reset_count[net.first] = 0;
|
||||||
|
cen_count[net.first] = 0;
|
||||||
|
|
||||||
for (auto user : ni->users) {
|
for (auto user : ni->users) {
|
||||||
if (is_clock_port(user))
|
if (is_clock_port(user))
|
||||||
clock_count[net.first]++;
|
clock_count[net.first]++;
|
||||||
|
if (is_reset_port(user))
|
||||||
|
reset_count[net.first]++;
|
||||||
|
if (is_enable_port(user))
|
||||||
|
cen_count[net.first]++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto global_clock = std::max_element(clock_count.begin(), clock_count.end(),
|
int prom_globals = 0, prom_resets = 0, prom_cens = 0;
|
||||||
[](const std::pair<IdString, int> &a,
|
int gbs_available = 8;
|
||||||
const std::pair<IdString, int> &b) {
|
for (auto cell : design->cells)
|
||||||
return a.second < b.second;
|
if (is_gbuf(cell.second))
|
||||||
});
|
--gbs_available;
|
||||||
if (global_clock->second > 0) {
|
while (prom_globals < gbs_available) {
|
||||||
NetInfo *clknet = design->nets[global_clock->first];
|
auto global_clock =
|
||||||
CellInfo *gb = create_ice_cell(design, "SB_GB");
|
std::max_element(clock_count.begin(), clock_count.end(),
|
||||||
gb->ports["USER_SIGNAL_TO_GLOBAL_BUFFER"].net = clknet;
|
[](const std::pair<IdString, int> &a,
|
||||||
PortRef pr;
|
const std::pair<IdString, int> &b) {
|
||||||
pr.cell = gb;
|
return a.second < b.second;
|
||||||
pr.port = "USER_SIGNAL_TO_GLOBAL_BUFFER";
|
});
|
||||||
clknet->users.push_back(pr);
|
|
||||||
|
|
||||||
pr.cell = gb;
|
auto global_reset =
|
||||||
pr.port = "GLOBAL_BUFFER_OUTPUT";
|
std::max_element(reset_count.begin(), reset_count.end(),
|
||||||
NetInfo *glbnet = new NetInfo();
|
[](const std::pair<IdString, int> &a,
|
||||||
glbnet->name = clknet->name.str() + "_glb";
|
const std::pair<IdString, int> &b) {
|
||||||
glbnet->driver = pr;
|
return a.second < b.second;
|
||||||
design->nets[glbnet->name] = glbnet;
|
});
|
||||||
std::vector<PortRef> keep_users;
|
auto global_cen =
|
||||||
for (auto user : clknet->users) {
|
std::max_element(cen_count.begin(), cen_count.end(),
|
||||||
if (is_clock_port(user)) {
|
[](const std::pair<IdString, int> &a,
|
||||||
user.cell->ports[user.port].net = glbnet;
|
const std::pair<IdString, int> &b) {
|
||||||
glbnet->users.push_back(user);
|
return a.second < b.second;
|
||||||
} else {
|
});
|
||||||
keep_users.push_back(user);
|
if (global_reset->second > global_clock->second && prom_resets < 4) {
|
||||||
}
|
NetInfo *rstnet = design->nets[global_reset->first];
|
||||||
|
insert_global(design, rstnet, true, false);
|
||||||
|
++prom_globals;
|
||||||
|
++prom_resets;
|
||||||
|
clock_count.erase(rstnet->name);
|
||||||
|
reset_count.erase(rstnet->name);
|
||||||
|
|
||||||
|
} else if (global_cen->second > global_clock->second && prom_cens < 4) {
|
||||||
|
NetInfo *cennet = design->nets[global_cen->first];
|
||||||
|
insert_global(design, cennet, false, true);
|
||||||
|
++prom_globals;
|
||||||
|
++prom_cens;
|
||||||
|
cen_count.erase(cennet->name);
|
||||||
|
clock_count.erase(cennet->name);
|
||||||
|
} else if (global_clock->second != 0) {
|
||||||
|
NetInfo *clknet = design->nets[global_clock->first];
|
||||||
|
insert_global(design, clknet, false, false);
|
||||||
|
++prom_globals;
|
||||||
|
clock_count.erase(clknet->name);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
clknet->users = keep_users;
|
|
||||||
design->cells[gb->name] = gb;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
* nextpnr -- Next Generation Place and Route
|
* nextpnr -- Next Generation Place and Route
|
||||||
*
|
*
|
||||||
* Copyright (C) 2018 Clifford Wolf <clifford@clifford.at>
|
* Copyright (C) 2018 Clifford Wolf <clifford@clifford.at>
|
||||||
|
* Copyright (C) 2018 David Shah <david@symbioticeda.com>
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for any
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
* nextpnr -- Next Generation Place and Route
|
* nextpnr -- Next Generation Place and Route
|
||||||
*
|
*
|
||||||
* Copyright (C) 2018 Clifford Wolf <clifford@clifford.at>
|
* Copyright (C) 2018 Clifford Wolf <clifford@clifford.at>
|
||||||
|
* Copyright (C) 2018 David Shah <david@symbioticeda.com>
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for any
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
* nextpnr -- Next Generation Place and Route
|
* nextpnr -- Next Generation Place and Route
|
||||||
*
|
*
|
||||||
* Copyright (C) 2018 Clifford Wolf <clifford@clifford.at>
|
* Copyright (C) 2018 Clifford Wolf <clifford@clifford.at>
|
||||||
|
* Copyright (C) 2018 David Shah <david@symbioticeda.com>
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for any
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
* nextpnr -- Next Generation Place and Route
|
* nextpnr -- Next Generation Place and Route
|
||||||
*
|
*
|
||||||
* Copyright (C) 2018 Clifford Wolf <clifford@clifford.at>
|
* Copyright (C) 2018 Clifford Wolf <clifford@clifford.at>
|
||||||
* Copyright (C) 2018 David Shah <dave@ds0.me>
|
* Copyright (C) 2018 David Shah <david@symbioticeda.com>
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for any
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
Loading…
Reference in New Issue
Block a user