aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClifford Wolf <clifford@clifford.at>2018-06-17 14:31:43 +0200
committerClifford Wolf <clifford@clifford.at>2018-06-17 14:31:43 +0200
commitc0a2f0b89fa1505c728d57a4529a62aa78013da4 (patch)
treef74bbf4e63857251a65e3ca50b1da62da7934d5a
parent3b5c33d685b1330747612e4cebb422b09b2bd8de (diff)
parent153b800f6a5da9af277e64b4cd4aee1c10ca0a01 (diff)
downloadnextpnr-c0a2f0b89fa1505c728d57a4529a62aa78013da4.tar.gz
nextpnr-c0a2f0b89fa1505c728d57a4529a62aa78013da4.tar.bz2
nextpnr-c0a2f0b89fa1505c728d57a4529a62aa78013da4.zip
Merge branch 'master' of gitlab.com:SymbioticEDA/nextpnr into chipdbng
-rw-r--r--common/design_utils.cc24
-rw-r--r--common/design_utils.h3
-rw-r--r--common/place_sa.cc (renamed from common/place.cc)70
-rw-r--r--common/place_sa.h (renamed from common/place.h)0
-rw-r--r--common/pybindings.cc2
-rw-r--r--common/pybindings.h2
-rw-r--r--common/pycontainers.h2
-rw-r--r--common/route.cc4
-rw-r--r--common/util.h61
-rw-r--r--frontend/json/jsonparse.cc50
-rw-r--r--ice40/arch_place.cc50
-rw-r--r--ice40/arch_place.h6
-rw-r--r--ice40/bitstream.cc16
-rw-r--r--ice40/bitstream.h1
-rw-r--r--ice40/cells.cc36
-rw-r--r--ice40/cells.h10
-rw-r--r--ice40/main.cc4
-rw-r--r--ice40/pack.cc125
-rw-r--r--ice40/pack.h1
-rw-r--r--ice40/pcf.cc1
-rw-r--r--ice40/pcf.h1
-rw-r--r--ice40/pybindings.cc2
22 files changed, 387 insertions, 84 deletions
diff --git a/common/design_utils.cc b/common/design_utils.cc
index 85895a75..ae6e21ed 100644
--- a/common/design_utils.cc
+++ b/common/design_utils.cc
@@ -2,6 +2,7 @@
* nextpnr -- Next Generation Place and Route
*
* 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
* purpose with or without fee is hereby granted, provided that the above
@@ -18,7 +19,9 @@
*/
#include "design_utils.h"
-
+#include <map>
+#include "log.h"
+#include "util.h"
NEXTPNR_NAMESPACE_BEGIN
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
diff --git a/common/design_utils.h b/common/design_utils.h
index 8d231d4c..d640bf68 100644
--- a/common/design_utils.h
+++ b/common/design_utils.h
@@ -2,6 +2,7 @@
* nextpnr -- Next Generation Place and Route
*
* 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
* 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
#endif
diff --git a/common/place.cc b/common/place_sa.cc
index 55a4d021..22e750c2 100644
--- a/common/place.cc
+++ b/common/place_sa.cc
@@ -2,6 +2,10 @@
* nextpnr -- Next Generation Place and Route
*
* 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
* 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 <cmath>
#include <iostream>
@@ -107,6 +111,7 @@ struct SAState
int n_move, n_accept;
int diameter = 35;
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
@@ -122,6 +127,8 @@ static float get_wirelength(Chip *chip, NetInfo *net)
return 0;
consider_driver =
chip->estimatePosition(driver_cell->bel, driver_x, driver_y);
+ WireId drv_wire = chip->getWireBelPin(driver_cell->bel,
+ portPinFromId(net->driver.port));
if (!consider_driver)
return 0;
for (auto load : net->users) {
@@ -131,8 +138,12 @@ static float get_wirelength(Chip *chip, NetInfo *net)
int load_x = 0, load_y = 0;
if (load_cell->bel == BelId())
continue;
- chip->estimatePosition(load_cell->bel, load_x, load_y);
- wirelength += std::abs(load_x - driver_x) + std::abs(load_y - driver_y);
+ // chip->estimatePosition(load_cell->bel, load_x, load_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;
}
@@ -171,13 +182,17 @@ static bool try_swap_position(Design *design, CellInfo *cell, BelId newBel,
}
chip.bindBel(newBel, cell->name);
+
if (other != IdString()) {
- if (!isValidBelForCell(design, other_cell, oldBel)) {
- chip.unbindBel(newBel);
- goto swap_fail;
- } else {
- chip.bindBel(oldBel, other_cell->name);
- }
+ chip.bindBel(oldBel, other_cell->name);
+ }
+
+ if (!isBelLocationValid(design, newBel) ||
+ ((other != IdString() && !isBelLocationValid(design, oldBel)))) {
+ chip.unbindBel(newBel);
+ if (other != IdString())
+ chip.unbindBel(oldBel);
+ goto swap_fail;
}
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);
if (fb.size() == 0)
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)
{
+ SAState state;
+
size_t total_cells = design->cells.size(), placed_cells = 0;
std::queue<CellInfo *> visit_cells;
// Initial constraints placer
@@ -277,6 +297,7 @@ void place_design_sa(Design *design)
cell->bel = bel;
design->chip.bindBel(bel, cell->name);
+ state.locked_bels.insert(bel);
placed_cells++;
visit_cells.push(cell);
}
@@ -285,16 +306,19 @@ void place_design_sa(Design *design)
rnd_state rnd;
rnd.state = 1;
std::vector<CellInfo *> autoplaced;
- SAState state;
- // Place cells randomly initially
+ // Sort to-place cells for deterministic initial placement
for (auto cell : design->cells) {
CellInfo *ci = cell.second;
if (ci->bel == BelId()) {
- place_initial(design, ci, rnd);
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
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.improved = false;
- // if (iter % 50 == 0)
- log(" at iteration #%d: temp = %f, wire length = %f\n", iter,
- state.temp, state.curr_wirelength);
+ if (iter % 5 == 0)
+ log(" at iteration #%d: temp = %f, wire length = %f\n", iter,
+ state.temp, state.curr_wirelength);
for (int m = 0; m < 15; ++m) {
// 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
diff --git a/common/place.h b/common/place_sa.h
index f320111e..f320111e 100644
--- a/common/place.h
+++ b/common/place_sa.h
diff --git a/common/pybindings.cc b/common/pybindings.cc
index 10bbab7b..89f98716 100644
--- a/common/pybindings.cc
+++ b/common/pybindings.cc
@@ -2,7 +2,7 @@
* nextpnr -- Next Generation Place and Route
*
* 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
* purpose with or without fee is hereby granted, provided that the above
diff --git a/common/pybindings.h b/common/pybindings.h
index de6aa4c7..7616c055 100644
--- a/common/pybindings.h
+++ b/common/pybindings.h
@@ -2,7 +2,7 @@
* nextpnr -- Next Generation Place and Route
*
* 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
* purpose with or without fee is hereby granted, provided that the above
diff --git a/common/pycontainers.h b/common/pycontainers.h
index 992d0de9..9160dfb6 100644
--- a/common/pycontainers.h
+++ b/common/pycontainers.h
@@ -2,7 +2,7 @@
* nextpnr -- Next Generation Place and Route
*
* 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
* purpose with or without fee is hereby granted, provided that the above
diff --git a/common/route.cc b/common/route.cc
index 247c8840..32212c7d 100644
--- a/common/route.cc
+++ b/common/route.cc
@@ -440,8 +440,8 @@ void route_design(Design *design, bool verbose)
"routing.\n",
int(netsQueue.size()));
- ripup_pip_penalty *= 1.5;
- ripup_wire_penalty *= 1.5;
+ ripup_pip_penalty += 5;
+ ripup_wire_penalty += 5;
}
}
diff --git a/common/util.h b/common/util.h
new file mode 100644
index 00000000..34b2ed02
--- /dev/null
+++ b/common/util.h
@@ -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
diff --git a/frontend/json/jsonparse.cc b/frontend/json/jsonparse.cc
index 82874703..3c060fd7 100644
--- a/frontend/json/jsonparse.cc
+++ b/frontend/json/jsonparse.cc
@@ -345,6 +345,7 @@ static int const_net_idx = 0;
template <typename F>
void json_import_ports(Design *design, const string &modname,
+ const std::vector<IdString> &netnames,
const string &obj_name, const string &port_name,
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
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) {
// The net doesn't exist in the design (yet)
// 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,
- string cell_name)
+void json_import_cell(Design *design, string modname,
+ const std::vector<IdString> &netnames,
+ JsonNode *cell_node, string cell_name)
{
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);
json_import_ports(
- design, modname, cell->name, port_name, dir_node,
+ design, modname, netnames, cell->name, port_name, dir_node,
wire_group_node,
[cell](PortType type, const std::string &name, NetInfo *net) {
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,
+ const std::vector<IdString> &netnames,
const string &portname, JsonNode *node)
{
JsonNode *dir_node = node->data_dict.at("direction");
JsonNode *nets_node = node->data_dict.at("bits");
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) {
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());
+ // 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")) {
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(
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]);
}
}
@@ -744,7 +780,7 @@ void json_import(Design *design, string modname, JsonNode *node)
here = ports_parent->data_dict.at(
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],
here);
}
diff --git a/ice40/arch_place.cc b/ice40/arch_place.cc
index 492ed846..1c6361a1 100644
--- a/ice40/arch_place.cc
+++ b/ice40/arch_place.cc
@@ -2,6 +2,7 @@
* nextpnr -- Next Generation Place and Route
*
* 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
* purpose with or without fee is hereby granted, provided that the above
@@ -19,6 +20,7 @@
#include "arch_place.h"
#include "cells.h"
+#include "util.h"
NEXTPNR_NAMESPACE_BEGIN
@@ -39,7 +41,7 @@ static bool logicCellsCompatible(const std::vector<const CellInfo *> &cells)
std::unordered_set<const NetInfo *> locals;
for (auto cell : cells) {
- if (std::stoi(cell->params.at("DFF_ENABLE"))) {
+ if (bool_or_default(cell->params, "DFF_ENABLE")) {
if (!dffs_exist) {
dffs_exist = true;
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))
locals.insert(sr);
- if (std::stoi(cell->params.at("NEG_CLK"))) {
+ if (bool_or_default(cell->params, "NEG_CLK")) {
dffs_neg = true;
}
} else {
@@ -63,7 +65,7 @@ static bool logicCellsCompatible(const std::vector<const CellInfo *> &cells)
return false;
if (sr != get_net_or_nullptr(cell, "SR"))
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;
}
}
@@ -79,6 +81,28 @@ static bool logicCellsCompatible(const std::vector<const CellInfo *> &cells)
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)
{
const Chip &chip = design->chip;
@@ -99,6 +123,26 @@ bool isValidBelForCell(Design *design, CellInfo *cell, BelId bel)
return logicCellsCompatible(cells);
} else if (cell->type == "SB_IO") {
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 {
// TODO: IO cell clock checks
return true;
diff --git a/ice40/arch_place.h b/ice40/arch_place.h
index a505f4db..5cd14809 100644
--- a/ice40/arch_place.h
+++ b/ice40/arch_place.h
@@ -2,6 +2,7 @@
* nextpnr -- Next Generation Place and Route
*
* 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
* 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
* 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
+ * ACTION OF CONTRACT, NeEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* 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
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
#endif
diff --git a/ice40/bitstream.cc b/ice40/bitstream.cc
index 61a6959d..2913303c 100644
--- a/ice40/bitstream.cc
+++ b/ice40/bitstream.cc
@@ -2,7 +2,7 @@
* nextpnr -- Next Generation Place and Route
*
* 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
* 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);
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)
bool setColBufCtrl = true;
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
diff --git a/ice40/bitstream.h b/ice40/bitstream.h
index 11547163..0e2a4aa9 100644
--- a/ice40/bitstream.h
+++ b/ice40/bitstream.h
@@ -2,6 +2,7 @@
* nextpnr -- Next Generation Place and Route
*
* 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
* purpose with or without fee is hereby granted, provided that the above
diff --git a/ice40/cells.cc b/ice40/cells.cc
index 61b24ce3..b11a2a77 100644
--- a/ice40/cells.cc
+++ b/ice40/cells.cc
@@ -2,6 +2,7 @@
* nextpnr -- Next Generation Place and Route
*
* 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
* 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)
{
return bool(net_driven_by(net, is_gbuf, "GLOBAL_BUFFER_OUTPUT"));
diff --git a/ice40/cells.h b/ice40/cells.h
index a2fa4c16..45e81fd1 100644
--- a/ice40/cells.h
+++ b/ice40/cells.h
@@ -2,6 +2,7 @@
* nextpnr -- Next Generation Place and Route
*
* 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
* 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
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
#endif
diff --git a/ice40/main.cc b/ice40/main.cc
index fea53631..eb92d92f 100644
--- a/ice40/main.cc
+++ b/ice40/main.cc
@@ -25,13 +25,14 @@
#include <fstream>
#include <iostream>
#include "bitstream.h"
+#include "design_utils.h"
#include "jsonparse.h"
#include "log.h"
#include "mainwindow.h"
#include "nextpnr.h"
#include "pack.h"
#include "pcf.h"
-#include "place.h"
+#include "place_sa.h"
#include "pybindings.h"
#include "route.h"
#include "version.h"
@@ -221,6 +222,7 @@ int main(int argc, char *argv[])
}
pack_design(&design);
+ print_utilisation(&design);
if (!vm.count("pack-only")) {
place_design_sa(&design);
route_design(&design, verbose);
diff --git a/ice40/pack.cc b/ice40/pack.cc
index e045c05c..0b76f3f3 100644
--- a/ice40/pack.cc
+++ b/ice40/pack.cc
@@ -2,7 +2,7 @@
* nextpnr -- Next Generation Place and Route
*
* 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
* 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)
- return false;
- if (is_ff(port.cell))
- return port.port == "C";
- if (is_ram(port.cell))
- return port.port == "RCLK" || port.port == "WCLK";
- return false;
+ CellInfo *gb = create_ice_cell(design, "SB_GB");
+ gb->ports["USER_SIGNAL_TO_GLOBAL_BUFFER"].net = net;
+ PortRef pr;
+ pr.cell = gb;
+ pr.port = "USER_SIGNAL_TO_GLOBAL_BUFFER";
+ net->users.push_back(pr);
+
+ 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)
@@ -292,48 +313,72 @@ static void promote_globals(Design *design)
{
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) {
NetInfo *ni = net.second;
if (ni->driver.cell != nullptr && !is_global_net(ni)) {
clock_count[net.first] = 0;
+ reset_count[net.first] = 0;
+ cen_count[net.first] = 0;
+
for (auto user : ni->users) {
if (is_clock_port(user))
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(),
- [](const std::pair<IdString, int> &a,
- const std::pair<IdString, int> &b) {
- return a.second < b.second;
- });
- if (global_clock->second > 0) {
- NetInfo *clknet = design->nets[global_clock->first];
- CellInfo *gb = create_ice_cell(design, "SB_GB");
- gb->ports["USER_SIGNAL_TO_GLOBAL_BUFFER"].net = clknet;
- PortRef pr;
- pr.cell = gb;
- pr.port = "USER_SIGNAL_TO_GLOBAL_BUFFER";
- clknet->users.push_back(pr);
-
- pr.cell = gb;
- pr.port = "GLOBAL_BUFFER_OUTPUT";
- NetInfo *glbnet = new NetInfo();
- glbnet->name = clknet->name.str() + "_glb";
- glbnet->driver = pr;
- design->nets[glbnet->name] = glbnet;
- std::vector<PortRef> keep_users;
- for (auto user : clknet->users) {
- if (is_clock_port(user)) {
- user.cell->ports[user.port].net = glbnet;
- glbnet->users.push_back(user);
- } else {
- keep_users.push_back(user);
- }
+ int prom_globals = 0, prom_resets = 0, prom_cens = 0;
+ int gbs_available = 8;
+ for (auto cell : design->cells)
+ if (is_gbuf(cell.second))
+ --gbs_available;
+ while (prom_globals < gbs_available) {
+ auto global_clock =
+ std::max_element(clock_count.begin(), clock_count.end(),
+ [](const std::pair<IdString, int> &a,
+ const std::pair<IdString, int> &b) {
+ return a.second < b.second;
+ });
+
+ auto global_reset =
+ std::max_element(reset_count.begin(), reset_count.end(),
+ [](const std::pair<IdString, int> &a,
+ const std::pair<IdString, int> &b) {
+ return a.second < b.second;
+ });
+ auto global_cen =
+ std::max_element(cen_count.begin(), cen_count.end(),
+ [](const std::pair<IdString, int> &a,
+ const std::pair<IdString, int> &b) {
+ return a.second < b.second;
+ });
+ 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;
}
}
diff --git a/ice40/pack.h b/ice40/pack.h
index 4a92a7ab..60f22ef3 100644
--- a/ice40/pack.h
+++ b/ice40/pack.h
@@ -2,6 +2,7 @@
* nextpnr -- Next Generation Place and Route
*
* 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
* purpose with or without fee is hereby granted, provided that the above
diff --git a/ice40/pcf.cc b/ice40/pcf.cc
index 75c32731..3bef962f 100644
--- a/ice40/pcf.cc
+++ b/ice40/pcf.cc
@@ -2,6 +2,7 @@
* nextpnr -- Next Generation Place and Route
*
* 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
* purpose with or without fee is hereby granted, provided that the above
diff --git a/ice40/pcf.h b/ice40/pcf.h
index c4a7d991..ec2f4923 100644
--- a/ice40/pcf.h
+++ b/ice40/pcf.h
@@ -2,6 +2,7 @@
* nextpnr -- Next Generation Place and Route
*
* 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
* purpose with or without fee is hereby granted, provided that the above
diff --git a/ice40/pybindings.cc b/ice40/pybindings.cc
index 5ccf9495..c161949b 100644
--- a/ice40/pybindings.cc
+++ b/ice40/pybindings.cc
@@ -2,7 +2,7 @@
* nextpnr -- Next Generation Place and Route
*
* 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
* purpose with or without fee is hereby granted, provided that the above