aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--CMakeLists.txt2
-rw-r--r--ecp5/arch.cc12
-rw-r--r--ecp5/arch.h6
-rw-r--r--ecp5/arch_place.cc24
-rw-r--r--ecp5/archdefs.h2
-rw-r--r--ecp5/bitstream.cc10
-rw-r--r--ecp5/constids.inc8
-rw-r--r--ecp5/family.cmake4
-rw-r--r--ecp5/pack.cc57
-rwxr-xr-xecp5/trellis_import.py8
-rw-r--r--generic/cells.cc14
-rw-r--r--generic/examples/bitstream.py2
-rw-r--r--generic/examples/simple.py7
-rwxr-xr-xgeneric/examples/simple.sh3
-rw-r--r--generic/examples/simple_timing.py26
-rw-r--r--generic/pack.cc8
-rw-r--r--generic/synth/prims.v15
-rw-r--r--ice40/family.cmake8
-rw-r--r--python/interactive.py6
20 files changed, 167 insertions, 58 deletions
diff --git a/.gitignore b/.gitignore
index 9b3ffd02..9796d242 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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())