Merge branch 'redist_slack' into 'redist_slack'
Redist slack See merge request eddiehung/nextpnr!5
This commit is contained in:
commit
f176ee48cd
@ -27,6 +27,8 @@
|
|||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <boost/functional/hash.hpp>
|
||||||
|
|
||||||
#ifndef NEXTPNR_H
|
#ifndef NEXTPNR_H
|
||||||
#define NEXTPNR_H
|
#define NEXTPNR_H
|
||||||
|
|
||||||
@ -158,8 +160,30 @@ struct GraphicElement
|
|||||||
std::string text;
|
std::string text;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Loc
|
||||||
|
{
|
||||||
|
int x = -1, y = -1, z = -1;
|
||||||
|
|
||||||
|
bool operator==(const Loc &other) const { return (x == other.x) && (y == other.y) && (z == other.z); }
|
||||||
|
bool operator!=(const Loc &other) const { return (x != other.x) || (y != other.y) || (z == other.z); }
|
||||||
|
};
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
|
||||||
|
namespace std {
|
||||||
|
template <> struct hash<NEXTPNR_NAMESPACE_PREFIX Loc>
|
||||||
|
{
|
||||||
|
std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX Loc &obj) const noexcept
|
||||||
|
{
|
||||||
|
std::size_t seed = 0;
|
||||||
|
boost::hash_combine(seed, hash<int>()(obj.x));
|
||||||
|
boost::hash_combine(seed, hash<int>()(obj.y));
|
||||||
|
boost::hash_combine(seed, hash<int>()(obj.z));
|
||||||
|
return seed;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace std
|
||||||
|
|
||||||
#include "archdefs.h"
|
#include "archdefs.h"
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_BEGIN
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
|
@ -402,6 +402,21 @@ struct Router
|
|||||||
|
|
||||||
NEXTPNR_NAMESPACE_BEGIN
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
static void prioritise_nets(Context *ctx, std::vector<IdString> &netsArray)
|
||||||
|
{
|
||||||
|
std::unordered_map<IdString, delay_t> netScores;
|
||||||
|
for (auto net_name : netsArray) {
|
||||||
|
delay_t score = std::numeric_limits<delay_t>::max();
|
||||||
|
for (const auto &sink : ctx->nets.at(net_name)->users) {
|
||||||
|
if (sink.budget < score)
|
||||||
|
score = sink.budget;
|
||||||
|
}
|
||||||
|
netScores[net_name] = score;
|
||||||
|
}
|
||||||
|
std::sort(netsArray.begin(), netsArray.end(),
|
||||||
|
[&netScores](IdString a, IdString b) { return netScores[a] < netScores[b]; });
|
||||||
|
}
|
||||||
|
|
||||||
bool router1(Context *ctx)
|
bool router1(Context *ctx)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
@ -508,7 +523,7 @@ bool router1(Context *ctx)
|
|||||||
bool printNets = ctx->verbose && (netsQueue.size() < 10);
|
bool printNets = ctx->verbose && (netsQueue.size() < 10);
|
||||||
|
|
||||||
std::vector<IdString> netsArray(netsQueue.begin(), netsQueue.end());
|
std::vector<IdString> netsArray(netsQueue.begin(), netsQueue.end());
|
||||||
ctx->sorted_shuffle(netsArray);
|
prioritise_nets(ctx, netsArray);
|
||||||
netsQueue.clear();
|
netsQueue.clear();
|
||||||
|
|
||||||
for (auto net_name : netsArray) {
|
for (auto net_name : netsArray) {
|
||||||
@ -560,7 +575,7 @@ bool router1(Context *ctx)
|
|||||||
int ripCnt = 0;
|
int ripCnt = 0;
|
||||||
|
|
||||||
std::vector<IdString> ripupArray(ripupQueue.begin(), ripupQueue.end());
|
std::vector<IdString> ripupArray(ripupQueue.begin(), ripupQueue.end());
|
||||||
ctx->sorted_shuffle(ripupArray);
|
prioritise_nets(ctx, ripupArray);
|
||||||
|
|
||||||
for (auto net_name : ripupArray) {
|
for (auto net_name : ripupArray) {
|
||||||
if (printNets)
|
if (printNets)
|
||||||
|
@ -217,6 +217,11 @@ void update_budget(Context *ctx)
|
|||||||
if (it == updates.end()) continue;
|
if (it == updates.end()) continue;
|
||||||
user.budget = delays.at(pi) + it->second;
|
user.budget = delays.at(pi) + it->second;
|
||||||
|
|
||||||
|
// HACK HACK HACK
|
||||||
|
if (net.second->driver.port == ctx->id("COUT"))
|
||||||
|
user.budget = 0;
|
||||||
|
// HACK HACK HACK
|
||||||
|
|
||||||
// Post-update check
|
// Post-update check
|
||||||
// if (user.budget < 0)
|
// if (user.budget < 0)
|
||||||
// log_warning("port %s.%s, connected to net '%s', has negative "
|
// log_warning("port %s.%s, connected to net '%s', has negative "
|
||||||
|
@ -29,8 +29,8 @@ void Arch::addWire(IdString name, int x, int y)
|
|||||||
NPNR_ASSERT(wires.count(name) == 0);
|
NPNR_ASSERT(wires.count(name) == 0);
|
||||||
WireInfo &wi = wires[name];
|
WireInfo &wi = wires[name];
|
||||||
wi.name = name;
|
wi.name = name;
|
||||||
wi.grid_x = x;
|
wi.x = x;
|
||||||
wi.grid_y = y;
|
wi.y = y;
|
||||||
|
|
||||||
wire_ids.push_back(name);
|
wire_ids.push_back(name);
|
||||||
}
|
}
|
||||||
@ -62,18 +62,28 @@ void Arch::addAlias(IdString name, IdString srcWire, IdString dstWire, DelayInfo
|
|||||||
pip_ids.push_back(name);
|
pip_ids.push_back(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Arch::addBel(IdString name, IdString type, int x, int y, bool gb)
|
void Arch::addBel(IdString name, IdString type, int x, int y, int z, bool gb)
|
||||||
{
|
{
|
||||||
|
Loc loc;
|
||||||
|
loc.x = x;
|
||||||
|
loc.y = y;
|
||||||
|
loc.z = z;
|
||||||
|
|
||||||
NPNR_ASSERT(bels.count(name) == 0);
|
NPNR_ASSERT(bels.count(name) == 0);
|
||||||
|
NPNR_ASSERT(bel_by_loc.count(loc) == 0);
|
||||||
BelInfo &bi = bels[name];
|
BelInfo &bi = bels[name];
|
||||||
bi.name = name;
|
bi.name = name;
|
||||||
bi.type = type;
|
bi.type = type;
|
||||||
bi.grid_x = x;
|
bi.x = x;
|
||||||
bi.grid_y = y;
|
bi.y = y;
|
||||||
|
bi.z = z;
|
||||||
bi.gb = gb;
|
bi.gb = gb;
|
||||||
|
|
||||||
bel_ids.push_back(name);
|
bel_ids.push_back(name);
|
||||||
bel_ids_by_type[type].push_back(name);
|
bel_ids_by_type[type].push_back(name);
|
||||||
|
|
||||||
|
bel_by_loc[loc] = name;
|
||||||
|
bels_by_tile[x][y].push_back(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Arch::addBelInput(IdString bel, IdString name, IdString wire)
|
void Arch::addBelInput(IdString bel, IdString name, IdString wire)
|
||||||
@ -348,8 +358,8 @@ const std::vector<GroupId> &Arch::getGroupGroups(GroupId group) const { return g
|
|||||||
|
|
||||||
void Arch::estimatePosition(BelId bel, int &x, int &y, bool &gb) const
|
void Arch::estimatePosition(BelId bel, int &x, int &y, bool &gb) const
|
||||||
{
|
{
|
||||||
x = bels.at(bel).grid_x;
|
x = bels.at(bel).x;
|
||||||
y = bels.at(bel).grid_y;
|
y = bels.at(bel).y;
|
||||||
gb = bels.at(bel).gb;
|
gb = bels.at(bel).gb;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -357,8 +367,8 @@ delay_t Arch::estimateDelay(WireId src, WireId dst) const
|
|||||||
{
|
{
|
||||||
const WireInfo &s = wires.at(src);
|
const WireInfo &s = wires.at(src);
|
||||||
const WireInfo &d = wires.at(dst);
|
const WireInfo &d = wires.at(dst);
|
||||||
int dx = abs(s.grid_x - d.grid_x);
|
int dx = abs(s.x - d.x);
|
||||||
int dy = abs(s.grid_y - d.grid_y);
|
int dy = abs(s.y - d.y);
|
||||||
return (dx + dy) * grid_distance_to_delay;
|
return (dx + dy) * grid_distance_to_delay;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ struct WireInfo
|
|||||||
BelPin uphill_bel_pin;
|
BelPin uphill_bel_pin;
|
||||||
std::vector<BelPin> downhill_bel_pins;
|
std::vector<BelPin> downhill_bel_pins;
|
||||||
DecalXY decalxy;
|
DecalXY decalxy;
|
||||||
int grid_x, grid_y;
|
int x, y;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PinInfo
|
struct PinInfo
|
||||||
@ -59,7 +59,7 @@ struct BelInfo
|
|||||||
IdString name, type, bound_cell;
|
IdString name, type, bound_cell;
|
||||||
std::unordered_map<IdString, PinInfo> pins;
|
std::unordered_map<IdString, PinInfo> pins;
|
||||||
DecalXY decalxy;
|
DecalXY decalxy;
|
||||||
int grid_x, grid_y;
|
int x, y, z;
|
||||||
bool gb;
|
bool gb;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -85,6 +85,9 @@ struct Arch : BaseCtx
|
|||||||
std::vector<IdString> bel_ids, wire_ids, pip_ids;
|
std::vector<IdString> bel_ids, wire_ids, pip_ids;
|
||||||
std::unordered_map<IdString, std::vector<IdString>> bel_ids_by_type;
|
std::unordered_map<IdString, std::vector<IdString>> bel_ids_by_type;
|
||||||
|
|
||||||
|
std::unordered_map<Loc, BelId> bel_by_loc;
|
||||||
|
std::unordered_map<int, std::unordered_map<int, std::vector<BelId>>> bels_by_tile;
|
||||||
|
|
||||||
std::unordered_map<DecalId, std::vector<GraphicElement>> decal_graphics;
|
std::unordered_map<DecalId, std::vector<GraphicElement>> decal_graphics;
|
||||||
DecalXY frame_decalxy;
|
DecalXY frame_decalxy;
|
||||||
|
|
||||||
@ -94,7 +97,7 @@ struct Arch : BaseCtx
|
|||||||
void addPip(IdString name, IdString srcWire, IdString dstWire, DelayInfo delay);
|
void addPip(IdString name, IdString srcWire, IdString dstWire, DelayInfo delay);
|
||||||
void addAlias(IdString name, IdString srcWire, IdString dstWire, DelayInfo delay);
|
void addAlias(IdString name, IdString srcWire, IdString dstWire, DelayInfo delay);
|
||||||
|
|
||||||
void addBel(IdString name, IdString type, int x, int y, bool gb);
|
void addBel(IdString name, IdString type, int x, int y, int z, bool gb);
|
||||||
void addBelInput(IdString bel, IdString name, IdString wire);
|
void addBelInput(IdString bel, IdString name, IdString wire);
|
||||||
void addBelOutput(IdString bel, IdString name, IdString wire);
|
void addBelOutput(IdString bel, IdString name, IdString wire);
|
||||||
void addBelInout(IdString bel, IdString name, IdString wire);
|
void addBelInout(IdString bel, IdString name, IdString wire);
|
||||||
@ -129,6 +132,10 @@ struct Arch : BaseCtx
|
|||||||
|
|
||||||
BelId getBelByName(IdString name) const;
|
BelId getBelByName(IdString name) const;
|
||||||
IdString getBelName(BelId bel) const;
|
IdString getBelName(BelId bel) const;
|
||||||
|
Loc getBelLocation(BelId bel) const;
|
||||||
|
BelId getBelByLocation(Loc loc) const;
|
||||||
|
std::vector<BelId> getBelsByTile(int x, int y) const;
|
||||||
|
bool getBelGlobalBuf(BelId bel) const;
|
||||||
uint32_t getBelChecksum(BelId bel) const;
|
uint32_t getBelChecksum(BelId bel) const;
|
||||||
void bindBel(BelId bel, IdString cell, PlaceStrength strength);
|
void bindBel(BelId bel, IdString cell, PlaceStrength strength);
|
||||||
void unbindBel(BelId bel);
|
void unbindBel(BelId bel);
|
||||||
|
@ -230,6 +230,9 @@ void DesignWidget::addToHistory(QTreeWidgetItem *item)
|
|||||||
void DesignWidget::newContext(Context *ctx)
|
void DesignWidget::newContext(Context *ctx)
|
||||||
{
|
{
|
||||||
treeWidget->clear();
|
treeWidget->clear();
|
||||||
|
// reset pointers since they are not valid after clear
|
||||||
|
nets_root = nullptr;
|
||||||
|
cells_root = nullptr;
|
||||||
history_ignore = false;
|
history_ignore = false;
|
||||||
history_index = -1;
|
history_index = -1;
|
||||||
history.clear();
|
history.clear();
|
||||||
@ -334,16 +337,7 @@ void DesignWidget::newContext(Context *ctx)
|
|||||||
for (auto pip : nameToItem[2].toStdMap()) {
|
for (auto pip : nameToItem[2].toStdMap()) {
|
||||||
pip_root->addChild(pip.second);
|
pip_root->addChild(pip.second);
|
||||||
}
|
}
|
||||||
|
updateTree();
|
||||||
// Add nets to tree
|
|
||||||
nets_root = new QTreeWidgetItem(treeWidget);
|
|
||||||
nets_root->setText(0, "Nets");
|
|
||||||
treeWidget->insertTopLevelItem(0, nets_root);
|
|
||||||
|
|
||||||
// Add cells to tree
|
|
||||||
cells_root = new QTreeWidgetItem(treeWidget);
|
|
||||||
cells_root->setText(0, "Cells");
|
|
||||||
treeWidget->insertTopLevelItem(0, cells_root);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DesignWidget::updateTree()
|
void DesignWidget::updateTree()
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
#include "placer1.h"
|
#include "placer1.h"
|
||||||
#include "router1.h"
|
#include "router1.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "cells.h"
|
||||||
NEXTPNR_NAMESPACE_BEGIN
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
// -----------------------------------------------------------------------
|
||||||
@ -255,11 +255,52 @@ BelId Arch::getBelByName(IdString name) const
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BelId Arch::getBelByLocation(Loc loc) const
|
||||||
|
{
|
||||||
|
BelId bel;
|
||||||
|
|
||||||
|
if (bel_by_loc.empty()) {
|
||||||
|
for (int i = 0; i < chip_info->num_bels; i++) {
|
||||||
|
BelId b;
|
||||||
|
b.index = i;
|
||||||
|
bel_by_loc[getBelLocation(b)] = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto it = bel_by_loc.find(loc);
|
||||||
|
if (it != bel_by_loc.end())
|
||||||
|
bel.index = it->second;
|
||||||
|
|
||||||
|
return bel;
|
||||||
|
}
|
||||||
|
|
||||||
|
BelRange Arch::getBelsByTile(int x, int y) const
|
||||||
|
{
|
||||||
|
// In iCE40 chipdb bels at the same tile are consecutive and dense z ordinates are used
|
||||||
|
BelRange br;
|
||||||
|
|
||||||
|
Loc loc;
|
||||||
|
loc.x = x;
|
||||||
|
loc.y = y;
|
||||||
|
loc.z = 0;
|
||||||
|
|
||||||
|
br.b.cursor = Arch::getBelByLocation(loc).index;
|
||||||
|
br.e.cursor = br.b.cursor;
|
||||||
|
|
||||||
|
if (br.e.cursor != -1) {
|
||||||
|
while (br.e.cursor < chip_info->num_bels &&
|
||||||
|
chip_info->bel_data[br.e.cursor].x == x &&
|
||||||
|
chip_info->bel_data[br.e.cursor].y == y)
|
||||||
|
br.e.cursor++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return br;
|
||||||
|
}
|
||||||
|
|
||||||
BelRange Arch::getBelsAtSameTile(BelId bel) const
|
BelRange Arch::getBelsAtSameTile(BelId bel) const
|
||||||
{
|
{
|
||||||
BelRange br;
|
BelRange br;
|
||||||
NPNR_ASSERT(bel != BelId());
|
NPNR_ASSERT(bel != BelId());
|
||||||
// This requires Bels at the same tile are consecutive
|
|
||||||
int x = chip_info->bel_data[bel.index].x;
|
int x = chip_info->bel_data[bel.index].x;
|
||||||
int y = chip_info->bel_data[bel.index].y;
|
int y = chip_info->bel_data[bel.index].y;
|
||||||
int start = bel.index, end = bel.index;
|
int start = bel.index, end = bel.index;
|
||||||
@ -704,6 +745,14 @@ void Arch::assignArchInfo()
|
|||||||
NetInfo *ni = net.second.get();
|
NetInfo *ni = net.second.get();
|
||||||
if (isGlobalNet(ni))
|
if (isGlobalNet(ni))
|
||||||
ni->is_global = true;
|
ni->is_global = true;
|
||||||
|
ni->is_enable = false;
|
||||||
|
ni->is_reset = false;
|
||||||
|
for (auto usr : ni->users) {
|
||||||
|
if (is_enable_port(this, usr))
|
||||||
|
ni->is_enable = true;
|
||||||
|
if (is_reset_port(this, usr))
|
||||||
|
ni->is_reset = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (auto &cell : getCtx()->cells) {
|
for (auto &cell : getCtx()->cells) {
|
||||||
CellInfo *ci = cell.second.get();
|
CellInfo *ci = cell.second.get();
|
||||||
|
22
ice40/arch.h
22
ice40/arch.h
@ -350,6 +350,7 @@ struct Arch : BaseCtx
|
|||||||
mutable std::unordered_map<IdString, int> bel_by_name;
|
mutable std::unordered_map<IdString, int> bel_by_name;
|
||||||
mutable std::unordered_map<IdString, int> wire_by_name;
|
mutable std::unordered_map<IdString, int> wire_by_name;
|
||||||
mutable std::unordered_map<IdString, int> pip_by_name;
|
mutable std::unordered_map<IdString, int> pip_by_name;
|
||||||
|
mutable std::unordered_map<Loc, int> bel_by_loc;
|
||||||
|
|
||||||
std::vector<IdString> bel_to_cell;
|
std::vector<IdString> bel_to_cell;
|
||||||
std::vector<IdString> wire_to_net;
|
std::vector<IdString> wire_to_net;
|
||||||
@ -440,7 +441,24 @@ struct Arch : BaseCtx
|
|||||||
return range;
|
return range;
|
||||||
}
|
}
|
||||||
|
|
||||||
BelRange getBelsAtSameTile(BelId bel) const;
|
Loc getBelLocation(BelId bel) const
|
||||||
|
{
|
||||||
|
Loc loc;
|
||||||
|
loc.x = chip_info->bel_data[bel.index].x;
|
||||||
|
loc.y = chip_info->bel_data[bel.index].y;
|
||||||
|
loc.z = chip_info->bel_data[bel.index].z;
|
||||||
|
return loc;
|
||||||
|
}
|
||||||
|
|
||||||
|
BelId getBelByLocation(Loc loc) const;
|
||||||
|
BelRange getBelsByTile(int x, int y) const;
|
||||||
|
|
||||||
|
bool getBelGlobalBuf(BelId bel) const
|
||||||
|
{
|
||||||
|
return chip_info->bel_data[bel.index].type == TYPE_SB_GB;
|
||||||
|
}
|
||||||
|
|
||||||
|
BelRange getBelsAtSameTile(BelId bel) const NPNR_DEPRECATED;
|
||||||
|
|
||||||
BelType getBelType(BelId bel) const
|
BelType getBelType(BelId bel) const
|
||||||
{
|
{
|
||||||
@ -671,7 +689,7 @@ struct Arch : BaseCtx
|
|||||||
|
|
||||||
// -------------------------------------------------
|
// -------------------------------------------------
|
||||||
|
|
||||||
void estimatePosition(BelId bel, int &x, int &y, bool &gb) const;
|
void estimatePosition(BelId bel, int &x, int &y, bool &gb) const NPNR_DEPRECATED;
|
||||||
delay_t estimateDelay(WireId src, WireId dst) const;
|
delay_t estimateDelay(WireId src, WireId dst) const;
|
||||||
delay_t getDelayEpsilon() const { return 20; }
|
delay_t getDelayEpsilon() const { return 20; }
|
||||||
delay_t getRipupDelayPenalty() const { return 200; }
|
delay_t getRipupDelayPenalty() const { return 200; }
|
||||||
|
@ -108,21 +108,15 @@ bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const
|
|||||||
} else if (cell->type == id_sb_io) {
|
} else if (cell->type == id_sb_io) {
|
||||||
return getBelPackagePin(bel) != "";
|
return getBelPackagePin(bel) != "";
|
||||||
} else if (cell->type == id_sb_gb) {
|
} else if (cell->type == id_sb_gb) {
|
||||||
bool is_reset = false, is_cen = false;
|
|
||||||
NPNR_ASSERT(cell->ports.at(id_glb_buf_out).net != nullptr);
|
NPNR_ASSERT(cell->ports.at(id_glb_buf_out).net != nullptr);
|
||||||
for (auto user : cell->ports.at(id_glb_buf_out).net->users) {
|
const NetInfo *net = cell->ports.at(id_glb_buf_out).net;
|
||||||
if (is_reset_port(this, user))
|
|
||||||
is_reset = true;
|
|
||||||
if (is_enable_port(this, user))
|
|
||||||
is_cen = true;
|
|
||||||
}
|
|
||||||
IdString glb_net = getWireName(getWireBelPin(bel, PIN_GLOBAL_BUFFER_OUTPUT));
|
IdString glb_net = getWireName(getWireBelPin(bel, PIN_GLOBAL_BUFFER_OUTPUT));
|
||||||
int glb_id = std::stoi(std::string("") + glb_net.str(this).back());
|
int glb_id = std::stoi(std::string("") + glb_net.str(this).back());
|
||||||
if (is_reset && is_cen)
|
if (net->is_reset && net->is_enable)
|
||||||
return false;
|
return false;
|
||||||
else if (is_reset)
|
else if (net->is_reset)
|
||||||
return (glb_id % 2) == 0;
|
return (glb_id % 2) == 0;
|
||||||
else if (is_cen)
|
else if (net->is_enable)
|
||||||
return (glb_id % 2) == 1;
|
return (glb_id % 2) == 1;
|
||||||
else
|
else
|
||||||
return true;
|
return true;
|
||||||
|
@ -21,8 +21,6 @@
|
|||||||
#error Include "archdefs.h" via "nextpnr.h" only.
|
#error Include "archdefs.h" via "nextpnr.h" only.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <boost/functional/hash.hpp>
|
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_BEGIN
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
typedef int delay_t;
|
typedef int delay_t;
|
||||||
@ -153,6 +151,7 @@ struct DecalId
|
|||||||
struct ArchNetInfo
|
struct ArchNetInfo
|
||||||
{
|
{
|
||||||
bool is_global = false;
|
bool is_global = false;
|
||||||
|
bool is_reset = false, is_enable = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NetInfo;
|
struct NetInfo;
|
||||||
|
@ -157,6 +157,42 @@ void configure_extra_cell(chipconfig_t &config, const Context *ctx, CellInfo *ce
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string tagTileType(TileType &tile)
|
||||||
|
{
|
||||||
|
if (tile == TILE_NONE)
|
||||||
|
return "";
|
||||||
|
switch (tile) {
|
||||||
|
case TILE_LOGIC:
|
||||||
|
return ".logic_tile";
|
||||||
|
break;
|
||||||
|
case TILE_IO:
|
||||||
|
return ".io_tile";
|
||||||
|
break;
|
||||||
|
case TILE_RAMB:
|
||||||
|
return ".ramb_tile";
|
||||||
|
break;
|
||||||
|
case TILE_RAMT:
|
||||||
|
return ".ramt_tile";
|
||||||
|
break;
|
||||||
|
case TILE_DSP0:
|
||||||
|
return ".dsp0_tile";
|
||||||
|
break;
|
||||||
|
case TILE_DSP1:
|
||||||
|
return ".dsp1_tile";
|
||||||
|
break;
|
||||||
|
case TILE_DSP2:
|
||||||
|
return ".dsp2_tile";
|
||||||
|
break;
|
||||||
|
case TILE_DSP3:
|
||||||
|
return ".dsp3_tile";
|
||||||
|
break;
|
||||||
|
case TILE_IPCON:
|
||||||
|
return ".ipcon_tile";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
NPNR_ASSERT(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
void write_asc(const Context *ctx, std::ostream &out)
|
void write_asc(const Context *ctx, std::ostream &out)
|
||||||
{
|
{
|
||||||
// [y][x][row][col]
|
// [y][x][row][col]
|
||||||
@ -191,7 +227,7 @@ void write_asc(const Context *ctx, std::ostream &out)
|
|||||||
out << ".device 5k" << std::endl;
|
out << ".device 5k" << std::endl;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
NPNR_ASSERT_FALSE("unsupported device type");
|
NPNR_ASSERT_FALSE("unsupported device type\n");
|
||||||
}
|
}
|
||||||
// Set pips
|
// Set pips
|
||||||
for (auto pip : ctx->getPips()) {
|
for (auto pip : ctx->getPips()) {
|
||||||
@ -214,9 +250,9 @@ void write_asc(const Context *ctx, std::ostream &out)
|
|||||||
std::cout << "Found unplaced cell " << cell.first.str(ctx) << " while generating bitstream!" << std::endl;
|
std::cout << "Found unplaced cell " << cell.first.str(ctx) << " while generating bitstream!" << std::endl;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const BelInfoPOD &beli = ci.bel_data[bel.index];
|
|
||||||
int x = beli.x, y = beli.y, z = beli.z;
|
|
||||||
if (cell.second->type == ctx->id("ICESTORM_LC")) {
|
if (cell.second->type == ctx->id("ICESTORM_LC")) {
|
||||||
|
const BelInfoPOD &beli = ci.bel_data[bel.index];
|
||||||
|
int x = beli.x, y = beli.y, z = beli.z;
|
||||||
const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_LOGIC];
|
const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_LOGIC];
|
||||||
unsigned lut_init = get_param_or_def(cell.second.get(), ctx->id("LUT_INIT"));
|
unsigned lut_init = get_param_or_def(cell.second.get(), ctx->id("LUT_INIT"));
|
||||||
bool neg_clk = get_param_or_def(cell.second.get(), ctx->id("NEG_CLK"));
|
bool neg_clk = get_param_or_def(cell.second.get(), ctx->id("NEG_CLK"));
|
||||||
@ -251,6 +287,8 @@ void write_asc(const Context *ctx, std::ostream &out)
|
|||||||
set_config(ti, config.at(y).at(x), "CarryInSet", carry_set);
|
set_config(ti, config.at(y).at(x), "CarryInSet", carry_set);
|
||||||
}
|
}
|
||||||
} else if (cell.second->type == ctx->id("SB_IO")) {
|
} else if (cell.second->type == ctx->id("SB_IO")) {
|
||||||
|
const BelInfoPOD &beli = ci.bel_data[bel.index];
|
||||||
|
int x = beli.x, y = beli.y, z = beli.z;
|
||||||
const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_IO];
|
const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_IO];
|
||||||
unsigned pin_type = get_param_or_def(cell.second.get(), ctx->id("PIN_TYPE"));
|
unsigned pin_type = get_param_or_def(cell.second.get(), ctx->id("PIN_TYPE"));
|
||||||
bool neg_trigger = get_param_or_def(cell.second.get(), ctx->id("NEG_TRIGGER"));
|
bool neg_trigger = get_param_or_def(cell.second.get(), ctx->id("NEG_TRIGGER"));
|
||||||
@ -445,37 +483,7 @@ void write_asc(const Context *ctx, std::ostream &out)
|
|||||||
TileType tile = tile_at(ctx, x, y);
|
TileType tile = tile_at(ctx, x, y);
|
||||||
if (tile == TILE_NONE)
|
if (tile == TILE_NONE)
|
||||||
continue;
|
continue;
|
||||||
switch (tile) {
|
out << tagTileType(tile);
|
||||||
case TILE_LOGIC:
|
|
||||||
out << ".logic_tile";
|
|
||||||
break;
|
|
||||||
case TILE_IO:
|
|
||||||
out << ".io_tile";
|
|
||||||
break;
|
|
||||||
case TILE_RAMB:
|
|
||||||
out << ".ramb_tile";
|
|
||||||
break;
|
|
||||||
case TILE_RAMT:
|
|
||||||
out << ".ramt_tile";
|
|
||||||
break;
|
|
||||||
case TILE_DSP0:
|
|
||||||
out << ".dsp0_tile";
|
|
||||||
break;
|
|
||||||
case TILE_DSP1:
|
|
||||||
out << ".dsp1_tile";
|
|
||||||
break;
|
|
||||||
case TILE_DSP2:
|
|
||||||
out << ".dsp2_tile";
|
|
||||||
break;
|
|
||||||
case TILE_DSP3:
|
|
||||||
out << ".dsp3_tile";
|
|
||||||
break;
|
|
||||||
case TILE_IPCON:
|
|
||||||
out << ".ipcon_tile";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
NPNR_ASSERT(false);
|
|
||||||
}
|
|
||||||
out << " " << x << " " << y << std::endl;
|
out << " " << x << " " << y << std::endl;
|
||||||
for (auto row : config.at(y).at(x)) {
|
for (auto row : config.at(y).at(x)) {
|
||||||
for (auto col : row) {
|
for (auto col : row) {
|
||||||
@ -526,4 +534,106 @@ void write_asc(const Context *ctx, std::ostream &out)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void read_config(Context *ctx, std::istream &in, chipconfig_t &config)
|
||||||
|
{
|
||||||
|
constexpr size_t line_buf_size = 65536;
|
||||||
|
char buffer[line_buf_size];
|
||||||
|
int tile_x = -1, tile_y = -1, line_nr = -1;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
in.getline(buffer, line_buf_size);
|
||||||
|
if (buffer[0] == '.') {
|
||||||
|
line_nr = -1;
|
||||||
|
const char *tok = strtok(buffer, " \t\r\n");
|
||||||
|
|
||||||
|
if (!strcmp(tok, ".device")) {
|
||||||
|
std::string config_device = strtok(nullptr, " \t\r\n");
|
||||||
|
std::string expected;
|
||||||
|
switch (ctx->args.type) {
|
||||||
|
case ArchArgs::LP384:
|
||||||
|
expected = "384";
|
||||||
|
break;
|
||||||
|
case ArchArgs::HX1K:
|
||||||
|
case ArchArgs::LP1K:
|
||||||
|
expected = "1k";
|
||||||
|
break;
|
||||||
|
case ArchArgs::HX8K:
|
||||||
|
case ArchArgs::LP8K:
|
||||||
|
expected = "8k";
|
||||||
|
break;
|
||||||
|
case ArchArgs::UP5K:
|
||||||
|
expected = "5k";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
log_error("unsupported device type\n");
|
||||||
|
}
|
||||||
|
if (expected != config_device)
|
||||||
|
log_error("device type does not match\n");
|
||||||
|
} else if (!strcmp(tok, ".io_tile") || !strcmp(tok, ".logic_tile") || !strcmp(tok, ".ramb_tile") ||
|
||||||
|
!strcmp(tok, ".ramt_tile") || !strcmp(tok, ".ipcon_tile") || !strcmp(tok, ".dsp0_tile") ||
|
||||||
|
!strcmp(tok, ".dsp1_tile") || !strcmp(tok, ".dsp2_tile") || !strcmp(tok, ".dsp3_tile")) {
|
||||||
|
line_nr = 0;
|
||||||
|
tile_x = atoi(strtok(nullptr, " \t\r\n"));
|
||||||
|
tile_y = atoi(strtok(nullptr, " \t\r\n"));
|
||||||
|
|
||||||
|
TileType tile = tile_at(ctx, tile_x, tile_y);
|
||||||
|
if (tok != tagTileType(tile))
|
||||||
|
log_error("Wrong tile type for specified position\n");
|
||||||
|
|
||||||
|
} else if (!strcmp(tok, ".extra_bit")) {
|
||||||
|
/*
|
||||||
|
int b = atoi(strtok(nullptr, " \t\r\n"));
|
||||||
|
int x = atoi(strtok(nullptr, " \t\r\n"));
|
||||||
|
int y = atoi(strtok(nullptr, " \t\r\n"));
|
||||||
|
std::tuple<int, int, int> key(b, x, y);
|
||||||
|
extra_bits.insert(key);
|
||||||
|
*/
|
||||||
|
} else if (!strcmp(tok, ".sym")) {
|
||||||
|
int wireIndex = atoi(strtok(nullptr, " \t\r\n"));
|
||||||
|
const char *name = strtok(nullptr, " \t\r\n");
|
||||||
|
|
||||||
|
std::unique_ptr<NetInfo> created_net = std::unique_ptr<NetInfo>(new NetInfo);
|
||||||
|
IdString netName = ctx->id(name);
|
||||||
|
created_net->name = netName;
|
||||||
|
ctx->nets[netName] = std::move(created_net);
|
||||||
|
|
||||||
|
WireId wire;
|
||||||
|
wire.index = wireIndex;
|
||||||
|
ctx->bindWire(wire, netName, STRENGTH_WEAK);
|
||||||
|
}
|
||||||
|
} else if (line_nr >= 0 && strlen(buffer) > 0) {
|
||||||
|
if (line_nr > int(config.at(tile_y).at(tile_x).size() - 1))
|
||||||
|
log_error("Invalid data in input asc file");
|
||||||
|
for (int i = 0; buffer[i] == '0' || buffer[i] == '1'; i++)
|
||||||
|
config.at(tile_y).at(tile_x).at(line_nr).at(i) = (buffer[i] == '1') ? 1 : 0;
|
||||||
|
line_nr++;
|
||||||
|
}
|
||||||
|
if (in.eof())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool read_asc(Context *ctx, std::istream &in)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// [y][x][row][col]
|
||||||
|
const ChipInfoPOD &ci = *ctx->chip_info;
|
||||||
|
const BitstreamInfoPOD &bi = *ci.bits_info;
|
||||||
|
chipconfig_t config;
|
||||||
|
config.resize(ci.height);
|
||||||
|
for (int y = 0; y < ci.height; y++) {
|
||||||
|
config.at(y).resize(ci.width);
|
||||||
|
for (int x = 0; x < ci.width; x++) {
|
||||||
|
TileType tile = tile_at(ctx, x, y);
|
||||||
|
int rows = bi.tiles_nonrouting[tile].rows;
|
||||||
|
int cols = bi.tiles_nonrouting[tile].cols;
|
||||||
|
config.at(y).at(x).resize(rows, std::vector<int8_t>(cols));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
read_config(ctx, in, config);
|
||||||
|
return true;
|
||||||
|
} catch (log_execution_error_exception) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
NEXTPNR_NAMESPACE_BEGIN
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
void write_asc(const Context *ctx, std::ostream &out);
|
void write_asc(const Context *ctx, std::ostream &out);
|
||||||
|
bool read_asc(Context *ctx, std::istream &in);
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
|
||||||
|
@ -66,6 +66,12 @@ void svg_dump_decal(const Context *ctx, const DecalXY &decal)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void conflicting_options(const boost::program_options::variables_map &vm, const char *opt1, const char *opt2)
|
||||||
|
{
|
||||||
|
if (vm.count(opt1) && !vm[opt1].defaulted() && vm.count(opt2) && !vm[opt2].defaulted())
|
||||||
|
log_error((std::string("Conflicting options '") + opt1 + "' and '" + opt2 + "'.").c_str());
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
@ -95,6 +101,7 @@ int main(int argc, char *argv[])
|
|||||||
options.add_options()("json", po::value<std::string>(), "JSON design file to ingest");
|
options.add_options()("json", po::value<std::string>(), "JSON design file to ingest");
|
||||||
options.add_options()("pcf", po::value<std::string>(), "PCF constraints file to ingest");
|
options.add_options()("pcf", po::value<std::string>(), "PCF constraints file to ingest");
|
||||||
options.add_options()("asc", po::value<std::string>(), "asc bitstream file to write");
|
options.add_options()("asc", po::value<std::string>(), "asc bitstream file to write");
|
||||||
|
options.add_options()("read", po::value<std::string>(), "asc bitstream file to read");
|
||||||
options.add_options()("seed", po::value<int>(), "seed value for random number generator");
|
options.add_options()("seed", po::value<int>(), "seed value for random number generator");
|
||||||
options.add_options()("version,V", "show version");
|
options.add_options()("version,V", "show version");
|
||||||
options.add_options()("tmfuzz", "run path delay estimate fuzzer");
|
options.add_options()("tmfuzz", "run path delay estimate fuzzer");
|
||||||
@ -121,13 +128,17 @@ int main(int argc, char *argv[])
|
|||||||
po::store(parsed, vm);
|
po::store(parsed, vm);
|
||||||
|
|
||||||
po::notify(vm);
|
po::notify(vm);
|
||||||
}
|
} catch (std::exception &e) {
|
||||||
|
|
||||||
catch (std::exception &e) {
|
|
||||||
std::cout << e.what() << "\n";
|
std::cout << e.what() << "\n";
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
conflicting_options(vm, "read", "json");
|
||||||
|
#ifndef ICE40_HX1K_ONLY
|
||||||
|
if ((vm.count("lp384") + vm.count("lp1k") + vm.count("lp8k") + vm.count("hx1k") + vm.count("hx8k") +
|
||||||
|
vm.count("up5k")) > 1)
|
||||||
|
log_error("Only one device type can be set\n");
|
||||||
|
#endif
|
||||||
if (vm.count("help") || argc == 1) {
|
if (vm.count("help") || argc == 1) {
|
||||||
help:
|
help:
|
||||||
std::cout << boost::filesystem::basename(argv[0])
|
std::cout << boost::filesystem::basename(argv[0])
|
||||||
@ -353,6 +364,13 @@ int main(int argc, char *argv[])
|
|||||||
if (vm.count("no-tmdriv"))
|
if (vm.count("no-tmdriv"))
|
||||||
ctx->timing_driven = false;
|
ctx->timing_driven = false;
|
||||||
|
|
||||||
|
if (vm.count("read")) {
|
||||||
|
std::string filename = vm["read"].as<std::string>();
|
||||||
|
std::ifstream f(filename);
|
||||||
|
if (!read_asc(ctx.get(), f))
|
||||||
|
log_error("Loading ASC failed.\n");
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef NO_GUI
|
#ifndef NO_GUI
|
||||||
if (vm.count("gui")) {
|
if (vm.count("gui")) {
|
||||||
Application a(argc, argv);
|
Application a(argc, argv);
|
||||||
|
Loading…
Reference in New Issue
Block a user