Merge branch 'master' of ssh.github.com:YosysHQ/nextpnr
This commit is contained in:
commit
d20ce45c1b
@ -97,7 +97,9 @@ such as pack, place, route, and write output files.)
|
|||||||
### nextpnr-ecp5
|
### nextpnr-ecp5
|
||||||
|
|
||||||
For ECP5 support, you must download [Project Trellis](https://github.com/SymbiFlow/prjtrellis),
|
For ECP5 support, you must download [Project Trellis](https://github.com/SymbiFlow/prjtrellis),
|
||||||
then follow its instructions to download the latest database and build _libtrellis_.
|
then follow its instructions to download the latest database and build _libtrellis_.
|
||||||
|
(for example: `-DTRELLIS_INSTALL_PREFIX=/usr` tells nextpnr to look in `/usr/share/trellis`
|
||||||
|
and `/usr/lib/trellis`)
|
||||||
|
|
||||||
```
|
```
|
||||||
cmake -DARCH=ecp5 -DTRELLIS_INSTALL_PREFIX=/path/to/prjtrellis .
|
cmake -DARCH=ecp5 -DTRELLIS_INSTALL_PREFIX=/path/to/prjtrellis .
|
||||||
|
@ -25,6 +25,8 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include "nextpnr.h"
|
#include "nextpnr.h"
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_BEGIN
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
// Get a value from a map-style container, returning default if value is not
|
// Get a value from a map-style container, returning default if value is not
|
||||||
@ -47,8 +49,9 @@ std::string str_or_default(const Container &ct, const KeyType &key, std::string
|
|||||||
auto found = ct.find(key);
|
auto found = ct.find(key);
|
||||||
if (found == ct.end())
|
if (found == ct.end())
|
||||||
return def;
|
return def;
|
||||||
else
|
else {
|
||||||
return found->second;
|
return found->second;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename KeyType>
|
template <typename KeyType>
|
||||||
@ -57,8 +60,11 @@ std::string str_or_default(const std::unordered_map<KeyType, Property> &ct, cons
|
|||||||
auto found = ct.find(key);
|
auto found = ct.find(key);
|
||||||
if (found == ct.end())
|
if (found == ct.end())
|
||||||
return def;
|
return def;
|
||||||
else
|
else {
|
||||||
|
if (!found->second.is_string)
|
||||||
|
log_error("Expecting string value but got integer %d.\n", int(found->second.intval));
|
||||||
return found->second.as_string();
|
return found->second.as_string();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get a value from a map-style container, converting to int, and returning
|
// Get a value from a map-style container, converting to int, and returning
|
||||||
@ -79,9 +85,13 @@ int int_or_default(const std::unordered_map<KeyType, Property> &ct, const KeyTyp
|
|||||||
if (found == ct.end())
|
if (found == ct.end())
|
||||||
return def;
|
return def;
|
||||||
else {
|
else {
|
||||||
if (found->second.is_string)
|
if (found->second.is_string) {
|
||||||
return std::stoi(found->second.as_string());
|
try {
|
||||||
else
|
return std::stoi(found->second.as_string());
|
||||||
|
} catch (std::invalid_argument &e) {
|
||||||
|
log_error("Expecting numeric value but got '%s'.\n", found->second.as_string().c_str());
|
||||||
|
}
|
||||||
|
} else
|
||||||
return found->second.as_int64();
|
return found->second.as_int64();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -650,7 +650,7 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex
|
|||||||
}
|
}
|
||||||
// Find bank voltages
|
// Find bank voltages
|
||||||
std::unordered_map<int, IOVoltage> bankVcc;
|
std::unordered_map<int, IOVoltage> bankVcc;
|
||||||
std::unordered_map<int, bool> bankLvds, bankVref;
|
std::unordered_map<int, bool> bankLvds, bankVref, bankDiff;
|
||||||
|
|
||||||
for (auto &cell : ctx->cells) {
|
for (auto &cell : ctx->cells) {
|
||||||
CellInfo *ci = cell.second.get();
|
CellInfo *ci = cell.second.get();
|
||||||
@ -675,6 +675,8 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex
|
|||||||
|
|
||||||
if (iotype == "LVDS")
|
if (iotype == "LVDS")
|
||||||
bankLvds[bank] = true;
|
bankLvds[bank] = true;
|
||||||
|
if ((dir == "INPUT" || dir == "BIDIR") && is_differential(ioType_from_str(iotype)))
|
||||||
|
bankDiff[bank] = true;
|
||||||
if ((dir == "INPUT" || dir == "BIDIR") && is_referenced(ioType_from_str(iotype)))
|
if ((dir == "INPUT" || dir == "BIDIR") && is_referenced(ioType_from_str(iotype)))
|
||||||
bankVref[bank] = true;
|
bankVref[bank] = true;
|
||||||
}
|
}
|
||||||
@ -698,6 +700,9 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex
|
|||||||
cc.tiles[tile.first].add_enum("BANK.DIFF_REF", "ON");
|
cc.tiles[tile.first].add_enum("BANK.DIFF_REF", "ON");
|
||||||
cc.tiles[tile.first].add_enum("BANK.LVDSO", "ON");
|
cc.tiles[tile.first].add_enum("BANK.LVDSO", "ON");
|
||||||
}
|
}
|
||||||
|
if (bankDiff[bank]) {
|
||||||
|
cc.tiles[tile.first].add_enum("BANK.DIFF_REF", "ON");
|
||||||
|
}
|
||||||
if (bankVref[bank]) {
|
if (bankVref[bank]) {
|
||||||
cc.tiles[tile.first].add_enum("BANK.DIFF_REF", "ON");
|
cc.tiles[tile.first].add_enum("BANK.DIFF_REF", "ON");
|
||||||
cc.tiles[tile.first].add_enum("BANK.VREF", "ON");
|
cc.tiles[tile.first].add_enum("BANK.VREF", "ON");
|
||||||
|
@ -432,7 +432,13 @@ void nxio_to_tr(Context *ctx, CellInfo *nxio, CellInfo *trio, std::vector<std::u
|
|||||||
replace_port(nxio, ctx->id("I"), trio, ctx->id("I"));
|
replace_port(nxio, ctx->id("I"), trio, ctx->id("I"));
|
||||||
} else if (nxio->type == ctx->id("$nextpnr_iobuf")) {
|
} else if (nxio->type == ctx->id("$nextpnr_iobuf")) {
|
||||||
// N.B. tristate will be dealt with below
|
// N.B. tristate will be dealt with below
|
||||||
trio->params[ctx->id("DIR")] = std::string("BIDIR");
|
NetInfo *i = get_net_or_empty(nxio, ctx->id("I"));
|
||||||
|
if (i == nullptr || i->driver.cell == nullptr)
|
||||||
|
trio->params[ctx->id("DIR")] = std::string("INPUT");
|
||||||
|
else {
|
||||||
|
log_info("%s: %s.%s\n", ctx->nameOf(i), ctx->nameOf(i->driver.cell), ctx->nameOf(i->driver.port));
|
||||||
|
trio->params[ctx->id("DIR")] = std::string("BIDIR");
|
||||||
|
}
|
||||||
replace_port(nxio, ctx->id("I"), trio, ctx->id("I"));
|
replace_port(nxio, ctx->id("I"), trio, ctx->id("I"));
|
||||||
replace_port(nxio, ctx->id("O"), trio, ctx->id("O"));
|
replace_port(nxio, ctx->id("O"), trio, ctx->id("O"));
|
||||||
} else {
|
} else {
|
||||||
@ -446,6 +452,15 @@ void nxio_to_tr(Context *ctx, CellInfo *nxio, CellInfo *trio, std::vector<std::u
|
|||||||
if (dinet != nullptr && dinet->name == nxio->name)
|
if (dinet != nullptr && dinet->name == nxio->name)
|
||||||
rename_net(ctx, dinet, ctx->id(dinet->name.str(ctx) + "$TRELLIS_IO_IN"));
|
rename_net(ctx, dinet, ctx->id(dinet->name.str(ctx) + "$TRELLIS_IO_IN"));
|
||||||
|
|
||||||
|
if (ctx->nets.count(nxio->name)) {
|
||||||
|
int i = 0;
|
||||||
|
IdString new_name;
|
||||||
|
do {
|
||||||
|
new_name = ctx->id(nxio->name.str(ctx) + "$rename$" + std::to_string(i++));
|
||||||
|
} while (ctx->nets.count(new_name));
|
||||||
|
rename_net(ctx, ctx->nets.at(nxio->name).get(), new_name);
|
||||||
|
}
|
||||||
|
|
||||||
// Create a new top port net for accurate IO timing analysis and simulation netlists
|
// Create a new top port net for accurate IO timing analysis and simulation netlists
|
||||||
if (ctx->ports.count(nxio->name)) {
|
if (ctx->ports.count(nxio->name)) {
|
||||||
IdString tn_netname = nxio->name;
|
IdString tn_netname = nxio->name;
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include "cells.h"
|
#include "cells.h"
|
||||||
#include "design_utils.h"
|
#include "design_utils.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_BEGIN
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
@ -424,7 +425,14 @@ void nxio_to_sb(Context *ctx, CellInfo *nxio, CellInfo *sbio, std::unordered_set
|
|||||||
replace_port(nxio, ctx->id("I"), sbio, ctx->id("D_OUT_0"));
|
replace_port(nxio, ctx->id("I"), sbio, ctx->id("D_OUT_0"));
|
||||||
} else if (nxio->type == ctx->id("$nextpnr_iobuf")) {
|
} else if (nxio->type == ctx->id("$nextpnr_iobuf")) {
|
||||||
// N.B. tristate will be dealt with below
|
// N.B. tristate will be dealt with below
|
||||||
sbio->params[ctx->id("PIN_TYPE")] = 25;
|
NetInfo *i = get_net_or_empty(nxio, ctx->id("I"));
|
||||||
|
if (i == nullptr || i->driver.cell == nullptr)
|
||||||
|
sbio->params[ctx->id("PIN_TYPE")] = 1;
|
||||||
|
else
|
||||||
|
sbio->params[ctx->id("PIN_TYPE")] = 25;
|
||||||
|
auto pu_attr = nxio->attrs.find(ctx->id("PULLUP"));
|
||||||
|
if (pu_attr != nxio->attrs.end())
|
||||||
|
sbio->params[ctx->id("PULLUP")] = pu_attr->second;
|
||||||
replace_port(nxio, ctx->id("I"), sbio, ctx->id("D_OUT_0"));
|
replace_port(nxio, ctx->id("I"), sbio, ctx->id("D_OUT_0"));
|
||||||
replace_port(nxio, ctx->id("O"), sbio, ctx->id("D_IN_0"));
|
replace_port(nxio, ctx->id("O"), sbio, ctx->id("D_IN_0"));
|
||||||
} else {
|
} else {
|
||||||
@ -438,6 +446,15 @@ void nxio_to_sb(Context *ctx, CellInfo *nxio, CellInfo *sbio, std::unordered_set
|
|||||||
if (dinet != nullptr && dinet->name == nxio->name)
|
if (dinet != nullptr && dinet->name == nxio->name)
|
||||||
rename_net(ctx, dinet, ctx->id(dinet->name.str(ctx) + "$SB_IO_IN"));
|
rename_net(ctx, dinet, ctx->id(dinet->name.str(ctx) + "$SB_IO_IN"));
|
||||||
|
|
||||||
|
if (ctx->nets.count(nxio->name)) {
|
||||||
|
int i = 0;
|
||||||
|
IdString new_name;
|
||||||
|
do {
|
||||||
|
new_name = ctx->id(nxio->name.str(ctx) + "$rename$" + std::to_string(i++));
|
||||||
|
} while (ctx->nets.count(new_name));
|
||||||
|
rename_net(ctx, ctx->nets.at(nxio->name).get(), new_name);
|
||||||
|
}
|
||||||
|
|
||||||
// Create a new top port net for accurate IO timing analysis and simulation netlists
|
// Create a new top port net for accurate IO timing analysis and simulation netlists
|
||||||
if (ctx->ports.count(nxio->name)) {
|
if (ctx->ports.count(nxio->name)) {
|
||||||
IdString tn_netname = nxio->name;
|
IdString tn_netname = nxio->name;
|
||||||
|
Loading…
Reference in New Issue
Block a user