Merge master

This commit is contained in:
Miodrag Milanovic 2019-06-25 18:14:51 +02:00
commit ec47ce2320
15 changed files with 157 additions and 32 deletions

View File

@ -14,6 +14,9 @@ We hope to see Xilinx 7 Series thanks to
supported in the future. We would love your help in developing this supported in the future. We would love your help in developing this
awesome new project! awesome new project!
A brief (academic) paper describing the Yosys+nextpnr flow can be found
on [arXiv](https://arxiv.org/abs/1903.10407).
Here is a screenshot of nextpnr for iCE40. Build instructions and Here is a screenshot of nextpnr for iCE40. Build instructions and
[getting started notes](#getting-started) can be found below. [getting started notes](#getting-started) can be found below.

View File

@ -546,7 +546,8 @@ struct Timing
for (size_t i = 0; i < sink_net->users.size(); i++) { for (size_t i = 0; i < sink_net->users.size(); i++) {
auto &user = sink_net->users.at(i); auto &user = sink_net->users.at(i);
if (user.cell == drv.cell && user.port == port.first) { if (user.cell == drv.cell && user.port == port.first) {
sink_nd.min_required.at(i) = net_min_required - comb_delay.maxDelay(); sink_nd.min_required.at(i) = std::min(sink_nd.min_required.at(i),
net_min_required - comb_delay.maxDelay());
break; break;
} }
} }
@ -752,7 +753,7 @@ void timing_analysis(Context *ctx, bool print_histogram, bool print_fmax, bool p
} }
if (clock_reports.empty()) { if (clock_reports.empty()) {
log_warning("No clocks found in design"); log_warning("No clocks found in design\n");
} }
std::sort(xclock_paths.begin(), xclock_paths.end(), [ctx](const ClockPair &a, const ClockPair &b) { std::sort(xclock_paths.begin(), xclock_paths.end(), [ctx](const ClockPair &a, const ClockPair &b) {

View File

@ -458,7 +458,7 @@ delay_t Arch::estimateDelay(WireId src, WireId dst) const
int dx = abs(src_loc.first - dst_loc.first), dy = abs(src_loc.second - dst_loc.second); int dx = abs(src_loc.first - dst_loc.first), dy = abs(src_loc.second - dst_loc.second);
return (130 - 25 * args.speed) * return (120 - 22 * args.speed) *
(6 + std::max(dx - 5, 0) + std::max(dy - 5, 0) + 2 * (std::min(dx, 5) + std::min(dy, 5))); (6 + std::max(dx - 5, 0) + std::max(dy - 5, 0) + 2 * (std::min(dx, 5) + std::min(dy, 5)));
} }
@ -487,7 +487,7 @@ delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const
int dx = abs(driver_loc.x - sink_loc.x), dy = abs(driver_loc.y - sink_loc.y); int dx = abs(driver_loc.x - sink_loc.x), dy = abs(driver_loc.y - sink_loc.y);
return (130 - 25 * args.speed) * return (120 - 22 * args.speed) *
(6 + std::max(dx - 5, 0) + std::max(dy - 5, 0) + 2 * (std::min(dx, 5) + std::min(dy, 5))); (6 + std::max(dx - 5, 0) + std::max(dy - 5, 0) + 2 * (std::min(dx, 5) + std::min(dy, 5)));
} }
@ -504,6 +504,8 @@ bool Arch::getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay
} }
} }
delay_t Arch::getRipupDelayPenalty() const { return 400; }
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
bool Arch::place() bool Arch::place()
@ -512,7 +514,7 @@ bool Arch::place()
if (placer == "heap") { if (placer == "heap") {
PlacerHeapCfg cfg(getCtx()); PlacerHeapCfg cfg(getCtx());
cfg.criticalityExponent = 7; cfg.criticalityExponent = 4;
cfg.ioBufTypes.insert(id_TRELLIS_IO); cfg.ioBufTypes.insert(id_TRELLIS_IO);
if (!placer_heap(getCtx(), cfg)) if (!placer_heap(getCtx(), cfg))
return false; return false;

View File

@ -942,7 +942,7 @@ struct Arch : BaseCtx
delay_t estimateDelay(WireId src, WireId dst) const; delay_t estimateDelay(WireId src, WireId dst) const;
delay_t predictDelay(const NetInfo *net_info, const PortRef &sink) const; delay_t predictDelay(const NetInfo *net_info, const PortRef &sink) const;
delay_t getDelayEpsilon() const { return 20; } delay_t getDelayEpsilon() const { return 20; }
delay_t getRipupDelayPenalty() const { return 400; } delay_t getRipupDelayPenalty() const;
float getDelayNS(delay_t v) const { return v * 0.001; } float getDelayNS(delay_t v) const { return v * 0.001; }
DelayInfo getDelayFromNS(float ns) const DelayInfo getDelayFromNS(float ns) const
{ {

View File

@ -134,7 +134,7 @@ inline int chtohex(char c)
return hex.find(c); return hex.find(c);
} }
std::vector<bool> parse_init_str(const std::string &str, int length) std::vector<bool> parse_init_str(const std::string &str, int length, const char *cellname)
{ {
// Parse a string that may be binary or hex // Parse a string that may be binary or hex
std::vector<bool> result; std::vector<bool> result;
@ -161,7 +161,8 @@ std::vector<bool> parse_init_str(const std::string &str, int length)
log_error("hex string value too long, expected up to %d bits and found %d.\n", length, int(str.length())); log_error("hex string value too long, expected up to %d bits and found %d.\n", length, int(str.length()));
for (int i = 0; i < int(str.length()); i++) { for (int i = 0; i < int(str.length()); i++) {
char c = str.at((str.size() - i) - 1); char c = str.at((str.size() - i) - 1);
NPNR_ASSERT(c == '0' || c == '1' || c == 'X' || c == 'x'); if (c != '0' && c != '1' && c != 'X' && c != 'x')
log_error("Found illegal character '%c' while processing parameters for cell '%s'\n", c, cellname);
result.at(i) = (c == '1'); result.at(i) = (c == '1');
} }
} }
@ -970,7 +971,7 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex
for (int i = 0; i <= 0x3F; i++) { for (int i = 0; i <= 0x3F; i++) {
IdString param = ctx->id("INITVAL_" + IdString param = ctx->id("INITVAL_" +
fmt_str(std::hex << std::uppercase << std::setw(2) << std::setfill('0') << i)); fmt_str(std::hex << std::uppercase << std::setw(2) << std::setfill('0') << i));
auto value = parse_init_str(str_or_default(ci->params, param, "0"), 320); auto value = parse_init_str(str_or_default(ci->params, param, "0"), 320, ci->name.c_str(ctx));
for (int j = 0; j < 16; j++) { for (int j = 0; j < 16; j++) {
// INIT parameter consists of 16 18-bit words with 2-bit padding // INIT parameter consists of 16 18-bit words with 2-bit padding
int ofs = 20 * j; int ofs = 20 * j;
@ -1078,17 +1079,21 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex
tg.config.add_enum(dsp + ".MASKPAT_SOURCE", tg.config.add_enum(dsp + ".MASKPAT_SOURCE",
str_or_default(ci->params, ctx->id("MASKPAT_SOURCE"), "STATIC")); str_or_default(ci->params, ctx->id("MASKPAT_SOURCE"), "STATIC"));
tg.config.add_word(dsp + ".MASK01", tg.config.add_word(dsp + ".MASK01",
parse_init_str(str_or_default(ci->params, ctx->id("MASK01"), "0x00000000000000"), 56)); parse_init_str(str_or_default(ci->params, ctx->id("MASK01"), "0x00000000000000"), 56,
ci->name.c_str(ctx)));
tg.config.add_enum(dsp + ".CLK0_DIV", str_or_default(ci->params, ctx->id("CLK0_DIV"), "ENABLED")); tg.config.add_enum(dsp + ".CLK0_DIV", str_or_default(ci->params, ctx->id("CLK0_DIV"), "ENABLED"));
tg.config.add_enum(dsp + ".CLK1_DIV", str_or_default(ci->params, ctx->id("CLK1_DIV"), "ENABLED")); tg.config.add_enum(dsp + ".CLK1_DIV", str_or_default(ci->params, ctx->id("CLK1_DIV"), "ENABLED"));
tg.config.add_enum(dsp + ".CLK2_DIV", str_or_default(ci->params, ctx->id("CLK2_DIV"), "ENABLED")); tg.config.add_enum(dsp + ".CLK2_DIV", str_or_default(ci->params, ctx->id("CLK2_DIV"), "ENABLED"));
tg.config.add_enum(dsp + ".CLK3_DIV", str_or_default(ci->params, ctx->id("CLK3_DIV"), "ENABLED")); tg.config.add_enum(dsp + ".CLK3_DIV", str_or_default(ci->params, ctx->id("CLK3_DIV"), "ENABLED"));
tg.config.add_word(dsp + ".MCPAT", tg.config.add_word(dsp + ".MCPAT",
parse_init_str(str_or_default(ci->params, ctx->id("MCPAT"), "0x00000000000000"), 56)); parse_init_str(str_or_default(ci->params, ctx->id("MCPAT"), "0x00000000000000"), 56,
ci->name.c_str(ctx)));
tg.config.add_word(dsp + ".MASKPAT", tg.config.add_word(dsp + ".MASKPAT",
parse_init_str(str_or_default(ci->params, ctx->id("MASKPAT"), "0x00000000000000"), 56)); parse_init_str(str_or_default(ci->params, ctx->id("MASKPAT"), "0x00000000000000"), 56,
ci->name.c_str(ctx)));
tg.config.add_word(dsp + ".RNDPAT", tg.config.add_word(dsp + ".RNDPAT",
parse_init_str(str_or_default(ci->params, ctx->id("RNDPAT"), "0x00000000000000"), 56)); parse_init_str(str_or_default(ci->params, ctx->id("RNDPAT"), "0x00000000000000"), 56,
ci->name.c_str(ctx)));
tg.config.add_enum(dsp + ".GSR", str_or_default(ci->params, ctx->id("GSR"), "ENABLED")); tg.config.add_enum(dsp + ".GSR", str_or_default(ci->params, ctx->id("GSR"), "ENABLED"));
tg.config.add_enum(dsp + ".RESETMODE", str_or_default(ci->params, ctx->id("RESETMODE"), "SYNC")); tg.config.add_enum(dsp + ".RESETMODE", str_or_default(ci->params, ctx->id("RESETMODE"), "SYNC"));
tg.config.add_enum(dsp + ".FORCE_ZERO_BARREL_SHIFT", tg.config.add_enum(dsp + ".FORCE_ZERO_BARREL_SHIFT",

View File

@ -20,12 +20,12 @@
*/ */
#include "application.h" #include "application.h"
#include "log.h"
#include <QOpenGLContext>
#include <QMessageBox> #include <QMessageBox>
#include <QOpenGLContext>
#include <QSurfaceFormat> #include <QSurfaceFormat>
#include <QTextStream> #include <QTextStream>
#include <exception> #include <exception>
#include "log.h"
NEXTPNR_NAMESPACE_BEGIN NEXTPNR_NAMESPACE_BEGIN

View File

@ -1052,6 +1052,14 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, in
return TMG_COMB_INPUT; return TMG_COMB_INPUT;
} else if (cell->type == id_SB_WARMBOOT) { } else if (cell->type == id_SB_WARMBOOT) {
return TMG_ENDPOINT; return TMG_ENDPOINT;
} else if (cell->type == id_SB_LED_DRV_CUR) {
if (port == id_LEDPU)
return TMG_IGNORE;
return TMG_ENDPOINT;
} else if (cell->type == id_SB_RGB_DRV) {
if (port == id_RGB0 || port == id_RGB1 || port == id_RGB2 || port == id_RGBPU)
return TMG_IGNORE;
return TMG_ENDPOINT;
} else if (cell->type == id_SB_RGBA_DRV) { } else if (cell->type == id_SB_RGBA_DRV) {
if (port == id_RGB0 || port == id_RGB1 || port == id_RGB2) if (port == id_RGB0 || port == id_RGB1 || port == id_RGB2)
return TMG_IGNORE; return TMG_IGNORE;

View File

@ -159,6 +159,10 @@ struct ArchCellInfo
{ {
bool forPadIn; bool forPadIn;
} gbInfo; } gbInfo;
struct
{
bool ledCurConnected;
} ledInfo;
}; };
}; };

View File

@ -610,6 +610,14 @@ void write_asc(const Context *ctx, std::ostream &out)
set_config(ti_ramt, config.at(y + 1).at(x), "RamConfig.CBIT_1", write_mode & 0x2); set_config(ti_ramt, config.at(y + 1).at(x), "RamConfig.CBIT_1", write_mode & 0x2);
set_config(ti_ramt, config.at(y + 1).at(x), "RamConfig.CBIT_2", read_mode & 0x1); set_config(ti_ramt, config.at(y + 1).at(x), "RamConfig.CBIT_2", read_mode & 0x1);
set_config(ti_ramt, config.at(y + 1).at(x), "RamConfig.CBIT_3", read_mode & 0x2); set_config(ti_ramt, config.at(y + 1).at(x), "RamConfig.CBIT_3", read_mode & 0x2);
} else if (cell.second->type == ctx->id("SB_LED_DRV_CUR")) {
set_ec_cbit(config, ctx, get_ec_config(ctx->chip_info, cell.second->bel), "LED_DRV_CUR_EN", true,
"IpConfig.");
} else if (cell.second->type == ctx->id("SB_RGB_DRV")) {
const std::vector<std::pair<std::string, int>> rgb_params = {
{"RGB0_CURRENT", 6}, {"RGB1_CURRENT", 6}, {"RGB2_CURRENT", 6}};
configure_extra_cell(config, ctx, cell.second.get(), rgb_params, true, std::string("IpConfig."));
set_ec_cbit(config, ctx, get_ec_config(ctx->chip_info, cell.second->bel), "RGB_DRV_EN", true, "IpConfig.");
} else if (cell.second->type == ctx->id("SB_RGBA_DRV")) { } else if (cell.second->type == ctx->id("SB_RGBA_DRV")) {
const std::vector<std::pair<std::string, int>> rgba_params = { const std::vector<std::pair<std::string, int>> rgba_params = {
{"CURRENT_MODE", 1}, {"RGB0_CURRENT", 6}, {"RGB1_CURRENT", 6}, {"RGB2_CURRENT", 6}}; {"CURRENT_MODE", 1}, {"RGB0_CURRENT", 6}, {"RGB1_CURRENT", 6}, {"RGB2_CURRENT", 6}};

View File

@ -260,6 +260,22 @@ std::unique_ptr<CellInfo> create_ice_cell(Context *ctx, IdString type, std::stri
add_port(ctx, new_cell.get(), "RGB0", PORT_OUT); add_port(ctx, new_cell.get(), "RGB0", PORT_OUT);
add_port(ctx, new_cell.get(), "RGB1", PORT_OUT); add_port(ctx, new_cell.get(), "RGB1", PORT_OUT);
add_port(ctx, new_cell.get(), "RGB2", PORT_OUT); add_port(ctx, new_cell.get(), "RGB2", PORT_OUT);
} else if (type == ctx->id("SB_LED_DRV_CUR")) {
add_port(ctx, new_cell.get(), "EN", PORT_IN);
add_port(ctx, new_cell.get(), "LEDPU", PORT_OUT);
} else if (type == ctx->id("SB_RGB_DRV")) {
new_cell->params[ctx->id("RGB0_CURRENT")] = "0b000000";
new_cell->params[ctx->id("RGB1_CURRENT")] = "0b000000";
new_cell->params[ctx->id("RGB2_CURRENT")] = "0b000000";
add_port(ctx, new_cell.get(), "RGBPU", PORT_IN);
add_port(ctx, new_cell.get(), "RGBLEDEN", PORT_IN);
add_port(ctx, new_cell.get(), "RGB0PWM", PORT_IN);
add_port(ctx, new_cell.get(), "RGB1PWM", PORT_IN);
add_port(ctx, new_cell.get(), "RGB2PWM", PORT_IN);
add_port(ctx, new_cell.get(), "RGB0", PORT_OUT);
add_port(ctx, new_cell.get(), "RGB1", PORT_OUT);
add_port(ctx, new_cell.get(), "RGB2", PORT_OUT);
} else if (type == ctx->id("SB_LEDDA_IP")) { } else if (type == ctx->id("SB_LEDDA_IP")) {
add_port(ctx, new_cell.get(), "LEDDCS", PORT_IN); add_port(ctx, new_cell.get(), "LEDDCS", PORT_IN);
add_port(ctx, new_cell.get(), "LEDDCLK", PORT_IN); add_port(ctx, new_cell.get(), "LEDDCLK", PORT_IN);

View File

@ -76,6 +76,13 @@ inline bool is_sb_mac16(const BaseCtx *ctx, const CellInfo *cell) { return cell-
inline bool is_sb_rgba_drv(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_RGBA_DRV"); } inline bool is_sb_rgba_drv(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_RGBA_DRV"); }
inline bool is_sb_rgb_drv(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_RGB_DRV"); }
inline bool is_sb_led_drv_cur(const BaseCtx *ctx, const CellInfo *cell)
{
return cell->type == ctx->id("SB_LED_DRV_CUR");
}
inline bool is_sb_ledda_ip(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_LEDDA_IP"); } inline bool is_sb_ledda_ip(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_LEDDA_IP"); }
inline bool is_sb_i2c(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_I2C"); } inline bool is_sb_i2c(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_I2C"); }

View File

@ -81,6 +81,8 @@ constids["SPI"] = constids["SB_SPI"]
constids["LEDDA_IP"] = constids["SB_LEDDA_IP"] constids["LEDDA_IP"] = constids["SB_LEDDA_IP"]
constids["RGBA_DRV"] = constids["SB_RGBA_DRV"] constids["RGBA_DRV"] = constids["SB_RGBA_DRV"]
constids["SPRAM"] = constids["ICESTORM_SPRAM"] constids["SPRAM"] = constids["ICESTORM_SPRAM"]
constids["LED_DRV_CUR"] = constids["SB_LED_DRV_CUR"]
constids["RGB_DRV"] = constids["SB_RGB_DRV"]
with open(args.gfxh) as f: with open(args.gfxh) as f:
state = 0 state = 0

View File

@ -355,6 +355,9 @@ X(PWMOUT0)
X(PWMOUT1) X(PWMOUT1)
X(PWMOUT2) X(PWMOUT2)
X(LEDPU)
X(EN)
X(RGBPU)
X(CURREN) X(CURREN)
X(RGB0PWM) X(RGB0PWM)
X(RGB1PWM) X(RGB1PWM)
@ -438,6 +441,8 @@ X(IO_I3C)
X(SB_LEDDA_IP) X(SB_LEDDA_IP)
X(SB_RGBA_DRV) X(SB_RGBA_DRV)
X(ICESTORM_SPRAM) X(ICESTORM_SPRAM)
X(SB_LED_DRV_CUR)
X(SB_RGB_DRV)
// cell parameters // cell parameters
X(DFF_ENABLE) X(DFF_ENABLE)

View File

@ -465,7 +465,8 @@ static void pack_io(Context *ctx)
} else if (ci->type == ctx->id("$nextpnr_obuf")) { } else if (ci->type == ctx->id("$nextpnr_obuf")) {
NetInfo *net = ci->ports.at(ctx->id("I")).net; NetInfo *net = ci->ports.at(ctx->id("I")).net;
sb = net_only_drives(ctx, net, is_ice_iob, ctx->id("PACKAGE_PIN"), true, ci); sb = net_only_drives(ctx, net, is_ice_iob, ctx->id("PACKAGE_PIN"), true, ci);
if (net && net->driver.cell && is_sb_rgba_drv(ctx, net->driver.cell)) if (net && net->driver.cell &&
(is_sb_rgba_drv(ctx, net->driver.cell) || is_sb_rgb_drv(ctx, net->driver.cell)))
rgb = net->driver.cell; rgb = net->driver.cell;
} }
if (sb != nullptr) { if (sb != nullptr) {
@ -491,7 +492,8 @@ static void pack_io(Context *ctx)
} }
} }
} else if (rgb != nullptr) { } else if (rgb != nullptr) {
log_info("%s use by SB_RGBA_DRV %s, not creating SB_IO\n", ci->name.c_str(ctx), rgb->name.c_str(ctx)); log_info("%s use by SB_RGBA_DRV/SB_RGB_DRV %s, not creating SB_IO\n", ci->name.c_str(ctx),
rgb->name.c_str(ctx));
disconnect_port(ctx, ci, ctx->id("I")); disconnect_port(ctx, ci, ctx->id("I"));
packed_cells.insert(ci->name); packed_cells.insert(ci->name);
continue; continue;
@ -1053,6 +1055,27 @@ static void pack_special(Context *ctx)
std::unordered_set<IdString> packed_cells; std::unordered_set<IdString> packed_cells;
std::vector<std::unique_ptr<CellInfo>> new_cells; std::vector<std::unique_ptr<CellInfo>> new_cells;
// Handle LED_DRV_CUR first to set the ledCurConnected flag before RGB_DRV is handled below.
for (auto cell : sorted(ctx->cells)) {
CellInfo *ci = cell.second;
if (is_sb_led_drv_cur(ctx, ci)) {
/* Force placement (no choices anyway) */
cell_place_unique(ctx, ci);
NetInfo *ledpu_net = ci->ports.at(ctx->id("LEDPU")).net;
for (auto &user : ledpu_net->users) {
if (!is_sb_rgb_drv(ctx, user.cell)) {
log_error("SB_LED_DRV_CUR LEDPU port can only be connected to SB_RGB_DRV!\n");
} else {
user.cell->ledInfo.ledCurConnected = true;
user.cell->ports.at(user.port).net = nullptr;
}
}
ci->ports.erase(ctx->id("LEDPU"));
ctx->nets.erase(ledpu_net->name);
}
}
for (auto cell : sorted(ctx->cells)) { for (auto cell : sorted(ctx->cells)) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second;
if (is_sb_lfosc(ctx, ci)) { if (is_sb_lfosc(ctx, ci)) {
@ -1128,7 +1151,7 @@ static void pack_special(Context *ctx)
replace_port(ci, ctx->id(pi.name.c_str(ctx)), packed.get(), ctx->id(newname)); replace_port(ci, ctx->id(pi.name.c_str(ctx)), packed.get(), ctx->id(newname));
} }
new_cells.push_back(std::move(packed)); new_cells.push_back(std::move(packed));
} else if (is_sb_rgba_drv(ctx, ci)) { } else if (is_sb_rgba_drv(ctx, ci) || is_sb_rgb_drv(ctx, ci)) {
/* Force placement (no choices anyway) */ /* Force placement (no choices anyway) */
cell_place_unique(ctx, ci); cell_place_unique(ctx, ci);
@ -1140,14 +1163,20 @@ static void pack_special(Context *ctx)
if (net == nullptr) if (net == nullptr)
continue; continue;
if ((pi.name != ctx->id("RGB0")) && (pi.name != ctx->id("RGB1")) && (pi.name != ctx->id("RGB2"))) if ((pi.name != ctx->id("RGB0")) && (pi.name != ctx->id("RGB1")) && (pi.name != ctx->id("RGB2")))
continue; continue;
if (net->users.size() > 0) if (net->users.size() > 0)
log_error("SB_RGBA_DRV port connected to more than just package pin !\n"); log_error("SB_RGB_DRV/SB_RGBA_DRV port connected to more than just package pin !\n");
ctx->nets.erase(net->name); ctx->nets.erase(net->name);
} }
if (is_sb_rgb_drv(ctx, ci) && !ci->ledInfo.ledCurConnected)
log_error("Port RGBPU of SB_RGB_DRV should be driven by port LEDPU of SB_LED_DRV_CUR!\n");
ci->ports.erase(ctx->id("RGBPU"));
ci->ports.erase(ctx->id("RGB0")); ci->ports.erase(ctx->id("RGB0"));
ci->ports.erase(ctx->id("RGB1")); ci->ports.erase(ctx->id("RGB1"));
ci->ports.erase(ctx->id("RGB2")); ci->ports.erase(ctx->id("RGB2"));

View File

@ -285,7 +285,7 @@ void vcc_net(Context *ctx, NetInfo *net)
// true, false otherwise // true, false otherwise
bool is_blackbox(JsonNode *node) bool is_blackbox(JsonNode *node)
{ {
JsonNode *attr_node, *bbox_node; JsonNode *attr_node, *bbox_node = nullptr, *wbox_node = nullptr;
if (node->data_dict.count("attributes") == 0) if (node->data_dict.count("attributes") == 0)
return false; return false;
@ -296,14 +296,19 @@ bool is_blackbox(JsonNode *node)
return false; return false;
if (GetSize(attr_node->data_dict) == 0) if (GetSize(attr_node->data_dict) == 0)
return false; return false;
if (attr_node->data_dict.count("blackbox") == 0) if (attr_node->data_dict.count("blackbox"))
bbox_node = attr_node->data_dict.at("blackbox");
if (attr_node->data_dict.count("whitebox"))
wbox_node = attr_node->data_dict.at("whitebox");
if (bbox_node == NULL && wbox_node == NULL)
return false; return false;
bbox_node = attr_node->data_dict.at("blackbox"); if (bbox_node && bbox_node->type != 'N')
if (bbox_node == NULL) log_error("JSON module blackbox attribute value is not a number\n");
if (bbox_node && bbox_node->data_number == 0)
return false; return false;
if (bbox_node->type != 'N') if (wbox_node && wbox_node->type != 'N')
log_error("JSON module blackbox is not a number\n"); log_error("JSON module whitebox attribute value is not a number\n");
if (bbox_node->data_number == 0) if (wbox_node && wbox_node->data_number == 0)
return false; return false;
return true; return true;
} }
@ -381,7 +386,7 @@ static int const_net_idx = 0;
template <typename F> template <typename F>
void json_import_ports(Context *ctx, const string &modname, const std::vector<IdString> &netnames, void json_import_ports(Context *ctx, const string &modname, const std::vector<IdString> &netnames,
const string &obj_name, const string &port_name, JsonNode *dir_node, JsonNode *wire_group_node, const string &obj_name, const string &port_name, JsonNode *dir_node, JsonNode *wire_group_node,
F visitor) bool upto, int start_offset, F visitor)
{ {
// Examine a port of a cell or the design. For every bit of the port, // Examine a port of a cell or the design. For every bit of the port,
// the connected net will be processed and `visitor` will be called // the connected net will be processed and `visitor` will be called
@ -450,8 +455,11 @@ void json_import_ports(Context *ctx, const string &modname, const std::vector<Id
wire_node = wire_group_node->data_array[index]; wire_node = wire_group_node->data_array[index];
// //
// Pick a name for this port // Pick a name for this port
int ndx = index + start_offset;
if (upto)
ndx = start_offset + wire_group_node->data_array.size() - index - 1;
if (is_bus) if (is_bus)
this_port.name = ctx->id(port_info.name.str(ctx) + "[" + std::to_string(index) + "]"); this_port.name = ctx->id(port_info.name.str(ctx) + "[" + std::to_string(ndx) + "]");
else else
this_port.name = port_info.name; this_port.name = port_info.name;
this_port.type = port_info.type; this_port.type = port_info.type;
@ -628,7 +636,7 @@ void json_import_cell(Context *ctx, string modname, const std::vector<IdString>
dir_node = pdir_node->data_dict.at(port_name); dir_node = pdir_node->data_dict.at(port_name);
wire_group_node = connections->data_dict.at(port_name); wire_group_node = connections->data_dict.at(port_name);
json_import_ports(ctx, modname, netnames, cell->name.str(ctx), port_name, dir_node, wire_group_node, json_import_ports(ctx, modname, netnames, cell->name.str(ctx), port_name, dir_node, wire_group_node, false, 0,
[&cell, ctx](PortType type, const std::string &name, NetInfo *net) { [&cell, ctx](PortType type, const std::string &name, NetInfo *net) {
cell->ports[ctx->id(name)] = PortInfo{ctx->id(name), net, type}; cell->ports[ctx->id(name)] = PortInfo{ctx->id(name), net, type};
PortRef pr; PortRef pr;
@ -732,8 +740,20 @@ void json_import_toplevel_port(Context *ctx, const string &modname, const std::v
{ {
JsonNode *dir_node = node->data_dict.at("direction"); JsonNode *dir_node = node->data_dict.at("direction");
JsonNode *nets_node = node->data_dict.at("bits"); JsonNode *nets_node = node->data_dict.at("bits");
bool upto = false;
int start_offset = 0;
if (node->data_dict.count("upto") != 0) {
JsonNode *val = node->data_dict.at("upto");
if (val->type == 'N')
upto = val->data_number != 0;
}
if (node->data_dict.count("offset") != 0) {
JsonNode *val = node->data_dict.at("offset");
if (val->type == 'N')
start_offset = val->data_number;
}
json_import_ports( json_import_ports(
ctx, modname, netnames, "Top Level IO", portname, dir_node, nets_node, ctx, modname, netnames, "Top Level IO", portname, dir_node, nets_node, upto, start_offset,
[ctx](PortType type, const std::string &name, NetInfo *net) { insert_iobuf(ctx, net, type, name); }); [ctx](PortType type, const std::string &name, NetInfo *net) { insert_iobuf(ctx, net, type, name); });
} }
@ -789,6 +809,18 @@ void json_import(Context *ctx, string modname, JsonNode *node)
here = cell_parent->data_dict.at(cell_parent->data_dict_keys[nnid]); here = cell_parent->data_dict.at(cell_parent->data_dict_keys[nnid]);
std::string basename = cell_parent->data_dict_keys[nnid]; std::string basename = cell_parent->data_dict_keys[nnid];
bool upto = false;
int start_offset = 0;
if (here->data_dict.count("upto") != 0) {
JsonNode *val = here->data_dict.at("upto");
if (val->type == 'N')
upto = val->data_number != 0;
}
if (here->data_dict.count("offset") != 0) {
JsonNode *val = here->data_dict.at("offset");
if (val->type == 'N')
start_offset = val->data_number;
}
if (here->data_dict.count("bits")) { if (here->data_dict.count("bits")) {
JsonNode *bits = here->data_dict.at("bits"); JsonNode *bits = here->data_dict.at("bits");
assert(bits->type == 'A'); assert(bits->type == 'A');
@ -797,8 +829,11 @@ void json_import(Context *ctx, string modname, JsonNode *node)
int netid = bits->data_array.at(i)->data_number; int netid = bits->data_array.at(i)->data_number;
if (netid >= int(netlabels.size())) if (netid >= int(netlabels.size()))
netlabels.resize(netid + 1); netlabels.resize(netid + 1);
int ndx = i + start_offset;
if (upto)
ndx = start_offset + num_bits - i - 1;
std::string name = std::string name =
basename + (num_bits == 1 ? "" : std::string("[") + std::to_string(i) + std::string("]")); basename + (num_bits == 1 ? "" : std::string("[") + std::to_string(ndx) + std::string("]"));
if (prefer_netlabel(name, netlabels.at(netid))) if (prefer_netlabel(name, netlabels.at(netid)))
netlabels.at(netid) = name; netlabels.at(netid) = name;
} }