Cleanup
This commit is contained in:
parent
463d9a6920
commit
a630758ca7
371
xc7/arch.cc
371
xc7/arch.cc
@ -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
|
||||
|
70
xc7/arch.h
70
xc7/arch.h
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
224
xc7/cells.cc
224
xc7/cells.cc
@ -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;
|
||||
}
|
||||
|
||||
|
73
xc7/delay.cc
73
xc7/delay.cc
@ -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];
|
||||
|
418
xc7/pack.cc
418
xc7/pack.cc
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user