diff options
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | CMakeLists.txt | 2 | ||||
-rw-r--r-- | ecp5/arch.cc | 12 | ||||
-rw-r--r-- | ecp5/arch.h | 6 | ||||
-rw-r--r-- | ecp5/arch_place.cc | 24 | ||||
-rw-r--r-- | ecp5/archdefs.h | 2 | ||||
-rw-r--r-- | ecp5/bitstream.cc | 10 | ||||
-rw-r--r-- | ecp5/constids.inc | 8 | ||||
-rw-r--r-- | ecp5/family.cmake | 4 | ||||
-rw-r--r-- | ecp5/pack.cc | 57 | ||||
-rwxr-xr-x | ecp5/trellis_import.py | 8 | ||||
-rw-r--r-- | generic/cells.cc | 14 | ||||
-rw-r--r-- | generic/examples/bitstream.py | 2 | ||||
-rw-r--r-- | generic/examples/simple.py | 7 | ||||
-rwxr-xr-x | generic/examples/simple.sh | 3 | ||||
-rw-r--r-- | generic/examples/simple_timing.py | 26 | ||||
-rw-r--r-- | generic/pack.cc | 8 | ||||
-rw-r--r-- | generic/synth/prims.v | 15 | ||||
-rw-r--r-- | ice40/family.cmake | 8 | ||||
-rw-r--r-- | python/interactive.py | 6 |
20 files changed, 167 insertions, 58 deletions
@@ -19,6 +19,9 @@ CMakeCache.txt .*.swp a.out *.json +*.dot +*.il +/generic/examples/blinky.png build/ *.asc *.bin diff --git a/CMakeLists.txt b/CMakeLists.txt index 7bdff611..9af4bb6c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -97,7 +97,7 @@ endif() find_package(Sanitizers) # List of Boost libraries to include -set(boost_libs filesystem thread program_options iostreams) +set(boost_libs filesystem thread program_options iostreams system) if (BUILD_GUI AND NOT BUILD_PYTHON) message(FATAL_ERROR "GUI requires Python to build") diff --git a/ecp5/arch.cc b/ecp5/arch.cc index 8ce0653c..d931c5b2 100644 --- a/ecp5/arch.cc +++ b/ecp5/arch.cc @@ -117,6 +117,9 @@ Arch::Arch(ArchArgs args) : args(args) log_error("Unsupported ECP5 chip type.\n"); } #endif + if (chip_info->const_id_count != DB_CONST_ID_COUNT) + log_error("Chip database 'bba' and nextpnr code are out of sync; please rebuild (or contact distribution " + "maintainer)!\n"); package_info = nullptr; for (int i = 0; i < chip_info->num_packages; i++) { if (args.package == chip_info->package_info[i].name.get()) { @@ -477,7 +480,13 @@ delay_t Arch::estimateDelay(WireId src, WireId dst) const } }; - auto src_loc = est_location(src), dst_loc = est_location(dst); + auto src_loc = est_location(src); + std::pair<int, int> dst_loc; + if (wire_loc_overrides.count(dst)) { + dst_loc = wire_loc_overrides.at(dst); + } else { + dst_loc = est_location(dst); + } int dx = abs(src_loc.first - dst_loc.first), dy = abs(src_loc.second - dst_loc.second); @@ -562,6 +571,7 @@ bool Arch::place() bool Arch::route() { + setupWireLocations(); route_ecp5_globals(getCtx()); assignArchInfo(); assign_budget(getCtx(), true); diff --git a/ecp5/arch.h b/ecp5/arch.h index a479abb6..3df2d84f 100644 --- a/ecp5/arch.h +++ b/ecp5/arch.h @@ -194,6 +194,7 @@ NPNR_PACKED_STRUCT(struct ChipInfoPOD { int32_t num_tiles; int32_t num_location_types; int32_t num_packages, num_pios; + int32_t const_id_count; RelPtr<LocationTypePOD> locations; RelPtr<int32_t> location_type; RelPtr<GlobalInfoPOD> location_glbinfo; @@ -1048,6 +1049,11 @@ struct Arch : BaseCtx // Special case for delay estimates due to its physical location // being far from the logical location of its primitive WireId gsrclk_wire; + // Improves directivity of routing to DSP inputs, avoids issues + // with different routes to the same physical reset wire causing + // conflicts and slow routing + std::unordered_map<WireId, std::pair<int, int>> wire_loc_overrides; + void setupWireLocations(); mutable std::unordered_map<DelayKey, std::pair<bool, DelayInfo>> celldelay_cache; diff --git a/ecp5/arch_place.cc b/ecp5/arch_place.cc index d5c345af..6057605b 100644 --- a/ecp5/arch_place.cc +++ b/ecp5/arch_place.cc @@ -196,4 +196,28 @@ void Arch::permute_luts() } } +void Arch::setupWireLocations() +{ + wire_loc_overrides.clear(); + for (auto cell : sorted(cells)) { + CellInfo *ci = cell.second; + if (ci->bel == BelId()) + continue; + if (ci->type == id_MULT18X18D || ci->type == id_DCUA) { + for (auto &port : ci->ports) { + if (port.second.type != PORT_IN || port.second.net == nullptr) + continue; + WireId pw = getBelPinWire(ci->bel, port.first); + if (pw == WireId()) + continue; + for (auto uh : getPipsUphill(pw)) { + WireId pip_src = getPipSrcWire(uh); + wire_loc_overrides[pw] = std::make_pair(pip_src.location.x, pip_src.location.y); + break; + } + } + } + } +} + NEXTPNR_NAMESPACE_END diff --git a/ecp5/archdefs.h b/ecp5/archdefs.h index da12eeaa..3cd92119 100644 --- a/ecp5/archdefs.h +++ b/ecp5/archdefs.h @@ -58,6 +58,8 @@ enum ConstIds #define X(t) , ID_##t #include "constids.inc" #undef X + , + DB_CONST_ID_COUNT }; #define X(t) static constexpr auto id_##t = IdString(ID_##t); diff --git a/ecp5/bitstream.cc b/ecp5/bitstream.cc index acab95dd..9732cd52 100644 --- a/ecp5/bitstream.cc +++ b/ecp5/bitstream.cc @@ -865,6 +865,16 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex if (ci->attrs.count(ctx->id("DIFFRESISTOR"))) cc.tiles[pio_tile].add_enum(pio + ".DIFFRESISTOR", str_or_default(ci->attrs, ctx->id("DIFFRESISTOR"), "OFF")); + if (ci->attrs.count(ctx->id("DRIVE"))) { + static bool drive_3v3_warning_done = false; + if (iotype == "LVCMOS33") { + cc.tiles[pio_tile].add_enum(pio + ".DRIVE", str_or_default(ci->attrs, ctx->id("DRIVE"), "8")); + } else { + if (!drive_3v3_warning_done) + log_warning("Trellis limitation: DRIVE can only be set on 3V3 IO pins.\n"); + drive_3v3_warning_done = true; + } + } if (ci->attrs.count(ctx->id("TERMINATION"))) { auto vccio = get_vccio(ioType_from_str(iotype)); switch (vccio) { diff --git a/ecp5/constids.inc b/ecp5/constids.inc index 5e8fc7da..4b5e3a3a 100644 --- a/ecp5/constids.inc +++ b/ecp5/constids.inc @@ -1294,3 +1294,11 @@ X(P) X(ECLKBRIDGECS) X(SEL) X(ECSOUT) + +X(IOLOGIC_MODE_IDDRX1F) +X(IOLOGIC_MODE_IDDRX2F) +X(IOLOGIC_MODE_IREG) +X(IOLOGIC_MODE_ODDRX1F) +X(IOLOGIC_MODE_ODDRX2F) +X(IOLOGIC_MODE_OREG) +X(IOLOGIC_MODE_TSREG) diff --git a/ecp5/family.cmake b/ecp5/family.cmake index 5512e7dd..2d8dcfcc 100644 --- a/ecp5/family.cmake +++ b/ecp5/family.cmake @@ -48,7 +48,7 @@ if (NOT EXTERNAL_CHIPDB) else() add_custom_command(OUTPUT ${DEV_CC_BBA_DB} COMMAND ${ENV_CMD} ${PYTHON_EXECUTABLE} ${DB_PY} -p ${DEV_CONSTIDS_INC} ${dev} > ${DEV_CC_BBA_DB} - DEPENDS ${DB_PY} ${PREV_DEV_CC_BBA_DB} + DEPENDS ${DB_PY} ${DEV_CONSTIDS_INC} ${PREV_DEV_CC_BBA_DB} ) add_custom_command(OUTPUT ${DEV_CC_DB} COMMAND bbasm ${BBASM_ENDIAN_FLAG} ${DEV_CC_BBA_DB} ${DEV_CC_DB} @@ -80,7 +80,7 @@ if (NOT EXTERNAL_CHIPDB) add_custom_command(OUTPUT ${DEV_CC_BBA_DB} COMMAND ${ENV_CMD} ${PYTHON_EXECUTABLE} ${DB_PY} -p ${DEV_CONSTIDS_INC} ${dev} > ${DEV_CC_BBA_DB}.new COMMAND mv ${DEV_CC_BBA_DB}.new ${DEV_CC_BBA_DB} - DEPENDS ${DB_PY} ${PREV_DEV_CC_BBA_DB} + DEPENDS ${DB_PY} ${DEV_CONSTIDS_INC} ${PREV_DEV_CC_BBA_DB} ) add_custom_command(OUTPUT ${DEV_CC_DB} COMMAND bbasm --c ${BBASM_ENDIAN_FLAG} ${DEV_CC_BBA_DB} ${DEV_CC_DB}.new diff --git a/ecp5/pack.cc b/ecp5/pack.cc index 00ed891a..c498d20a 100644 --- a/ecp5/pack.cc +++ b/ecp5/pack.cc @@ -2345,6 +2345,7 @@ class Ecp5Packer for (auto cell : sorted(ctx->cells)) { CellInfo *ci = cell.second; if (ci->type == id_ECLKBRIDGECS) { + Loc loc; NetInfo *i0 = get_net_or_empty(ci, id_CLK0), *i1 = get_net_or_empty(ci, id_CLK1), *o = get_net_or_empty(ci, id_ECSOUT); for (NetInfo *input : {i0, i1}) { @@ -2358,24 +2359,53 @@ class Ecp5Packer for (auto bel : ctx->getBels()) { if (ctx->getBelType(bel) != id_ECLKBRIDGECS) continue; - Loc loc = ctx->getBelLocation(bel); + loc = ctx->getBelLocation(bel); if (loc.x == user_loc.x) { ci->attrs[ctx->id("BEL")] = ctx->getBelName(bel).str(ctx); - if (o != nullptr) - for (auto user2 : o->users) { - // Set side hint to ensure edge clock choice is routeable - if (user2.cell->type == id_ECLKSYNCB && user2.port == id_ECLKI) { - NetInfo *synco = get_net_or_empty(user2.cell, id_ECLKO); - if (synco != nullptr) - bridge_side_hint[synco] = (loc.x > 1) ? 0 : 1; - } - } goto eclkbridge_done; } } } + if (input->driver.cell != nullptr) { + CellInfo *drv = input->driver.cell; + if (!drv->attrs.count(ctx->id("BEL"))) + continue; + Loc drv_loc = ctx->getBelLocation( + ctx->getBelByName(ctx->id(drv->attrs.at(ctx->id("BEL")).as_string()))); + BelId closest; + int closest_x = -1; // aim for same side of chip + for (auto bel : ctx->getBels()) { + if (ctx->getBelType(bel) != id_ECLKBRIDGECS) + continue; + loc = ctx->getBelLocation(bel); + if (closest_x == -1 || std::abs(loc.x - drv_loc.x) < std::abs(closest_x - drv_loc.x)) { + closest_x = loc.x; + closest = bel; + } + } + NPNR_ASSERT(closest != BelId()); + loc = ctx->getBelLocation(closest); + ci->attrs[ctx->id("BEL")] = ctx->getBelName(closest).str(ctx); + goto eclkbridge_done; + } + } + // If all else fails, place randomly + for (auto bel : ctx->getBels()) { + if (ctx->getBelType(bel) != id_ECLKBRIDGECS) + continue; + loc = ctx->getBelLocation(bel); + ci->attrs[ctx->id("BEL")] = ctx->getBelName(bel).str(ctx); } eclkbridge_done: + if (o != nullptr) + for (auto user2 : o->users) { + // Set side hint to ensure edge clock choice is routeable + if (user2.cell->type == id_ECLKSYNCB && user2.port == id_ECLKI) { + NetInfo *synco = get_net_or_empty(user2.cell, id_ECLKO); + if (synco != nullptr) + bridge_side_hint[synco] = (loc.x > 1) ? 0 : 1; + } + } continue; } } @@ -2575,7 +2605,7 @@ class Ecp5Packer std::unordered_set<IdString> changed_cells; for (auto net : changed_nets) for (auto &user : ctx->nets.at(net)->users) - if (user.port == id_CLKI || user.port == id_ECLKI) + if (user.port == id_CLKI || user.port == id_ECLKI || user.port == id_CLK0 || user.port == id_CLK1) changed_cells.insert(user.cell->name); changed_nets.clear(); for (auto cell : sorted(changed_cells)) { @@ -2592,6 +2622,9 @@ class Ecp5Packer copy_constraint(ci, id_CLKI, id_CDIVX, ratio); } else if (ci->type == id_ECLKSYNCB || ci->type == id_TRELLIS_ECLKBUF) { copy_constraint(ci, id_ECLKI, id_ECLKO, 1); + } else if (ci->type == id_ECLKBRIDGECS) { + copy_constraint(ci, id_CLK0, id_ECSOUT, 1); + copy_constraint(ci, id_CLK1, id_ECSOUT, 1); } else if (ci->type == id_DCCA) { copy_constraint(ci, id_CLKI, id_CLKO, 1); } else if (ci->type == id_EHXPLLL) { @@ -2651,12 +2684,12 @@ class Ecp5Packer prepack_checks(); pack_io(); pack_dqsbuf(); + preplace_plls(); pack_iologic(); pack_ebr(); pack_dsps(); pack_dcus(); pack_misc(); - preplace_plls(); pack_constants(); pack_dram(); pack_carries(); diff --git a/ecp5/trellis_import.py b/ecp5/trellis_import.py index 610bd331..ee960fd3 100755 --- a/ecp5/trellis_import.py +++ b/ecp5/trellis_import.py @@ -186,6 +186,8 @@ def process_timing_data(): max_delay = min(entry["rising"][2], entry["falling"][2]) delays.append((constids[from_pin], constids[to_pin], min_delay, max_delay)) elif entry["type"] == "SetupHold": + if type(entry["pin"]) is list: + continue pin = constids[entry["pin"]] clock = constids[entry["clock"][1]] min_setup = entry["setup"][0] @@ -441,6 +443,7 @@ def write_database(dev_name, chip, ddrg, endianness): bba.u32(len(location_types), "num_location_types") bba.u32(len(packages), "num_packages") bba.u32(len(pindata), "num_pios") + bba.u32(const_id_count, "const_id_count") bba.r("locations", "locations") bba.r("location_types", "location_type") @@ -457,11 +460,12 @@ def write_database(dev_name, chip, ddrg, endianness): dev_names = {"25k": "LFE5UM5G-25F", "45k": "LFE5UM5G-45F", "85k": "LFE5UM5G-85F"} def main(): - global max_row, max_col + global max_row, max_col, const_id_count pytrellis.load_database(database.get_db_root()) args = parser.parse_args() # Read port pin file + const_id_count = 1 # count ID_NONE with open(args.constids) as f: for line in f: line = line.replace("(", " ") @@ -473,7 +477,7 @@ def main(): assert line[0] == "X" idx = len(constids) + 1 constids[line[1]] = idx - + const_id_count += 1 constids["SLICE"] = constids["TRELLIS_SLICE"] constids["PIO"] = constids["TRELLIS_IO"] diff --git a/generic/cells.cc b/generic/cells.cc index 53886e33..2b555f62 100644 --- a/generic/cells.cc +++ b/generic/cells.cc @@ -42,7 +42,7 @@ std::unique_ptr<CellInfo> create_generic_cell(Context *ctx, IdString type, std:: } new_cell->type = type; if (type == ctx->id("GENERIC_SLICE")) { - new_cell->params[ctx->id("K")] = std::to_string(ctx->args.K); + new_cell->params[ctx->id("K")] = ctx->args.K; new_cell->params[ctx->id("INIT")] = 0; new_cell->params[ctx->id("FF_USED")] = 0; @@ -51,6 +51,7 @@ std::unique_ptr<CellInfo> create_generic_cell(Context *ctx, IdString type, std:: add_port(ctx, new_cell.get(), "CLK", PORT_IN); + add_port(ctx, new_cell.get(), "F", PORT_OUT); add_port(ctx, new_cell.get(), "Q", PORT_OUT); } else if (type == ctx->id("GENERIC_IOB")) { new_cell->params[ctx->id("INPUT_USED")] = 0; @@ -80,8 +81,8 @@ void lut_to_lc(const Context *ctx, CellInfo *lut, CellInfo *lc, bool no_dff) } if (no_dff) { - replace_port(lut, ctx->id("Q"), lc, ctx->id("Q")); lc->params[ctx->id("FF_USED")] = 0; + replace_port(lut, ctx->id("Q"), lc, ctx->id("F")); } } @@ -91,7 +92,14 @@ void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_l replace_port(dff, ctx->id("CLK"), lc, ctx->id("CLK")); if (pass_thru_lut) { - lc->params[ctx->id("INIT")] = 2; + // Fill LUT with alternating 10 + const int init_size = 1 << lc->params[ctx->id("K")].as_int64(); + std::string init; + init.reserve(init_size); + for(int i = 0; i < init_size; i+=2) + init.append("10"); + lc->params[ctx->id("INIT")] = Property::from_string(init); + replace_port(dff, ctx->id("D"), lc, ctx->id("I[0]")); } diff --git a/generic/examples/bitstream.py b/generic/examples/bitstream.py index 1ab94f0c..7f0b5c07 100644 --- a/generic/examples/bitstream.py +++ b/generic/examples/bitstream.py @@ -14,4 +14,4 @@ param_map = { } with open("blinky.fasm", "w") as f: - write_fasm(ctx, param_map, f)
\ No newline at end of file + write_fasm(ctx, param_map, f) diff --git a/generic/examples/simple.py b/generic/examples/simple.py index 9339b68a..9379b505 100644 --- a/generic/examples/simple.py +++ b/generic/examples/simple.py @@ -9,6 +9,7 @@ for x in range(X): for z in range(N): ctx.addWire(name="X%dY%dZ%d_CLK" % (x, y, z), type="BEL_CLK", x=x, y=y) ctx.addWire(name="X%dY%dZ%d_Q" % (x, y, z), type="BEL_Q", x=x, y=y) + ctx.addWire(name="X%dY%dZ%d_F" % (x, y, z), type="BEL_F", x=x, y=y) for i in range(K): ctx.addWire(name="X%dY%dZ%d_I%d" % (x, y, z, i), type="BEL_I", x=x, y=y) # Local wires @@ -29,6 +30,7 @@ for x in range(X): ctx.addBelInput(bel="X%dY%d_SLICE%d" % (x, y, z), name="CLK", wire="X%dY%dZ%d_CLK" % (x, y, z)) for k in range(K): ctx.addBelInput(bel="X%dY%d_SLICE%d" % (x, y, z), name="I[%d]" % k, wire="X%dY%dZ%d_I%d" % (x, y, z, k)) + ctx.addBelOutput(bel="X%dY%d_SLICE%d" % (x, y, z), name="F", wire="X%dY%dZ%d_F" % (x, y, z)) ctx.addBelOutput(bel="X%dY%d_SLICE%d" % (x, y, z), name="Q", wire="X%dY%dZ%d_Q" % (x, y, z)) for x in range(X): @@ -48,6 +50,9 @@ for x in range(X): # Pips from bel outputs to locals def create_output_pips(dst, offset, skip): for i in range(offset % skip, N, skip): + src = "X%dY%dZ%d_F" % (x, y, i) + ctx.addPip(name="X%dY%d.%s.%s" % (x, y, src, dst), type="BEL_OUTPUT", + srcWire=src, dstWire=dst, delay=ctx.getDelayFromNS(0.05), loc=Loc(x, y, 0)) src = "X%dY%dZ%d_Q" % (x, y, i) ctx.addPip(name="X%dY%d.%s.%s" % (x, y, src, dst), type="BEL_OUTPUT", srcWire=src, dstWire=dst, delay=ctx.getDelayFromNS(0.05), loc=Loc(x, y, 0)) @@ -69,4 +74,4 @@ for x in range(X): create_neighbour_pips(dst, x, y+1, (l + 4) % Sl, Sl) create_neighbour_pips(dst, x+1, y-1, (l + 5) % Sl, Sl) create_neighbour_pips(dst, x+1, y, (l + 6) % Sl, Sl) - create_neighbour_pips(dst, x+1, y+1, (l + 7) % Sl, Sl)
\ No newline at end of file + create_neighbour_pips(dst, x+1, y+1, (l + 7) % Sl, Sl) diff --git a/generic/examples/simple.sh b/generic/examples/simple.sh index 8ae903f9..76bc6168 100755 --- a/generic/examples/simple.sh +++ b/generic/examples/simple.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash set -ex yosys -p "tcl ../synth/synth_generic.tcl 4 blinky.json" blinky.v -${NEXTPNR:-../../nextpnr-generic} --pre-pack simple.py --pre-place simple_timing.py --json blinky.json --post-route bitstream.py +${NEXTPNR:-../../nextpnr-generic} --pre-pack simple.py --pre-place simple_timing.py --json blinky.json --post-route bitstream.py --write pnrblinky.json +yosys -p "read_verilog -lib ../synth/prims.v; read_json pnrblinky.json; dump -o blinky.il; show -format png -prefix blinky" diff --git a/generic/examples/simple_timing.py b/generic/examples/simple_timing.py index 2ccb197e..1067b556 100644 --- a/generic/examples/simple_timing.py +++ b/generic/examples/simple_timing.py @@ -1,15 +1,13 @@ for cname, cell in ctx.cells: - if cell.type != "GENERIC_SLICE": - continue - if cname in ("$PACKER_GND", "$PACKER_VCC"): - continue - K = int(cell.params["K"]) - if int(cell.params["FF_USED"], 2) == 1: - ctx.addCellTimingClock(cell=cname, port="CLK") - for i in range(K): - ctx.addCellTimingSetupHold(cell=cname, port="I[%d]" % i, clock="CLK", - setup=ctx.getDelayFromNS(0.2), hold=ctx.getDelayFromNS(0)) - ctx.addCellTimingClockToOut(cell=cname, port="Q", clock="CLK", clktoq=ctx.getDelayFromNS(0.2)) - else: - for i in range(K): - ctx.addCellTimingDelay(cell=cname, fromPort="I[%d]" % i, toPort="Q", delay=ctx.getDelayFromNS(0.2))
\ No newline at end of file + if cell.type != "GENERIC_SLICE": + continue + if cname in ("$PACKER_GND", "$PACKER_VCC"): + continue + K = int(cell.params["K"]) + ctx.addCellTimingClock(cell=cname, port="CLK") + for i in range(K): + ctx.addCellTimingSetupHold(cell=cname, port="I[%d]" % i, clock="CLK", + setup=ctx.getDelayFromNS(0.2), hold=ctx.getDelayFromNS(0)) + ctx.addCellTimingClockToOut(cell=cname, port="Q", clock="CLK", clktoq=ctx.getDelayFromNS(0.2)) + for i in range(K): + ctx.addCellTimingDelay(cell=cname, fromPort="I[%d]" % i, toPort="F", delay=ctx.getDelayFromNS(0.2)) diff --git a/generic/pack.cc b/generic/pack.cc index 3dc12bc1..69f248d2 100644 --- a/generic/pack.cc +++ b/generic/pack.cc @@ -154,16 +154,16 @@ static void pack_constants(Context *ctx) std::unique_ptr<NetInfo> gnd_net = std::unique_ptr<NetInfo>(new NetInfo); gnd_net->name = ctx->id("$PACKER_GND_NET"); gnd_net->driver.cell = gnd_cell.get(); - gnd_net->driver.port = ctx->id("Q"); - gnd_cell->ports.at(ctx->id("Q")).net = gnd_net.get(); + gnd_net->driver.port = ctx->id("F"); + gnd_cell->ports.at(ctx->id("F")).net = gnd_net.get(); std::unique_ptr<CellInfo> vcc_cell = create_generic_cell(ctx, ctx->id("GENERIC_SLICE"), "$PACKER_VCC"); vcc_cell->params[ctx->id("INIT")] = 1; std::unique_ptr<NetInfo> vcc_net = std::unique_ptr<NetInfo>(new NetInfo); vcc_net->name = ctx->id("$PACKER_VCC_NET"); vcc_net->driver.cell = vcc_cell.get(); - vcc_net->driver.port = ctx->id("Q"); - vcc_cell->ports.at(ctx->id("Q")).net = vcc_net.get(); + vcc_net->driver.port = ctx->id("F"); + vcc_cell->ports.at(ctx->id("F")).net = vcc_net.get(); std::vector<IdString> dead_nets; diff --git a/generic/synth/prims.v b/generic/synth/prims.v index 95fcfac7..1148041c 100644 --- a/generic/synth/prims.v +++ b/generic/synth/prims.v @@ -25,17 +25,16 @@ module GENERIC_SLICE #( ) ( input CLK, input [K-1:0] I, + output F, output Q ); + wire f_wire; - wire lut_q; - LUT #(.K(K), .INIT(INIT)) lut_i(.I(I), .Q(lut_q)); + LUT #(.K(K), .INIT(INIT)) lut_i(.I(I), .Q(f_wire)); - generate if (FF_USED) - DFF dff_i(.CLK(CLK), .D(lut_q), .Q(Q)); - else - assign Q = lut_q; - endgenerate + DFF dff_i(.CLK(CLK), .D(f_wire), .Q(Q)); + + assign F = f_wire; endmodule module GENERIC_IOB #( @@ -56,4 +55,4 @@ module GENERIC_IOB #( generate if (INPUT_USED) assign O = PAD; endgenerate -endmodule
\ No newline at end of file +endmodule diff --git a/ice40/family.cmake b/ice40/family.cmake index f22883fb..e31fce2d 100644 --- a/ice40/family.cmake +++ b/ice40/family.cmake @@ -40,14 +40,6 @@ if (NOT EXTERNAL_CHIPDB) set(DEV_CC_DB ${CMAKE_CURRENT_BINARY_DIR}/ice40/chipdbs/chipdb-${dev}.bin) set(DEV_CONSTIDS_INC ${CMAKE_CURRENT_SOURCE_DIR}/ice40/constids.inc) set(DEV_GFXH ${CMAKE_CURRENT_SOURCE_DIR}/ice40/gfx.h) - add_custom_command(OUTPUT ${DEV_CC_BBA_DB} - COMMAND ${PYTHON_EXECUTABLE} ${DB_PY} -p ${DEV_CONSTIDS_INC} -g ${DEV_GFXH} ${OPT_FAST} ${OPT_SLOW} ${DEV_TXT_DB} > ${DEV_CC_BBA_DB} - DEPENDS ${DEV_CONSTIDS_INC} ${DEV_GFXH} ${DEV_TXT_DB} ${DB_PY} ${PREV_DEV_CC_BBA_DB} - ) - add_custom_command(OUTPUT ${DEV_CC_DB} - COMMAND bbasm ${BBASM_ENDIAN_FLAG} ${DEV_CC_BBA_DB} ${DEV_CC_DB} - DEPENDS bbasm ${DEV_CC_BBA_DB} - ) if(PREGENERATED_BBA_PATH) add_custom_command(OUTPUT ${DEV_CC_DB} diff --git a/python/interactive.py b/python/interactive.py new file mode 100644 index 00000000..a2f09edb --- /dev/null +++ b/python/interactive.py @@ -0,0 +1,6 @@ +# Pass this file to one of the Python script arguments (e.g. --pre-place interactive.py) +# to drop to a command-line interactive Python session in the middle of place and route + +import code +print("Press Ctrl+D to finish interactive session") +code.interact(local=locals()) |