Merge branch 'redist_slack' of gitlab.com:SymbioticEDA/nextpnr into redist_slack

This commit is contained in:
Eddie Hung 2018-07-31 18:26:39 -07:00
commit 5d58d6ad1b
14 changed files with 220 additions and 70 deletions

View File

@ -162,3 +162,8 @@ Links and references
- [SymbiFlow](https://github.com/SymbiFlow/symbiflow-arch-defs) - [SymbiFlow](https://github.com/SymbiFlow/symbiflow-arch-defs)
- [Gaffe](https://github.com/kc8apf/gaffe) - [Gaffe](https://github.com/kc8apf/gaffe)
- [KinglerPAR](https://github.com/rqou/KinglerPAR) - [KinglerPAR](https://github.com/rqou/KinglerPAR)
> SymbiFlow is working with the Verilog to Routing tool to extend the current
research tool to support real architectures. VtR is strongly focused on
architecture research but having support for real architectures might enable
research nextpnr zu providing documentation and explanation.

View File

@ -39,6 +39,8 @@ wirelen_t get_net_metric(const Context *ctx, const NetInfo *net, MetricType type
driver_loc = ctx->getBelLocation(driver_cell->bel); driver_loc = ctx->getBelLocation(driver_cell->bel);
if (driver_gb) if (driver_gb)
return 0; return 0;
delay_t negative_slack = 0;
delay_t worst_slack = std::numeric_limits<delay_t>::max(); delay_t worst_slack = std::numeric_limits<delay_t>::max();
int xmin = driver_loc.x, xmax = driver_loc.x, ymin = driver_loc.y, ymax = driver_loc.y; int xmin = driver_loc.x, xmax = driver_loc.x, ymin = driver_loc.y, ymax = driver_loc.y;
for (auto load : net->users) { for (auto load : net->users) {
@ -51,7 +53,7 @@ wirelen_t get_net_metric(const Context *ctx, const NetInfo *net, MetricType type
delay_t net_delay = ctx->predictDelay(net, load); delay_t net_delay = ctx->predictDelay(net, load);
auto slack = load.budget - net_delay; auto slack = load.budget - net_delay;
if (slack < 0) if (slack < 0)
tns += slack; negative_slack += slack;
worst_slack = std::min(slack, worst_slack); worst_slack = std::min(slack, worst_slack);
} }
@ -70,7 +72,7 @@ wirelen_t get_net_metric(const Context *ctx, const NetInfo *net, MetricType type
wirelength = wirelen_t((ymax - ymin) + (xmax - xmin)); wirelength = wirelen_t((ymax - ymin) + (xmax - xmin));
} }
tns = ctx->getDelayNS(tns); tns += ctx->getDelayNS(negative_slack);
return wirelength; return wirelength;
} }

View File

@ -21,6 +21,7 @@
#include <algorithm> #include <algorithm>
#include <cmath> #include <cmath>
#include <cstring> #include <cstring>
#include "gfx.h"
#include "log.h" #include "log.h"
#include "nextpnr.h" #include "nextpnr.h"
#include "placer1.h" #include "placer1.h"
@ -140,9 +141,8 @@ Arch::Arch(ArchArgs args) : args(args)
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
std::string Arch::getChipName() std::string Arch::getChipName() const
{ {
if (args.type == ArchArgs::LFE5U_25F) { if (args.type == ArchArgs::LFE5U_25F) {
return "LFE5U-25F"; return "LFE5U-25F";
} else if (args.type == ArchArgs::LFE5U_45F) { } else if (args.type == ArchArgs::LFE5U_45F) {
@ -432,16 +432,64 @@ bool Arch::route() { return router1(getCtx()); }
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
std::vector<GraphicElement> Arch::getDecalGraphics(DecalId decalId) const std::vector<GraphicElement> Arch::getDecalGraphics(DecalId decal) const
{ {
std::vector<GraphicElement> ret; std::vector<GraphicElement> ret;
// FIXME
if (decal.type == DecalId::TYPE_FRAME) {
/* nothing */
}
if (decal.type == DecalId::TYPE_BEL) {
BelId bel;
bel.index = decal.z;
bel.location = decal.location;
int z = locInfo(bel)->bel_data[bel.index].z;
auto bel_type = getBelType(bel);
if (bel_type == TYPE_TRELLIS_SLICE) {
GraphicElement el;
el.type = GraphicElement::TYPE_BOX;
el.style = decal.active ? GraphicElement::STYLE_ACTIVE : GraphicElement::STYLE_INACTIVE;
el.x1 = bel.location.x + logic_cell_x1;
el.x2 = bel.location.x + logic_cell_x2;
el.y1 = bel.location.y + logic_cell_y1 + (z)*logic_cell_pitch;
el.y2 = bel.location.y + logic_cell_y2 + (z)*logic_cell_pitch;
ret.push_back(el);
}
if (bel_type == TYPE_TRELLIS_IO) {
GraphicElement el;
el.type = GraphicElement::TYPE_BOX;
el.style = decal.active ? GraphicElement::STYLE_ACTIVE : GraphicElement::STYLE_INACTIVE;
el.x1 = bel.location.x + logic_cell_x1;
el.x2 = bel.location.x + logic_cell_x2;
el.y1 = bel.location.y + logic_cell_y1 + (2 * z) * logic_cell_pitch;
el.y2 = bel.location.y + logic_cell_y2 + (2 * z + 1) * logic_cell_pitch;
ret.push_back(el);
}
}
return ret; return ret;
} }
DecalXY Arch::getFrameDecal() const { return {}; } DecalXY Arch::getFrameDecal() const
{
DecalXY decalxy;
decalxy.decal.type = DecalId::TYPE_FRAME;
decalxy.decal.active = true;
return decalxy;
}
DecalXY Arch::getBelDecal(BelId bel) const { return {}; } DecalXY Arch::getBelDecal(BelId bel) const
{
DecalXY decalxy;
decalxy.decal.type = DecalId::TYPE_BEL;
decalxy.decal.location = bel.location;
decalxy.decal.z = bel.index;
decalxy.decal.active = bel_to_cell.count(bel) && (bel_to_cell.at(bel) != IdString());
return decalxy;
}
DecalXY Arch::getWireDecal(WireId wire) const { return {}; } DecalXY Arch::getWireDecal(WireId wire) const { return {}; }

View File

@ -399,7 +399,7 @@ struct Arch : BaseCtx
ArchArgs args; ArchArgs args;
Arch(ArchArgs args); Arch(ArchArgs args);
std::string getChipName(); std::string getChipName() const;
IdString archId() const { return id("ecp5"); } IdString archId() const { return id("ecp5"); }
IdString archArgsToId(ArchArgs args) const; IdString archArgsToId(ArchArgs args) const;

View File

@ -120,17 +120,21 @@ struct GroupId
struct DecalId struct DecalId
{ {
char type = 0; // Bel/Wire/Pip/Frame (b/w/p/f) enum
{
TYPE_FRAME,
TYPE_BEL
} type;
Location location; Location location;
uint32_t z = 0; uint32_t z = 0;
bool active = false;
bool operator==(const DecalId &other) const bool operator==(const DecalId &other) const
{ {
return type == other.type && location == other.location && z == other.z; return type == other.type && location == other.location && z == other.z && active == other.active;
} }
bool operator!=(const DecalId &other) const bool operator!=(const DecalId &other) const
{ {
return type != other.type || location != other.location || z != other.z; return type != other.type || location != other.location || z != other.z || active != other.active;
} }
}; };
@ -200,6 +204,7 @@ template <> struct hash<NEXTPNR_NAMESPACE_PREFIX DecalId>
boost::hash_combine(seed, hash<int>()(decal.type)); boost::hash_combine(seed, hash<int>()(decal.type));
boost::hash_combine(seed, hash<NEXTPNR_NAMESPACE_PREFIX Location>()(decal.location)); boost::hash_combine(seed, hash<NEXTPNR_NAMESPACE_PREFIX Location>()(decal.location));
boost::hash_combine(seed, hash<int>()(decal.z)); boost::hash_combine(seed, hash<int>()(decal.z));
boost::hash_combine(seed, hash<bool>()(decal.active));
return seed; return seed;
} }
}; };

35
ecp5/gfx.h Normal file
View File

@ -0,0 +1,35 @@
/*
* 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 ECP5_GFX_H
#define ECP5_GFX_H
#include "nextpnr.h"
NEXTPNR_NAMESPACE_BEGIN
const float logic_cell_x1 = 0.76;
const float logic_cell_x2 = 0.95;
const float logic_cell_y1 = 0.05;
const float logic_cell_y2 = 0.15;
const float logic_cell_pitch = 0.125;
NEXTPNR_NAMESPACE_END
#endif

View File

@ -100,16 +100,18 @@ int main(int argc, char *argv[])
} }
if (vm.count("help") || argc == 1) { if (vm.count("help") || argc == 1) {
std::cout << boost::filesystem::basename(argv[0]) << " -- Next Generation Place and Route (git " std::cout << boost::filesystem::basename(argv[0])
"sha1 " GIT_COMMIT_HASH_STR ")\n"; << " -- Next Generation Place and Route (git "
"sha1 " GIT_COMMIT_HASH_STR ")\n";
std::cout << "\n"; std::cout << "\n";
std::cout << options << "\n"; std::cout << options << "\n";
return argc != 1; return argc != 1;
} }
if (vm.count("version")) { if (vm.count("version")) {
std::cout << boost::filesystem::basename(argv[0]) << " -- Next Generation Place and Route (git " std::cout << boost::filesystem::basename(argv[0])
"sha1 " GIT_COMMIT_HASH_STR ")\n"; << " -- Next Generation Place and Route (git "
"sha1 " GIT_COMMIT_HASH_STR ")\n";
return 1; return 1;
} }

View File

@ -122,7 +122,7 @@ struct Arch : BaseCtx
Arch(ArchArgs args); Arch(ArchArgs args);
std::string getChipName() { return chipName; } std::string getChipName() const { return chipName; }
IdString archId() const { return id("generic"); } IdString archId() const { return id("generic"); }
IdString archArgsToId(ArchArgs args) const { return id("none"); } IdString archArgsToId(ArchArgs args) const { return id("none"); }

View File

@ -40,6 +40,8 @@ void MainWindow::createMenu()
{ {
QMenu *menu_Custom = new QMenu("&Generic", menuBar); QMenu *menu_Custom = new QMenu("&Generic", menuBar);
menuBar->addAction(menu_Custom->menuAction()); menuBar->addAction(menu_Custom->menuAction());
createGraphicsBar();
} }
void MainWindow::new_proj() {} void MainWindow::new_proj() {}

View File

@ -40,6 +40,8 @@ void MainWindow::createMenu()
{ {
QMenu *menu_Custom = new QMenu("&Generic", menuBar); QMenu *menu_Custom = new QMenu("&Generic", menuBar);
menuBar->addAction(menu_Custom->menuAction()); menuBar->addAction(menu_Custom->menuAction());
createGraphicsBar();
} }
void MainWindow::new_proj() {} void MainWindow::new_proj() {}

View File

@ -141,6 +141,7 @@ void ContextTreeModel::loadData(Context *ctx)
QMap<QString, ContextTreeItem *> pip_items; QMap<QString, ContextTreeItem *> pip_items;
// Add pips to tree // Add pips to tree
#ifndef ARCH_ECP5
for (auto pip : ctx->getPips()) { for (auto pip : ctx->getPips()) {
auto id = ctx->getPipName(pip); auto id = ctx->getPipName(pip);
QStringList items = QString(id.c_str(ctx)).split("/"); QStringList items = QString(id.c_str(ctx)).split("/");
@ -164,6 +165,7 @@ void ContextTreeModel::loadData(Context *ctx)
parent = pip_items[name]; parent = pip_items[name];
} }
} }
#endif
pip_root->sort(); pip_root->sort();
nets_root = new ContextTreeItem("Nets"); nets_root = new ContextTreeItem("Nets");
@ -341,4 +343,4 @@ QList<QModelIndex> ContextTreeModel::search(QString text)
} }
return list; return list;
} }
NEXTPNR_NAMESPACE_END NEXTPNR_NAMESPACE_END

View File

@ -204,7 +204,7 @@ Arch::Arch(ArchArgs args) : args(args)
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
std::string Arch::getChipName() std::string Arch::getChipName() const
{ {
#ifdef ICE40_HX1K_ONLY #ifdef ICE40_HX1K_ONLY
if (args.type == ArchArgs::HX1K) { if (args.type == ArchArgs::HX1K) {
@ -311,9 +311,23 @@ PortType Arch::getBelPinType(BelId bel, PortPin pin) const
int num_bel_wires = chip_info->bel_data[bel.index].num_bel_wires; int num_bel_wires = chip_info->bel_data[bel.index].num_bel_wires;
const BelWirePOD *bel_wires = chip_info->bel_data[bel.index].bel_wires.get(); const BelWirePOD *bel_wires = chip_info->bel_data[bel.index].bel_wires.get();
for (int i = 0; i < num_bel_wires; i++) if (num_bel_wires < 7) {
if (bel_wires[i].port == pin) for (int i = 0; i < num_bel_wires; i++) {
return PortType(bel_wires[i].type); if (bel_wires[i].port == pin)
return PortType(bel_wires[i].type);
}
} else {
int b = 0, e = num_bel_wires-1;
while (b <= e) {
int i = (b+e) / 2;
if (bel_wires[i].port == pin)
return PortType(bel_wires[i].type);
if (bel_wires[i].port > pin)
e = i-1;
else
b = i+1;
}
}
return PORT_INOUT; return PORT_INOUT;
} }
@ -327,10 +341,25 @@ WireId Arch::getBelPinWire(BelId bel, PortPin pin) const
int num_bel_wires = chip_info->bel_data[bel.index].num_bel_wires; int num_bel_wires = chip_info->bel_data[bel.index].num_bel_wires;
const BelWirePOD *bel_wires = chip_info->bel_data[bel.index].bel_wires.get(); const BelWirePOD *bel_wires = chip_info->bel_data[bel.index].bel_wires.get();
for (int i = 0; i < num_bel_wires; i++) { if (num_bel_wires < 7) {
if (bel_wires[i].port == pin) { for (int i = 0; i < num_bel_wires; i++) {
ret.index = bel_wires[i].wire_index; if (bel_wires[i].port == pin) {
break; ret.index = bel_wires[i].wire_index;
break;
}
}
} else {
int b = 0, e = num_bel_wires-1;
while (b <= e) {
int i = (b+e) / 2;
if (bel_wires[i].port == pin) {
ret.index = bel_wires[i].wire_index;
break;
}
if (bel_wires[i].port > pin)
e = i-1;
else
b = i+1;
} }
} }
@ -602,6 +631,11 @@ delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const
int xd = sink_loc.x - driver_loc.x, yd = sink_loc.y - driver_loc.y; int xd = sink_loc.x - driver_loc.x, yd = sink_loc.y - driver_loc.y;
int xscale = 120, yscale = 120, offset = 0; int xscale = 120, yscale = 120, offset = 0;
// if (chip_info->wire_data[src.index].type == WIRE_TYPE_SP4_VERT) {
// yd = yd < -4 ? yd + 4 : (yd < 0 ? 0 : yd);
// offset = 500;
// }
if (driver.port == id_o) offset += 330; if (driver.port == id_o) offset += 330;
if (sink.port == id_i0 || sink.port == id_i1 || sink.port == id_i2 || sink.port == id_i3) offset += 260; if (sink.port == id_i0 || sink.port == id_i1 || sink.port == id_i2 || sink.port == id_i3) offset += 260;

View File

@ -44,9 +44,9 @@ template <typename T> struct RelPtr
}; };
NPNR_PACKED_STRUCT(struct BelWirePOD { NPNR_PACKED_STRUCT(struct BelWirePOD {
int32_t wire_index;
PortPin port; PortPin port;
int32_t type; int32_t type;
int32_t wire_index;
}); });
NPNR_PACKED_STRUCT(struct BelInfoPOD { NPNR_PACKED_STRUCT(struct BelInfoPOD {
@ -365,7 +365,7 @@ struct Arch : BaseCtx
ArchArgs args; ArchArgs args;
Arch(ArchArgs args); Arch(ArchArgs args);
std::string getChipName(); std::string getChipName() const;
IdString archId() const { return id("ice40"); } IdString archId() const { return id("ice40"); }
IdString archArgsToId(ArchArgs args) const; IdString archArgsToId(ArchArgs args) const;

View File

@ -214,56 +214,71 @@ def wire_type(name):
assert 0 assert 0
return wt return wt
def pipdelay(src, dst, db): def pipdelay(src_idx, dst_idx, db):
if db is None: if db is None:
return 0 return 0
src = wire_names_r[src] src = wire_names_r[src_idx]
dst = wire_names_r[dst] dst = wire_names_r[dst_idx]
src_type = wire_type(src[2]) src_type = wire_type(src[2])
dst_type = wire_type(dst[2]) dst_type = wire_type(dst[2])
if dst[2].startswith("sp4_") or dst[2].startswith("span4_"):
if src[2].startswith("sp12_") or src[2].startswith("span12_"):
return db["Sp12to4.I.O"]
if src[2].startswith("span4_"):
return db["IoSpan4Mux.I.O"]
if dst[2].startswith("sp4_h_"):
return db["Span4Mux_h4.I.O"]
else:
return db["Span4Mux_v4.I.O"]
if dst[2].startswith("sp12_") or dst[2].startswith("span12_"):
if dst[2].startswith("sp12_h_"):
return db["Span12Mux_h12.I.O"]
else:
return db["Span12Mux_v12.I.O"]
if dst[2] in ("fabout", "clk"):
return 0 # FIXME?
if src[2].startswith("glb_netwk_") and dst[2].startswith("glb2local_"):
return 0 # FIXME?
if dst[2] == "carry_in_mux":
return db["ICE_CARRY_IN_MUX.carryinitin.carryinitout"]
if dst[2] in ("lutff_global/clk", "io_global/inclk", "io_global/outclk", "ram/RCLK", "ram/WCLK"):
return db["ClkMux.I.O"]
if dst[2] in ("lutff_global/s_r", "io_global/latch", "ram/RE", "ram/WE"):
return db["SRMux.I.O"]
if dst[2] in ("lutff_global/cen", "io_global/cen", "ram/RCLKE", "ram/WCLKE"):
return db["CEMux.I.O"]
if dst[2].startswith("local_"): if dst[2].startswith("local_"):
return db["LocalMux.I.O"] return db["LocalMux.I.O"]
if src_type == "LOCAL" and dst_type == "LOCAL": if src[2].startswith("local_") and dst[2] in ("io_0/D_OUT_0", "io_0/D_OUT_1", "io_0/OUT_ENB", "io_1/D_OUT_0", "io_1/D_OUT_1", "io_1/OUT_ENB"):
return 250 return db["IoInMux.I.O"]
if src_type == "GLOBAL" and dst_type == "LOCAL": if re.match(r"lutff_\d+/in_\d+", dst[2]):
return 400 return db["InMux.I.O"]
# Local -> Span if re.match(r"ram/(MASK|RADDR|WADDR|WDATA)_", dst[2]):
return db["InMux.I.O"]
if src_type == "LOCAL" and dst_type in ("SP4_HORZ", "SP4_VERT"): print(src, dst, src_idx, dst_idx, src_type, dst_type, file=sys.stderr)
return 350
if src_type == "LOCAL" and dst_type in ("SP12_HORZ", "SP12_VERT"):
return 500
# Span -> Local
if src_type in ("SP4_HORZ", "SP4_VERT", "SP12_HORZ", "SP12_VERT") and dst_type == "LOCAL":
return 300
# Span -> Span
if src_type in ("SP12_HORZ", "SP12_VERT") and dst_type in ("SP12_HORZ", "SP12_VERT"):
return 450
if src_type in ("SP4_HORZ", "SP4_VERT") and dst_type in ("SP4_HORZ", "SP4_VERT"):
return 300
if src_type in ("SP12_HORZ", "SP12_VERT") and dst_type in ("SP4_HORZ", "SP4_VERT"):
return 380
# print(src, dst, src_type, dst_type, file=sys.stderr)
assert 0 assert 0
def wiredelay(wire, db): def wiredelay(wire_idx, db):
if db is None: if db is None:
return 0 return 0
wire = wire_names_r[wire] wire = wire_names_r[wire_idx]
wtype = wire_type(wire[2]) wtype = wire_type(wire[2])
# FIXME # FIXME
@ -492,13 +507,13 @@ def add_bel_input(bel, wire, port):
if wire not in wire_belports: if wire not in wire_belports:
wire_belports[wire] = set() wire_belports[wire] = set()
wire_belports[wire].add((bel, port)) wire_belports[wire].add((bel, port))
bel_wires[bel].append((wire, port, 0)) bel_wires[bel].append((portpins[port], 0, wire))
def add_bel_output(bel, wire, port): def add_bel_output(bel, wire, port):
if wire not in wire_belports: if wire not in wire_belports:
wire_belports[wire] = set() wire_belports[wire] = set()
wire_belports[wire].add((bel, port)) wire_belports[wire].add((bel, port))
bel_wires[bel].append((wire, port, 1)) bel_wires[bel].append((portpins[port], 1, wire))
def add_bel_lc(x, y, z): def add_bel_lc(x, y, z):
bel = len(bel_name) bel = len(bel_name)
@ -759,14 +774,12 @@ bba.post('NEXTPNR_NAMESPACE_END')
bba.push("chipdb_blob_%s" % dev_name) bba.push("chipdb_blob_%s" % dev_name)
bba.r("chip_info_%s" % dev_name, "chip_info") bba.r("chip_info_%s" % dev_name, "chip_info")
index = 0
for bel in range(len(bel_name)): for bel in range(len(bel_name)):
bba.l("bel_wires_%d" % bel, "BelWirePOD") bba.l("bel_wires_%d" % bel, "BelWirePOD")
for i in range(len(bel_wires[bel])): for data in sorted(bel_wires[bel]):
bba.u32(bel_wires[bel][i][0], "wire_index") bba.u32(data[0], "port")
bba.u32(portpins[bel_wires[bel][i][1]], "port") bba.u32(data[1], "type")
bba.u32(bel_wires[bel][i][2], "type") bba.u32(data[2], "wire_index")
index += 1
bba.l("bel_data_%s" % dev_name, "BelInfoPOD") bba.l("bel_data_%s" % dev_name, "BelInfoPOD")
for bel in range(len(bel_name)): for bel in range(len(bel_name)):