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)
- [Gaffe](https://github.com/kc8apf/gaffe)
- [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);
if (driver_gb)
return 0;
delay_t negative_slack = 0;
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;
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);
auto slack = load.budget - net_delay;
if (slack < 0)
tns += slack;
negative_slack += 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));
}
tns = ctx->getDelayNS(tns);
tns += ctx->getDelayNS(negative_slack);
return wirelength;
}

View File

@ -21,6 +21,7 @@
#include <algorithm>
#include <cmath>
#include <cstring>
#include "gfx.h"
#include "log.h"
#include "nextpnr.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) {
return "LFE5U-25F";
} 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;
// 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;
}
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 {}; }

View File

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

View File

@ -120,17 +120,21 @@ struct GroupId
struct DecalId
{
char type = 0; // Bel/Wire/Pip/Frame (b/w/p/f)
enum
{
TYPE_FRAME,
TYPE_BEL
} type;
Location location;
uint32_t z = 0;
bool active = false;
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
{
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<NEXTPNR_NAMESPACE_PREFIX Location>()(decal.location));
boost::hash_combine(seed, hash<int>()(decal.z));
boost::hash_combine(seed, hash<bool>()(decal.active));
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) {
std::cout << boost::filesystem::basename(argv[0]) << " -- Next Generation Place and Route (git "
"sha1 " GIT_COMMIT_HASH_STR ")\n";
std::cout << boost::filesystem::basename(argv[0])
<< " -- Next Generation Place and Route (git "
"sha1 " GIT_COMMIT_HASH_STR ")\n";
std::cout << "\n";
std::cout << options << "\n";
return argc != 1;
}
if (vm.count("version")) {
std::cout << boost::filesystem::basename(argv[0]) << " -- Next Generation Place and Route (git "
"sha1 " GIT_COMMIT_HASH_STR ")\n";
std::cout << boost::filesystem::basename(argv[0])
<< " -- Next Generation Place and Route (git "
"sha1 " GIT_COMMIT_HASH_STR ")\n";
return 1;
}

View File

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

View File

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

View File

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

View File

@ -141,6 +141,7 @@ void ContextTreeModel::loadData(Context *ctx)
QMap<QString, ContextTreeItem *> pip_items;
// Add pips to tree
#ifndef ARCH_ECP5
for (auto pip : ctx->getPips()) {
auto id = ctx->getPipName(pip);
QStringList items = QString(id.c_str(ctx)).split("/");
@ -164,6 +165,7 @@ void ContextTreeModel::loadData(Context *ctx)
parent = pip_items[name];
}
}
#endif
pip_root->sort();
nets_root = new ContextTreeItem("Nets");
@ -341,4 +343,4 @@ QList<QModelIndex> ContextTreeModel::search(QString text)
}
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
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;
const BelWirePOD *bel_wires = chip_info->bel_data[bel.index].bel_wires.get();
for (int i = 0; i < num_bel_wires; i++)
if (bel_wires[i].port == pin)
return PortType(bel_wires[i].type);
if (num_bel_wires < 7) {
for (int i = 0; i < num_bel_wires; i++) {
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;
}
@ -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;
const BelWirePOD *bel_wires = chip_info->bel_data[bel.index].bel_wires.get();
for (int i = 0; i < num_bel_wires; i++) {
if (bel_wires[i].port == pin) {
ret.index = bel_wires[i].wire_index;
break;
if (num_bel_wires < 7) {
for (int i = 0; i < num_bel_wires; i++) {
if (bel_wires[i].port == pin) {
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 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 (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 {
int32_t wire_index;
PortPin port;
int32_t type;
int32_t wire_index;
});
NPNR_PACKED_STRUCT(struct BelInfoPOD {
@ -365,7 +365,7 @@ struct Arch : BaseCtx
ArchArgs args;
Arch(ArchArgs args);
std::string getChipName();
std::string getChipName() const;
IdString archId() const { return id("ice40"); }
IdString archArgsToId(ArchArgs args) const;

View File

@ -214,56 +214,71 @@ def wire_type(name):
assert 0
return wt
def pipdelay(src, dst, db):
def pipdelay(src_idx, dst_idx, db):
if db is None:
return 0
src = wire_names_r[src]
dst = wire_names_r[dst]
src = wire_names_r[src_idx]
dst = wire_names_r[dst_idx]
src_type = wire_type(src[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_"):
return db["LocalMux.I.O"]
if src_type == "LOCAL" and dst_type == "LOCAL":
return 250
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 db["IoInMux.I.O"]
if src_type == "GLOBAL" and dst_type == "LOCAL":
return 400
if re.match(r"lutff_\d+/in_\d+", dst[2]):
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"):
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)
print(src, dst, src_idx, dst_idx, src_type, dst_type, file=sys.stderr)
assert 0
def wiredelay(wire, db):
def wiredelay(wire_idx, db):
if db is None:
return 0
wire = wire_names_r[wire]
wire = wire_names_r[wire_idx]
wtype = wire_type(wire[2])
# FIXME
@ -492,13 +507,13 @@ def add_bel_input(bel, wire, port):
if wire not in wire_belports:
wire_belports[wire] = set()
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):
if wire not in wire_belports:
wire_belports[wire] = set()
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):
bel = len(bel_name)
@ -759,14 +774,12 @@ bba.post('NEXTPNR_NAMESPACE_END')
bba.push("chipdb_blob_%s" % dev_name)
bba.r("chip_info_%s" % dev_name, "chip_info")
index = 0
for bel in range(len(bel_name)):
bba.l("bel_wires_%d" % bel, "BelWirePOD")
for i in range(len(bel_wires[bel])):
bba.u32(bel_wires[bel][i][0], "wire_index")
bba.u32(portpins[bel_wires[bel][i][1]], "port")
bba.u32(bel_wires[bel][i][2], "type")
index += 1
for data in sorted(bel_wires[bel]):
bba.u32(data[0], "port")
bba.u32(data[1], "type")
bba.u32(data[2], "wire_index")
bba.l("bel_data_%s" % dev_name, "BelInfoPOD")
for bel in range(len(bel_name)):