This commit is contained in:
Eddie Hung 2018-12-26 18:14:23 -08:00
parent 463d9a6920
commit a630758ca7
7 changed files with 56 additions and 1218 deletions

View File

@ -28,27 +28,8 @@
#include "router1.h"
#include "util.h"
#include <boost/serialization/unique_ptr.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/unordered_map.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/iostreams/filter/zlib.hpp>
#include <boost/iostreams/filtering_streambuf.hpp>
struct nextpnr_binary_iarchive : public boost::archive::binary_iarchive {
nextpnr_binary_iarchive(boost::iostreams::filtering_istreambuf &ifs, NEXTPNR_NAMESPACE::BaseCtx* ctx, const std::string& inDeviceName, const std::string& inPackageName) : boost::archive::binary_iarchive(ifs), ctx(ctx), inDeviceName(inDeviceName), inPackageName(inPackageName) {}
NEXTPNR_NAMESPACE::BaseCtx *ctx;
std::string inDeviceName, inPackageName;
};
struct nextpnr_binary_oarchive : public boost::archive::binary_oarchive {
nextpnr_binary_oarchive(boost::iostreams::filtering_ostreambuf &ofs, NEXTPNR_NAMESPACE::BaseCtx* ctx) : boost::archive::binary_oarchive(ofs), ctx(ctx) {}
NEXTPNR_NAMESPACE::BaseCtx *ctx;
};
#include "torc/common/DirectoryTree.hpp"
//#define TORC_INFO_DB "torc_info.ar"
NEXTPNR_NAMESPACE_BEGIN
std::unique_ptr<const TorcInfo> torc_info;
@ -369,29 +350,7 @@ Arch::Arch(ArchArgs args) : args(args)
{
torc::common::DirectoryTree directoryTree("/opt/torc/src/torc");
if (args.type == ArchArgs::Z020) {
#ifdef TORC_INFO_DB
std::ifstream ifs(TORC_INFO_DB, std::ios::binary);
if (ifs) {
boost::iostreams::filtering_istreambuf fifs;
fifs.push(boost::iostreams::zlib_decompressor());
fifs.push(ifs);
nextpnr_binary_iarchive ia(fifs, this, "xc7z020", args.package);
ia >> torc_info;
} else
#endif
{
torc_info = std::unique_ptr<TorcInfo>(new TorcInfo(this, "xc7z020", args.package));
#ifdef TORC_INFO_DB
std::ofstream ofs(TORC_INFO_DB, std::ios::binary);
if (ofs) {
boost::iostreams::filtering_ostreambuf fofs;
fofs.push(boost::iostreams::zlib_compressor());
fofs.push(ofs);
nextpnr_binary_oarchive oa(fofs, this);
oa << torc_info;
}
#endif
}
torc_info = std::unique_ptr<TorcInfo>(new TorcInfo(this, "xc7z020", args.package));
} else if (args.type == ArchArgs::VX980) {
torc_info = std::unique_ptr<TorcInfo>(new TorcInfo(this, "xc7vx980t", args.package));
} else {
@ -406,21 +365,9 @@ Arch::Arch(ArchArgs args) : args(args)
log_info("Number of pips: %d\n", torc_info->num_pips);
}
// package_info = nullptr;
// for (int i = 0; i < chip_info->num_packages; i++) {
// if (chip_info->packages_data[i].name.get() == args.package) {
// package_info = &(chip_info->packages_data[i]);
// break;
// }
// }
// if (package_info == nullptr)
// log_error("Unsupported package '%s'.\n", args.package.c_str());
// bel_carry.resize(chip_info->num_bels);
bel_to_cell.resize(torc_info->num_bels);
wire_to_net.resize(torc_info->num_wires);
pip_to_net.resize(torc_info->num_pips);
// switches_locked.resize(chip_info->num_switches);
}
// -----------------------------------------------------------------------
@ -429,6 +376,8 @@ std::string Arch::getChipName() const
{
if (args.type == ArchArgs::Z020) {
return "z020";
} else if (args.type == ArchArgs::VX980) {
return "vx980";
} else {
log_error("Unsupported XC7 chip type.\n");
}
@ -440,6 +389,8 @@ IdString Arch::archArgsToId(ArchArgs args) const
{
if (args.type == ArchArgs::Z020)
return id("z020");
if (args.type == ArchArgs::VX980)
return id("vx980");
return IdString();
}
@ -564,49 +515,12 @@ WireId Arch::getBelPinWire(BelId bel, IdString pin) const
pin_name.c_str());
return torc_info->tilewire_to_wire(tw);
// NPNR_ASSERT(bel != BelId());
//
// 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();
//
// if (num_bel_wires < 7) {
// for (int i = 0; i < num_bel_wires; i++) {
// if (bel_wires[i].port == pin.index) {
// 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.index) {
// ret.index = bel_wires[i].wire_index;
// break;
// }
// if (bel_wires[i].port > pin.index)
// e = i - 1;
// else
// b = i + 1;
// }
// }
//
//return ret;
}
std::vector<IdString> Arch::getBelPins(BelId bel) const
{
std::vector<IdString> ret;
/* NPNR_ASSERT(bel != BelId());
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++)
ret.push_back(IdString(bel_wires[i].port));
*/
NPNR_ASSERT("TODO");
return ret;
}
@ -615,54 +529,17 @@ std::vector<IdString> Arch::getBelPins(BelId bel) const
WireId Arch::getWireByName(IdString name) const
{
WireId ret;
if (wire_by_name.empty()) {
for (int i = 0; i < chip_info->num_wires; i++)
wire_by_name[id(chip_info->wire_data[i].name.get())] = i;
}
// auto it = wire_by_name.find(name);
// if (it != wire_by_name.end())
// ret.index = it->second;
return ret;
}
IdString Arch::getWireType(WireId wire) const
{
NPNR_ASSERT(wire != WireId());
// switch (chip_info->wire_data[wire.index].type) {
// case WireInfoPOD::WIRE_TYPE_NONE:
// return IdString();
// case WireInfoPOD::WIRE_TYPE_GLB2LOCAL:
// return id("GLB2LOCAL");
// case WireInfoPOD::WIRE_TYPE_GLB_NETWK:
// return id("GLB_NETWK");
// case WireInfoPOD::WIRE_TYPE_LOCAL:
// return id("LOCAL");
// case WireInfoPOD::WIRE_TYPE_LUTFF_IN:
// return id("LUTFF_IN");
// case WireInfoPOD::WIRE_TYPE_LUTFF_IN_LUT:
// return id("LUTFF_IN_LUT");
// case WireInfoPOD::WIRE_TYPE_LUTFF_LOUT:
// return id("LUTFF_LOUT");
// case WireInfoPOD::WIRE_TYPE_LUTFF_OUT:
// return id("LUTFF_OUT");
// case WireInfoPOD::WIRE_TYPE_LUTFF_COUT:
// return id("LUTFF_COUT");
// case WireInfoPOD::WIRE_TYPE_LUTFF_GLOBAL:
// return id("LUTFF_GLOBAL");
// case WireInfoPOD::WIRE_TYPE_CARRY_IN_MUX:
// return id("CARRY_IN_MUX");
// case WireInfoPOD::WIRE_TYPE_SP4_V:
// return id("SP4_V");
// case WireInfoPOD::WIRE_TYPE_SP4_H:
// return id("SP4_H");
// case WireInfoPOD::WIRE_TYPE_SP12_V:
// return id("SP12_V");
// case WireInfoPOD::WIRE_TYPE_SP12_H:
// return id("SP12_H");
// }
NPNR_ASSERT("TODO");
return IdString();
}
@ -670,6 +547,7 @@ IdString Arch::getWireType(WireId wire) const
std::vector<std::pair<IdString, std::string>> Arch::getWireAttrs(WireId wire) const
{
std::vector<std::pair<IdString, std::string>> ret;
NPNR_ASSERT("TODO");
return ret;
}
@ -678,19 +556,7 @@ std::vector<std::pair<IdString, std::string>> Arch::getWireAttrs(WireId wire) co
PipId Arch::getPipByName(IdString name) const
{
PipId ret;
/* if (pip_by_name.empty()) {
for (int i = 0; i < chip_info->num_pips; i++) {
PipId pip;
pip.index = i;
pip_by_name[getPipName(pip)] = i;
}
}
auto it = pip_by_name.find(name);
if (it != pip_by_name.end())
ret.index = it->second;
*/
NPNR_ASSERT("TODO");
return ret;
}
@ -703,33 +569,12 @@ IdString Arch::getPipName(PipId pip) const
std::stringstream pip_name;
pip_name << ewi_src.mTileName << "." << ewi_src.mWireName << ".->." << ewi_dst.mWireName;
return id(pip_name.str());
//#if 1
// int x = chip_info->pip_data[pip.index].x;
// int y = chip_info->pip_data[pip.index].y;
//
// std::string src_name = chip_info->wire_data[chip_info->pip_data[pip.index].src].name.get();
// std::replace(src_name.begin(), src_name.end(), '/', '.');
//
// std::string dst_name = chip_info->wire_data[chip_info->pip_data[pip.index].dst].name.get();
// std::replace(dst_name.begin(), dst_name.end(), '/', '.');
//
// return id("X" + std::to_string(x) + "/Y" + std::to_string(y) + "/" + src_name + ".->." + dst_name);
//#else
// return id(chip_info->pip_data[pip.index].name.get());
//#endif
}
//IdString Arch::getPipType(PipId pip) const
//{
// NPNR_ASSERT(pip != PipId());
// return IdString();
//}
std::vector<std::pair<IdString, std::string>> Arch::getPipAttrs(PipId pip) const
{
std::vector<std::pair<IdString, std::string>> ret;
NPNR_ASSERT("TODO");
return ret;
}
@ -739,11 +584,7 @@ BelId Arch::getPackagePinBel(const std::string &pin) const { return getBelByName
std::string Arch::getBelPackagePin(BelId bel) const
{
// for (int i = 0; i < package_info->num_pins; i++) {
// if (package_info->pins[i].bel_index == bel.index) {
// return std::string(package_info->pins[i].name.get());
// }
// }
NPNR_ASSERT("TODO");
return "";
}
@ -762,39 +603,7 @@ IdString Arch::getGroupName(GroupId group) const
std::string suffix;
switch (group.type) {
case GroupId::TYPE_FRAME:
suffix = "tile";
break;
case GroupId::TYPE_MAIN_SW:
suffix = "main_sw";
break;
case GroupId::TYPE_LOCAL_SW:
suffix = "local_sw";
break;
case GroupId::TYPE_LC0_SW:
suffix = "lc0_sw";
break;
case GroupId::TYPE_LC1_SW:
suffix = "lc1_sw";
break;
case GroupId::TYPE_LC2_SW:
suffix = "lc2_sw";
break;
case GroupId::TYPE_LC3_SW:
suffix = "lc3_sw";
break;
case GroupId::TYPE_LC4_SW:
suffix = "lc4_sw";
break;
case GroupId::TYPE_LC5_SW:
suffix = "lc5_sw";
break;
case GroupId::TYPE_LC6_SW:
suffix = "lc6_sw";
break;
case GroupId::TYPE_LC7_SW:
suffix = "lc7_sw";
break;
NPNR_ASSERT("TODO");
default:
return IdString();
}
@ -805,52 +614,7 @@ IdString Arch::getGroupName(GroupId group) const
std::vector<GroupId> Arch::getGroups() const
{
std::vector<GroupId> ret;
/*
for (int y = 0; y < chip_info->height; y++) {
for (int x = 0; x < chip_info->width; x++) {
TileType type = chip_info->tile_grid[y * chip_info->width + x];
if (type == TILE_NONE)
continue;
GroupId group;
group.type = GroupId::TYPE_FRAME;
group.x = x;
group.y = y;
// ret.push_back(group);
group.type = GroupId::TYPE_MAIN_SW;
ret.push_back(group);
group.type = GroupId::TYPE_LOCAL_SW;
ret.push_back(group);
if (type == TILE_LOGIC) {
group.type = GroupId::TYPE_LC0_SW;
ret.push_back(group);
group.type = GroupId::TYPE_LC1_SW;
ret.push_back(group);
group.type = GroupId::TYPE_LC2_SW;
ret.push_back(group);
group.type = GroupId::TYPE_LC3_SW;
ret.push_back(group);
group.type = GroupId::TYPE_LC4_SW;
ret.push_back(group);
group.type = GroupId::TYPE_LC5_SW;
ret.push_back(group);
group.type = GroupId::TYPE_LC6_SW;
ret.push_back(group);
group.type = GroupId::TYPE_LC7_SW;
ret.push_back(group);
}
}
}*/
NPNR_ASSERT("TODO");
return ret;
}
@ -869,12 +633,14 @@ std::vector<WireId> Arch::getGroupWires(GroupId group) const
std::vector<PipId> Arch::getGroupPips(GroupId group) const
{
std::vector<PipId> ret;
NPNR_ASSERT("TODO");
return ret;
}
std::vector<GroupId> Arch::getGroupGroups(GroupId group) const
{
std::vector<GroupId> ret;
NPNR_ASSERT("TODO");
return ret;
}
@ -929,6 +695,7 @@ DecalXY Arch::getGroupDecal(GroupId group) const
std::vector<GraphicElement> Arch::getDecalGraphics(DecalId decal) const
{
std::vector<GraphicElement> ret;
NPNR_ASSERT("TODO");
return ret;
}
@ -1078,109 +845,3 @@ void Arch::assignCellInfo(CellInfo *cell)
}
NEXTPNR_NAMESPACE_END
// outside of any namespace
BOOST_SERIALIZATION_SPLIT_FREE(Segments::SegmentReference)
BOOST_SERIALIZATION_SPLIT_FREE(CompactSegmentIndex)
BOOST_SERIALIZATION_SPLIT_FREE(TileIndex)
BOOST_SERIALIZATION_SPLIT_FREE(Arc)
BOOST_SERIALIZATION_SPLIT_FREE(Tilewire)
BOOST_SERIALIZATION_SPLIT_FREE(WireIndex)
BOOST_SERIALIZATION_SPLIT_FREE(SiteIndex)
BOOST_SERIALIZATION_SPLIT_FREE(NEXTPNR_NAMESPACE::IdString)
namespace boost { namespace serialization {
template<class Archive>
inline void load_construct_data(
Archive & ar, NEXTPNR_NAMESPACE::TorcInfo * t, const unsigned int file_version
){
const auto& inDeviceName = static_cast<const nextpnr_binary_iarchive&>(ar).inDeviceName;
const auto& inPackageName = static_cast<const nextpnr_binary_iarchive&>(ar).inPackageName;
::new(t)NEXTPNR_NAMESPACE::TorcInfo(inDeviceName, inPackageName);
}
template<class Archive>
void save(Archive& ar, const Segments::SegmentReference& o, unsigned int) {
ar & o.getCompactSegmentIndex();
ar & o.getAnchorTileIndex();
}
template<class Archive>
void load(Archive& ar, Segments::SegmentReference& o, unsigned int) {
CompactSegmentIndex i;
TileIndex j;
ar & i;
ar & j;
o = Segments::SegmentReference(i, j);
}
#define SERIALIZE_POD(__T__) \
template<class Archive> \
void save(Archive& ar, const __T__& o, unsigned int) { \
ar & static_cast<__T__::pod>(o); \
} \
template<class Archive> \
void load(Archive& ar, __T__& o, unsigned int) { \
__T__::pod i; \
ar & i; \
o = __T__(i); \
}
SERIALIZE_POD(CompactSegmentIndex)
SERIALIZE_POD(TileIndex)
SERIALIZE_POD(WireIndex)
SERIALIZE_POD(SiteIndex)
template<class Archive>
void save(Archive& ar, const Arc& o, unsigned int) {
ar & o.getSourceTilewire();
ar & o.getSinkTilewire();
}
template<class Archive>
void load(Archive& ar, Arc& o, unsigned int) {
Tilewire s, t;
ar & s;
ar & t;
o = Arc(s, t);
}
template<class Archive>
void save(Archive& ar, const Tilewire& o, unsigned int) {
ar & o.getTileIndex();
ar & o.getWireIndex();
}
template<class Archive>
void load(Archive& ar, Tilewire& o, unsigned int) {
TileIndex i;
WireIndex j;
ar & i;
ar & j;
o.setTileIndex(TileIndex(i));
o.setWireIndex(WireIndex(j));
}
template<class Archive>
void serialize(Archive& ar, NEXTPNR_NAMESPACE::Loc& o, unsigned int) {
ar & o.x;
ar & o.y;
ar & o.z;
}
template<class Archive>
void serialize(Archive& ar, NEXTPNR_NAMESPACE::DelayInfo& o, unsigned int) {
ar & o.delay;
}
template<class Archive>
void save(Archive& ar, const NEXTPNR_NAMESPACE::IdString& o, unsigned int) {
const std::string i = o.str(static_cast<const nextpnr_binary_oarchive&>(ar).ctx);
ar & i;
}
template<class Archive>
void load(Archive& ar, NEXTPNR_NAMESPACE::IdString& o, unsigned int) {
std::string i;
ar & i;
o = static_cast<nextpnr_binary_iarchive&>(ar).ctx->id(i);
}
#define SERIALIZE_INDEX(__T__) \
template<class Archive> \
void serialize(Archive& ar, __T__& o, unsigned int) { \
ar & o.index; \
}
SERIALIZE_INDEX(NEXTPNR_NAMESPACE::BelId)
SERIALIZE_INDEX(NEXTPNR_NAMESPACE::WireId)
SERIALIZE_INDEX(NEXTPNR_NAMESPACE::PipId)
}} // namespace boost::serialization

View File

@ -21,8 +21,6 @@
#error Include "arch.h" via "nextpnr.h" only.
#endif
#include <boost/serialization/access.hpp>
#include "torc/Architecture.hpp"
#include "torc/Common.hpp"
using namespace torc::architecture;
@ -327,29 +325,6 @@ struct TorcInfo
std::vector<std::pair<int,int>> tile_to_xy;
TorcInfo(const std::string &inDeviceName, const std::string &inPackageName);
private:
friend class boost::serialization::access;
//TorcInfo(const std::string &inDeviceName, const std::string &inPackageName);
//template<class Archive, class T> friend inline void load_construct_data(Archive &ar, T *t, const unsigned int file_version);
template<class Archive>
void serialize(Archive & ar, const unsigned int /*version*/)
{
ar & bel_to_site_index;
ar & num_bels;
ar & site_index_to_bel;
ar & site_index_to_type;
ar & bel_to_loc;
ar & segment_to_wire;
ar & trivial_to_wire;
ar & wire_to_tilewire;
ar & num_wires;
ar & wire_to_delay;
ar & wire_to_pips_downhill;
ar & pip_to_arc;
ar & num_pips;
ar & wire_is_global;
ar & tile_to_xy;
}
};
extern std::unique_ptr<const TorcInfo> torc_info;
@ -675,7 +650,6 @@ struct Arch : BaseCtx
auto pip = it->second.pip;
if (pip != PipId()) {
pip_to_net[pip.index] = nullptr;
// switches_locked[chip_info->pip_data[pip.index].switch_index] = nullptr;
}
net_wires.erase(it);
@ -708,10 +682,7 @@ struct Arch : BaseCtx
BelPinRange getWireBelPins(WireId wire) const
{
BelPinRange range;
// NPNR_ASSERT(wire != WireId());
// range.b.ptr = chip_info->wire_data[wire.index].bel_pins.get();
// range.e.ptr = range.b.ptr + chip_info->wire_data[wire.index].num_bel_pins;
throw;
NPNR_ASSERT("TODO");
return range;
}
@ -731,10 +702,8 @@ struct Arch : BaseCtx
{
NPNR_ASSERT(pip != PipId());
NPNR_ASSERT(pip_to_net[pip.index] == nullptr);
// NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] == nullptr);
pip_to_net[pip.index] = net;
// switches_locked[chip_info->pip_data[pip.index].switch_index] = net;
WireId dst = getPipDstWire(pip);
NPNR_ASSERT(wire_to_net[dst.index] == nullptr);
@ -749,7 +718,6 @@ struct Arch : BaseCtx
{
NPNR_ASSERT(pip != PipId());
NPNR_ASSERT(pip_to_net[pip.index] != nullptr);
// NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] != nullptr);
WireId dst = getPipDstWire(pip);
NPNR_ASSERT(wire_to_net[dst.index] != nullptr);
@ -757,7 +725,6 @@ struct Arch : BaseCtx
pip_to_net[pip.index]->wires.erase(dst);
pip_to_net[pip.index] = nullptr;
// switches_locked[chip_info->pip_data[pip.index].switch_index] = nullptr;
refreshUiPip(pip);
refreshUiWire(dst);
}
@ -765,25 +732,6 @@ struct Arch : BaseCtx
bool checkPipAvail(PipId pip) const
{
NPNR_ASSERT(pip != PipId());
// auto &pi = chip_info->pip_data[pip.index];
// auto &si = chip_info->bits_info->switches[pi.switch_index];
// if (switches_locked[pi.switch_index] != nullptr)
// return false;
// if (pi.flags & PipInfoPOD::FLAG_ROUTETHRU) {
// NPNR_ASSERT(si.bel >= 0);
// if (bel_to_cell[si.bel] != nullptr)
// return false;
//}
// if (pi.flags & PipInfoPOD::FLAG_NOCARRY) {
// NPNR_ASSERT(si.bel >= 0);
// if (bel_carry[si.bel])
// return false;
//}
// return true;
return pip_to_net[pip.index] == nullptr;
}
@ -798,7 +746,6 @@ struct Arch : BaseCtx
NetInfo *getConflictingPipNet(PipId pip) const
{
NPNR_ASSERT(pip != PipId());
// return switches_locked[chip_info->pip_data[pip.index].switch_index];
return pip_to_net[pip.index];
}
@ -812,16 +759,9 @@ struct Arch : BaseCtx
Loc getPipLocation(PipId pip) const
{
//const auto &arc = torc_info->pip_to_arc[pip.index];
//const auto &tw = arc.getSourceTilewire();
//const auto &tile_info = torc_info->tiles.getTileInfo(tw.getTileIndex());
//Loc loc;
//loc.x = tile_info.getCol();
//loc.y = tile_info.getRow();
//loc.z = 0;
//return loc;
throw;
Loc loc;
NPNR_ASSERT("TODO");
return loc;
}
IdString getPipName(PipId pip) const;
@ -980,6 +920,4 @@ struct Arch : BaseCtx
float placer_constraintWeight = 10;
};
// void ice40DelayFuzzerMain(Context *ctx);
NEXTPNR_NAMESPACE_END

View File

@ -29,43 +29,14 @@ NEXTPNR_NAMESPACE_BEGIN
bool Arch::logicCellsCompatible(const CellInfo **it, const size_t size) const
{
// bool dffs_exist = false, dffs_neg = false;
// const NetInfo *cen = nullptr, *clk = nullptr, *sr = nullptr;
//
// for (auto cell : boost::make_iterator_range(it, it+size)) {
// NPNR_ASSERT(cell->belType == id_ICESTORM_LC);
// if (cell->lcInfo.dffEnable) {
// if (!dffs_exist) {
// dffs_exist = true;
// cen = cell->lcInfo.cen;
// clk = cell->lcInfo.clk;
// sr = cell->lcInfo.sr;
//
// if (cell->lcInfo.negClk) {
// dffs_neg = true;
// }
// } else {
// if (cen != cell->lcInfo.cen)
// return false;
// if (clk != cell->lcInfo.clk)
// return false;
// if (sr != cell->lcInfo.sr)
// return false;
// if (dffs_neg != cell->lcInfo.negClk)
// return false;
// }
// }
// locals_count += cell->lcInfo.inputCount;
// }
//
// return locals_count <= 32;
// TODO: Check clock, clock-enable, and set-reset compatiility
return true;
}
bool Arch::isBelLocationValid(BelId bel) const
{
if (getBelType(bel) == id_ICESTORM_LC) {
std::array<const CellInfo *, 8> bel_cells;
if (getBelType(bel) == id("XC7_LC")) {
std::array<const CellInfo *, 4> bel_cells;
size_t num_cells = 0;
Loc bel_loc = getBelLocation(bel);
for (auto bel_other : getBelsByTile(bel_loc.x, bel_loc.y)) {
@ -85,70 +56,23 @@ bool Arch::isBelLocationValid(BelId bel) const
bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const
{
// if (cell->type == id_ICESTORM_LC) {
// NPNR_ASSERT(getBelType(bel) == id_ICESTORM_LC);
//
// std::array<const CellInfo *, 8> bel_cells;
// size_t num_cells = 0;
//
// Loc bel_loc = getBelLocation(bel);
// for (auto bel_other : getBelsByTile(bel_loc.x, bel_loc.y)) {
// CellInfo *ci_other = getBoundBelCell(bel_other);
// if (ci_other != nullptr && bel_other != bel)
// bel_cells[num_cells++] = ci_other;
// }
//
// bel_cells[num_cells++] = cell;
// return logicCellsCompatible(bel_cells.data(), num_cells);
// } else if (cell->type == id_SB_IO) {
// // Do not allow placement of input SB_IOs on blocks where there a PLL is outputting to.
//
// // Find shared PLL by looking for driving bel siblings from D_IN_0
// // that are a PLL clock output.
// auto wire = getBelPinWire(bel, id_D_IN_0);
// IdString pll_bel_pin;
// BelId pll_bel;
// for (auto pin : getWireBelPins(wire)) {
// if (pin.pin == id_PLLOUT_A || pin.pin == id_PLLOUT_B) {
// pll_bel = pin.bel;
// pll_bel_pin = pin.pin;
// break;
// }
// }
// // Is there a PLL that shares this IO buffer?
// if (pll_bel.index != -1) {
// auto pll_cell = getBoundBelCell(pll_bel);
// // Is a PLL placed in this PLL bel?
// if (pll_cell != nullptr) {
// // Is the shared port driving a net?
// auto pi = pll_cell->ports[pll_bel_pin];
// if (pi.net != nullptr) {
// // Are we perhaps a PAD INPUT Bel that can be placed here?
// if (pll_cell->attrs[id("BEL_PAD_INPUT")] == getBelName(bel).str(this)) {
// return true;
// }
// return false;
// }
// }
// }
// return getBelPackagePin(bel) != "";
// } else if (cell->type == id_SB_GB) {
// NPNR_ASSERT(cell->ports.at(id_GLOBAL_BUFFER_OUTPUT).net != nullptr);
// const NetInfo *net = cell->ports.at(id_GLOBAL_BUFFER_OUTPUT).net;
// IdString glb_net = getWireName(getBelPinWire(bel, id_GLOBAL_BUFFER_OUTPUT));
// int glb_id = std::stoi(std::string("") + glb_net.str(this).back());
// if (net->is_reset && net->is_enable)
// return false;
// else if (net->is_reset)
// return (glb_id % 2) == 0;
// else if (net->is_enable)
// return (glb_id % 2) == 1;
// else
// return true;
// } else {
// // TODO: IO cell clock checks
return true;
// }
if (cell->type == id("XC7_LC")) {
std::array<const CellInfo *, 4> bel_cells;
size_t num_cells = 0;
Loc bel_loc = getBelLocation(bel);
for (auto bel_other : getBelsByTile(bel_loc.x, bel_loc.y)) {
CellInfo *ci_other = getBoundBelCell(bel_other);
if (ci_other != nullptr && bel_other != bel)
bel_cells[num_cells++] = ci_other;
}
bel_cells[num_cells++] = cell;
return logicCellsCompatible(bel_cells.data(), num_cells);
}
else {
return true;
}
}
NEXTPNR_NAMESPACE_END

View File

@ -1,7 +1,7 @@
#!/bin/bash
set -ex
yosys blinky.ys
- ../nextpnr-xc7 --json blinky.json --pcf blinky.pcf --xdl blinky.xdl --freq 150
../nextpnr-xc7 --json blinky.json --pcf blinky.pcf --xdl blinky.xdl --freq 150
xdl -xdl2ncd blinky.xdl
bitgen -w blinky.ncd -g UnconstrainedPins:Allow
trce blinky.ncd -v 10

View File

@ -68,190 +68,15 @@ std::unique_ptr<CellInfo> create_xc7_cell(Context *ctx, IdString type, std::stri
add_port(ctx, new_cell.get(), "OMUX", PORT_OUT);
add_port(ctx, new_cell.get(), "COUT", PORT_OUT);
} else if (type == ctx->id("IOBUF")) {
if (ctx->args.type == ArchArgs::Z020) {
new_cell->type = id_IOB33;
} else {
new_cell->type = id_IOB18;
}
//new_cell->params[ctx->id("PIN_TYPE")] = "0";
//new_cell->params[ctx->id("PULLUP")] = "0";
//new_cell->params[ctx->id("NEG_TRIGGER")] = "0";
//new_cell->params[ctx->id("IOSTANDARD")] = "SB_LVCMOS";
// add_port(ctx, new_cell.get(), "PACKAGE_PIN", PORT_INOUT);
//
// add_port(ctx, new_cell.get(), "LATCH_INPUT_VALUE", PORT_IN);
// add_port(ctx, new_cell.get(), "CLOCK_ENABLE", PORT_IN);
// add_port(ctx, new_cell.get(), "INPUT_CLK", PORT_IN);
// add_port(ctx, new_cell.get(), "OUTPUT_CLK", PORT_IN);
//
// add_port(ctx, new_cell.get(), "OUTPUT_ENABLE", PORT_IN);
// add_port(ctx, new_cell.get(), "D_OUT_0", PORT_IN);
// add_port(ctx, new_cell.get(), "D_OUT_1", PORT_IN);
//
// add_port(ctx, new_cell.get(), "D_IN_0", PORT_OUT);
// add_port(ctx, new_cell.get(), "D_IN_1", PORT_OUT);
if (ctx->args.type == ArchArgs::Z020)
new_cell->type = id_IOB33;
else
new_cell->type = id_IOB18;
add_port(ctx, new_cell.get(), "I", PORT_OUT);
add_port(ctx, new_cell.get(), "O", PORT_IN);
// } else if (type == ctx->id("ICESTORM_RAM")) {
// new_cell->params[ctx->id("NEG_CLK_W")] = "0";
// new_cell->params[ctx->id("NEG_CLK_R")] = "0";
// new_cell->params[ctx->id("WRITE_MODE")] = "0";
// new_cell->params[ctx->id("READ_MODE")] = "0";
//
// add_port(ctx, new_cell.get(), "RCLK", PORT_IN);
// add_port(ctx, new_cell.get(), "RCLKE", PORT_IN);
// add_port(ctx, new_cell.get(), "RE", PORT_IN);
//
// add_port(ctx, new_cell.get(), "WCLK", PORT_IN);
// add_port(ctx, new_cell.get(), "WCLKE", PORT_IN);
// add_port(ctx, new_cell.get(), "WE", PORT_IN);
//
// for (int i = 0; i < 16; i++) {
// add_port(ctx, new_cell.get(), "WDATA_" + std::to_string(i), PORT_IN);
// add_port(ctx, new_cell.get(), "MASK_" + std::to_string(i), PORT_IN);
// add_port(ctx, new_cell.get(), "RDATA_" + std::to_string(i), PORT_OUT);
// }
//
// for (int i = 0; i < 11; i++) {
// add_port(ctx, new_cell.get(), "RADDR_" + std::to_string(i), PORT_IN);
// add_port(ctx, new_cell.get(), "WADDR_" + std::to_string(i), PORT_IN);
// }
// } else if (type == ctx->id("ICESTORM_LFOSC")) {
// add_port(ctx, new_cell.get(), "CLKLFEN", PORT_IN);
// add_port(ctx, new_cell.get(), "CLKLFPU", PORT_IN);
// add_port(ctx, new_cell.get(), "CLKLF", PORT_OUT);
// add_port(ctx, new_cell.get(), "CLKLF_FABRIC", PORT_OUT);
// } else if (type == ctx->id("ICESTORM_HFOSC")) {
// new_cell->params[ctx->id("CLKHF_DIV")] = "0b00";
// new_cell->params[ctx->id("TRIM_EN")] = "0b0";
//
// add_port(ctx, new_cell.get(), "CLKHFEN", PORT_IN);
// add_port(ctx, new_cell.get(), "CLKHFPU", PORT_IN);
// add_port(ctx, new_cell.get(), "CLKHF", PORT_OUT);
// add_port(ctx, new_cell.get(), "CLKHF_FABRIC", PORT_OUT);
// for (int i = 0; i < 10; i++)
// add_port(ctx, new_cell.get(), "TRIM" + std::to_string(i), PORT_IN);
} else if (type == id_BUFGCTRL) {
add_port(ctx, new_cell.get(), "I0", PORT_IN);
add_port(ctx, new_cell.get(), "O", PORT_OUT);
// } else if (type == ctx->id("ICESTORM_SPRAM")) {
// add_port(ctx, new_cell.get(), "WREN", PORT_IN);
// add_port(ctx, new_cell.get(), "CHIPSELECT", PORT_IN);
// add_port(ctx, new_cell.get(), "CLOCK", PORT_IN);
// add_port(ctx, new_cell.get(), "STANDBY", PORT_IN);
// add_port(ctx, new_cell.get(), "SLEEP", PORT_IN);
// add_port(ctx, new_cell.get(), "POWEROFF", PORT_IN);
//
// for (int i = 0; i < 16; i++) {
// add_port(ctx, new_cell.get(), "DATAIN_" + std::to_string(i), PORT_IN);
// add_port(ctx, new_cell.get(), "DATAOUT_" + std::to_string(i), PORT_OUT);
// }
// for (int i = 0; i < 14; i++) {
// add_port(ctx, new_cell.get(), "ADDRESS_" + std::to_string(i), PORT_IN);
// }
// for (int i = 0; i < 4; i++) {
// add_port(ctx, new_cell.get(), "MASKWREN_" + std::to_string(i), PORT_IN);
// }
// } else if (type == ctx->id("ICESTORM_DSP")) {
// new_cell->params[ctx->id("NEG_TRIGGER")] = "0";
//
// new_cell->params[ctx->id("C_REG")] = "0";
// new_cell->params[ctx->id("A_REG")] = "0";
// new_cell->params[ctx->id("B_REG")] = "0";
// new_cell->params[ctx->id("D_REG")] = "0";
// new_cell->params[ctx->id("TOP_8x8_MULT_REG")] = "0";
// new_cell->params[ctx->id("BOT_8x8_MULT_REG")] = "0";
// new_cell->params[ctx->id("PIPELINE_16x16_MULT_REG1")] = "0";
// new_cell->params[ctx->id("PIPELINE_16x16_MULT_REG2")] = "0";
//
// new_cell->params[ctx->id("TOPOUTPUT_SELECT")] = "0";
// new_cell->params[ctx->id("TOPADDSUB_LOWERINPUT")] = "0";
// new_cell->params[ctx->id("TOPADDSUB_UPPERINPUT")] = "0";
// new_cell->params[ctx->id("TOPADDSUB_CARRYSELECT")] = "0";
//
// new_cell->params[ctx->id("BOTOUTPUT_SELECT")] = "0";
// new_cell->params[ctx->id("BOTADDSUB_LOWERINPUT")] = "0";
// new_cell->params[ctx->id("BOTADDSUB_UPPERINPUT")] = "0";
// new_cell->params[ctx->id("BOTADDSUB_CARRYSELECT")] = "0";
//
// new_cell->params[ctx->id("MODE_8x8")] = "0";
// new_cell->params[ctx->id("A_SIGNED")] = "0";
// new_cell->params[ctx->id("B_SIGNED")] = "0";
//
// add_port(ctx, new_cell.get(), "CLK", PORT_IN);
// add_port(ctx, new_cell.get(), "CE", PORT_IN);
// for (int i = 0; i < 16; i++) {
// add_port(ctx, new_cell.get(), "C_" + std::to_string(i), PORT_IN);
// add_port(ctx, new_cell.get(), "A_" + std::to_string(i), PORT_IN);
// add_port(ctx, new_cell.get(), "B_" + std::to_string(i), PORT_IN);
// add_port(ctx, new_cell.get(), "D_" + std::to_string(i), PORT_IN);
// }
// add_port(ctx, new_cell.get(), "AHOLD", PORT_IN);
// add_port(ctx, new_cell.get(), "BHOLD", PORT_IN);
// add_port(ctx, new_cell.get(), "CHOLD", PORT_IN);
// add_port(ctx, new_cell.get(), "DHOLD", PORT_IN);
//
// add_port(ctx, new_cell.get(), "IRSTTOP", PORT_IN);
// add_port(ctx, new_cell.get(), "IRSTBOT", PORT_IN);
// add_port(ctx, new_cell.get(), "ORSTTOP", PORT_IN);
// add_port(ctx, new_cell.get(), "ORSTBOT", PORT_IN);
//
// add_port(ctx, new_cell.get(), "OLOADTOP", PORT_IN);
// add_port(ctx, new_cell.get(), "OLOADBOT", PORT_IN);
//
// add_port(ctx, new_cell.get(), "ADDSUBTOP", PORT_IN);
// add_port(ctx, new_cell.get(), "ADDSUBBOT", PORT_IN);
//
// add_port(ctx, new_cell.get(), "OHOLDTOP", PORT_IN);
// add_port(ctx, new_cell.get(), "OHOLDBOT", PORT_IN);
//
// add_port(ctx, new_cell.get(), "CI", PORT_IN);
// add_port(ctx, new_cell.get(), "ACCUMCI", PORT_IN);
// add_port(ctx, new_cell.get(), "SIGNEXTIN", PORT_IN);
//
// for (int i = 0; i < 32; i++) {
// add_port(ctx, new_cell.get(), "O_" + std::to_string(i), PORT_OUT);
// }
//
// add_port(ctx, new_cell.get(), "CO", PORT_OUT);
// add_port(ctx, new_cell.get(), "ACCUMCO", PORT_OUT);
// add_port(ctx, new_cell.get(), "SIGNEXTOUT", PORT_OUT);
//
// } else if (type == ctx->id("ICESTORM_PLL")) {
// new_cell->params[ctx->id("DELAY_ADJMODE_FB")] = "0";
// new_cell->params[ctx->id("DELAY_ADJMODE_REL")] = "0";
//
// new_cell->params[ctx->id("DIVF")] = "0";
// new_cell->params[ctx->id("DIVQ")] = "0";
// new_cell->params[ctx->id("DIVR")] = "0";
//
// new_cell->params[ctx->id("FDA_FEEDBACK")] = "0";
// new_cell->params[ctx->id("FDA_RELATIVE")] = "0";
// new_cell->params[ctx->id("FEEDBACK_PATH")] = "0";
// new_cell->params[ctx->id("FILTER_RANGE")] = "0";
//
// new_cell->params[ctx->id("PLLOUT_SELECT_A")] = "0";
// new_cell->params[ctx->id("PLLOUT_SELECT_B")] = "0";
//
// new_cell->params[ctx->id("PLLTYPE")] = "0";
// new_cell->params[ctx->id("SHIFTREG_DIVMODE")] = "0";
// new_cell->params[ctx->id("TEST_MODE")] = "0";
//
// add_port(ctx, new_cell.get(), "BYPASS", PORT_IN);
// add_port(ctx, new_cell.get(), "DYNAMICDELAY", PORT_IN);
// add_port(ctx, new_cell.get(), "EXTFEEDBACK", PORT_IN);
// add_port(ctx, new_cell.get(), "LATCHINPUTVALUE", PORT_IN);
// add_port(ctx, new_cell.get(), "REFERENCECLK", PORT_IN);
// add_port(ctx, new_cell.get(), "RESETB", PORT_IN);
//
// add_port(ctx, new_cell.get(), "SCLK", PORT_IN);
// add_port(ctx, new_cell.get(), "SDI", PORT_IN);
// add_port(ctx, new_cell.get(), "SDI", PORT_OUT);
//
// add_port(ctx, new_cell.get(), "LOCK", PORT_OUT);
// add_port(ctx, new_cell.get(), "PLLOUT_A", PORT_OUT);
// add_port(ctx, new_cell.get(), "PLLOUT_B", PORT_OUT);
} else {
log_error("unable to create XC7 cell of type %s\n", type.c_str(ctx));
}
@ -390,34 +215,11 @@ void nxio_to_sb(Context *ctx, CellInfo *nxio, CellInfo *sbio)
}
}
uint8_t sb_pll40_type(const BaseCtx *ctx, const CellInfo *cell)
{
if (cell->type == ctx->id("SB_PLL40_PAD"))
return 2;
if (cell->type == ctx->id("SB_PLL40_2_PAD"))
return 4;
if (cell->type == ctx->id("SB_PLL40_2F_PAD"))
return 5;
if (cell->type == ctx->id("SB_PLL40_CORE"))
return 3;
if (cell->type == ctx->id("SB_PLL40_2F_CORE"))
return 7;
NPNR_ASSERT(0);
}
bool is_clock_port(const BaseCtx *ctx, const PortRef &port)
{
if (port.cell == nullptr)
return false;
if (is_ff(ctx, port.cell))
return port.port == ctx->id("C");
if (port.cell->type == ctx->id("ICESTORM_LC"))
return port.port == id_CLK;
if (is_ram(ctx, port.cell) || port.cell->type == ctx->id("ICESTORM_RAM"))
return port.port == ctx->id("RCLK") || port.port == ctx->id("WCLK") || port.port == ctx->id("RCLKN") ||
port.port == ctx->id("WCLKN");
if (is_sb_mac16(ctx, port.cell) || port.cell->type == ctx->id("ICESTORM_DSP"))
return port.port == id_CLK;
NPNR_ASSERT("TODO");
return false;
}
@ -425,13 +227,7 @@ bool is_reset_port(const BaseCtx *ctx, const PortRef &port)
{
if (port.cell == nullptr)
return false;
if (is_ff(ctx, port.cell))
return port.port == id_R || port.port == id_S;
if (port.cell->type == ctx->id("ICESTORM_LC"))
return port.port == id_SR;
if (is_sb_mac16(ctx, port.cell) || port.cell->type == ctx->id("ICESTORM_DSP"))
return port.port == ctx->id("IRSTTOP") || port.port == ctx->id("IRSTBOT") || port.port == ctx->id("ORSTTOP") ||
port.port == ctx->id("ORSTBOT");
NPNR_ASSERT("TODO");
return false;
}
@ -439,13 +235,7 @@ bool is_enable_port(const BaseCtx *ctx, const PortRef &port)
{
if (port.cell == nullptr)
return false;
if (is_ff(ctx, port.cell))
return port.port == ctx->id("E");
if (port.cell->type == ctx->id("ICESTORM_LC"))
return port.port == id_CEN;
// FIXME
// if (is_sb_mac16(ctx, port.cell) || port.cell->type == ctx->id("ICESTORM_DSP"))
// return port.port == ctx->id("CE");
NPNR_ASSERT("TODO");
return false;
}

View File

@ -25,79 +25,6 @@ NEXTPNR_NAMESPACE_BEGIN
#define NUM_FUZZ_ROUTES 100000
void ice40DelayFuzzerMain(Context *ctx)
{
// std::vector<WireId> srcWires, dstWires;
//
// for (int i = 0; i < ctx->chip_info->num_wires; i++) {
// WireId wire;
// wire.index = i;
//
// switch (ctx->chip_info->wire_data[i].type) {
// case WireInfoPOD::WIRE_TYPE_LUTFF_OUT:
// srcWires.push_back(wire);
// break;
//
// case WireInfoPOD::WIRE_TYPE_LUTFF_IN_LUT:
// dstWires.push_back(wire);
// break;
//
// default:
// break;
// }
// }
//
// ctx->shuffle(srcWires);
// ctx->shuffle(dstWires);
//
// int index = 0;
// int cnt = 0;
//
// while (cnt < NUM_FUZZ_ROUTES) {
// if (index >= int(srcWires.size()) || index >= int(dstWires.size())) {
// index = 0;
// ctx->shuffle(srcWires);
// ctx->shuffle(dstWires);
// }
//
// WireId src = srcWires[index];
// WireId dst = dstWires[index++];
// std::unordered_map<WireId, PipId> route;
//
//#if NUM_FUZZ_ROUTES <= 1000
// if (!ctx->getActualRouteDelay(src, dst, nullptr, &route, false))
// continue;
//#else
// if (!ctx->getActualRouteDelay(src, dst, nullptr, &route, true))
// continue;
//#endif
//
// WireId cursor = dst;
// delay_t delay = 0;
//
// while (1) {
// delay += ctx->getWireDelay(cursor).maxDelay();
//
// printf("%s %d %d %s %s %d %d\n", cursor == dst ? "dst" : "src",
// int(ctx->chip_info->wire_data[cursor.index].x), int(ctx->chip_info->wire_data[cursor.index].y),
// ctx->getWireType(cursor).c_str(ctx), ctx->getWireName(cursor).c_str(ctx), int(delay),
// int(ctx->estimateDelay(cursor, dst)));
//
// if (cursor == src)
// break;
//
// PipId pip = route.at(cursor);
// delay += ctx->getPipDelay(pip).maxDelay();
// cursor = ctx->getPipSrcWire(pip);
// }
//
// cnt++;
//
// if (cnt % 100 == 0)
// fprintf(stderr, "Fuzzed %d arcs.\n", cnt);
// }
}
delay_t Arch::estimateDelay(WireId src, WireId dst) const
{
const auto &src_tw = torc_info->wire_to_tilewire[src.index];

View File

@ -128,172 +128,15 @@ static bool net_is_constant(const Context *ctx, NetInfo *net, bool &value)
// Pack carry logic
static void pack_carries(Context *ctx)
{
log_info("Packing carries..\n");
std::unordered_set<IdString> exhausted_cells;
std::unordered_set<IdString> packed_cells;
std::vector<std::unique_ptr<CellInfo>> new_cells;
for (auto cell : sorted(ctx->cells)) {
CellInfo *ci = cell.second;
if (is_carry(ctx, ci)) {
packed_cells.insert(cell.first);
CellInfo *carry_ci_lc;
bool ci_value;
bool ci_const = net_is_constant(ctx, ci->ports.at(ctx->id("CI")).net, ci_value);
if (ci_const) {
carry_ci_lc = nullptr;
} else {
carry_ci_lc = net_only_drives(ctx, ci->ports.at(ctx->id("CI")).net, is_lc, ctx->id("I3"), false);
}
std::set<IdString> i0_matches, i1_matches;
NetInfo *i0_net = ci->ports.at(ctx->id("I0")).net;
NetInfo *i1_net = ci->ports.at(ctx->id("I1")).net;
// Find logic cells connected to both I0 and I1
if (i0_net) {
for (auto usr : i0_net->users) {
if (is_lc(ctx, usr.cell) && usr.port == ctx->id("I1")) {
if (ctx->cells.find(usr.cell->name) != ctx->cells.end() &&
exhausted_cells.find(usr.cell->name) == exhausted_cells.end()) {
// This clause stops us double-packing cells
i0_matches.insert(usr.cell->name);
if (!i1_net) {
// I1 is don't care when disconnected, duplicate I0
i1_matches.insert(usr.cell->name);
}
}
}
}
}
if (i1_net) {
for (auto usr : i1_net->users) {
if (is_lc(ctx, usr.cell) && usr.port == ctx->id("I2")) {
if (ctx->cells.find(usr.cell->name) != ctx->cells.end() &&
exhausted_cells.find(usr.cell->name) == exhausted_cells.end()) {
// This clause stops us double-packing cells
i1_matches.insert(usr.cell->name);
if (!i0_net) {
// I0 is don't care when disconnected, duplicate I1
i0_matches.insert(usr.cell->name);
}
}
}
}
}
std::set<IdString> carry_lcs;
std::set_intersection(i0_matches.begin(), i0_matches.end(), i1_matches.begin(), i1_matches.end(),
std::inserter(carry_lcs, carry_lcs.end()));
CellInfo *carry_lc = nullptr;
if (carry_ci_lc && carry_lcs.find(carry_ci_lc->name) != carry_lcs.end()) {
carry_lc = carry_ci_lc;
} else {
// No LC to pack into matching I0/I1, insert a new one
std::unique_ptr<CellInfo> created_lc =
create_xc7_cell(ctx, ctx->id("XC7_LC"), cell.first.str(ctx) + "$CARRY");
carry_lc = created_lc.get();
created_lc->ports.at(ctx->id("I1")).net = i0_net;
if (i0_net) {
PortRef pr;
pr.cell = created_lc.get();
pr.port = ctx->id("I1");
i0_net->users.push_back(pr);
}
created_lc->ports.at(ctx->id("I2")).net = i1_net;
if (i1_net) {
PortRef pr;
pr.cell = created_lc.get();
pr.port = ctx->id("I2");
i1_net->users.push_back(pr);
}
new_cells.push_back(std::move(created_lc));
}
carry_lc->params[ctx->id("CARRY_ENABLE")] = "1";
replace_port(ci, ctx->id("CI"), carry_lc, ctx->id("CIN"));
replace_port(ci, ctx->id("CO"), carry_lc, ctx->id("COUT"));
if (i0_net) {
auto &i0_usrs = i0_net->users;
i0_usrs.erase(std::remove_if(i0_usrs.begin(), i0_usrs.end(), [ci, ctx](const PortRef &pr) {
return pr.cell == ci && pr.port == ctx->id("I0");
}));
}
if (i1_net) {
auto &i1_usrs = i1_net->users;
i1_usrs.erase(std::remove_if(i1_usrs.begin(), i1_usrs.end(), [ci, ctx](const PortRef &pr) {
return pr.cell == ci && pr.port == ctx->id("I1");
}));
}
// Check for constant driver on CIN
if (carry_lc->ports.at(ctx->id("CIN")).net != nullptr) {
IdString cin_net = carry_lc->ports.at(ctx->id("CIN")).net->name;
if (cin_net == ctx->id("$PACKER_GND_NET") || cin_net == ctx->id("$PACKER_VCC_NET")) {
carry_lc->params[ctx->id("CIN_CONST")] = "1";
carry_lc->params[ctx->id("CIN_SET")] = cin_net == ctx->id("$PACKER_VCC_NET") ? "1" : "0";
carry_lc->ports.at(ctx->id("CIN")).net = nullptr;
auto &cin_users = ctx->nets.at(cin_net)->users;
cin_users.erase(
std::remove_if(cin_users.begin(), cin_users.end(), [carry_lc, ctx](const PortRef &pr) {
return pr.cell == carry_lc && pr.port == ctx->id("CIN");
}));
}
}
exhausted_cells.insert(carry_lc->name);
}
}
for (auto pcell : packed_cells) {
ctx->cells.erase(pcell);
}
for (auto &ncell : new_cells) {
ctx->cells[ncell->name] = std::move(ncell);
}
//log_info("Packing carries..\n");
// TODO
}
// "Pack" RAMs
static void pack_ram(Context *ctx)
{
log_info("Packing RAMs..\n");
std::unordered_set<IdString> packed_cells;
std::vector<std::unique_ptr<CellInfo>> new_cells;
for (auto cell : sorted(ctx->cells)) {
CellInfo *ci = cell.second;
if (is_ram(ctx, ci)) {
std::unique_ptr<CellInfo> packed =
create_xc7_cell(ctx, ctx->id("ICESTORM_RAM"), ci->name.str(ctx) + "_RAM");
packed_cells.insert(ci->name);
for (auto param : ci->params)
packed->params[param.first] = param.second;
packed->params[ctx->id("NEG_CLK_W")] =
std::to_string(ci->type == ctx->id("SB_RAM40_4KNW") || ci->type == ctx->id("SB_RAM40_4KNRNW"));
packed->params[ctx->id("NEG_CLK_R")] =
std::to_string(ci->type == ctx->id("SB_RAM40_4KNR") || ci->type == ctx->id("SB_RAM40_4KNRNW"));
packed->type = ctx->id("ICESTORM_RAM");
for (auto port : ci->ports) {
PortInfo &pi = port.second;
std::string newname = pi.name.str(ctx);
size_t bpos = newname.find('[');
if (bpos != std::string::npos) {
newname = newname.substr(0, bpos) + "_" + newname.substr(bpos + 1, (newname.size() - bpos) - 2);
}
if (pi.name == ctx->id("RCLKN"))
newname = "RCLK";
else if (pi.name == ctx->id("WCLKN"))
newname = "WCLK";
replace_port(ci, ctx->id(pi.name.c_str(ctx)), packed.get(), ctx->id(newname));
}
new_cells.push_back(std::move(packed));
}
}
for (auto pcell : packed_cells) {
ctx->cells.erase(pcell);
}
for (auto &ncell : new_cells) {
ctx->cells[ncell->name] = std::move(ncell);
}
//log_info("Packing RAMs..\n");
// TODO
}
// Merge a net into a constant net
@ -308,14 +151,6 @@ static void set_net_constant(const Context *ctx, NetInfo *orig, NetInfo *constne
if ((is_lut(ctx, uc) || is_lc(ctx, uc) || is_carry(ctx, uc)) && (user.port.str(ctx).at(0) == 'I') &&
!constval) {
uc->ports[user.port].net = nullptr;
} else if ((is_sb_mac16(ctx, uc) || uc->type == ctx->id("ICESTORM_DSP")) &&
(user.port != id_CLK &&
((constval && user.port == ctx->id("CE")) || (!constval && user.port != ctx->id("CE"))))) {
uc->ports[user.port].net = nullptr;
} else if (is_ram(ctx, uc) && !constval && user.port != ctx->id("RCLK") && user.port != ctx->id("RCLKN") &&
user.port != ctx->id("WCLK") && user.port != ctx->id("WCLKN") && user.port != ctx->id("RCLKE") &&
user.port != ctx->id("WCLKE")) {
uc->ports[user.port].net = nullptr;
} else {
uc->ports[user.port].net = constnet;
constnet->users.push_back(user);
@ -421,9 +256,9 @@ static void pack_io(Context *ctx)
}
} else {
// Create a IOBUF buffer
std::unique_ptr<CellInfo> ice_cell = create_xc7_cell(ctx, ctx->id("IOBUF"), ci->name.str(ctx));
nxio_to_sb(ctx, ci, ice_cell.get());
new_cells.push_back(std::move(ice_cell));
std::unique_ptr<CellInfo> xc7_cell = create_xc7_cell(ctx, ctx->id("IOBUF"), ci->name.str(ctx));
nxio_to_sb(ctx, ci, xc7_cell.get());
new_cells.push_back(std::move(xc7_cell));
sb = new_cells.back().get();
}
packed_cells.insert(ci->name);
@ -443,8 +278,7 @@ static bool is_logic_port(BaseCtx *ctx, const PortRef &port)
{
if (is_clock_port(ctx, port) || is_reset_port(ctx, port) || is_enable_port(ctx, port))
return false;
return !is_sb_io(ctx, port.cell) && !is_sb_pll40(ctx, port.cell) && !is_sb_pll40_pad(ctx, port.cell) &&
port.cell->type != ctx->id("SB_GB");
return !is_sb_io(ctx, port.cell) && port.cell->type != id_BUFGCTRL;
}
static void insert_global(Context *ctx, NetInfo *net, bool is_reset, bool is_cen, bool is_logic)
@ -855,242 +689,6 @@ static void pack_special(Context *ctx)
ci->params.emplace(ctx->id("VREF_START"), "01");
ci->params[ctx->id("COMPENSATION")] = "INTERNAL";
} else if (is_sb_lfosc(ctx, ci)) {
std::unique_ptr<CellInfo> packed =
create_xc7_cell(ctx, ctx->id("ICESTORM_LFOSC"), ci->name.str(ctx) + "_OSC");
packed_cells.insert(ci->name);
replace_port(ci, ctx->id("CLKLFEN"), packed.get(), ctx->id("CLKLFEN"));
replace_port(ci, ctx->id("CLKLFPU"), packed.get(), ctx->id("CLKLFPU"));
if (/*bool_or_default(ci->attrs, ctx->id("ROUTE_THROUGH_FABRIC"))*/ true) { // FIXME
replace_port(ci, ctx->id("CLKLF"), packed.get(), ctx->id("CLKLF_FABRIC"));
} else {
replace_port(ci, ctx->id("CLKLF"), packed.get(), ctx->id("CLKLF"));
}
new_cells.push_back(std::move(packed));
} else if (is_sb_hfosc(ctx, ci)) {
std::unique_ptr<CellInfo> packed =
create_xc7_cell(ctx, ctx->id("ICESTORM_HFOSC"), ci->name.str(ctx) + "_OSC");
packed_cells.insert(ci->name);
packed->params[ctx->id("CLKHF_DIV")] = str_or_default(ci->params, ctx->id("CLKHF_DIV"), "0b00");
replace_port(ci, ctx->id("CLKHFEN"), packed.get(), ctx->id("CLKHFEN"));
replace_port(ci, ctx->id("CLKHFPU"), packed.get(), ctx->id("CLKHFPU"));
if (/*bool_or_default(ci->attrs, ctx->id("ROUTE_THROUGH_FABRIC"))*/ true) { // FIXME
replace_port(ci, ctx->id("CLKHF"), packed.get(), ctx->id("CLKHF_FABRIC"));
} else {
replace_port(ci, ctx->id("CLKHF"), packed.get(), ctx->id("CLKHF"));
}
new_cells.push_back(std::move(packed));
} else if (is_sb_spram(ctx, ci)) {
std::unique_ptr<CellInfo> packed =
create_xc7_cell(ctx, ctx->id("ICESTORM_SPRAM"), ci->name.str(ctx) + "_RAM");
packed_cells.insert(ci->name);
for (auto port : ci->ports) {
PortInfo &pi = port.second;
std::string newname = pi.name.str(ctx);
size_t bpos = newname.find('[');
if (bpos != std::string::npos) {
newname = newname.substr(0, bpos) + "_" + newname.substr(bpos + 1, (newname.size() - bpos) - 2);
}
replace_port(ci, ctx->id(pi.name.c_str(ctx)), packed.get(), ctx->id(newname));
}
new_cells.push_back(std::move(packed));
} else if (is_sb_mac16(ctx, ci)) {
std::unique_ptr<CellInfo> packed =
create_xc7_cell(ctx, ctx->id("ICESTORM_DSP"), ci->name.str(ctx) + "_DSP");
packed_cells.insert(ci->name);
for (auto attr : ci->attrs)
packed->attrs[attr.first] = attr.second;
for (auto param : ci->params)
packed->params[param.first] = param.second;
for (auto port : ci->ports) {
PortInfo &pi = port.second;
std::string newname = pi.name.str(ctx);
size_t bpos = newname.find('[');
if (bpos != std::string::npos) {
newname = newname.substr(0, bpos) + "_" + newname.substr(bpos + 1, (newname.size() - bpos) - 2);
}
replace_port(ci, ctx->id(pi.name.c_str(ctx)), packed.get(), ctx->id(newname));
}
new_cells.push_back(std::move(packed));
} else if (is_sb_pll40(ctx, ci)) {
bool is_pad = is_sb_pll40_pad(ctx, ci);
bool is_core = !is_pad;
std::unique_ptr<CellInfo> packed =
create_xc7_cell(ctx, ctx->id("ICESTORM_PLL"), ci->name.str(ctx) + "_PLL");
packed->attrs[ctx->id("TYPE")] = ci->type.str(ctx);
packed_cells.insert(ci->name);
for (auto attr : ci->attrs)
packed->attrs[attr.first] = attr.second;
for (auto param : ci->params)
packed->params[param.first] = param.second;
auto feedback_path = packed->params[ctx->id("FEEDBACK_PATH")];
packed->params[ctx->id("FEEDBACK_PATH")] =
feedback_path == "DELAY"
? "0"
: feedback_path == "SIMPLE" ? "1"
: feedback_path == "PHASE_AND_DELAY"
? "2"
: feedback_path == "EXTERNAL" ? "6" : feedback_path;
packed->params[ctx->id("PLLTYPE")] = std::to_string(sb_pll40_type(ctx, ci));
NetInfo *pad_packagepin_net = nullptr;
for (auto port : ci->ports) {
PortInfo &pi = port.second;
std::string newname = pi.name.str(ctx);
size_t bpos = newname.find('[');
if (bpos != std::string::npos) {
newname = newname.substr(0, bpos) + "_" + newname.substr(bpos + 1, (newname.size() - bpos) - 2);
}
if (pi.name == ctx->id("PLLOUTCOREA"))
newname = "PLLOUT_A";
if (pi.name == ctx->id("PLLOUTCOREB"))
newname = "PLLOUT_B";
if (pi.name == ctx->id("PLLOUTCORE"))
newname = "PLLOUT_A";
if (pi.name == ctx->id("PACKAGEPIN")) {
if (!is_pad) {
log_error(" PLL '%s' has a PACKAGEPIN but is not a PAD PLL", ci->name.c_str(ctx));
} else {
// We drop this port and instead place the PLL adequately below.
pad_packagepin_net = port.second.net;
NPNR_ASSERT(pad_packagepin_net != nullptr);
continue;
}
}
if (pi.name == ctx->id("REFERENCECLK")) {
if (!is_core)
log_error(" PLL '%s' has a REFERENCECLK but is not a CORE PLL", ci->name.c_str(ctx));
}
replace_port(ci, ctx->id(pi.name.c_str(ctx)), packed.get(), ctx->id(newname));
}
// If PLL is not constrained already, do that - we need this
// information to then constrain the LOCK LUT.
BelId pll_bel;
bool constrained = false;
if (packed->attrs.find(ctx->id("BEL")) == packed->attrs.end()) {
for (auto bel : ctx->getBels()) {
if (ctx->getBelType(bel) != id_ICESTORM_PLL)
continue;
// A PAD PLL must have its' PACKAGEPIN on the SB_IO that's shared
// with PLLOUT_A.
if (is_pad) {
auto pll_sb_io_belpin = ctx->getIOBSharingPLLPin(bel, id_PLLOUT_A);
NPNR_ASSERT(pad_packagepin_net != nullptr);
auto pll_packagepin_driver = pad_packagepin_net->driver;
NPNR_ASSERT(pll_packagepin_driver.cell != nullptr);
if (pll_packagepin_driver.cell->type != ctx->id("SB_IO")) {
log_error(" PLL '%s' has a PACKAGEPIN driven by "
"an %s, should be directly connected to an input SB_IO\n",
ci->name.c_str(ctx), pll_packagepin_driver.cell->type.c_str(ctx));
}
auto packagepin_cell = pll_packagepin_driver.cell;
auto packagepin_bel_name = packagepin_cell->attrs.find(ctx->id("BEL"));
if (packagepin_bel_name == packagepin_cell->attrs.end()) {
log_error(" PLL '%s' PACKAGEPIN SB_IO '%s' is unconstrained\n", ci->name.c_str(ctx),
packagepin_cell->name.c_str(ctx));
}
auto packagepin_bel = ctx->getBelByName(ctx->id(packagepin_bel_name->second));
if (pll_sb_io_belpin.bel != packagepin_bel) {
log_error(" PLL '%s' PACKAGEPIN is connected to pin %s, can only be pin %s\n",
ci->name.c_str(ctx), ctx->getBelPackagePin(packagepin_bel).c_str(),
ctx->getBelPackagePin(pll_sb_io_belpin.bel).c_str());
}
if (pad_packagepin_net->users.size() != 1) {
log_error(" PLL '%s' clock input '%s' can only drive PLL\n", ci->name.c_str(ctx),
pad_packagepin_net->name.c_str(ctx));
}
// Set an attribute about this PLL's PAD SB_IO.
packed->attrs[ctx->id("BEL_PAD_INPUT")] = packagepin_bel_name->second;
// Remove the connection from the SB_IO to the PLL.
packagepin_cell->ports.erase(pll_packagepin_driver.port);
}
log_info(" constrained '%s' to %s\n", packed->name.c_str(ctx), ctx->getBelName(bel).c_str(ctx));
packed->attrs[ctx->id("BEL")] = ctx->getBelName(bel).str(ctx);
pll_bel = bel;
constrained = true;
}
if (!constrained) {
log_error(" could not constrain '%s' to any PLL Bel\n", packed->name.c_str(ctx));
}
}
// Delete the original PACKAGEPIN net if needed.
if (pad_packagepin_net != nullptr) {
for (auto user : pad_packagepin_net->users) {
user.cell->ports.erase(user.port);
}
ctx->nets.erase(pad_packagepin_net->name);
pad_packagepin_net = nullptr;
}
// The LOCK signal on iCE40 PLLs goes through the neigh_op_bnl_1 wire.
// In practice, this means the LOCK signal can only directly reach LUT
// inputs.
// If we have a net connected to LOCK, make sure it only drives LUTs.
auto port = packed->ports[ctx->id("LOCK")];
if (port.net != nullptr) {
bool found_lut = false;
bool all_luts = true;
unsigned int lut_count = 0;
for (const auto &user : port.net->users) {
NPNR_ASSERT(user.cell != nullptr);
if (user.cell->type == ctx->id("XC7_LC")) {
found_lut = true;
lut_count++;
} else {
all_luts = false;
}
}
if (found_lut && all_luts) {
// Every user is a LUT, carry on now.
} else if (found_lut && !all_luts && lut_count < 8) {
// Strategy: create a pass-through LUT, move all non-LUT users behind it.
log_info(" LUT strategy for %s: move non-LUT users to new LUT\n", port.name.c_str(ctx));
auto pt = spliceLUT(ctx, packed.get(), port.name, true);
new_cells.push_back(std::move(pt));
} else {
// Strategy: create a pass-through LUT, move every user behind it.
log_info(" LUT strategy for %s: move all users to new LUT\n", port.name.c_str(ctx));
auto pt = spliceLUT(ctx, packed.get(), port.name, false);
new_cells.push_back(std::move(pt));
}
// Find wire that will be driven by this port.
const auto pll_out_wire = ctx->getBelPinWire(pll_bel, port.name);
NPNR_ASSERT(pll_out_wire != WireId());
// Now, constrain all LUTs on the output of the signal to be at
// the correct Bel relative to the PLL Bel.
// int x = ctx->chip_info->wire_data[pll_out_wire.index].x;
// int y = ctx->chip_info->wire_data[pll_out_wire.index].y;
// int z = 0;
// for (const auto &user : port.net->users) {
// NPNR_ASSERT(user.cell != nullptr);
// NPNR_ASSERT(user.cell->type == ctx->id("XC7_LC"));
// // TODO(q3k): handle when the Bel might be already the
// // target of another constraint.
// NPNR_ASSERT(z < 8);
// auto target_bel = ctx->getBelByLocation(Loc(x, y, z++));
// auto target_bel_name = ctx->getBelName(target_bel).str(ctx);
// user.cell->attrs[ctx->id("BEL")] = target_bel_name;
// log_info(" constrained '%s' to %s\n", user.cell->name.c_str(ctx), target_bel_name.c_str());
//}
}
new_cells.push_back(std::move(packed));
}
}