Merge master
This commit is contained in:
commit
ec47ce2320
@ -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
|
||||
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
|
||||
[getting started notes](#getting-started) can be found below.
|
||||
|
||||
|
@ -546,7 +546,8 @@ struct Timing
|
||||
for (size_t i = 0; i < sink_net->users.size(); i++) {
|
||||
auto &user = sink_net->users.at(i);
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -752,7 +753,7 @@ void timing_analysis(Context *ctx, bool print_histogram, bool print_fmax, bool p
|
||||
}
|
||||
|
||||
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) {
|
||||
|
@ -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);
|
||||
|
||||
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)));
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
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)));
|
||||
}
|
||||
|
||||
@ -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()
|
||||
@ -512,7 +514,7 @@ bool Arch::place()
|
||||
|
||||
if (placer == "heap") {
|
||||
PlacerHeapCfg cfg(getCtx());
|
||||
cfg.criticalityExponent = 7;
|
||||
cfg.criticalityExponent = 4;
|
||||
cfg.ioBufTypes.insert(id_TRELLIS_IO);
|
||||
if (!placer_heap(getCtx(), cfg))
|
||||
return false;
|
||||
|
@ -942,7 +942,7 @@ struct Arch : BaseCtx
|
||||
delay_t estimateDelay(WireId src, WireId dst) const;
|
||||
delay_t predictDelay(const NetInfo *net_info, const PortRef &sink) const;
|
||||
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; }
|
||||
DelayInfo getDelayFromNS(float ns) const
|
||||
{
|
||||
|
@ -134,7 +134,7 @@ inline int chtohex(char 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
|
||||
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()));
|
||||
for (int i = 0; i < int(str.length()); i++) {
|
||||
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');
|
||||
}
|
||||
}
|
||||
@ -970,7 +971,7 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex
|
||||
for (int i = 0; i <= 0x3F; i++) {
|
||||
IdString param = ctx->id("INITVAL_" +
|
||||
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++) {
|
||||
// INIT parameter consists of 16 18-bit words with 2-bit padding
|
||||
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",
|
||||
str_or_default(ci->params, ctx->id("MASKPAT_SOURCE"), "STATIC"));
|
||||
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 + ".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 + ".CLK3_DIV", str_or_default(ci->params, ctx->id("CLK3_DIV"), "ENABLED"));
|
||||
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",
|
||||
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",
|
||||
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 + ".RESETMODE", str_or_default(ci->params, ctx->id("RESETMODE"), "SYNC"));
|
||||
tg.config.add_enum(dsp + ".FORCE_ZERO_BARREL_SHIFT",
|
||||
|
@ -20,12 +20,12 @@
|
||||
*/
|
||||
|
||||
#include "application.h"
|
||||
#include "log.h"
|
||||
#include <QOpenGLContext>
|
||||
#include <QMessageBox>
|
||||
#include <QOpenGLContext>
|
||||
#include <QSurfaceFormat>
|
||||
#include <QTextStream>
|
||||
#include <exception>
|
||||
#include "log.h"
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
|
@ -1052,6 +1052,14 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, in
|
||||
return TMG_COMB_INPUT;
|
||||
} else if (cell->type == id_SB_WARMBOOT) {
|
||||
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) {
|
||||
if (port == id_RGB0 || port == id_RGB1 || port == id_RGB2)
|
||||
return TMG_IGNORE;
|
||||
|
@ -159,6 +159,10 @@ struct ArchCellInfo
|
||||
{
|
||||
bool forPadIn;
|
||||
} gbInfo;
|
||||
struct
|
||||
{
|
||||
bool ledCurConnected;
|
||||
} ledInfo;
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -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_2", read_mode & 0x1);
|
||||
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")) {
|
||||
const std::vector<std::pair<std::string, int>> rgba_params = {
|
||||
{"CURRENT_MODE", 1}, {"RGB0_CURRENT", 6}, {"RGB1_CURRENT", 6}, {"RGB2_CURRENT", 6}};
|
||||
|
@ -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(), "RGB1", 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")) {
|
||||
add_port(ctx, new_cell.get(), "LEDDCS", PORT_IN);
|
||||
add_port(ctx, new_cell.get(), "LEDDCLK", PORT_IN);
|
||||
|
@ -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_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_i2c(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_I2C"); }
|
||||
|
@ -81,6 +81,8 @@ constids["SPI"] = constids["SB_SPI"]
|
||||
constids["LEDDA_IP"] = constids["SB_LEDDA_IP"]
|
||||
constids["RGBA_DRV"] = constids["SB_RGBA_DRV"]
|
||||
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:
|
||||
state = 0
|
||||
|
@ -355,6 +355,9 @@ X(PWMOUT0)
|
||||
X(PWMOUT1)
|
||||
X(PWMOUT2)
|
||||
|
||||
X(LEDPU)
|
||||
X(EN)
|
||||
X(RGBPU)
|
||||
X(CURREN)
|
||||
X(RGB0PWM)
|
||||
X(RGB1PWM)
|
||||
@ -438,6 +441,8 @@ X(IO_I3C)
|
||||
X(SB_LEDDA_IP)
|
||||
X(SB_RGBA_DRV)
|
||||
X(ICESTORM_SPRAM)
|
||||
X(SB_LED_DRV_CUR)
|
||||
X(SB_RGB_DRV)
|
||||
|
||||
// cell parameters
|
||||
X(DFF_ENABLE)
|
||||
|
@ -465,7 +465,8 @@ static void pack_io(Context *ctx)
|
||||
} else if (ci->type == ctx->id("$nextpnr_obuf")) {
|
||||
NetInfo *net = ci->ports.at(ctx->id("I")).net;
|
||||
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;
|
||||
}
|
||||
if (sb != nullptr) {
|
||||
@ -491,7 +492,8 @@ static void pack_io(Context *ctx)
|
||||
}
|
||||
}
|
||||
} 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"));
|
||||
packed_cells.insert(ci->name);
|
||||
continue;
|
||||
@ -1053,6 +1055,27 @@ static void pack_special(Context *ctx)
|
||||
std::unordered_set<IdString> packed_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)) {
|
||||
CellInfo *ci = cell.second;
|
||||
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));
|
||||
}
|
||||
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) */
|
||||
cell_place_unique(ctx, ci);
|
||||
|
||||
@ -1140,14 +1163,20 @@ static void pack_special(Context *ctx)
|
||||
|
||||
if (net == nullptr)
|
||||
continue;
|
||||
|
||||
if ((pi.name != ctx->id("RGB0")) && (pi.name != ctx->id("RGB1")) && (pi.name != ctx->id("RGB2")))
|
||||
continue;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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("RGB1"));
|
||||
ci->ports.erase(ctx->id("RGB2"));
|
||||
|
@ -285,7 +285,7 @@ void vcc_net(Context *ctx, NetInfo *net)
|
||||
// true, false otherwise
|
||||
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)
|
||||
return false;
|
||||
@ -296,14 +296,19 @@ bool is_blackbox(JsonNode *node)
|
||||
return false;
|
||||
if (GetSize(attr_node->data_dict) == 0)
|
||||
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;
|
||||
bbox_node = attr_node->data_dict.at("blackbox");
|
||||
if (bbox_node == NULL)
|
||||
if (bbox_node && bbox_node->type != 'N')
|
||||
log_error("JSON module blackbox attribute value is not a number\n");
|
||||
if (bbox_node && bbox_node->data_number == 0)
|
||||
return false;
|
||||
if (bbox_node->type != 'N')
|
||||
log_error("JSON module blackbox is not a number\n");
|
||||
if (bbox_node->data_number == 0)
|
||||
if (wbox_node && wbox_node->type != 'N')
|
||||
log_error("JSON module whitebox attribute value is not a number\n");
|
||||
if (wbox_node && wbox_node->data_number == 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
@ -381,7 +386,7 @@ static int const_net_idx = 0;
|
||||
template <typename F>
|
||||
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,
|
||||
F visitor)
|
||||
bool upto, int start_offset, F visitor)
|
||||
{
|
||||
// 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
|
||||
@ -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];
|
||||
//
|
||||
// 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)
|
||||
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
|
||||
this_port.name = port_info.name;
|
||||
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);
|
||||
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->ports[ctx->id(name)] = PortInfo{ctx->id(name), net, type};
|
||||
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 *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(
|
||||
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); });
|
||||
}
|
||||
|
||||
@ -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]);
|
||||
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")) {
|
||||
JsonNode *bits = here->data_dict.at("bits");
|
||||
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;
|
||||
if (netid >= int(netlabels.size()))
|
||||
netlabels.resize(netid + 1);
|
||||
int ndx = i + start_offset;
|
||||
if (upto)
|
||||
ndx = start_offset + num_bits - i - 1;
|
||||
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)))
|
||||
netlabels.at(netid) = name;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user