From 2b1f7875bb8c3a761dfb9db21706f918b58be9c3 Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Sun, 22 Jul 2018 13:42:07 +0100 Subject: ice40: Implement emitting PLLs --- ice40/arch.cc | 3 +- ice40/bitstream.cc | 118 ++++++++++++++++++++++++++++++++++++++++++++++------- ice40/cells.cc | 49 ++++++++++++++++++++++ ice40/cells.h | 9 ++++ ice40/chipdb.py | 41 +++++++++++++++++++ ice40/gfx.h | 6 ++- ice40/pack.cc | 32 +++++++++++++++ ice40/pcf.cc | 25 ++++++++++++ ice40/portpins.inc | 2 + 9 files changed, 269 insertions(+), 16 deletions(-) (limited to 'ice40') diff --git a/ice40/arch.cc b/ice40/arch.cc index 65b21afd..d6ef800d 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -331,11 +331,12 @@ WireId Arch::getBelPinWire(BelId bel, PortPin pin) const 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++) + for (int i = 0; i < num_bel_wires; i++) { if (bel_wires[i].port == pin) { ret.index = bel_wires[i].wire_index; break; } + } return ret; } diff --git a/ice40/bitstream.cc b/ice40/bitstream.cc index 9ac8e857..77d92a89 100644 --- a/ice40/bitstream.cc +++ b/ice40/bitstream.cc @@ -74,23 +74,33 @@ void set_config(const TileInfoPOD &ti, std::vector> &tile_cf for (int i = 0; i < cfg.num_bits; i++) { int8_t &cbit = tile_cfg.at(cfg.bits[i].row).at(cfg.bits[i].col); if (cbit && !value) - log_error("clearing already set config bit %s", name.c_str()); + log_error("clearing already set config bit %s\n", name.c_str()); cbit = value; } } else { int8_t &cbit = tile_cfg.at(cfg.bits[index].row).at(cfg.bits[index].col); cbit = value; if (cbit && !value) - log_error("clearing already set config bit %s[%d]", name.c_str(), index); + log_error("clearing already set config bit %s[%d]\n", name.c_str(), index); + } +} + +// Set an IE_{EN,REN} logical bit in a tile config. Logical means enabled. +// On {HX,LP}1K devices these bits are active low, so we need to inver them. +void set_ie_bit_logical(const Context *ctx, const TileInfoPOD &ti, std::vector> &tile_cfg, const std::string &name, bool value) { + if (ctx->args.type == ArchArgs::LP1K || ctx->args.type == ArchArgs::HX1K) { + set_config(ti, tile_cfg, name, !value); + } else { + set_config(ti, tile_cfg, name, value); } } int get_param_or_def(const CellInfo *cell, const IdString param, int defval = 0) { auto found = cell->params.find(param); - if (found != cell->params.end()) + if (found != cell->params.end()) { return std::stoi(found->second); - else + } else return defval; } @@ -117,7 +127,7 @@ static const BelConfigPOD &get_ec_config(const ChipInfoPOD *chip, BelId bel) typedef std::vector>>> chipconfig_t; static void set_ec_cbit(chipconfig_t &config, const Context *ctx, const BelConfigPOD &cell_cbits, std::string name, - bool value) + bool value, std::string prefix) { const ChipInfoPOD *chip = ctx->chip_info; @@ -125,7 +135,7 @@ static void set_ec_cbit(chipconfig_t &config, const Context *ctx, const BelConfi const auto &cbit = cell_cbits.entries[i]; if (cbit.entry_name.get() == name) { const auto &ti = chip->bits_info->tiles_nonrouting[tile_at(ctx, cbit.x, cbit.y)]; - set_config(ti, config.at(cbit.y).at(cbit.x), std::string("IpConfig.") + cbit.cbit_name.get(), value); + set_config(ti, config.at(cbit.y).at(cbit.x), prefix + cbit.cbit_name.get(), value); return; } } @@ -133,7 +143,7 @@ static void set_ec_cbit(chipconfig_t &config, const Context *ctx, const BelConfi } void configure_extra_cell(chipconfig_t &config, const Context *ctx, CellInfo *cell, - const std::vector> ¶ms, bool string_style) + const std::vector> ¶ms, bool string_style, std::string prefix) { const ChipInfoPOD *chip = ctx->chip_info; const auto &bc = get_ec_config(chip, cell->bel); @@ -163,10 +173,10 @@ void configure_extra_cell(chipconfig_t &config, const Context *ctx, CellInfo *ce value.resize(p.second); if (p.second == 1) { - set_ec_cbit(config, ctx, bc, p.first, value.at(0)); + set_ec_cbit(config, ctx, bc, p.first, value.at(0), prefix); } else { for (int i = 0; i < p.second; i++) { - set_ec_cbit(config, ctx, bc, p.first + "_" + std::to_string(i), value.at(i)); + set_ec_cbit(config, ctx, bc, p.first + "_" + std::to_string(i), value.at(i), prefix); } } } @@ -258,8 +268,13 @@ void write_asc(const Context *ctx, std::ostream &out) } } } + + std::unordered_set sb_io_used_by_pll; + std::unordered_set sb_io_used_by_user; + // Set logic cell config for (auto &cell : ctx->cells) { + BelId bel = cell.second.get()->bel; if (bel == BelId()) { std::cout << "Found unplaced cell " << cell.first.str(ctx) << " while generating bitstream!" << std::endl; @@ -304,6 +319,7 @@ void write_asc(const Context *ctx, std::ostream &out) } else if (cell.second->type == ctx->id("SB_IO")) { const BelInfoPOD &beli = ci.bel_data[bel.index]; int x = beli.x, y = beli.y, z = beli.z; + sb_io_used_by_user.insert(Loc(x,y,z)); const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_IO]; unsigned pin_type = get_param_or_def(cell.second.get(), ctx->id("PIN_TYPE")); bool neg_trigger = get_param_or_def(cell.second.get(), ctx->id("NEG_TRIGGER")); @@ -405,7 +421,79 @@ void write_asc(const Context *ctx, std::ostream &out) {"MODE_8x8", 1}, {"A_SIGNED", 1}, {"B_SIGNED", 1}}; - configure_extra_cell(config, ctx, cell.second.get(), mac16_params, false); + configure_extra_cell(config, ctx, cell.second.get(), mac16_params, false, std::string("IpConfig.")); + } else if (cell.second->type == ctx->id("ICESTORM_PLL")) { + const std::vector> pll_params = { + {"DELAY_ADJMODE_FB", 1}, {"DELAY_ADJMODE_REL", 1}, + {"DIVF", 7}, {"DIVQ", 3}, {"DIVR", 4}, + {"FDA_FEEDBACK", 4}, {"FDA_RELATIVE", 4}, + {"FEEDBACK_PATH", 3}, {"FILTER_RANGE", 3}, + {"PLLOUT_SELECT_A", 2}, {"PLLOUT_SELECT_B", 2}, + {"PLLTYPE", 3}, {"SHIFTREG_DIV_MODE", 1}, {"TEST_MODE", 1} + }; + configure_extra_cell(config, ctx, cell.second.get(), pll_params, false, std::string("PLL.")); + + // Configure the SB_IOs that the clock outputs are going through. + for (auto &port : cell.second->ports) { + // If this port is not a PLLOUT port, ignore it. + if (port.second.name != ctx->id("PLLOUT_A") && port.second.name != ctx->id("PLLOUT_B")) + continue; + + // If the output is not driving any net, ignore it. + if (port.second.net == nullptr) + continue; + + // Find SB_IO Bel in net that's driving a wire. That's the one + // we're routing the signal through. + // TODO(q3k): Is there a nicer way to do this? + bool found = false; + + // For every wire in the PLLOUT net... + for (auto wp : port.second.net->wires) { + // ... get its' uphill bel ... + auto bel = ctx->getBelPinUphill(wp.first).bel; + if (bel == BelId()) { + continue; + } + // ... and check if it's an SB_IO. + if (ctx->getBelType(bel) != TYPE_SB_IO) + continue; + + // Check that this SB_IO is either unused or just used as an output. + const BelInfoPOD &io_beli = ci.bel_data[bel.index]; + auto io_loc = Loc(io_beli.x, io_beli.y, io_beli.z); + + if (sb_io_used_by_user.count(io_loc)) { + log_error("SB_IO '%s' already in use, cannot route PLL through\n", + ctx->getBelName(bel).c_str(ctx)); + } + sb_io_used_by_pll.insert(Loc(io_beli.x, io_beli.y, io_beli.z)); + + // Get IE/REN config location (cf. http://www.clifford.at/icestorm/io_tile.html) + auto ieren = get_ieren(bi, io_beli.x, io_beli.y, io_beli.z); + int iex, iey, iez; + std::tie(iex, iey, iez) = ieren; + NPNR_ASSERT(iez != -1); + + // Write config. + const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_IO]; + // Enable input buffer and disable pull-up resistor in block + // (this is used by the PLL). + set_ie_bit_logical(ctx, ti, config.at(iey).at(iex), "IoCtrl.IE_" + std::to_string(iez), true); + set_ie_bit_logical(ctx, ti, config.at(iey).at(iex), "IoCtrl.REN_" + std::to_string(iez), false); + // PINTYPE[0] passes the PLL through to the fabric. + set_config(ti, config.at(io_beli.y).at(io_beli.x), "IOB_" + std::to_string(io_beli.z) + ".PINTYPE_0", true); + + found = true; + break; + } + + if (!found) { + log_error("Could not find SB_IO forwarding PLL '%s' %s signal\n", + cell.second->name.c_str(ctx), port.second.name.c_str(ctx)); + } + } + } else { NPNR_ASSERT(false); } @@ -416,14 +504,16 @@ void write_asc(const Context *ctx, std::ostream &out) const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_IO]; const BelInfoPOD &beli = ci.bel_data[bel.index]; int x = beli.x, y = beli.y, z = beli.z; + if (sb_io_used_by_pll.count(Loc(x, y, z))) { + continue; + } + auto ieren = get_ieren(bi, x, y, z); int iex, iey, iez; std::tie(iex, iey, iez) = ieren; if (iez != -1) { - if (ctx->args.type == ArchArgs::LP1K || ctx->args.type == ArchArgs::HX1K) { - set_config(ti, config.at(iey).at(iex), "IoCtrl.IE_" + std::to_string(iez), true); - set_config(ti, config.at(iey).at(iex), "IoCtrl.REN_" + std::to_string(iez), false); - } + set_ie_bit_logical(ctx, ti, config.at(iey).at(iex), "IoCtrl.IE_" + std::to_string(iez), true); + set_ie_bit_logical(ctx, ti, config.at(iey).at(iex), "IoCtrl.REN_" + std::to_string(iez), false); } } else if (ctx->bel_to_cell[bel.index] == IdString() && ctx->getBelType(bel) == TYPE_ICESTORM_RAM) { const BelInfoPOD &beli = ci.bel_data[bel.index]; diff --git a/ice40/cells.cc b/ice40/cells.cc index 71a65d44..3215a38c 100644 --- a/ice40/cells.cc +++ b/ice40/cells.cc @@ -207,6 +207,40 @@ std::unique_ptr create_ice_cell(Context *ctx, IdString type, std::stri 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 iCE40 cell of type %s", type.c_str(ctx)); } @@ -312,6 +346,21 @@ 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) diff --git a/ice40/cells.h b/ice40/cells.h index 2f9c77e8..404f401c 100644 --- a/ice40/cells.h +++ b/ice40/cells.h @@ -71,6 +71,15 @@ inline bool is_sb_spram(const BaseCtx *ctx, const CellInfo *cell) { return cell- inline bool is_sb_mac16(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_MAC16"); } +inline bool is_sb_pll40(const BaseCtx *ctx, const CellInfo *cell) +{ + return cell->type == ctx->id("SB_PLL40_PAD") || cell->type == ctx->id("SB_PLL40_2_PAD") || + cell->type == ctx->id("SB_PLL40_2F_PAD") || cell->type == ctx->id("SB_PLL40_CORE") || + cell->type == ctx->id("SB_PLL40_2F_CORE"); +} + +uint8_t sb_pll40_type(const BaseCtx *ctx, const CellInfo *cell); + // Convert a SB_LUT primitive to (part of) an ICESTORM_LC, swapping ports // as needed. Set no_dff if a DFF is not being used, so that the output // can be reconnected diff --git a/ice40/chipdb.py b/ice40/chipdb.py index 0e8e3ba7..63f08e36 100644 --- a/ice40/chipdb.py +++ b/ice40/chipdb.py @@ -184,6 +184,8 @@ def wire_type(name): wt = "LOCAL" elif name in ("WCLK", "WCLKE", "WE", "RCLK", "RCLKE", "RE"): wt = "LOCAL" + elif name in ("PLLOUT_A", "PLLOUT_B"): + wt = "LOCAL" if wt is None: print("No type for wire: %s (%s)" % (longname, name), file=sys.stderr) @@ -591,6 +593,43 @@ def is_ec_output(ec_entry): if "glb_netwk_" in wirename: return True return False +def is_ec_pll_clock_output(ec, ec_entry): + return ec[0] == 'PLL' and ec_entry[0] in ('PLLOUT_A', 'PLLOUT_B') + +def add_pll_clock_output(bel, ec, ec_entry): + #print('add_pll_clock_output', ec, ec_entry) + pll_x, pll_y, pll_z = ec[1], ec[2], ec[3] + port = ec_entry[0] + io_x, io_y, io_z = ec_entry[1] + io_z = int(io_z) + + global num_wires + wire_idx = num_wires + num_wires = num_wires + 1 + + wire_xy[wire_idx] = [(pll_x, pll_y)] + + wire_names_r[wire_idx] = (pll_x, pll_y, port) + wire_names[(pll_x, pll_y, port)] = wire_idx + wire_segments[wire_idx] = { + (pll_x, pll_y): port, + (io_x, io_y): 'PLLIN', + } + + wire_downhill_belports[wire_idx] = {(bel, port),} + bel_wires[bel].append((wire_idx, port)) + + io_wire = wire_names[(io_x, io_y, 'io_{}/D_IN_0'.format(io_z))] + wire_downhill[wire_idx] = {io_wire,} + if io_wire not in wire_uphill: + wire_uphill[io_wire] = set() + wire_uphill[io_wire].add(wire_idx) + + switches.append((io_x, io_y, 0, [])) + switchnum = len(switches) - 1 + pip_xy[(wire_idx, io_wire)] = (io_x, io_y, 0, switchnum) + + def add_bel_ec(ec): ectype, x, y, z = ec bel = len(bel_name) @@ -605,6 +644,8 @@ def add_bel_ec(ec): add_bel_output(bel, wire_names[entry[1]], entry[0]) else: add_bel_input(bel, wire_names[entry[1]], entry[0]) + elif is_ec_pll_clock_output(ec, entry): + add_pll_clock_output(bel, ec, entry) else: extra_cell_config[bel].append(entry) diff --git a/ice40/gfx.h b/ice40/gfx.h index 8a55407d..7eeaccf1 100644 --- a/ice40/gfx.h +++ b/ice40/gfx.h @@ -464,7 +464,11 @@ enum GfxTileWireId TILE_WIRE_SP12_H_R_23, TILE_WIRE_SP12_H_L_22, - TILE_WIRE_SP12_H_L_23 + TILE_WIRE_SP12_H_L_23, + + TILE_WIRE_PLLIN, + TILE_WIRE_PLLOUT_A, + TILE_WIRE_PLLOUT_B }; void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id, GraphicElement::style_t style); diff --git a/ice40/pack.cc b/ice40/pack.cc index 7e2e389c..f63e14f6 100644 --- a/ice40/pack.cc +++ b/ice40/pack.cc @@ -591,6 +591,38 @@ 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_pll40(ctx, ci)) { + std::unique_ptr packed = + create_ice_cell(ctx, ctx->id("ICESTORM_PLL"), ci->name.str(ctx) + "_PLL"); + 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)); + + 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"; + replace_port(ci, ctx->id(pi.name.c_str(ctx)), packed.get(), ctx->id(newname)); + } + new_cells.push_back(std::move(packed)); } } diff --git a/ice40/pcf.cc b/ice40/pcf.cc index ac1c8598..3d0d0d84 100644 --- a/ice40/pcf.cc +++ b/ice40/pcf.cc @@ -62,6 +62,31 @@ bool apply_pcf(Context *ctx, std::istream &in) log_info("constrained '%s' to bel '%s'\n", cell.c_str(), fnd_cell->second->attrs[ctx->id("BEL")].c_str()); } + } else if (cmd == "set_loc") { + size_t args_end = 1; + while (args_end < words.size() && words.at(args_end).at(0) == '-') + args_end++; + std::string cell = words.at(args_end); + std::string x = words.at(args_end + 1); + std::string y = words.at(args_end + 2); + std::string z = words.at(args_end + 3); + auto fnd_cell = ctx->cells.find(ctx->id(cell)); + if (fnd_cell == ctx->cells.end()) { + log_error("unmatched pcf constraint %s\n", cell.c_str()); + } + + Loc loc; + loc.x = std::stoi(x); + loc.y = std::stoi(y); + loc.z = std::stoi(z); + auto bel = ctx->getBelByLocation(loc); + if (bel == BelId()) { + log_error("constrain '%s': unknown bel\n", line.c_str()); + } + + fnd_cell->second->attrs[ctx->id("BEL")] = ctx->getBelName(bel).str(ctx); + log_info("constrained '%s' to bel '%s'\n", cell.c_str(), ctx->getBelName(bel).c_str(ctx)); + } else { log_error("unsupported pcf command '%s'\n", cmd.c_str()); } diff --git a/ice40/portpins.inc b/ice40/portpins.inc index d78625d1..f9dac887 100644 --- a/ice40/portpins.inc +++ b/ice40/portpins.inc @@ -118,6 +118,8 @@ X(DYNAMICDELAY_5) X(DYNAMICDELAY_6) X(DYNAMICDELAY_7) X(LOCK) +X(PLLOUT_A) +X(PLLOUT_B) X(BYPASS) X(RESETB) X(LATCHINPUTVALUE) -- cgit v1.2.3 From db31c0625bb722dd9c42fead97d3988659656648 Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Mon, 23 Jul 2018 16:58:11 +0100 Subject: ice40: Fail early on SB_PLL40_*_PAD cells --- ice40/cells.h | 7 +++++++ ice40/pack.cc | 7 +++++++ 2 files changed, 14 insertions(+) (limited to 'ice40') diff --git a/ice40/cells.h b/ice40/cells.h index 404f401c..4bc50e8a 100644 --- a/ice40/cells.h +++ b/ice40/cells.h @@ -78,6 +78,13 @@ inline bool is_sb_pll40(const BaseCtx *ctx, const CellInfo *cell) cell->type == ctx->id("SB_PLL40_2F_CORE"); } +inline bool is_sb_pll40_pad(const BaseCtx *ctx, const CellInfo *cell) +{ + return cell->type == ctx->id("SB_PLL40_PAD") || cell->type == ctx->id("SB_PLL40_2_PAD") || + cell->type == ctx->id("SB_PLL40_2F_PAD"); +} + + uint8_t sb_pll40_type(const BaseCtx *ctx, const CellInfo *cell); // Convert a SB_LUT primitive to (part of) an ICESTORM_LC, swapping ports diff --git a/ice40/pack.cc b/ice40/pack.cc index f63e14f6..c4d47bf4 100644 --- a/ice40/pack.cc +++ b/ice40/pack.cc @@ -595,6 +595,13 @@ static void pack_special(Context *ctx) std::unique_ptr packed = create_ice_cell(ctx, ctx->id("ICESTORM_PLL"), ci->name.str(ctx) + "_PLL"); packed_cells.insert(ci->name); + + if (is_sb_pll40_pad(ctx, ci)) { + // TODO(q3k): Implement these after checking their behaviour on + // a board with exposed 'clock pads'. + log_error("SB_PLL40_*_PAD cells are not supported yet.\n"); + } + for (auto attr : ci->attrs) packed->attrs[attr.first] = attr.second; for (auto param : ci->params) -- cgit v1.2.3 From 69233385f875d01a36e36924d3099175e7544b4e Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Mon, 23 Jul 2018 21:49:02 +0100 Subject: ice40: Emit feed-through LUTs for PLL/LOCK --- ice40/chipdb.py | 2 +- ice40/pack.cc | 159 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 159 insertions(+), 2 deletions(-) (limited to 'ice40') diff --git a/ice40/chipdb.py b/ice40/chipdb.py index 63f08e36..602477a0 100644 --- a/ice40/chipdb.py +++ b/ice40/chipdb.py @@ -617,7 +617,7 @@ def add_pll_clock_output(bel, ec, ec_entry): } wire_downhill_belports[wire_idx] = {(bel, port),} - bel_wires[bel].append((wire_idx, port)) + bel_wires[bel].append((wire_idx, port, beltypes['PLL'])) io_wire = wire_names[(io_x, io_y, 'io_{}/D_IN_0'.format(io_z))] wire_downhill[wire_idx] = {io_wire,} diff --git a/ice40/pack.cc b/ice40/pack.cc index c4d47bf4..6e56c49b 100644 --- a/ice40/pack.cc +++ b/ice40/pack.cc @@ -613,7 +613,7 @@ static void pack_special(Context *ctx) 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)); - + for (auto port : ci->ports) { PortInfo &pi = port.second; std::string newname = pi.name.str(ctx); @@ -629,6 +629,162 @@ static void pack_special(Context *ctx) newname = "PLLOUT_A"; 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()) { + //FIXME replace by getBelsByType when implemented + for (auto bel : ctx->getBels()) { + if (ctx->getBelType(bel) != TYPE_ICESTORM_PLL) + continue; + 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)); + } + } + + // 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("ICESTORM_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)); + // Create pass-through LUT. + std::unique_ptr pt = + create_ice_cell(ctx, ctx->id("ICESTORM_LC"), ci->name.str(ctx) + "$nextpnr_ice40_pack_pll_lc"); + packed_cells.insert(pt->name); + pt->params[ctx->id("LUT_INIT")] = "255"; // all lower bits lit, so output is always I3 + + // Create net to which all non-LUTs will be moved. + std::unique_ptr out_net = std::unique_ptr(new NetInfo); + out_net->name = ctx->id(ci->name.str(ctx) + "$nextnr_ice40_pack_pll_net"); + out_net->driver.cell = pt.get(); + out_net->driver.port = ctx->id("O"); + pt->ports.at(ctx->id("O")).net = out_net.get(); + + // Move all non-LUTs to new net. + std::vector new_users; + for (const auto &user : port.net->users) { + if (user.cell->type == ctx->id("ICESTORM_LC")) { + new_users.push_back(user); + } + // Rewrite pointer into net in user. + user.cell->ports[user.port].net = out_net.get(); + // Add user to net. + PortRef pr; + pr.cell = user.cell; + pr.port = user.port; + out_net->users.push_back(pr); + } + // Add LUT to new users. + PortRef pr; + pr.cell = pt.get(); + pr.port = ctx->id("I3"); + new_users.push_back(pr); + pt->ports.at(ctx->id("I3")).net = port.net; + + // Replace users of the original net. + port.net->users = new_users; + + ctx->nets[out_net->name] = std::move(out_net); + 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)); + // Create pass-through LUT. + std::unique_ptr pt = + create_ice_cell(ctx, ctx->id("ICESTORM_LC"), ci->name.str(ctx) + "$nextpnr_ice40_pack_pll_lc"); + packed_cells.insert(pt->name); + pt->params[ctx->id("LUT_INIT")] = "255"; // all lower bits lit, so output is always I3 + + // Create net to which all current users will be moved. + std::unique_ptr out_net = std::unique_ptr(new NetInfo); + out_net->name = ctx->id(ci->name.str(ctx) + "$nextnr_ice40_pack_pll_net"); + out_net->driver.cell = pt.get(); + out_net->driver.port = ctx->id("O"); + pt->ports.at(ctx->id("O")).net = out_net.get(); + + // Move all users to new net. + for (const auto &user : port.net->users) { + // Rewrite pointer into net in user. + user.cell->ports[user.port].net = out_net.get(); + // Add user to net. + PortRef pr; + pr.cell = user.cell; + pr.port = user.port; + out_net->users.push_back(pr); + } + + // Add LUT to new users. + std::vector new_users; + PortRef pr; + pr.cell = pt.get(); + pr.port = ctx->id("I3"); + new_users.push_back(pr); + pt->ports.at(ctx->id("I3")).net = port.net; + + // Replace users of the original net. + port.net->users = new_users; + + ctx->nets[out_net->name] = std::move(out_net); + new_cells.push_back(std::move(pt)); + } + + // Find wire driven by this port. + const auto &pll_beli = ctx->chip_info->bel_data[pll_bel.index]; + const WireInfoPOD *wirei = nullptr; + for (int i = 0; i < pll_beli.num_bel_wires; i++) { + auto bel_port = ctx->portPinToId(pll_beli.bel_wires[i].port); + if (port.name != bel_port) + continue; + wirei = &ctx->chip_info->wire_data[pll_beli.bel_wires[i].wire_index]; + break; + } + NPNR_ASSERT(wirei != nullptr); + + // Now, constrain all LUTs on the output of the signal to be at + // the correct Bel relative to the PLL Bel. + int x = wirei->x; + int y = wirei->y; + int z = 0; + for (const auto &user : port.net->users) { + NPNR_ASSERT(user.cell != nullptr); + NPNR_ASSERT(user.cell->type == ctx->id("ICESTORM_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)); } } @@ -649,6 +805,7 @@ bool Arch::pack() log_break(); pack_constants(ctx); promote_globals(ctx); + pack_io(ctx); pack_lut_lutffs(ctx); pack_nonlut_ffs(ctx); -- cgit v1.2.3 From e6c7b1446580c92e9581593c78dd21753b409606 Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Mon, 23 Jul 2018 22:13:10 +0100 Subject: ice40: Refactor PLL/LOCK LUT splicing out into Arch:: --- ice40/arch.cc | 50 +++++++++++++++++++++++++++++++++++ ice40/arch.h | 5 ++++ ice40/bitstream.cc | 1 + ice40/pack.cc | 77 +++--------------------------------------------------- 4 files changed, 59 insertions(+), 74 deletions(-) (limited to 'ice40') diff --git a/ice40/arch.cc b/ice40/arch.cc index d6ef800d..6679217a 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -2,6 +2,7 @@ * nextpnr -- Next Generation Place and Route * * Copyright (C) 2018 Clifford Wolf + * Copyright (C) 2018 Serge Bazanski * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -805,4 +806,53 @@ void Arch::assignCellInfo(CellInfo *cell) } } +std::unique_ptr Arch::spliceLUT(CellInfo *ci, IdString portId, bool onlyNonLUTs) +{ + auto port = ci->ports[portId]; + + NPNR_ASSERT(port.net != nullptr); + + + // Create pass-through LUT. + std::unique_ptr pt = + create_ice_cell(getCtx(), id("ICESTORM_LC"), ci->name.str(this) + "$nextpnr_ice40_pack_pll_lc"); + pt->params[id("LUT_INIT")] = "255"; // output is always I3 + + // Create LUT output net. + std::unique_ptr out_net = std::unique_ptr(new NetInfo); + out_net->name = id(ci->name.str(this) + "$nextnr_ice40_pack_pll_net"); + out_net->driver.cell = pt.get(); + out_net->driver.port = id("O"); + pt->ports.at(id("O")).net = out_net.get(); + + // New users of the original cell's port + std::vector new_users; + for (const auto &user : port.net->users) { + if (onlyNonLUTs && user.cell->type == id("ICESTORM_LC")) { + new_users.push_back(user); + continue; + } + // Rewrite pointer into net in user. + user.cell->ports[user.port].net = out_net.get(); + // Add user to net. + PortRef pr; + pr.cell = user.cell; + pr.port = user.port; + out_net->users.push_back(pr); + } + + // Add LUT to new users. + PortRef pr; + pr.cell = pt.get(); + pr.port = id("I3"); + new_users.push_back(pr); + pt->ports.at(id("I3")).net = port.net; + + // Replace users of the original net. + port.net->users = new_users; + + nets[out_net->name] = std::move(out_net); + return pt; +} + NEXTPNR_NAMESPACE_END diff --git a/ice40/arch.h b/ice40/arch.h index d4d71cfc..15422aa7 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -746,6 +746,11 @@ struct Arch : BaseCtx IdString id_cen, id_clk, id_sr; IdString id_i0, id_i1, id_i2, id_i3; IdString id_dff_en, id_neg_clk; + + + // ------------------------------------------------- + // Insert a LUT/LC in between a given output port of a cell and all its' users. + std::unique_ptr spliceLUT(CellInfo *ci, IdString portId, bool onlyNonLUTs); }; NEXTPNR_NAMESPACE_END diff --git a/ice40/bitstream.cc b/ice40/bitstream.cc index 77d92a89..2ee8a294 100644 --- a/ice40/bitstream.cc +++ b/ice40/bitstream.cc @@ -3,6 +3,7 @@ * * Copyright (C) 2018 Clifford Wolf * Copyright (C) 2018 David Shah + * Copyright (C) 2018 Serge Bazanski * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/ice40/pack.cc b/ice40/pack.cc index 6e56c49b..dc0db578 100644 --- a/ice40/pack.cc +++ b/ice40/pack.cc @@ -3,6 +3,7 @@ * * Copyright (C) 2018 Clifford Wolf * Copyright (C) 2018 David Shah + * Copyright (C) 2018 Serge Bazanski * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -673,84 +674,12 @@ static void pack_special(Context *ctx) } 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)); - // Create pass-through LUT. - std::unique_ptr pt = - create_ice_cell(ctx, ctx->id("ICESTORM_LC"), ci->name.str(ctx) + "$nextpnr_ice40_pack_pll_lc"); - packed_cells.insert(pt->name); - pt->params[ctx->id("LUT_INIT")] = "255"; // all lower bits lit, so output is always I3 - - // Create net to which all non-LUTs will be moved. - std::unique_ptr out_net = std::unique_ptr(new NetInfo); - out_net->name = ctx->id(ci->name.str(ctx) + "$nextnr_ice40_pack_pll_net"); - out_net->driver.cell = pt.get(); - out_net->driver.port = ctx->id("O"); - pt->ports.at(ctx->id("O")).net = out_net.get(); - - // Move all non-LUTs to new net. - std::vector new_users; - for (const auto &user : port.net->users) { - if (user.cell->type == ctx->id("ICESTORM_LC")) { - new_users.push_back(user); - } - // Rewrite pointer into net in user. - user.cell->ports[user.port].net = out_net.get(); - // Add user to net. - PortRef pr; - pr.cell = user.cell; - pr.port = user.port; - out_net->users.push_back(pr); - } - // Add LUT to new users. - PortRef pr; - pr.cell = pt.get(); - pr.port = ctx->id("I3"); - new_users.push_back(pr); - pt->ports.at(ctx->id("I3")).net = port.net; - - // Replace users of the original net. - port.net->users = new_users; - - ctx->nets[out_net->name] = std::move(out_net); + auto pt = ctx->spliceLUT(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)); - // Create pass-through LUT. - std::unique_ptr pt = - create_ice_cell(ctx, ctx->id("ICESTORM_LC"), ci->name.str(ctx) + "$nextpnr_ice40_pack_pll_lc"); - packed_cells.insert(pt->name); - pt->params[ctx->id("LUT_INIT")] = "255"; // all lower bits lit, so output is always I3 - - // Create net to which all current users will be moved. - std::unique_ptr out_net = std::unique_ptr(new NetInfo); - out_net->name = ctx->id(ci->name.str(ctx) + "$nextnr_ice40_pack_pll_net"); - out_net->driver.cell = pt.get(); - out_net->driver.port = ctx->id("O"); - pt->ports.at(ctx->id("O")).net = out_net.get(); - - // Move all users to new net. - for (const auto &user : port.net->users) { - // Rewrite pointer into net in user. - user.cell->ports[user.port].net = out_net.get(); - // Add user to net. - PortRef pr; - pr.cell = user.cell; - pr.port = user.port; - out_net->users.push_back(pr); - } - - // Add LUT to new users. - std::vector new_users; - PortRef pr; - pr.cell = pt.get(); - pr.port = ctx->id("I3"); - new_users.push_back(pr); - pt->ports.at(ctx->id("I3")).net = port.net; - - // Replace users of the original net. - port.net->users = new_users; - - ctx->nets[out_net->name] = std::move(out_net); + auto pt = ctx->spliceLUT(packed.get(), port.name, false); new_cells.push_back(std::move(pt)); } -- cgit v1.2.3 From 1d3147e26a2d57085199b645c12df5ab4836850e Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Tue, 24 Jul 2018 01:18:49 +0100 Subject: ice40: Prevent placement of SB_IOs in IO blocks used by PLL outputs --- ice40/arch_place.cc | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'ice40') diff --git a/ice40/arch_place.cc b/ice40/arch_place.cc index cf1276a7..9c76851b 100644 --- a/ice40/arch_place.cc +++ b/ice40/arch_place.cc @@ -106,6 +106,30 @@ bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const bel_cells.push_back(cell); return logicCellsCompatible(bel_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. + for (auto iter_bel : getBels()) { + if (getBelType(iter_bel) != TYPE_ICESTORM_PLL) + continue; + if (checkBelAvail(iter_bel)) + continue; + + auto bel_cell = cells.at(getBoundBelCell(iter_bel)).get(); + for (auto type : {id("PLLOUT_A"), id("PLLOUT_B")}) { + auto it = bel_cell->ports.find(type); + if (it == bel_cell->ports.end()) + continue; + if (it->second.net == nullptr) + continue; + auto wire = getBelPinWire(iter_bel, portPinFromId(type)); + for (auto pip : getPipsDownhill(wire)) { + auto driven_wire = getPipDstWire(pip); + auto io_bel = chip_info->wire_data[driven_wire.index].bel_uphill.bel_index; + if (io_bel == bel.index) { + return false; + } + } + } + } return getBelPackagePin(bel) != ""; } else if (cell->type == id_sb_gb) { NPNR_ASSERT(cell->ports.at(id_glb_buf_out).net != nullptr); -- cgit v1.2.3 From 065ea95eaba3e0d2389695a3bddde774e5251ee9 Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Tue, 24 Jul 2018 01:24:07 +0100 Subject: ice40: Move spliceLUT back to pack.cc --- ice40/arch.cc | 49 ------------------------------------------------- ice40/arch.h | 5 ----- ice40/pack.cc | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 53 insertions(+), 56 deletions(-) (limited to 'ice40') diff --git a/ice40/arch.cc b/ice40/arch.cc index 6679217a..5c632faa 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -806,53 +806,4 @@ void Arch::assignCellInfo(CellInfo *cell) } } -std::unique_ptr Arch::spliceLUT(CellInfo *ci, IdString portId, bool onlyNonLUTs) -{ - auto port = ci->ports[portId]; - - NPNR_ASSERT(port.net != nullptr); - - - // Create pass-through LUT. - std::unique_ptr pt = - create_ice_cell(getCtx(), id("ICESTORM_LC"), ci->name.str(this) + "$nextpnr_ice40_pack_pll_lc"); - pt->params[id("LUT_INIT")] = "255"; // output is always I3 - - // Create LUT output net. - std::unique_ptr out_net = std::unique_ptr(new NetInfo); - out_net->name = id(ci->name.str(this) + "$nextnr_ice40_pack_pll_net"); - out_net->driver.cell = pt.get(); - out_net->driver.port = id("O"); - pt->ports.at(id("O")).net = out_net.get(); - - // New users of the original cell's port - std::vector new_users; - for (const auto &user : port.net->users) { - if (onlyNonLUTs && user.cell->type == id("ICESTORM_LC")) { - new_users.push_back(user); - continue; - } - // Rewrite pointer into net in user. - user.cell->ports[user.port].net = out_net.get(); - // Add user to net. - PortRef pr; - pr.cell = user.cell; - pr.port = user.port; - out_net->users.push_back(pr); - } - - // Add LUT to new users. - PortRef pr; - pr.cell = pt.get(); - pr.port = id("I3"); - new_users.push_back(pr); - pt->ports.at(id("I3")).net = port.net; - - // Replace users of the original net. - port.net->users = new_users; - - nets[out_net->name] = std::move(out_net); - return pt; -} - NEXTPNR_NAMESPACE_END diff --git a/ice40/arch.h b/ice40/arch.h index 15422aa7..d4d71cfc 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -746,11 +746,6 @@ struct Arch : BaseCtx IdString id_cen, id_clk, id_sr; IdString id_i0, id_i1, id_i2, id_i3; IdString id_dff_en, id_neg_clk; - - - // ------------------------------------------------- - // Insert a LUT/LC in between a given output port of a cell and all its' users. - std::unique_ptr spliceLUT(CellInfo *ci, IdString portId, bool onlyNonLUTs); }; NEXTPNR_NAMESPACE_END diff --git a/ice40/pack.cc b/ice40/pack.cc index dc0db578..14abc1d0 100644 --- a/ice40/pack.cc +++ b/ice40/pack.cc @@ -537,6 +537,57 @@ static void promote_globals(Context *ctx) } } +// spliceLUT adds a pass-through LUT LC between the given cell's output port +// and either all users or only non_LUT users. +static std::unique_ptr spliceLUT(Context *ctx, CellInfo *ci, IdString portId, bool onlyNonLUTs) +{ + auto port = ci->ports[portId]; + + NPNR_ASSERT(port.net != nullptr); + + + // Create pass-through LUT. + std::unique_ptr pt = + create_ice_cell(ctx, ctx->id("ICESTORM_LC"), ci->name.str(ctx) + "$nextpnr_ice40_pack_pll_lc"); + pt->params[ctx->id("LUT_INIT")] = "255"; // output is always I3 + + // Create LUT output net. + std::unique_ptr out_net = std::unique_ptr(new NetInfo); + out_net->name = ctx->id(ci->name.str(ctx) + "$nextnr_ice40_pack_pll_net"); + out_net->driver.cell = pt.get(); + out_net->driver.port = ctx->id("O"); + pt->ports.at(ctx->id("O")).net = out_net.get(); + + // New users of the original cell's port + std::vector new_users; + for (const auto &user : port.net->users) { + if (onlyNonLUTs && user.cell->type == ctx->id("ICESTORM_LC")) { + new_users.push_back(user); + continue; + } + // Rewrite pointer into net in user. + user.cell->ports[user.port].net = out_net.get(); + // Add user to net. + PortRef pr; + pr.cell = user.cell; + pr.port = user.port; + out_net->users.push_back(pr); + } + + // Add LUT to new users. + PortRef pr; + pr.cell = pt.get(); + pr.port = ctx->id("I3"); + new_users.push_back(pr); + pt->ports.at(ctx->id("I3")).net = port.net; + + // Replace users of the original net. + port.net->users = new_users; + + ctx->nets[out_net->name] = std::move(out_net); + return pt; +} + // Pack special functions static void pack_special(Context *ctx) { @@ -674,12 +725,12 @@ static void pack_special(Context *ctx) } 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 = ctx->spliceLUT(packed.get(), port.name, true); + 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 = ctx->spliceLUT(packed.get(), port.name, false); + auto pt = spliceLUT(ctx, packed.get(), port.name, false); new_cells.push_back(std::move(pt)); } -- cgit v1.2.3 From dbf79d78bbae387817fc442cfda06b5b17c32c40 Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Tue, 24 Jul 2018 01:36:55 +0100 Subject: ice40: A slightly nicer way to do this. --- ice40/bitstream.cc | 77 ++++++++++++++++++++++-------------------------------- 1 file changed, 31 insertions(+), 46 deletions(-) (limited to 'ice40') diff --git a/ice40/bitstream.cc b/ice40/bitstream.cc index 2ee8a294..c388fe2b 100644 --- a/ice40/bitstream.cc +++ b/ice40/bitstream.cc @@ -444,55 +444,40 @@ void write_asc(const Context *ctx, std::ostream &out) if (port.second.net == nullptr) continue; - // Find SB_IO Bel in net that's driving a wire. That's the one - // we're routing the signal through. - // TODO(q3k): Is there a nicer way to do this? - bool found = false; - - // For every wire in the PLLOUT net... - for (auto wp : port.second.net->wires) { - // ... get its' uphill bel ... - auto bel = ctx->getBelPinUphill(wp.first).bel; - if (bel == BelId()) { - continue; - } - // ... and check if it's an SB_IO. - if (ctx->getBelType(bel) != TYPE_SB_IO) - continue; + // Get IO Bel that this PLL port goes through. + // We navigate one pip downhill to the next wire (there should + // be only one). Then, the bel that drives that wire should be + // the SB_IO that we're looking for. + auto wire = ctx->getBelPinWire(cell.second->bel, ctx->portPinFromId(port.second.name)); + auto pips = ctx->getPipsDownhill(wire).begin(); + auto driven_wire = ctx->getPipDstWire(*pips); + auto io_bel = ctx->chip_info->wire_data[driven_wire.index].bel_uphill.bel_index; + auto io_beli = ctx->chip_info->bel_data[io_bel]; + NPNR_ASSERT(io_beli.type == TYPE_SB_IO); + + // Check that this SB_IO is either unused or just used as an output. + auto io_loc = Loc(io_beli.x, io_beli.y, io_beli.z); + if (sb_io_used_by_user.count(io_loc)) { + log_error("SB_IO '%s' already in use, cannot route PLL through\n", + ctx->getBelName(bel).c_str(ctx)); + } + sb_io_used_by_pll.insert(Loc(io_beli.x, io_beli.y, io_beli.z)); - // Check that this SB_IO is either unused or just used as an output. - const BelInfoPOD &io_beli = ci.bel_data[bel.index]; - auto io_loc = Loc(io_beli.x, io_beli.y, io_beli.z); + // Get IE/REN config location (cf. http://www.clifford.at/icestorm/io_tile.html) + auto ieren = get_ieren(bi, io_beli.x, io_beli.y, io_beli.z); + int iex, iey, iez; + std::tie(iex, iey, iez) = ieren; + NPNR_ASSERT(iez != -1); - if (sb_io_used_by_user.count(io_loc)) { - log_error("SB_IO '%s' already in use, cannot route PLL through\n", - ctx->getBelName(bel).c_str(ctx)); - } - sb_io_used_by_pll.insert(Loc(io_beli.x, io_beli.y, io_beli.z)); - - // Get IE/REN config location (cf. http://www.clifford.at/icestorm/io_tile.html) - auto ieren = get_ieren(bi, io_beli.x, io_beli.y, io_beli.z); - int iex, iey, iez; - std::tie(iex, iey, iez) = ieren; - NPNR_ASSERT(iez != -1); - - // Write config. - const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_IO]; - // Enable input buffer and disable pull-up resistor in block - // (this is used by the PLL). - set_ie_bit_logical(ctx, ti, config.at(iey).at(iex), "IoCtrl.IE_" + std::to_string(iez), true); - set_ie_bit_logical(ctx, ti, config.at(iey).at(iex), "IoCtrl.REN_" + std::to_string(iez), false); - // PINTYPE[0] passes the PLL through to the fabric. - set_config(ti, config.at(io_beli.y).at(io_beli.x), "IOB_" + std::to_string(io_beli.z) + ".PINTYPE_0", true); - - found = true; - break; - } + // Write config. + const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_IO]; + // Enable input buffer and disable pull-up resistor in block + // (this is used by the PLL). + set_ie_bit_logical(ctx, ti, config.at(iey).at(iex), "IoCtrl.IE_" + std::to_string(iez), true); + set_ie_bit_logical(ctx, ti, config.at(iey).at(iex), "IoCtrl.REN_" + std::to_string(iez), false); + // PINTYPE[0] passes the PLL through to the fabric. + set_config(ti, config.at(io_beli.y).at(io_beli.x), "IOB_" + std::to_string(io_beli.z) + ".PINTYPE_0", true); - if (!found) { - log_error("Could not find SB_IO forwarding PLL '%s' %s signal\n", - cell.second->name.c_str(ctx), port.second.name.c_str(ctx)); - } } } else { -- cgit v1.2.3 From fae7994bc34b302dbd35c0793a9ce9f81234dbc1 Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Tue, 24 Jul 2018 01:38:20 +0100 Subject: clang-format --- ice40/bitstream.cc | 35 ++++++++++-------- ice40/cells.h | 1 - ice40/pack.cc | 104 +++++++++++++++++++++++++++-------------------------- 3 files changed, 74 insertions(+), 66 deletions(-) (limited to 'ice40') diff --git a/ice40/bitstream.cc b/ice40/bitstream.cc index c388fe2b..1d799307 100644 --- a/ice40/bitstream.cc +++ b/ice40/bitstream.cc @@ -88,7 +88,9 @@ void set_config(const TileInfoPOD &ti, std::vector> &tile_cf // Set an IE_{EN,REN} logical bit in a tile config. Logical means enabled. // On {HX,LP}1K devices these bits are active low, so we need to inver them. -void set_ie_bit_logical(const Context *ctx, const TileInfoPOD &ti, std::vector> &tile_cfg, const std::string &name, bool value) { +void set_ie_bit_logical(const Context *ctx, const TileInfoPOD &ti, std::vector> &tile_cfg, + const std::string &name, bool value) +{ if (ctx->args.type == ArchArgs::LP1K || ctx->args.type == ArchArgs::HX1K) { set_config(ti, tile_cfg, name, !value); } else { @@ -320,7 +322,7 @@ void write_asc(const Context *ctx, std::ostream &out) } else if (cell.second->type == ctx->id("SB_IO")) { const BelInfoPOD &beli = ci.bel_data[bel.index]; int x = beli.x, y = beli.y, z = beli.z; - sb_io_used_by_user.insert(Loc(x,y,z)); + sb_io_used_by_user.insert(Loc(x, y, z)); const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_IO]; unsigned pin_type = get_param_or_def(cell.second.get(), ctx->id("PIN_TYPE")); bool neg_trigger = get_param_or_def(cell.second.get(), ctx->id("NEG_TRIGGER")); @@ -424,14 +426,20 @@ void write_asc(const Context *ctx, std::ostream &out) {"B_SIGNED", 1}}; configure_extra_cell(config, ctx, cell.second.get(), mac16_params, false, std::string("IpConfig.")); } else if (cell.second->type == ctx->id("ICESTORM_PLL")) { - const std::vector> pll_params = { - {"DELAY_ADJMODE_FB", 1}, {"DELAY_ADJMODE_REL", 1}, - {"DIVF", 7}, {"DIVQ", 3}, {"DIVR", 4}, - {"FDA_FEEDBACK", 4}, {"FDA_RELATIVE", 4}, - {"FEEDBACK_PATH", 3}, {"FILTER_RANGE", 3}, - {"PLLOUT_SELECT_A", 2}, {"PLLOUT_SELECT_B", 2}, - {"PLLTYPE", 3}, {"SHIFTREG_DIV_MODE", 1}, {"TEST_MODE", 1} - }; + const std::vector> pll_params = {{"DELAY_ADJMODE_FB", 1}, + {"DELAY_ADJMODE_REL", 1}, + {"DIVF", 7}, + {"DIVQ", 3}, + {"DIVR", 4}, + {"FDA_FEEDBACK", 4}, + {"FDA_RELATIVE", 4}, + {"FEEDBACK_PATH", 3}, + {"FILTER_RANGE", 3}, + {"PLLOUT_SELECT_A", 2}, + {"PLLOUT_SELECT_B", 2}, + {"PLLTYPE", 3}, + {"SHIFTREG_DIV_MODE", 1}, + {"TEST_MODE", 1}}; configure_extra_cell(config, ctx, cell.second.get(), pll_params, false, std::string("PLL.")); // Configure the SB_IOs that the clock outputs are going through. @@ -458,8 +466,7 @@ void write_asc(const Context *ctx, std::ostream &out) // Check that this SB_IO is either unused or just used as an output. auto io_loc = Loc(io_beli.x, io_beli.y, io_beli.z); if (sb_io_used_by_user.count(io_loc)) { - log_error("SB_IO '%s' already in use, cannot route PLL through\n", - ctx->getBelName(bel).c_str(ctx)); + log_error("SB_IO '%s' already in use, cannot route PLL through\n", ctx->getBelName(bel).c_str(ctx)); } sb_io_used_by_pll.insert(Loc(io_beli.x, io_beli.y, io_beli.z)); @@ -476,8 +483,8 @@ void write_asc(const Context *ctx, std::ostream &out) set_ie_bit_logical(ctx, ti, config.at(iey).at(iex), "IoCtrl.IE_" + std::to_string(iez), true); set_ie_bit_logical(ctx, ti, config.at(iey).at(iex), "IoCtrl.REN_" + std::to_string(iez), false); // PINTYPE[0] passes the PLL through to the fabric. - set_config(ti, config.at(io_beli.y).at(io_beli.x), "IOB_" + std::to_string(io_beli.z) + ".PINTYPE_0", true); - + set_config(ti, config.at(io_beli.y).at(io_beli.x), "IOB_" + std::to_string(io_beli.z) + ".PINTYPE_0", + true); } } else { diff --git a/ice40/cells.h b/ice40/cells.h index 4bc50e8a..16135448 100644 --- a/ice40/cells.h +++ b/ice40/cells.h @@ -84,7 +84,6 @@ inline bool is_sb_pll40_pad(const BaseCtx *ctx, const CellInfo *cell) cell->type == ctx->id("SB_PLL40_2F_PAD"); } - uint8_t sb_pll40_type(const BaseCtx *ctx, const CellInfo *cell); // Convert a SB_LUT primitive to (part of) an ICESTORM_LC, swapping ports diff --git a/ice40/pack.cc b/ice40/pack.cc index 14abc1d0..8552e381 100644 --- a/ice40/pack.cc +++ b/ice40/pack.cc @@ -541,51 +541,50 @@ static void promote_globals(Context *ctx) // and either all users or only non_LUT users. static std::unique_ptr spliceLUT(Context *ctx, CellInfo *ci, IdString portId, bool onlyNonLUTs) { - auto port = ci->ports[portId]; - - NPNR_ASSERT(port.net != nullptr); - - - // Create pass-through LUT. - std::unique_ptr pt = - create_ice_cell(ctx, ctx->id("ICESTORM_LC"), ci->name.str(ctx) + "$nextpnr_ice40_pack_pll_lc"); - pt->params[ctx->id("LUT_INIT")] = "255"; // output is always I3 - - // Create LUT output net. - std::unique_ptr out_net = std::unique_ptr(new NetInfo); - out_net->name = ctx->id(ci->name.str(ctx) + "$nextnr_ice40_pack_pll_net"); - out_net->driver.cell = pt.get(); - out_net->driver.port = ctx->id("O"); - pt->ports.at(ctx->id("O")).net = out_net.get(); - - // New users of the original cell's port - std::vector new_users; - for (const auto &user : port.net->users) { - if (onlyNonLUTs && user.cell->type == ctx->id("ICESTORM_LC")) { - new_users.push_back(user); - continue; - } - // Rewrite pointer into net in user. - user.cell->ports[user.port].net = out_net.get(); - // Add user to net. - PortRef pr; - pr.cell = user.cell; - pr.port = user.port; - out_net->users.push_back(pr); - } - - // Add LUT to new users. - PortRef pr; - pr.cell = pt.get(); - pr.port = ctx->id("I3"); - new_users.push_back(pr); - pt->ports.at(ctx->id("I3")).net = port.net; - - // Replace users of the original net. - port.net->users = new_users; - - ctx->nets[out_net->name] = std::move(out_net); - return pt; + auto port = ci->ports[portId]; + + NPNR_ASSERT(port.net != nullptr); + + // Create pass-through LUT. + std::unique_ptr pt = + create_ice_cell(ctx, ctx->id("ICESTORM_LC"), ci->name.str(ctx) + "$nextpnr_ice40_pack_pll_lc"); + pt->params[ctx->id("LUT_INIT")] = "255"; // output is always I3 + + // Create LUT output net. + std::unique_ptr out_net = std::unique_ptr(new NetInfo); + out_net->name = ctx->id(ci->name.str(ctx) + "$nextnr_ice40_pack_pll_net"); + out_net->driver.cell = pt.get(); + out_net->driver.port = ctx->id("O"); + pt->ports.at(ctx->id("O")).net = out_net.get(); + + // New users of the original cell's port + std::vector new_users; + for (const auto &user : port.net->users) { + if (onlyNonLUTs && user.cell->type == ctx->id("ICESTORM_LC")) { + new_users.push_back(user); + continue; + } + // Rewrite pointer into net in user. + user.cell->ports[user.port].net = out_net.get(); + // Add user to net. + PortRef pr; + pr.cell = user.cell; + pr.port = user.port; + out_net->users.push_back(pr); + } + + // Add LUT to new users. + PortRef pr; + pr.cell = pt.get(); + pr.port = ctx->id("I3"); + new_users.push_back(pr); + pt->ports.at(ctx->id("I3")).net = port.net; + + // Replace users of the original net. + port.net->users = new_users; + + ctx->nets[out_net->name] = std::move(out_net); + return pt; } // Pack special functions @@ -660,10 +659,13 @@ static void pack_special(Context *ctx) 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("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)); for (auto port : ci->ports) { @@ -687,7 +689,7 @@ static void pack_special(Context *ctx) BelId pll_bel; bool constrained = false; if (packed->attrs.find(ctx->id("BEL")) == packed->attrs.end()) { - //FIXME replace by getBelsByType when implemented + // FIXME replace by getBelsByType when implemented for (auto bel : ctx->getBels()) { if (ctx->getBelType(bel) != TYPE_ICESTORM_PLL) continue; @@ -759,7 +761,7 @@ static void pack_special(Context *ctx) // 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); + 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()); } -- cgit v1.2.3 From 65ceb20784ccd0e2be71c733dbc23dc61d83d653 Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Tue, 24 Jul 2018 02:05:30 +0100 Subject: ice40: emit list of upbels in chipdb --- ice40/arch.h | 4 ++-- ice40/arch_place.cc | 2 +- ice40/bitstream.cc | 2 +- ice40/chipdb.py | 30 ++++++++++++++++++------------ 4 files changed, 22 insertions(+), 16 deletions(-) (limited to 'ice40') diff --git a/ice40/arch.h b/ice40/arch.h index d4d71cfc..f0060d48 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -83,8 +83,8 @@ NPNR_PACKED_STRUCT(struct WireInfoPOD { int32_t num_uphill, num_downhill; RelPtr pips_uphill, pips_downhill; - int32_t num_bels_downhill; - BelPortPOD bel_uphill; + int32_t num_bels_uphill, num_bels_downhill; + RelPtr bels_uphill; RelPtr bels_downhill; int32_t num_bel_pins; diff --git a/ice40/arch_place.cc b/ice40/arch_place.cc index 9c76851b..95cebb48 100644 --- a/ice40/arch_place.cc +++ b/ice40/arch_place.cc @@ -123,7 +123,7 @@ bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const auto wire = getBelPinWire(iter_bel, portPinFromId(type)); for (auto pip : getPipsDownhill(wire)) { auto driven_wire = getPipDstWire(pip); - auto io_bel = chip_info->wire_data[driven_wire.index].bel_uphill.bel_index; + auto io_bel = chip_info->wire_data[driven_wire.index].bels_uphill[0].bel_index; if (io_bel == bel.index) { return false; } diff --git a/ice40/bitstream.cc b/ice40/bitstream.cc index 1d799307..934cca0c 100644 --- a/ice40/bitstream.cc +++ b/ice40/bitstream.cc @@ -459,7 +459,7 @@ void write_asc(const Context *ctx, std::ostream &out) auto wire = ctx->getBelPinWire(cell.second->bel, ctx->portPinFromId(port.second.name)); auto pips = ctx->getPipsDownhill(wire).begin(); auto driven_wire = ctx->getPipDstWire(*pips); - auto io_bel = ctx->chip_info->wire_data[driven_wire.index].bel_uphill.bel_index; + auto io_bel = ctx->chip_info->wire_data[driven_wire.index].bels_uphill[0].bel_index; auto io_beli = ctx->chip_info->bel_data[io_bel]; NPNR_ASSERT(io_beli.type == TYPE_SB_IO); diff --git a/ice40/chipdb.py b/ice40/chipdb.py index 602477a0..38989a0b 100644 --- a/ice40/chipdb.py +++ b/ice40/chipdb.py @@ -41,7 +41,7 @@ extra_cells = dict() extra_cell_config = dict() packages = list() -wire_uphill_belport = dict() +wire_uphill_belports = dict() wire_downhill_belports = dict() wire_belports = dict() @@ -462,8 +462,9 @@ def add_bel_input(bel, wire, port): bel_wires[bel].append((wire, port, 0)) def add_bel_output(bel, wire, port): - assert wire not in wire_uphill_belport - wire_uphill_belport[wire] = (bel, port) + if wire not in wire_uphill_belports: + wire_uphill_belports[wire] = set() + wire_uphill_belports[wire].add((bel, port)) if wire not in wire_belports: wire_belports[wire] = set() wire_belports[wire].add((bel, port)) @@ -1042,6 +1043,15 @@ for wire in range(num_wires): num_downhill = 0 list_downhill = None + if wire in wire_uphill_belports: + num_bels_uphill = len(wire_uphill_belports[wire]) + bba.l("wire%d_upbels" % wire, "BelPortPOD") + for belport in sorted(wire_uphill_belports[wire]): + bba.u32(belport[0], "bel_index") + bba.u32(portpins[belport[1]], "port") + else: + num_bels_uphill = 0 + if wire in wire_downhill_belports: num_bels_downhill = len(wire_downhill_belports[wire]) bba.l("wire%d_downbels" % wire, "BelPortPOD") @@ -1072,16 +1082,12 @@ for wire in range(num_wires): info["num_bels_downhill"] = num_bels_downhill info["list_bels_downhill"] = ("wire%d_downbels" % wire) if num_bels_downhill > 0 else None + info["num_bels_uphill"] = num_bels_uphill + info["list_bels_uphill"] = ("wire%d_upbels" % wire) if num_bels_uphill > 0 else None + info["num_bel_pins"] = num_bel_pins info["list_bel_pins"] = ("wire%d_bels" % wire) if num_bel_pins > 0 else None - if wire in wire_uphill_belport: - info["uphill_bel"] = wire_uphill_belport[wire][0] - info["uphill_pin"] = portpins[wire_uphill_belport[wire][1]] - else: - info["uphill_bel"] = -1 - info["uphill_pin"] = 0 - avg_x, avg_y = 0, 0 if wire in wire_xy: for x, y in wire_xy[wire]: @@ -1156,9 +1162,9 @@ for wire, info in enumerate(wireinfo): bba.u32(info["num_downhill"], "num_downhill") bba.r(info["list_uphill"], "pips_uphill") bba.r(info["list_downhill"], "pips_downhill") + bba.u32(info["num_bels_uphill"], "num_bels_uphill") bba.u32(info["num_bels_downhill"], "num_bels_downhill") - bba.u32(info["uphill_bel"], "bel_uphill.bel_index") - bba.u32(info["uphill_pin"], "bel_uphill.port") + bba.r(info["list_bels_uphill"], "bels_uphill") bba.r(info["list_bels_downhill"], "bels_downhill") bba.u32(info["num_bel_pins"], "num_bel_pins") bba.r(info["list_bel_pins"], "bel_pins") -- cgit v1.2.3 From eaae1d299c030be85aa9eb3a45ce2c02afe919f1 Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Tue, 24 Jul 2018 02:35:16 +0100 Subject: ice40: move PLL->IO from pseudo pip to second uphill bel --- ice40/arch_place.cc | 40 +++++++++++++++++++++------------------- ice40/bitstream.cc | 31 ++++++++++++++++--------------- ice40/chipdb.py | 38 +++----------------------------------- 3 files changed, 40 insertions(+), 69 deletions(-) (limited to 'ice40') diff --git a/ice40/arch_place.cc b/ice40/arch_place.cc index 95cebb48..00c960b6 100644 --- a/ice40/arch_place.cc +++ b/ice40/arch_place.cc @@ -107,26 +107,28 @@ bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const return logicCellsCompatible(bel_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. - for (auto iter_bel : getBels()) { - if (getBelType(iter_bel) != TYPE_ICESTORM_PLL) - continue; - if (checkBelAvail(iter_bel)) - continue; - auto bel_cell = cells.at(getBoundBelCell(iter_bel)).get(); - for (auto type : {id("PLLOUT_A"), id("PLLOUT_B")}) { - auto it = bel_cell->ports.find(type); - if (it == bel_cell->ports.end()) - continue; - if (it->second.net == nullptr) - continue; - auto wire = getBelPinWire(iter_bel, portPinFromId(type)); - for (auto pip : getPipsDownhill(wire)) { - auto driven_wire = getPipDstWire(pip); - auto io_bel = chip_info->wire_data[driven_wire.index].bels_uphill[0].bel_index; - if (io_bel == bel.index) { - return false; - } + // Find shared PLL by looking for driving bel siblings from D_IN_0 + // that are a PLL clock output. + auto wire = getBelPinWire(bel, PIN_D_IN_0); + PortPin pll_bel_pin; + BelId pll_bel; + for (auto pin : getWireBelPins(wire)) { + if (pin.pin == PIN_PLLOUT_A || pin.pin == PIN_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) { + // Is a PLL placed in this PLL bel? + if (!checkBelAvail(pll_bel)) { + // Is the shared port driving a net? + auto pll_cell = getBoundBelCell(pll_bel); + auto pi = cells.at(pll_cell)->ports[portPinToId(pll_bel_pin)]; + if (pi.net != nullptr) { + return false; } } } diff --git a/ice40/bitstream.cc b/ice40/bitstream.cc index 934cca0c..7c3a26ca 100644 --- a/ice40/bitstream.cc +++ b/ice40/bitstream.cc @@ -452,26 +452,27 @@ void write_asc(const Context *ctx, std::ostream &out) if (port.second.net == nullptr) continue; - // Get IO Bel that this PLL port goes through. - // We navigate one pip downhill to the next wire (there should - // be only one). Then, the bel that drives that wire should be - // the SB_IO that we're looking for. + // Get IO Bel that this PLL port goes through by finding sibling + // Bel driving the same wire via PIN_D_IN_0. auto wire = ctx->getBelPinWire(cell.second->bel, ctx->portPinFromId(port.second.name)); - auto pips = ctx->getPipsDownhill(wire).begin(); - auto driven_wire = ctx->getPipDstWire(*pips); - auto io_bel = ctx->chip_info->wire_data[driven_wire.index].bels_uphill[0].bel_index; - auto io_beli = ctx->chip_info->bel_data[io_bel]; - NPNR_ASSERT(io_beli.type == TYPE_SB_IO); + BelId io_bel; + for (auto pin : ctx->getWireBelPins(wire)) { + if (pin.pin == PIN_D_IN_0) { + io_bel = pin.bel; + break; + } + } + NPNR_ASSERT(io_bel.index != -1); + auto io_bel_loc = ctx->getBelLocation(io_bel); // Check that this SB_IO is either unused or just used as an output. - auto io_loc = Loc(io_beli.x, io_beli.y, io_beli.z); - if (sb_io_used_by_user.count(io_loc)) { + if (sb_io_used_by_user.count(io_bel_loc)) { log_error("SB_IO '%s' already in use, cannot route PLL through\n", ctx->getBelName(bel).c_str(ctx)); } - sb_io_used_by_pll.insert(Loc(io_beli.x, io_beli.y, io_beli.z)); + sb_io_used_by_pll.insert(io_bel_loc); // Get IE/REN config location (cf. http://www.clifford.at/icestorm/io_tile.html) - auto ieren = get_ieren(bi, io_beli.x, io_beli.y, io_beli.z); + auto ieren = get_ieren(bi, io_bel_loc.x, io_bel_loc.y, io_bel_loc.z); int iex, iey, iez; std::tie(iex, iey, iez) = ieren; NPNR_ASSERT(iez != -1); @@ -483,8 +484,8 @@ void write_asc(const Context *ctx, std::ostream &out) set_ie_bit_logical(ctx, ti, config.at(iey).at(iex), "IoCtrl.IE_" + std::to_string(iez), true); set_ie_bit_logical(ctx, ti, config.at(iey).at(iex), "IoCtrl.REN_" + std::to_string(iez), false); // PINTYPE[0] passes the PLL through to the fabric. - set_config(ti, config.at(io_beli.y).at(io_beli.x), "IOB_" + std::to_string(io_beli.z) + ".PINTYPE_0", - true); + set_config(ti, config.at(io_bel_loc.y).at(io_bel_loc.x), + "IOB_" + std::to_string(io_bel_loc.z) + ".PINTYPE_0", true); } } else { diff --git a/ice40/chipdb.py b/ice40/chipdb.py index 38989a0b..63d90b45 100644 --- a/ice40/chipdb.py +++ b/ice40/chipdb.py @@ -597,40 +597,6 @@ def is_ec_output(ec_entry): def is_ec_pll_clock_output(ec, ec_entry): return ec[0] == 'PLL' and ec_entry[0] in ('PLLOUT_A', 'PLLOUT_B') -def add_pll_clock_output(bel, ec, ec_entry): - #print('add_pll_clock_output', ec, ec_entry) - pll_x, pll_y, pll_z = ec[1], ec[2], ec[3] - port = ec_entry[0] - io_x, io_y, io_z = ec_entry[1] - io_z = int(io_z) - - global num_wires - wire_idx = num_wires - num_wires = num_wires + 1 - - wire_xy[wire_idx] = [(pll_x, pll_y)] - - wire_names_r[wire_idx] = (pll_x, pll_y, port) - wire_names[(pll_x, pll_y, port)] = wire_idx - wire_segments[wire_idx] = { - (pll_x, pll_y): port, - (io_x, io_y): 'PLLIN', - } - - wire_downhill_belports[wire_idx] = {(bel, port),} - bel_wires[bel].append((wire_idx, port, beltypes['PLL'])) - - io_wire = wire_names[(io_x, io_y, 'io_{}/D_IN_0'.format(io_z))] - wire_downhill[wire_idx] = {io_wire,} - if io_wire not in wire_uphill: - wire_uphill[io_wire] = set() - wire_uphill[io_wire].add(wire_idx) - - switches.append((io_x, io_y, 0, [])) - switchnum = len(switches) - 1 - pip_xy[(wire_idx, io_wire)] = (io_x, io_y, 0, switchnum) - - def add_bel_ec(ec): ectype, x, y, z = ec bel = len(bel_name) @@ -646,7 +612,9 @@ def add_bel_ec(ec): else: add_bel_input(bel, wire_names[entry[1]], entry[0]) elif is_ec_pll_clock_output(ec, entry): - add_pll_clock_output(bel, ec, entry) + x, y, z = entry[1] + z = 'io_{}/D_IN_0'.format(z) + add_bel_output(bel, wire_names[(x, y, z)], entry[0]) else: extra_cell_config[bel].append(entry) -- cgit v1.2.3 From 90ba958abe85ced03f16888644dd026b133cab36 Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Tue, 24 Jul 2018 03:03:31 +0100 Subject: ice40: fixes before review --- ice40/arch_place.cc | 1 + ice40/bitstream.cc | 12 ++++++------ ice40/cells.cc | 1 + ice40/pack.cc | 19 +++++-------------- ice40/pcf.cc | 25 ------------------------- 5 files changed, 13 insertions(+), 45 deletions(-) (limited to 'ice40') diff --git a/ice40/arch_place.cc b/ice40/arch_place.cc index 00c960b6..16cc757e 100644 --- a/ice40/arch_place.cc +++ b/ice40/arch_place.cc @@ -3,6 +3,7 @@ * * Copyright (C) 2018 Clifford Wolf * Copyright (C) 2018 David Shah + * Copyright (C) 2018 Serge Bazanski * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/ice40/bitstream.cc b/ice40/bitstream.cc index 7c3a26ca..e9851a83 100644 --- a/ice40/bitstream.cc +++ b/ice40/bitstream.cc @@ -87,7 +87,7 @@ void set_config(const TileInfoPOD &ti, std::vector> &tile_cf } // Set an IE_{EN,REN} logical bit in a tile config. Logical means enabled. -// On {HX,LP}1K devices these bits are active low, so we need to inver them. +// On {HX,LP}1K devices these bits are active low, so we need to invert them. void set_ie_bit_logical(const Context *ctx, const TileInfoPOD &ti, std::vector> &tile_cfg, const std::string &name, bool value) { @@ -101,9 +101,9 @@ void set_ie_bit_logical(const Context *ctx, const TileInfoPOD &ti, std::vectorparams.find(param); - if (found != cell->params.end()) { + if (found != cell->params.end()) return std::stoi(found->second); - } else + else return defval; } @@ -273,7 +273,7 @@ void write_asc(const Context *ctx, std::ostream &out) } std::unordered_set sb_io_used_by_pll; - std::unordered_set sb_io_used_by_user; + std::unordered_set sb_io_used_by_io; // Set logic cell config for (auto &cell : ctx->cells) { @@ -322,7 +322,7 @@ void write_asc(const Context *ctx, std::ostream &out) } else if (cell.second->type == ctx->id("SB_IO")) { const BelInfoPOD &beli = ci.bel_data[bel.index]; int x = beli.x, y = beli.y, z = beli.z; - sb_io_used_by_user.insert(Loc(x, y, z)); + sb_io_used_by_io.insert(Loc(x, y, z)); const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_IO]; unsigned pin_type = get_param_or_def(cell.second.get(), ctx->id("PIN_TYPE")); bool neg_trigger = get_param_or_def(cell.second.get(), ctx->id("NEG_TRIGGER")); @@ -466,7 +466,7 @@ void write_asc(const Context *ctx, std::ostream &out) auto io_bel_loc = ctx->getBelLocation(io_bel); // Check that this SB_IO is either unused or just used as an output. - if (sb_io_used_by_user.count(io_bel_loc)) { + if (sb_io_used_by_io.count(io_bel_loc)) { log_error("SB_IO '%s' already in use, cannot route PLL through\n", ctx->getBelName(bel).c_str(ctx)); } sb_io_used_by_pll.insert(io_bel_loc); diff --git a/ice40/cells.cc b/ice40/cells.cc index 3215a38c..610bf85e 100644 --- a/ice40/cells.cc +++ b/ice40/cells.cc @@ -3,6 +3,7 @@ * * Copyright (C) 2018 Clifford Wolf * Copyright (C) 2018 David Shah + * Copyright (C) 2018 Serge Bazanski * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/ice40/pack.cc b/ice40/pack.cc index 8552e381..03b33190 100644 --- a/ice40/pack.cc +++ b/ice40/pack.cc @@ -736,22 +736,14 @@ static void pack_special(Context *ctx) new_cells.push_back(std::move(pt)); } - // Find wire driven by this port. - const auto &pll_beli = ctx->chip_info->bel_data[pll_bel.index]; - const WireInfoPOD *wirei = nullptr; - for (int i = 0; i < pll_beli.num_bel_wires; i++) { - auto bel_port = ctx->portPinToId(pll_beli.bel_wires[i].port); - if (port.name != bel_port) - continue; - wirei = &ctx->chip_info->wire_data[pll_beli.bel_wires[i].wire_index]; - break; - } - NPNR_ASSERT(wirei != nullptr); + // Find wire that will be driven by this port. + const auto pll_out_wire = ctx->getBelPinWire(pll_bel, ctx->portPinFromId(port.name)); + NPNR_ASSERT(pll_out_wire.index != -1); // Now, constrain all LUTs on the output of the signal to be at // the correct Bel relative to the PLL Bel. - int x = wirei->x; - int y = wirei->y; + 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); @@ -787,7 +779,6 @@ bool Arch::pack() log_break(); pack_constants(ctx); promote_globals(ctx); - pack_io(ctx); pack_lut_lutffs(ctx); pack_nonlut_ffs(ctx); diff --git a/ice40/pcf.cc b/ice40/pcf.cc index 3d0d0d84..ac1c8598 100644 --- a/ice40/pcf.cc +++ b/ice40/pcf.cc @@ -62,31 +62,6 @@ bool apply_pcf(Context *ctx, std::istream &in) log_info("constrained '%s' to bel '%s'\n", cell.c_str(), fnd_cell->second->attrs[ctx->id("BEL")].c_str()); } - } else if (cmd == "set_loc") { - size_t args_end = 1; - while (args_end < words.size() && words.at(args_end).at(0) == '-') - args_end++; - std::string cell = words.at(args_end); - std::string x = words.at(args_end + 1); - std::string y = words.at(args_end + 2); - std::string z = words.at(args_end + 3); - auto fnd_cell = ctx->cells.find(ctx->id(cell)); - if (fnd_cell == ctx->cells.end()) { - log_error("unmatched pcf constraint %s\n", cell.c_str()); - } - - Loc loc; - loc.x = std::stoi(x); - loc.y = std::stoi(y); - loc.z = std::stoi(z); - auto bel = ctx->getBelByLocation(loc); - if (bel == BelId()) { - log_error("constrain '%s': unknown bel\n", line.c_str()); - } - - fnd_cell->second->attrs[ctx->id("BEL")] = ctx->getBelName(bel).str(ctx); - log_info("constrained '%s' to bel '%s'\n", cell.c_str(), ctx->getBelName(bel).c_str(ctx)); - } else { log_error("unsupported pcf command '%s'\n", cmd.c_str()); } -- cgit v1.2.3 From a09f95bb06025afecd5753c969443928f1f0894a Mon Sep 17 00:00:00 2001 From: David Shah Date: Tue, 24 Jul 2018 11:16:33 +0200 Subject: ice40: Fix SPRAM and other primitives in corners other than (0, 0) Signed-off-by: David Shah --- ice40/chipdb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ice40') diff --git a/ice40/chipdb.py b/ice40/chipdb.py index 0e8e3ba7..4dcddbed 100644 --- a/ice40/chipdb.py +++ b/ice40/chipdb.py @@ -662,7 +662,7 @@ for tile_xy, tile_type in sorted(tiles.items()): add_bel_ec(ec) for ec in sorted(extra_cells.keys()): - if ec[1] == 0 and ec[2] == 0: + if ec[1] in (0, dev_width - 1) and ec[2] in (0, dev_height - 1): add_bel_ec(ec) class BinaryBlobAssembler: -- cgit v1.2.3 From 4359197dfe49f981966222679d8270b0d4dc311d Mon Sep 17 00:00:00 2001 From: David Shah Date: Tue, 24 Jul 2018 11:21:10 +0200 Subject: ice40: Trim BRAM constant inputs, reduces routing congestion around BRAM Signed-off-by: David Shah --- ice40/pack.cc | 3 +++ 1 file changed, 3 insertions(+) (limited to 'ice40') diff --git a/ice40/pack.cc b/ice40/pack.cc index 7e2e389c..164fa756 100644 --- a/ice40/pack.cc +++ b/ice40/pack.cc @@ -311,6 +311,9 @@ static void set_net_constant(const Context *ctx, NetInfo *orig, NetInfo *constne (user.port != ctx->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); -- cgit v1.2.3 From 7858663aa7f211cebde2d543f7d0094d84ca11b1 Mon Sep 17 00:00:00 2001 From: David Shah Date: Tue, 24 Jul 2018 11:46:14 +0200 Subject: timing: Model clock to Q times Signed-off-by: David Shah --- ice40/arch.cc | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'ice40') diff --git a/ice40/arch.cc b/ice40/arch.cc index 65b21afd..c29673cc 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -733,6 +733,14 @@ bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort } else if (fromPort == id("I2") && toPort == id("COUT")) { delay = 230; return true; + } else if (fromPort == id("CLK") && toPort == id("O")) { + delay = 540; + return true; + } + } else if (cell->type == id("ICESTORM_RAM")) { + if (fromPort == id("RCLK")) { + delay = 2140; + return true; } } return false; @@ -743,6 +751,11 @@ IdString Arch::getPortClock(const CellInfo *cell, IdString port) const if (cell->type == id("ICESTORM_LC") && bool_or_default(cell->params, id("DFF_ENABLE"))) { if (port != id("LO") && port != id("CIN") && port != id("COUT")) return id("CLK"); + } else if (cell->type == id("ICESTORM_RAM")) { + if (port.str(this)[0] == 'R') + return id("RCLK"); + else + return id("WCLK"); } return IdString(); } @@ -751,6 +764,8 @@ bool Arch::isClockPort(const CellInfo *cell, IdString port) const { if (cell->type == id("ICESTORM_LC") && port == id("CLK")) return true; + if (cell->type == id("ICESTORM_RAM") && (port == id("RCLK") || (port == id("WCLK")))) + return true; return false; } -- cgit v1.2.3 From 9d38907e95dac76a6b9754562752c36e3f65b9ec Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Tue, 24 Jul 2018 12:18:01 +0200 Subject: Add G_ARROW (for now same look as G_LINE) Signed-off-by: Clifford Wolf --- ice40/gfx.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ice40') diff --git a/ice40/gfx.cc b/ice40/gfx.cc index f6ed789f..1b01cbd8 100644 --- a/ice40/gfx.cc +++ b/ice40/gfx.cc @@ -647,7 +647,7 @@ void pipGfx(std::vector &g, int x, int y, float x1, float y1, fl float ty = 0.5 * (y1 + y2); GraphicElement el; - el.type = GraphicElement::G_LINE; + el.type = GraphicElement::G_ARROW; el.style = style; if (fabsf(x1 - swx1) < 0.001 && fabsf(x2 - swx1) < 0.001) { -- cgit v1.2.3 From 942c552e079abef96d0d87fa367329fbdc0bc053 Mon Sep 17 00:00:00 2001 From: David Shah Date: Tue, 24 Jul 2018 15:31:00 +0200 Subject: Add bbasm target, use as passthru in iCE40 builder Signed-off-by: David Shah --- ice40/family.cmake | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) (limited to 'ice40') diff --git a/ice40/family.cmake b/ice40/family.cmake index 9af06f82..95cdf331 100644 --- a/ice40/family.cmake +++ b/ice40/family.cmake @@ -19,13 +19,18 @@ if (MSVC) set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/ice40/resources/chipdb.rc PROPERTIES LANGUAGE RC) foreach (dev ${devices}) set(DEV_TXT_DB ${ICEBOX_ROOT}/chipdb-${dev}.txt) + set(DEV_CC_BBA_DB ${CMAKE_CURRENT_SOURCE_DIR}/ice40/chipdbs/chipdb-${dev}.bba) set(DEV_CC_DB ${CMAKE_CURRENT_SOURCE_DIR}/ice40/chipdbs/chipdb-${dev}.bin) set(DEV_PORTS_INC ${CMAKE_CURRENT_SOURCE_DIR}/ice40/portpins.inc) set(DEV_GFXH ${CMAKE_CURRENT_SOURCE_DIR}/ice40/gfx.h) - add_custom_command(OUTPUT ${DEV_CC_DB} - COMMAND ${PYTHON_EXECUTABLE} ${DB_PY} -b -p ${DEV_PORTS_INC} -g ${DEV_GFXH} ${DEV_TXT_DB} > ${DEV_CC_DB} + add_custom_command(OUTPUT ${DEV_CC_BBA_DB} + COMMAND ${PYTHON_EXECUTABLE} ${DB_PY} -b -p ${DEV_PORTS_INC} -g ${DEV_GFXH} ${DEV_TXT_DB} > ${DEV_CC_BBA_DB} DEPENDS ${DEV_TXT_DB} ${DB_PY} ) + add_custom_command(OUTPUT ${DEV_CC_DB} + COMMAND bbasm < ${DEV_CC_BBA_DB} > ${DEV_CC_DB} + DEPENDS bbasm ${DEV_CC_BBA_DB} + ) target_sources(ice40_chipdb PRIVATE ${DEV_CC_DB}) set_source_files_properties(${DEV_CC_DB} PROPERTIES HEADER_FILE_ONLY TRUE) foreach (target ${family_targets}) @@ -36,14 +41,20 @@ else() target_compile_options(ice40_chipdb PRIVATE -g0 -O0 -w) foreach (dev ${devices}) set(DEV_TXT_DB ${ICEBOX_ROOT}/chipdb-${dev}.txt) + set(DEV_CC_BBA_DB ${CMAKE_CURRENT_SOURCE_DIR}/ice40/chipdbs/chipdb-${dev}.bba) set(DEV_CC_DB ${CMAKE_CURRENT_SOURCE_DIR}/ice40/chipdbs/chipdb-${dev}.cc) set(DEV_PORTS_INC ${CMAKE_CURRENT_SOURCE_DIR}/ice40/portpins.inc) set(DEV_GFXH ${CMAKE_CURRENT_SOURCE_DIR}/ice40/gfx.h) + add_custom_command(OUTPUT ${DEV_CC_BBA_DB} + COMMAND ${PYTHON_EXECUTABLE} ${DB_PY} -c -p ${DEV_PORTS_INC} -g ${DEV_GFXH} ${DEV_TXT_DB} > ${DEV_CC_BBA_DB}.new + COMMAND mv ${DEV_CC_BBA_DB}.new ${DEV_CC_BBA_DB} + DEPENDS ${DEV_TXT_DB} ${DB_PY} + ) add_custom_command(OUTPUT ${DEV_CC_DB} - COMMAND ${PYTHON_EXECUTABLE} ${DB_PY} -c -p ${DEV_PORTS_INC} -g ${DEV_GFXH} ${DEV_TXT_DB} > ${DEV_CC_DB}.new + COMMAND bbasm < ${DEV_CC_BBA_DB} > ${DEV_CC_DB}.new COMMAND mv ${DEV_CC_DB}.new ${DEV_CC_DB} - DEPENDS ${DEV_TXT_DB} ${DB_PY} - ) + DEPENDS bbasm ${DEV_CC_BBA_DB} + ) target_sources(ice40_chipdb PRIVATE ${DEV_CC_DB}) foreach (target ${family_targets}) target_sources(${target} PRIVATE $) -- cgit v1.2.3 From c0c8dc760290cb78611f3764219a7604f6f73c44 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Tue, 24 Jul 2018 15:44:39 +0200 Subject: Remove uphill/downhill bel pins from ice40 db Signed-off-by: Clifford Wolf --- ice40/arch.h | 4 ---- ice40/chipdb.py | 30 ------------------------------ 2 files changed, 34 deletions(-) (limited to 'ice40') diff --git a/ice40/arch.h b/ice40/arch.h index d4d71cfc..3f6a5324 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -83,10 +83,6 @@ NPNR_PACKED_STRUCT(struct WireInfoPOD { int32_t num_uphill, num_downhill; RelPtr pips_uphill, pips_downhill; - int32_t num_bels_downhill; - BelPortPOD bel_uphill; - RelPtr bels_downhill; - int32_t num_bel_pins; RelPtr bel_pins; diff --git a/ice40/chipdb.py b/ice40/chipdb.py index 4dcddbed..1127767d 100644 --- a/ice40/chipdb.py +++ b/ice40/chipdb.py @@ -41,8 +41,6 @@ extra_cells = dict() extra_cell_config = dict() packages = list() -wire_uphill_belport = dict() -wire_downhill_belports = dict() wire_belports = dict() wire_names = dict() @@ -451,17 +449,12 @@ for i in range(8): add_wire(0, 0, "padin_%d" % i) def add_bel_input(bel, wire, port): - if wire not in wire_downhill_belports: - wire_downhill_belports[wire] = set() - wire_downhill_belports[wire].add((bel, port)) if wire not in wire_belports: wire_belports[wire] = set() wire_belports[wire].add((bel, port)) bel_wires[bel].append((wire, port, 0)) def add_bel_output(bel, wire, port): - assert wire not in wire_uphill_belport - wire_uphill_belport[wire] = (bel, port) if wire not in wire_belports: wire_belports[wire] = set() wire_belports[wire].add((bel, port)) @@ -1001,15 +994,6 @@ for wire in range(num_wires): num_downhill = 0 list_downhill = None - if wire in wire_downhill_belports: - num_bels_downhill = len(wire_downhill_belports[wire]) - bba.l("wire%d_downbels" % wire, "BelPortPOD") - for belport in sorted(wire_downhill_belports[wire]): - bba.u32(belport[0], "bel_index") - bba.u32(portpins[belport[1]], "port") - else: - num_bels_downhill = 0 - if wire in wire_belports: num_bel_pins = len(wire_belports[wire]) bba.l("wire%d_bels" % wire, "BelPortPOD") @@ -1028,19 +1012,9 @@ for wire in range(num_wires): info["num_downhill"] = num_downhill info["list_downhill"] = list_downhill - info["num_bels_downhill"] = num_bels_downhill - info["list_bels_downhill"] = ("wire%d_downbels" % wire) if num_bels_downhill > 0 else None - info["num_bel_pins"] = num_bel_pins info["list_bel_pins"] = ("wire%d_bels" % wire) if num_bel_pins > 0 else None - if wire in wire_uphill_belport: - info["uphill_bel"] = wire_uphill_belport[wire][0] - info["uphill_pin"] = portpins[wire_uphill_belport[wire][1]] - else: - info["uphill_bel"] = -1 - info["uphill_pin"] = 0 - avg_x, avg_y = 0, 0 if wire in wire_xy: for x, y in wire_xy[wire]: @@ -1115,10 +1089,6 @@ for wire, info in enumerate(wireinfo): bba.u32(info["num_downhill"], "num_downhill") bba.r(info["list_uphill"], "pips_uphill") bba.r(info["list_downhill"], "pips_downhill") - bba.u32(info["num_bels_downhill"], "num_bels_downhill") - bba.u32(info["uphill_bel"], "bel_uphill.bel_index") - bba.u32(info["uphill_pin"], "bel_uphill.port") - bba.r(info["list_bels_downhill"], "bels_downhill") bba.u32(info["num_bel_pins"], "num_bel_pins") bba.r(info["list_bel_pins"], "bel_pins") bba.u32(len(wire_segments[wire]), "num_segments") -- cgit v1.2.3 From 5a170f286c2868375d93477ad3bd08ccc30a15a1 Mon Sep 17 00:00:00 2001 From: David Shah Date: Tue, 24 Jul 2018 15:52:56 +0200 Subject: ice40: Remove use of deprecated APIs Signed-off-by: David Shah --- ice40/arch_place.cc | 7 ++++--- ice40/pack.cc | 5 +++-- ice40/place_legaliser.cc | 8 +++----- 3 files changed, 10 insertions(+), 10 deletions(-) (limited to 'ice40') diff --git a/ice40/arch_place.cc b/ice40/arch_place.cc index cf1276a7..d32ebe98 100644 --- a/ice40/arch_place.cc +++ b/ice40/arch_place.cc @@ -71,7 +71,8 @@ bool Arch::isBelLocationValid(BelId bel) const { if (getBelType(bel) == TYPE_ICESTORM_LC) { std::vector bel_cells; - for (auto bel_other : getBelsAtSameTile(bel)) { + Loc bel_loc = getBelLocation(bel); + for (auto bel_other : getBelsByTile(bel_loc.x, bel_loc.y)) { IdString cell_other = getBoundBelCell(bel_other); if (cell_other != IdString()) { const CellInfo *ci_other = cells.at(cell_other).get(); @@ -94,8 +95,8 @@ bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const NPNR_ASSERT(getBelType(bel) == TYPE_ICESTORM_LC); std::vector bel_cells; - - for (auto bel_other : getBelsAtSameTile(bel)) { + Loc bel_loc = getBelLocation(bel); + for (auto bel_other : getBelsByTile(bel_loc.x, bel_loc.y)) { IdString cell_other = getBoundBelCell(bel_other); if (cell_other != IdString() && bel_other != bel) { const CellInfo *ci_other = cells.at(cell_other).get(); diff --git a/ice40/pack.cc b/ice40/pack.cc index 164fa756..f054be6b 100644 --- a/ice40/pack.cc +++ b/ice40/pack.cc @@ -311,8 +311,9 @@ static void set_net_constant(const Context *ctx, NetInfo *orig, NetInfo *constne (user.port != ctx->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")) { + } 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; diff --git a/ice40/place_legaliser.cc b/ice40/place_legaliser.cc index 2aefb839..ebc2b865 100644 --- a/ice40/place_legaliser.cc +++ b/ice40/place_legaliser.cc @@ -75,11 +75,9 @@ static void get_chain_midpoint(const Context *ctx, const CellChain &chain, float for (auto cell : chain.cells) { if (cell->bel == BelId()) continue; - int bel_x, bel_y; - bool bel_gb; - ctx->estimatePosition(cell->bel, bel_x, bel_y, bel_gb); - total_x += bel_x; - total_y += bel_y; + Loc bel_loc = ctx->getBelLocation(cell->bel); + total_x += bel_loc.x; + total_y += bel_loc.y; N++; } NPNR_ASSERT(N > 0); -- cgit v1.2.3 From 974ca143e80ac48b0e87054001a48b0d6597c6fa Mon Sep 17 00:00:00 2001 From: David Shah Date: Tue, 24 Jul 2018 16:09:29 +0200 Subject: Remove implementations of deprecated APIs Signed-off-by: David Shah --- ice40/arch.cc | 25 ------------------------- ice40/arch.h | 3 --- ice40/arch_pybindings.cc | 2 -- 3 files changed, 30 deletions(-) (limited to 'ice40') diff --git a/ice40/arch.cc b/ice40/arch.cc index c29673cc..2270fdc1 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -291,23 +291,6 @@ BelRange Arch::getBelsByTile(int x, int y) const return br; } -BelRange Arch::getBelsAtSameTile(BelId bel) const -{ - BelRange br; - NPNR_ASSERT(bel != BelId()); - int x = chip_info->bel_data[bel.index].x; - int y = chip_info->bel_data[bel.index].y; - int start = bel.index, end = bel.index; - while (start >= 0 && chip_info->bel_data[start].x == x && chip_info->bel_data[start].y == y) - start--; - start++; - br.b.cursor = start; - while (end < chip_info->num_bels && chip_info->bel_data[end].x == x && chip_info->bel_data[end].y == y) - end++; - br.e.cursor = end; - return br; -} - PortType Arch::getBelPinType(BelId bel, PortPin pin) const { NPNR_ASSERT(bel != BelId()); @@ -482,14 +465,6 @@ std::vector Arch::getGroupGroups(GroupId group) const // ----------------------------------------------------------------------- -void Arch::estimatePosition(BelId bel, int &x, int &y, bool &gb) const -{ - NPNR_ASSERT(bel != BelId()); - x = chip_info->bel_data[bel.index].x; - y = chip_info->bel_data[bel.index].y; - gb = chip_info->bel_data[bel.index].type == TYPE_SB_GB; -} - delay_t Arch::estimateDelay(WireId src, WireId dst) const { NPNR_ASSERT(src != WireId()); diff --git a/ice40/arch.h b/ice40/arch.h index 3f6a5324..3aec25a2 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -449,8 +449,6 @@ struct Arch : BaseCtx bool getBelGlobalBuf(BelId bel) const { return chip_info->bel_data[bel.index].type == TYPE_SB_GB; } - BelRange getBelsAtSameTile(BelId bel) const NPNR_DEPRECATED; - BelType getBelType(BelId bel) const { NPNR_ASSERT(bel != BelId()); @@ -681,7 +679,6 @@ struct Arch : BaseCtx // ------------------------------------------------- - void estimatePosition(BelId bel, int &x, int &y, bool &gb) const NPNR_DEPRECATED; delay_t estimateDelay(WireId src, WireId dst) const; delay_t getDelayEpsilon() const { return 20; } delay_t getRipupDelayPenalty() const { return 200; } diff --git a/ice40/arch_pybindings.cc b/ice40/arch_pybindings.cc index 246d0f57..98164e87 100644 --- a/ice40/arch_pybindings.cc +++ b/ice40/arch_pybindings.cc @@ -79,8 +79,6 @@ void arch_wrap_python() conv_to_str, conv_from_str>::def_wrap(ctx_cls, "getConflictingBelCell"); fn_wrapper_0a>::def_wrap(ctx_cls, "getBels"); - fn_wrapper_1a, - conv_from_str>::def_wrap(ctx_cls, "getBelsAtSameTile"); fn_wrapper_2a, conv_from_str, conv_from_str>::def_wrap(ctx_cls, "getBelPinWire"); -- cgit v1.2.3 From 2039112a472fade4b161502dc683461640386304 Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Tue, 24 Jul 2018 15:59:18 +0100 Subject: ice40: after review --- ice40/pack.cc | 1 - 1 file changed, 1 deletion(-) (limited to 'ice40') diff --git a/ice40/pack.cc b/ice40/pack.cc index b1e7380e..b4f711f3 100644 --- a/ice40/pack.cc +++ b/ice40/pack.cc @@ -693,7 +693,6 @@ static void pack_special(Context *ctx) BelId pll_bel; bool constrained = false; if (packed->attrs.find(ctx->id("BEL")) == packed->attrs.end()) { - // FIXME replace by getBelsByType when implemented for (auto bel : ctx->getBels()) { if (ctx->getBelType(bel) != TYPE_ICESTORM_PLL) continue; -- cgit v1.2.3