aboutsummaryrefslogtreecommitdiffstats
path: root/ice40
diff options
context:
space:
mode:
authorClifford Wolf <clifford@clifford.at>2018-06-13 12:38:28 +0200
committerClifford Wolf <clifford@clifford.at>2018-06-13 12:38:28 +0200
commit145c849596bdcd24f3b4e617eeb4ee06e1b93452 (patch)
tree243d63251d31498f4e92bfdae3ae0d0f087f9957 /ice40
parent4d7f18dd98a7ef9540a279a8e27cb9dbef355af7 (diff)
parentde0918c28758b09f638e02ffc04fad989321da1b (diff)
downloadnextpnr-145c849596bdcd24f3b4e617eeb4ee06e1b93452.tar.gz
nextpnr-145c849596bdcd24f3b4e617eeb4ee06e1b93452.tar.bz2
nextpnr-145c849596bdcd24f3b4e617eeb4ee06e1b93452.zip
Merge branch 'master' of gitlab.com:SymbioticEDA/nextpnr
Diffstat (limited to 'ice40')
-rw-r--r--ice40/cells.cc36
-rw-r--r--ice40/cells.h6
-rw-r--r--ice40/chip.cc24
-rw-r--r--ice40/chip.h20
-rw-r--r--ice40/chipdb.py38
-rw-r--r--ice40/main.cc92
-rw-r--r--ice40/pack.cc55
-rw-r--r--ice40/pack_tests/io_wrapper.v169
-rwxr-xr-xice40/pack_tests/test.sh4
-rw-r--r--ice40/pcf.cc71
-rw-r--r--ice40/pcf.h33
11 files changed, 306 insertions, 242 deletions
diff --git a/ice40/cells.cc b/ice40/cells.cc
index ad728d2c..b038db68 100644
--- a/ice40/cells.cc
+++ b/ice40/cells.cc
@@ -60,6 +60,26 @@ CellInfo *create_ice_cell(Design *design, IdString type, IdString name)
add_port(new_cell, "LO", PORT_OUT);
add_port(new_cell, "O", PORT_OUT);
add_port(new_cell, "OUT", PORT_OUT);
+ } else if (type == "SB_IO") {
+ new_cell->params["PIN_TYPE"] = "0";
+ new_cell->params["PULLUP"] = "0";
+ new_cell->params["NEG_TRIGGER"] = "0";
+ new_cell->params["IOSTANDARD"] = "SB_LVCMOS";
+
+ add_port(new_cell, "PACKAGE_PIN", PORT_INOUT);
+
+ add_port(new_cell, "LATCH_INPUT_VALUE", PORT_IN);
+ add_port(new_cell, "CLOCK_ENABLE", PORT_IN);
+ add_port(new_cell, "INPUT_CLK", PORT_IN);
+ add_port(new_cell, "OUTPUT_CLK", PORT_IN);
+
+ add_port(new_cell, "OUTPUT_ENABLE", PORT_IN);
+ add_port(new_cell, "D_OUT_0", PORT_IN);
+ add_port(new_cell, "D_OUT_1", PORT_IN);
+
+ add_port(new_cell, "D_IN_0", PORT_OUT);
+ add_port(new_cell, "D_IN_1", PORT_OUT);
+
} else {
log_error("unable to create iCE40 cell of type %s", type.c_str());
}
@@ -128,4 +148,20 @@ void dff_to_lc(CellInfo *dff, CellInfo *lc, bool pass_thru_lut)
replace_port(dff, "Q", lc, "O");
}
+void nxio_to_sb(CellInfo *nxio, CellInfo *sbio)
+{
+ if (nxio->type == "$nextpnr_ibuf") {
+ sbio->params["PIN_TYPE"] = "1";
+ auto pu_attr = nxio->attrs.find("PULLUP");
+ if (pu_attr != nxio->attrs.end())
+ sbio->params["PULLUP"] = pu_attr->second;
+ replace_port(nxio, "O", sbio, "D_IN_0");
+ } else if (nxio->type == "$nextpnr_obuf") {
+ sbio->params["PIN_TYPE"] = "25";
+ replace_port(nxio, "I", sbio, "D_OUT_0");
+ } else {
+ assert(false);
+ }
+}
+
NEXTPNR_NAMESPACE_END
diff --git a/ice40/cells.h b/ice40/cells.h
index 34a034cd..3cf0b718 100644
--- a/ice40/cells.h
+++ b/ice40/cells.h
@@ -47,6 +47,9 @@ inline bool is_ff(const CellInfo *cell)
cell->type == "SB_DFFNESS" || cell->type == "SB_DFFNES";
}
+// Return true if a cell is a SB_IO
+inline bool is_sb_io(const CellInfo *cell) { return cell->type == "SB_IO"; }
+
// 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
@@ -58,6 +61,9 @@ void lut_to_lc(CellInfo *lut, CellInfo *lc, bool no_dff = true);
// ignored
void dff_to_lc(CellInfo *dff, CellInfo *lc, bool pass_thru_lut = false);
+// Convert a nextpnr IO buffer to a SB_IO
+void nxio_to_sb(CellInfo *nxio, CellInfo *sbio);
+
NEXTPNR_NAMESPACE_END
#endif
diff --git a/ice40/chip.cc b/ice40/chip.cc
index de33b020..441e65f2 100644
--- a/ice40/chip.cc
+++ b/ice40/chip.cc
@@ -99,6 +99,16 @@ Chip::Chip(ChipArgs args) : args(args)
}
#endif
+ package_info = nullptr;
+ for (int i = 0; i < chip_info.num_packages; i++) {
+ if (chip_info.packages_data[i].name == args.package) {
+ package_info = &(chip_info.packages_data[i]);
+ break;
+ }
+ }
+ if (package_info == nullptr)
+ log_error("Unsupported package '%s'.\n", args.package.c_str());
+
bel_to_cell.resize(chip_info.num_bels);
wire_to_net.resize(chip_info.num_wires);
pip_to_net.resize(chip_info.num_pips);
@@ -231,6 +241,20 @@ PipId Chip::getPipByName(IdString name) const
// -----------------------------------------------------------------------
+BelId Chip::getPackagePinBel(const std::string &pin) const
+{
+ for (int i = 0; i < package_info->num_pins; i++) {
+ if (package_info->pins[i].name == pin) {
+ BelId id;
+ id.index = package_info->pins[i].bel_index;
+ return id;
+ }
+ }
+ return BelId();
+}
+
+// -----------------------------------------------------------------------
+
PosInfo Chip::getBelPosition(BelId bel) const
{
PosInfo pos;
diff --git a/ice40/chip.h b/ice40/chip.h
index 2c95bf4e..5eea1b8e 100644
--- a/ice40/chip.h
+++ b/ice40/chip.h
@@ -118,6 +118,19 @@ struct WireInfoPOD
float x, y;
};
+struct PackagePinPOD
+{
+ const char *name;
+ int32_t bel_index;
+};
+
+struct PackageInfoPOD
+{
+ const char *name;
+ int num_pins;
+ PackagePinPOD *pins;
+};
+
enum TileType
{
TILE_NONE = 0,
@@ -173,12 +186,13 @@ struct ChipInfoPOD
{
int width, height;
int num_bels, num_wires, num_pips;
- int num_switches;
+ int num_switches, num_packages;
BelInfoPOD *bel_data;
WireInfoPOD *wire_data;
PipInfoPOD *pip_data;
TileType *tile_grid;
BitstreamInfoPOD *bits_info;
+ PackageInfoPOD *packages_data;
};
extern ChipInfoPOD chip_info_384;
@@ -417,11 +431,13 @@ struct ChipArgs
HX8K,
UP5K
} type = NONE;
+ std::string package;
};
struct Chip
{
ChipInfoPOD chip_info;
+ PackageInfoPOD *package_info;
mutable std::unordered_map<IdString, int> bel_by_name;
mutable std::unordered_map<IdString, int> wire_by_name;
@@ -682,6 +698,8 @@ struct Chip
return range;
}
+ BelId getPackagePinBel(const std::string &pin) const;
+
// -------------------------------------------------
PosInfo getBelPosition(BelId bel) const;
diff --git a/ice40/chipdb.py b/ice40/chipdb.py
index 9b246f8b..946197d3 100644
--- a/ice40/chipdb.py
+++ b/ice40/chipdb.py
@@ -23,6 +23,8 @@ switches = list()
ierens = list()
+packages = list()
+
wire_uphill_belport = dict()
wire_downhill_belports = dict()
@@ -123,6 +125,11 @@ with open(sys.argv[1], "r") as f:
mode = ("ieren",)
continue
+ if line[0] == ".pins":
+ mode = ("pins", line[1])
+ packages.append((line[1], []))
+ continue
+
if (line[0][0] == ".") or (mode is None):
mode = None
continue
@@ -157,9 +164,16 @@ with open(sys.argv[1], "r") as f:
assert m
bits.append((int(m.group(1)), int(m.group(2))))
tile_bits[mode[1]].append((name, bits))
+ continue
if mode[0] == "ieren":
ierens.append(tuple([int(_) for _ in line]))
+ continue
+
+ if mode[0] == "pins":
+ packages[-1][1].append((line[0], int(line[1]), int(line[2]), int(line[3])))
+ continue
+
def add_bel_input(bel, wire, port):
if wire not in wire_downhill_belports:
wire_downhill_belports[wire] = set()
@@ -392,6 +406,21 @@ for wire in range(num_wires):
wireinfo.append(info)
+packageinfo = []
+
+for package in packages:
+ name, pins = package
+ pins_info = []
+ for pin in pins:
+ pinname, x, y, z = pin
+ pin_bel = "%d_%d_io%d" % (x, y, z)
+ bel_idx = bel_name.index(pin_bel)
+ pins_info.append('{"%s", %d}' % (pinname, bel_idx))
+ print("static PackagePinPOD package_%s_pins[%d] = {" % (name, len(pins_info)))
+ print(",\n".join(pins_info))
+ print("};")
+ packageinfo.append('{"%s", %d, package_%s_pins}' % (name, len(pins_info), name))
+
tilegrid = []
for y in range(dev_height):
for x in range(dev_width):
@@ -460,13 +489,18 @@ print("static TileType tile_grid_%s[%d] = {" % (dev_name, len(tilegrid)))
print(",\n".join(tilegrid))
print("};")
+
+print("static PackageInfoPOD package_info_%s[%d] = {" % (dev_name, len(packageinfo)))
+print(",\n".join(packageinfo))
+print("};")
+
print('}')
print('NEXTPNR_NAMESPACE_BEGIN')
print("ChipInfoPOD chip_info_%s = {" % dev_name)
-print(" %d, %d, %d, %d, %d, %d," % (dev_width, dev_height, len(bel_name), num_wires, len(pipinfo), len(switchinfo)))
+print(" %d, %d, %d, %d, %d, %d, %d," % (dev_width, dev_height, len(bel_name), num_wires, len(pipinfo), len(switchinfo), len(packageinfo)))
print(" bel_data_%s, wire_data_%s, pip_data_%s," % (dev_name, dev_name, dev_name))
-print(" tile_grid_%s, &bits_info_%s" % (dev_name, dev_name))
+print(" tile_grid_%s, &bits_info_%s, package_info_%s" % (dev_name, dev_name, dev_name))
print("};")
print('NEXTPNR_NAMESPACE_END')
diff --git a/ice40/main.cc b/ice40/main.cc
index 0e989819..8ccec77b 100644
--- a/ice40/main.cc
+++ b/ice40/main.cc
@@ -17,7 +17,7 @@
*
*/
-#ifndef PYTHON_MODULE
+#ifdef MAIN_EXECUTABLE
#include <QApplication>
#include <boost/filesystem/convenience.hpp>
@@ -30,6 +30,7 @@
#include "mainwindow.h"
#include "nextpnr.h"
#include "pack.h"
+#include "pcf.h"
#include "place.h"
#include "pybindings.h"
#include "route.h"
@@ -65,10 +66,8 @@ int main(int argc, char *argv[])
po::options_description options("Allowed options");
options.add_options()("help,h", "show help");
- options.add_options()("test", "just a check");
options.add_options()("gui", "start gui");
options.add_options()("svg", "dump SVG file");
- options.add_options()("pack", "pack design prior to place and route");
options.add_options()("pack-only",
"pack design only without placement or routing");
@@ -76,6 +75,8 @@ int main(int argc, char *argv[])
"python file to execute");
options.add_options()("json", po::value<std::string>(),
"JSON design file to ingest");
+ options.add_options()("pcf", po::value<std::string>(),
+ "PCF constraints file to ingest");
options.add_options()("asc", po::value<std::string>(),
"asc bitstream file to write");
options.add_options()("version,v", "show version");
@@ -85,7 +86,8 @@ int main(int argc, char *argv[])
options.add_options()("hx1k", "set device type to iCE40HX1K");
options.add_options()("hx8k", "set device type to iCE40HX8K");
options.add_options()("up5k", "set device type to iCE40UP5K");
-
+ options.add_options()("package", po::value<std::string>(),
+ "set device package");
po::positional_options_description pos;
pos.add("run", -1);
@@ -129,41 +131,48 @@ int main(int argc, char *argv[])
if (chipArgs.type != ChipArgs::NONE)
goto help;
chipArgs.type = ChipArgs::LP384;
+ chipArgs.package = "qn32";
}
if (vm.count("lp1k")) {
if (chipArgs.type != ChipArgs::NONE)
goto help;
chipArgs.type = ChipArgs::LP1K;
+ chipArgs.package = "tq144";
}
if (vm.count("lp8k")) {
if (chipArgs.type != ChipArgs::NONE)
goto help;
chipArgs.type = ChipArgs::LP8K;
+ chipArgs.package = "ct256";
}
if (vm.count("hx1k")) {
if (chipArgs.type != ChipArgs::NONE)
goto help;
chipArgs.type = ChipArgs::HX1K;
+ chipArgs.package = "tq144";
}
if (vm.count("hx8k")) {
if (chipArgs.type != ChipArgs::NONE)
goto help;
chipArgs.type = ChipArgs::HX8K;
+ chipArgs.package = "ct256";
}
if (vm.count("up5k")) {
if (chipArgs.type != ChipArgs::NONE)
goto help;
chipArgs.type = ChipArgs::UP5K;
+ chipArgs.package = "sg48";
}
- if (chipArgs.type == ChipArgs::NONE)
+ if (chipArgs.type == ChipArgs::NONE) {
chipArgs.type = ChipArgs::HX1K;
-
+ chipArgs.package = "tq144";
+ }
#ifdef ICE40_HX1K_ONLY
if (chipArgs.type != ChipArgs::HX1K) {
std::cout << "This version of nextpnr-ice40 is built with HX1K-support "
@@ -172,71 +181,14 @@ int main(int argc, char *argv[])
}
#endif
+ if (vm.count("package"))
+ chipArgs.package = vm["package"].as<std::string>();
+
Design design(chipArgs);
init_python(argv[0]);
python_export_global("design", design);
python_export_global("chip", design.chip);
- if (vm.count("test")) {
- int bel_count = 0, wire_count = 0, pip_count = 0;
-
- std::cout << "Checking bel names.\n";
- for (auto bel : design.chip.getBels()) {
- auto name = design.chip.getBelName(bel);
- assert(bel == design.chip.getBelByName(name));
- bel_count++;
- }
- std::cout << " checked " << bel_count << " bels.\n";
-
- std::cout << "Checking wire names.\n";
- for (auto wire : design.chip.getWires()) {
- auto name = design.chip.getWireName(wire);
- assert(wire == design.chip.getWireByName(name));
- wire_count++;
- }
- std::cout << " checked " << wire_count << " wires.\n";
-
- std::cout << "Checking pip names.\n";
- for (auto pip : design.chip.getPips()) {
- auto name = design.chip.getPipName(pip);
- assert(pip == design.chip.getPipByName(name));
- pip_count++;
- }
- std::cout << " checked " << pip_count << " pips.\n";
-
- std::cout << "Checking uphill -> downhill consistency.\n";
- for (auto dst : design.chip.getWires()) {
- for (auto uphill_pip : design.chip.getPipsUphill(dst)) {
- bool found_downhill = false;
- for (auto downhill_pip : design.chip.getPipsDownhill(
- design.chip.getPipSrcWire(uphill_pip))) {
- if (uphill_pip == downhill_pip) {
- assert(!found_downhill);
- found_downhill = true;
- }
- }
- assert(found_downhill);
- }
- }
-
- std::cout << "Checking downhill -> uphill consistency.\n";
- for (auto dst : design.chip.getWires()) {
- for (auto downhill_pip : design.chip.getPipsDownhill(dst)) {
- bool found_uphill = false;
- for (auto uphill_pip : design.chip.getPipsUphill(
- design.chip.getPipDstWire(downhill_pip))) {
- if (uphill_pip == downhill_pip) {
- assert(!found_uphill);
- found_uphill = true;
- }
- }
- assert(found_uphill);
- }
- }
-
- return 0;
- }
-
if (vm.count("svg")) {
std::cout << "<svg xmlns=\"http://www.w3.org/2000/svg\" "
"xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n";
@@ -256,9 +208,13 @@ int main(int argc, char *argv[])
std::istream *f = new std::ifstream(filename);
parse_json_file(f, filename, &design);
- if (vm.count("pack") || vm.count("pack-only")) {
- pack_design(&design);
+
+ if (vm.count("pcf")) {
+ std::ifstream pcf(vm["pcf"].as<std::string>());
+ apply_pcf(&design, pcf);
}
+
+ pack_design(&design);
if (!vm.count("pack-only")) {
place_design(&design);
route_design(&design);
diff --git a/ice40/pack.cc b/ice40/pack.cc
index 8f770a07..72dcadea 100644
--- a/ice40/pack.cc
+++ b/ice40/pack.cc
@@ -134,10 +134,65 @@ static void pack_constants(Design *design)
}
}
+static bool is_nextpnr_iob(CellInfo *cell)
+{
+ return cell->type == "$nextpnr_ibuf" || cell->type == "$nextpnr_obuf" ||
+ cell->type == "$nextpnr_iobuf";
+}
+
+// Pack IO buffers
+static void pack_io(Design *design)
+{
+ std::unordered_set<IdString> packed_cells;
+ std::vector<CellInfo *> new_cells;
+
+ for (auto cell : design->cells) {
+ CellInfo *ci = cell.second;
+ if (is_nextpnr_iob(ci)) {
+ CellInfo *sb = nullptr;
+ if (ci->type == "$nextpnr_ibuf" || ci->type == "$nextpnr_iobuf") {
+ sb = net_only_drives(ci->ports.at("O").net, is_sb_io,
+ "PACKAGE_PIN", true, ci);
+
+ } else if (ci->type == "$nextpnr_obuf") {
+ sb = net_only_drives(ci->ports.at("I").net, is_sb_io,
+ "PACKAGE_PIN", true, ci);
+ }
+ if (sb != nullptr) {
+ // Trivial case, SB_IO used. Just destroy the net and the
+ // iobuf
+ log_info("%s feeds SB_IO %s, removing %s %s.\n",
+ ci->name.c_str(), sb->name.c_str(), ci->type.c_str(),
+ ci->name.c_str());
+ NetInfo *net = sb->ports.at("PACKAGE_PIN").net;
+ if (net != nullptr) {
+ design->nets.erase(net->name);
+ sb->ports.at("PACKAGE_PIN").net = nullptr;
+ }
+ } else {
+ // Create a SB_IO buffer
+ sb = create_ice_cell(design, "SB_IO");
+ nxio_to_sb(ci, sb);
+ new_cells.push_back(sb);
+ }
+ packed_cells.insert(ci->name);
+ std::copy(ci->attrs.begin(), ci->attrs.end(),
+ std::inserter(sb->attrs, sb->attrs.begin()));
+ }
+ }
+ for (auto pcell : packed_cells) {
+ design->cells.erase(pcell);
+ }
+ for (auto ncell : new_cells) {
+ design->cells[ncell->name] = ncell;
+ }
+}
+
// Main pack function
void pack_design(Design *design)
{
pack_constants(design);
+ pack_io(design);
pack_lut_lutffs(design);
pack_nonlut_ffs(design);
}
diff --git a/ice40/pack_tests/io_wrapper.v b/ice40/pack_tests/io_wrapper.v
deleted file mode 100644
index b58d6c0c..00000000
--- a/ice40/pack_tests/io_wrapper.v
+++ /dev/null
@@ -1,169 +0,0 @@
-module io_wrapper(input clk_pin, cen_pin, rst_pin, ina_pin, inb_pin,
- output outa_pin, outb_pin, outc_pin, outd_pin);
-
- wire clk, cen, rst, ina, inb, outa, outb, outc, outd;
-
- (* BEL="0_14_io1" *)
- SB_IO #(
- .PIN_TYPE(6'b 0000_01),
- .PULLUP(1'b0),
- .NEG_TRIGGER(1'b0)
- ) clk_iob (
- .PACKAGE_PIN(clk_pin),
- .LATCH_INPUT_VALUE(),
- .CLOCK_ENABLE(),
- .INPUT_CLK(),
- .OUTPUT_CLK(),
- .OUTPUT_ENABLE(),
- .D_OUT_0(),
- .D_OUT_1(),
- .D_IN_0(clk),
- .D_IN_1()
- );
-
- (* BEL="0_14_io0" *)
- SB_IO #(
- .PIN_TYPE(6'b 0000_01),
- .PULLUP(1'b0),
- .NEG_TRIGGER(1'b0)
- ) cen_iob (
- .PACKAGE_PIN(cen_pin),
- .LATCH_INPUT_VALUE(),
- .CLOCK_ENABLE(),
- .INPUT_CLK(),
- .OUTPUT_CLK(),
- .OUTPUT_ENABLE(),
- .D_OUT_0(),
- .D_OUT_1(),
- .D_IN_0(cen),
- .D_IN_1()
- );
-
- (* BEL="0_13_io1" *)
- SB_IO #(
- .PIN_TYPE(6'b 0000_01),
- .PULLUP(1'b0),
- .NEG_TRIGGER(1'b0)
- ) rst_iob (
- .PACKAGE_PIN(rst_pin),
- .LATCH_INPUT_VALUE(),
- .CLOCK_ENABLE(),
- .INPUT_CLK(),
- .OUTPUT_CLK(),
- .OUTPUT_ENABLE(),
- .D_OUT_0(),
- .D_OUT_1(),
- .D_IN_0(rst),
- .D_IN_1()
- );
-
- (* BEL="0_13_io0" *)
- SB_IO #(
- .PIN_TYPE(6'b 0000_01),
- .PULLUP(1'b0),
- .NEG_TRIGGER(1'b0)
- ) ina_iob (
- .PACKAGE_PIN(ina_pin),
- .LATCH_INPUT_VALUE(),
- .CLOCK_ENABLE(),
- .INPUT_CLK(),
- .OUTPUT_CLK(),
- .OUTPUT_ENABLE(),
- .D_OUT_0(),
- .D_OUT_1(),
- .D_IN_0(ina),
- .D_IN_1()
- );
-
- (* BEL="0_12_io1" *)
- SB_IO #(
- .PIN_TYPE(6'b 0000_01),
- .PULLUP(1'b0),
- .NEG_TRIGGER(1'b0)
- ) inb_iob (
- .PACKAGE_PIN(inb_pin),
- .LATCH_INPUT_VALUE(),
- .CLOCK_ENABLE(),
- .INPUT_CLK(),
- .OUTPUT_CLK(),
- .OUTPUT_ENABLE(),
- .D_OUT_0(),
- .D_OUT_1(),
- .D_IN_0(inb),
- .D_IN_1()
- );
-
- (* BEL="0_12_io0" *)
- SB_IO #(
- .PIN_TYPE(6'b 0110_01),
- .PULLUP(1'b0),
- .NEG_TRIGGER(1'b0)
- ) outa_iob (
- .PACKAGE_PIN(outa_pin),
- .LATCH_INPUT_VALUE(),
- .CLOCK_ENABLE(),
- .INPUT_CLK(),
- .OUTPUT_CLK(),
- .OUTPUT_ENABLE(),
- .D_OUT_0(outa),
- .D_OUT_1(),
- .D_IN_0(),
- .D_IN_1()
- );
-
- (* BEL="0_11_io1" *)
- SB_IO #(
- .PIN_TYPE(6'b 0110_01),
- .PULLUP(1'b0),
- .NEG_TRIGGER(1'b0)
- ) outb_iob (
- .PACKAGE_PIN(outb_pin),
- .LATCH_INPUT_VALUE(),
- .CLOCK_ENABLE(),
- .INPUT_CLK(),
- .OUTPUT_CLK(),
- .OUTPUT_ENABLE(),
- .D_OUT_0(outb),
- .D_OUT_1(),
- .D_IN_0(),
- .D_IN_1()
- );
-
- (* BEL="0_11_io0" *)
- SB_IO #(
- .PIN_TYPE(6'b 0110_01),
- .PULLUP(1'b0),
- .NEG_TRIGGER(1'b0)
- ) outc_iob (
- .PACKAGE_PIN(outc_pin),
- .LATCH_INPUT_VALUE(),
- .CLOCK_ENABLE(),
- .INPUT_CLK(),
- .OUTPUT_CLK(),
- .OUTPUT_ENABLE(),
- .D_OUT_0(outc),
- .D_OUT_1(),
- .D_IN_0(),
- .D_IN_1()
- );
-
- (* BEL="0_10_io1" *)
- SB_IO #(
- .PIN_TYPE(6'b 0110_01),
- .PULLUP(1'b0),
- .NEG_TRIGGER(1'b0)
- ) outd_iob (
- .PACKAGE_PIN(outa_pin),
- .LATCH_INPUT_VALUE(),
- .CLOCK_ENABLE(),
- .INPUT_CLK(),
- .OUTPUT_CLK(),
- .OUTPUT_ENABLE(),
- .D_OUT_0(outd),
- .D_OUT_1(),
- .D_IN_0(),
- .D_IN_1()
- );
-
- top top_i(.clk(clk), .rst(rst), .cen(cen), .ina(ina), .inb(inb), .outa(outa), .outb(outb), .outc(outc), .outd(outd));
-endmodule
diff --git a/ice40/pack_tests/test.sh b/ice40/pack_tests/test.sh
index dd1f345c..b36c01dc 100755
--- a/ice40/pack_tests/test.sh
+++ b/ice40/pack_tests/test.sh
@@ -1,8 +1,8 @@
#!/usr/bin/env bash
set -ex
NAME=${1%.v}
-yosys -p "synth_ice40 -nocarry -top io_wrapper; write_json ${NAME}.json" $1 io_wrapper.v
-../../nextpnr-ice40 --json ${NAME}.json --pack --asc ${NAME}.asc
+yosys -p "synth_ice40 -nocarry -top top; write_json ${NAME}.json" $1
+../../nextpnr-ice40 --json ${NAME}.json --pcf test.pcf --asc ${NAME}.asc
icebox_vlog -p test.pcf ${NAME}.asc > ${NAME}_out.v
yosys -p "read_verilog +/ice40/cells_sim.v;\
diff --git a/ice40/pcf.cc b/ice40/pcf.cc
new file mode 100644
index 00000000..75c32731
--- /dev/null
+++ b/ice40/pcf.cc
@@ -0,0 +1,71 @@
+/*
+ * nextpnr -- Next Generation Place and Route
+ *
+ * Copyright (C) 2018 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "pcf.h"
+#include <sstream>
+#include "log.h"
+
+NEXTPNR_NAMESPACE_BEGIN
+
+// Read a w
+
+// Apply PCF constraints to a pre-packing design
+void apply_pcf(Design *design, std::istream &in)
+{
+ if (!in)
+ log_error("failed to open PCF file");
+ std::string line;
+ while (std::getline(in, line)) {
+ size_t cstart = line.find("#");
+ if (cstart != std::string::npos)
+ line = line.substr(0, cstart);
+ std::stringstream ss(line);
+ std::vector<std::string> words;
+ std::string tmp;
+ while (ss >> tmp)
+ words.push_back(tmp);
+ if (words.size() == 0)
+ continue;
+ std::string cmd = words.at(0);
+ if (cmd == "set_io") {
+ 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 pin = words.at(args_end + 1);
+ auto fnd_cell = design->cells.find(cell);
+ if (fnd_cell == design->cells.end()) {
+ log_warning("unmatched pcf constraint %s\n", cell.c_str());
+ } else {
+ BelId pin_bel = design->chip.getPackagePinBel(pin);
+ if (pin_bel == BelId())
+ log_error("package does not have a pin named %s\n",
+ pin.c_str());
+ fnd_cell->second->attrs["BEL"] =
+ design->chip.getBelName(pin_bel).str();
+ log_info("constrained '%s' to bel '%s'\n", cell.c_str(),
+ fnd_cell->second->attrs["BEL"].c_str());
+ }
+ } else {
+ log_error("unsupported pcf command '%s'\n", cmd.c_str());
+ }
+ }
+}
+
+NEXTPNR_NAMESPACE_END
diff --git a/ice40/pcf.h b/ice40/pcf.h
new file mode 100644
index 00000000..c4a7d991
--- /dev/null
+++ b/ice40/pcf.h
@@ -0,0 +1,33 @@
+/*
+ * nextpnr -- Next Generation Place and Route
+ *
+ * Copyright (C) 2018 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#ifndef PCF_H
+#define PCF_H
+
+#include <iostream>
+#include "nextpnr.h"
+
+NEXTPNR_NAMESPACE_BEGIN
+
+// Apply PCF constraints to a pre-packing design
+void apply_pcf(Design *design, std::istream &in);
+
+NEXTPNR_NAMESPACE_END
+
+#endif // ROUTE_H