Have a go at generating FASM from Torc XDL
This commit is contained in:
parent
5f75a8447f
commit
557011cfe6
@ -56,6 +56,7 @@ po::options_description Xc7CommandHandler::getArchOptions()
|
|||||||
specific.add_options()("package", po::value<std::string>(), "set device package");
|
specific.add_options()("package", po::value<std::string>(), "set device package");
|
||||||
specific.add_options()("pcf", po::value<std::string>(), "PCF constraints file to ingest");
|
specific.add_options()("pcf", po::value<std::string>(), "PCF constraints file to ingest");
|
||||||
specific.add_options()("xdl", po::value<std::string>(), "XDL file to write");
|
specific.add_options()("xdl", po::value<std::string>(), "XDL file to write");
|
||||||
|
specific.add_options()("fasm", po::value<std::string>(), "FASM file to write");
|
||||||
// specific.add_options()("tmfuzz", "run path delay estimate fuzzer");
|
// specific.add_options()("tmfuzz", "run path delay estimate fuzzer");
|
||||||
return specific;
|
return specific;
|
||||||
}
|
}
|
||||||
@ -83,6 +84,11 @@ void Xc7CommandHandler::customBitstream(Context *ctx)
|
|||||||
std::ofstream f(filename);
|
std::ofstream f(filename);
|
||||||
write_xdl(ctx, f);
|
write_xdl(ctx, f);
|
||||||
}
|
}
|
||||||
|
if (vm.count("fasm")) {
|
||||||
|
std::string filename = vm["fasm"].as<std::string>();
|
||||||
|
std::ofstream f(filename);
|
||||||
|
write_fasm(ctx, f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Xc7CommandHandler::setupArchContext(Context *ctx)
|
void Xc7CommandHandler::setupArchContext(Context *ctx)
|
||||||
|
88
xc7/xdl.cc
88
xc7/xdl.cc
@ -25,6 +25,7 @@
|
|||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "nextpnr.h"
|
#include "nextpnr.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include <boost/range/adaptor/reversed.hpp>
|
||||||
|
|
||||||
#include "torc/Physical.hpp"
|
#include "torc/Physical.hpp"
|
||||||
using namespace torc::architecture::xilinx;
|
using namespace torc::architecture::xilinx;
|
||||||
@ -32,9 +33,8 @@ using namespace torc::physical;
|
|||||||
|
|
||||||
NEXTPNR_NAMESPACE_BEGIN
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
void write_xdl(const Context *ctx, std::ostream &out)
|
DesignSharedPtr create_torc_design(const Context *ctx)
|
||||||
{
|
{
|
||||||
XdlExporter exporter(out);
|
|
||||||
auto designPtr = Factory::newDesignPtr("name", torc_info->ddb->getDeviceName(), ctx->args.package, "-1", "");
|
auto designPtr = Factory::newDesignPtr("name", torc_info->ddb->getDeviceName(), ctx->args.package, "-1", "");
|
||||||
|
|
||||||
std::unordered_map<int32_t, InstanceSharedPtr> site_to_instance;
|
std::unordered_map<int32_t, InstanceSharedPtr> site_to_instance;
|
||||||
@ -232,6 +232,7 @@ void write_xdl(const Context *ctx, std::ostream &out)
|
|||||||
auto pinPtr = Factory::newInstancePinPtr(instPtr, pin_name);
|
auto pinPtr = Factory::newInstancePinPtr(instPtr, pin_name);
|
||||||
netPtr->addSource(pinPtr);
|
netPtr->addSource(pinPtr);
|
||||||
|
|
||||||
|
if (!net.second->users.empty()) {
|
||||||
for (const auto &user : net.second->users) {
|
for (const auto &user : net.second->users) {
|
||||||
site_index = torc_info->bel_to_site_index[user.cell->bel.index];
|
site_index = torc_info->bel_to_site_index[user.cell->bel.index];
|
||||||
instPtr = site_to_instance.at(site_index);
|
instPtr = site_to_instance.at(site_index);
|
||||||
@ -264,8 +265,91 @@ void write_xdl(const Context *ctx, std::ostream &out)
|
|||||||
netPtr->addPip(p);
|
netPtr->addPip(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return designPtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_xdl(const Context *ctx, std::ostream &out)
|
||||||
|
{
|
||||||
|
XdlExporter exporter(out);
|
||||||
|
auto designPtr = create_torc_design(ctx);
|
||||||
exporter(designPtr);
|
exporter(designPtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void write_fasm(const Context *ctx, std::ostream &out)
|
||||||
|
{
|
||||||
|
auto designPtr = create_torc_design(ctx);
|
||||||
|
|
||||||
|
static const boost::regex re_loc(".+_X(\\d+)Y(\\d+)");
|
||||||
|
boost::smatch what;
|
||||||
|
|
||||||
|
// export the instances
|
||||||
|
Circuit::InstanceSharedPtrConstIterator pi = designPtr->instancesBegin();
|
||||||
|
Circuit::InstanceSharedPtrConstIterator ei = designPtr->instancesEnd();
|
||||||
|
for (; pi < ei; ++pi) {
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << (*pi)->getTile() << '.';
|
||||||
|
const auto& type = (*pi)->getType();
|
||||||
|
if (type == "SLICEL") {
|
||||||
|
const auto& site_name = (*pi)->getSite();
|
||||||
|
if (!boost::regex_match(site_name, what, re_loc))
|
||||||
|
throw;
|
||||||
|
|
||||||
|
const auto x = boost::lexical_cast<int>(what.str(1));
|
||||||
|
ss << type << "_X" << static_cast<int>(x & 1) << '.';
|
||||||
|
|
||||||
|
out << "# " << (*pi)->getName() << std::endl;
|
||||||
|
|
||||||
|
auto pc = (*pi)->configBegin();
|
||||||
|
auto ec = (*pi)->configEnd();
|
||||||
|
for (; pc != ec; ++pc)
|
||||||
|
if (pc->first == "A6LUT" || pc->first == "B6LUT" || pc->first == "C6LUT" || pc->first == "D6LUT") {
|
||||||
|
auto name = pc->second.getName();
|
||||||
|
boost::replace_all(name, "\\:", ":");
|
||||||
|
auto it = ctx->cells.find(ctx->id(name));
|
||||||
|
if (it == ctx->cells.end()) it = ctx->cells.find(ctx->id(name + "_LC"));
|
||||||
|
assert(it != ctx->cells.end());
|
||||||
|
auto cell = it->second.get();
|
||||||
|
const auto &init = cell->params[ctx->id("INIT")];
|
||||||
|
if (cell->lcInfo.inputCount <= 5) {
|
||||||
|
auto num_bits = (1 << cell->lcInfo.inputCount);
|
||||||
|
auto init_as_uint = boost::lexical_cast<uint32_t>(init);
|
||||||
|
out << ss.str() << pc->first[0] << pc->first.substr(2,std::string::npos) << ".INIT";
|
||||||
|
out << "[" << num_bits-1 << ":0]" << "=";
|
||||||
|
out << num_bits << "'b";
|
||||||
|
for (auto i = 0; i < num_bits; ++i)
|
||||||
|
out << ((init_as_uint >> i) & 1 ? '1' : '0');
|
||||||
|
out << std::endl;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
out << ss.str() << pc->first[0] << pc->first.substr(2,std::string::npos) << ".INIT[31:0]=";
|
||||||
|
out << "32'b" << boost::adaptors::reverse(init.substr(0,32)) << std::endl;
|
||||||
|
out << ss.str() << pc->first[0] << pc->first.substr(2,std::string::npos) << ".INIT[63:32]=";
|
||||||
|
out << "32'b" << boost::adaptors::reverse(init.substr(32,32)) << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
out << ss.str() << pc->first << '.' << pc->second.getValue() << std::endl;
|
||||||
|
|
||||||
|
out << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// export the nets
|
||||||
|
Circuit::NetSharedPtrConstIterator pn = designPtr->netsBegin();
|
||||||
|
Circuit::NetSharedPtrConstIterator en = designPtr->netsEnd();
|
||||||
|
for (; pn < en; ++pn) {
|
||||||
|
|
||||||
|
out << "# " << (*pn)->getName() << std::endl;
|
||||||
|
|
||||||
|
auto pp = (*pn)->pipsBegin();
|
||||||
|
auto ep = (*pn)->pipsEnd();
|
||||||
|
for (; pp != ep; ++pp)
|
||||||
|
out << pp->getTileName() << "." << pp->getSourceWireName() << "." << pp->getSinkWireName() << std::endl;
|
||||||
|
|
||||||
|
out << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
Loading…
Reference in New Issue
Block a user