From 9953012154f18ea51ff9216529089715ba79fb41 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Tue, 12 Jun 2018 19:56:03 +0200 Subject: reveresed logic for enabling main file, and made tests link arch files --- ice40/main.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ice40') diff --git a/ice40/main.cc b/ice40/main.cc index 0e989819..c89079cf 100644 --- a/ice40/main.cc +++ b/ice40/main.cc @@ -17,7 +17,7 @@ * */ -#ifndef PYTHON_MODULE +#ifdef MAIN_EXECUTABLE #include #include -- cgit v1.2.3 From b7c747f15bcad48f4e1b82704bc9d00c28b9d62d Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Tue, 12 Jun 2018 20:39:20 +0200 Subject: Write tests to replace -test option from main --- ice40/main.cc | 61 ----------------------------------------------------------- 1 file changed, 61 deletions(-) (limited to 'ice40') diff --git a/ice40/main.cc b/ice40/main.cc index c89079cf..6bda4d78 100644 --- a/ice40/main.cc +++ b/ice40/main.cc @@ -65,7 +65,6 @@ 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"); @@ -177,66 +176,6 @@ int main(int argc, char *argv[]) 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 << "\n"; -- cgit v1.2.3 From a76f5c5678980c8b2e958252a68ba03676d63229 Mon Sep 17 00:00:00 2001 From: David Shah Date: Wed, 13 Jun 2018 10:50:05 +0200 Subject: Remove IO buffers when fed by SB_IO Signed-off-by: David Shah --- ice40/cells.h | 3 +++ ice40/pack.cc | 59 +++++++++++++++++++++++++++++++++++++++++++ ice40/pack_tests/io_wrapper.v | 2 +- 3 files changed, 63 insertions(+), 1 deletion(-) (limited to 'ice40') diff --git a/ice40/cells.h b/ice40/cells.h index 34a034cd..da4e2bd8 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 diff --git a/ice40/pack.cc b/ice40/pack.cc index 8f770a07..73ba0e3d 100644 --- a/ice40/pack.cc +++ b/ice40/pack.cc @@ -134,10 +134,69 @@ 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 packed_cells; + std::vector new_cells; + + for (auto cell : design->cells) { + CellInfo *ci = cell.second; + if (is_nextpnr_iob(ci)) { + if (ci->type == "$nextpnr_ibuf" || ci->type == "$nextpnr_iobuf") { + CellInfo *sb = net_only_drives(ci->ports.at("O").net, is_sb_io, + "PACKAGE_PIN", true, ci); + if (sb != nullptr) { + // Trivial case, SB_IO used. Just destroy the net and the + // iobuf + packed_cells.insert(ci->name); + 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 if (ci->type == "$nextpnr_obuf") { + CellInfo *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 + packed_cells.insert(ci->name); + 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; + } + } + } + } + } + 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 index b58d6c0c..e10ec419 100644 --- a/ice40/pack_tests/io_wrapper.v +++ b/ice40/pack_tests/io_wrapper.v @@ -153,7 +153,7 @@ module io_wrapper(input clk_pin, cen_pin, rst_pin, ina_pin, inb_pin, .PULLUP(1'b0), .NEG_TRIGGER(1'b0) ) outd_iob ( - .PACKAGE_PIN(outa_pin), + .PACKAGE_PIN(outd_pin), .LATCH_INPUT_VALUE(), .CLOCK_ENABLE(), .INPUT_CLK(), -- cgit v1.2.3 From 94eea289ae0fb4d262276d17c474ade3ef21634b Mon Sep 17 00:00:00 2001 From: David Shah Date: Wed, 13 Jun 2018 11:08:20 +0200 Subject: Simple IO buffer insertion, enable packer by default Signed-off-by: David Shah --- ice40/cells.cc | 36 ++++++++++++++++++++++++++++++++++++ ice40/cells.h | 3 +++ ice40/main.cc | 5 +---- ice40/pack.cc | 54 +++++++++++++++++++++++++----------------------------- 4 files changed, 65 insertions(+), 33 deletions(-) (limited to 'ice40') 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 da4e2bd8..3cf0b718 100644 --- a/ice40/cells.h +++ b/ice40/cells.h @@ -61,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/main.cc b/ice40/main.cc index 6bda4d78..8c418cae 100644 --- a/ice40/main.cc +++ b/ice40/main.cc @@ -67,7 +67,6 @@ int main(int argc, char *argv[]) options.add_options()("help,h", "show help"); 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"); @@ -195,9 +194,7 @@ 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); - } + 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 73ba0e3d..72dcadea 100644 --- a/ice40/pack.cc +++ b/ice40/pack.cc @@ -149,39 +149,35 @@ static void pack_io(Design *design) 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") { - CellInfo *sb = net_only_drives(ci->ports.at("O").net, is_sb_io, - "PACKAGE_PIN", true, ci); - if (sb != nullptr) { - // Trivial case, SB_IO used. Just destroy the net and the - // iobuf - packed_cells.insert(ci->name); - 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; - } - } + sb = net_only_drives(ci->ports.at("O").net, is_sb_io, + "PACKAGE_PIN", true, ci); + } else if (ci->type == "$nextpnr_obuf") { - CellInfo *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 - packed_cells.insert(ci->name); - 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; - } + 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) { -- cgit v1.2.3 From 696aaee24c3e859283e79f9a753e8402524d8f2b Mon Sep 17 00:00:00 2001 From: David Shah Date: Wed, 13 Jun 2018 11:40:28 +0200 Subject: ice40: Add package pins to database Signed-off-by: David Shah --- ice40/chip.h | 17 ++++++++++++++++- ice40/chipdb.py | 38 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 52 insertions(+), 3 deletions(-) (limited to 'ice40') diff --git a/ice40/chip.h b/ice40/chip.h index f8946610..e1fc09a6 100644 --- a/ice40/chip.h +++ b/ice40/chip.h @@ -113,6 +113,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, @@ -168,12 +181,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; @@ -412,6 +426,7 @@ struct ChipArgs HX8K, UP5K } type = NONE; + std::string package; }; struct Chip 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') -- cgit v1.2.3 From 5435a970246081f9239bca86519aed4c12ad0a03 Mon Sep 17 00:00:00 2001 From: David Shah Date: Wed, 13 Jun 2018 11:51:09 +0200 Subject: ice40: Add package selection Signed-off-by: David Shah --- ice40/chip.cc | 10 ++++++++++ ice40/chip.h | 1 + ice40/main.cc | 17 ++++++++++++++--- 3 files changed, 25 insertions(+), 3 deletions(-) (limited to 'ice40') diff --git a/ice40/chip.cc b/ice40/chip.cc index 918a7fb4..464b226c 100644 --- a/ice40/chip.cc +++ b/ice40/chip.cc @@ -98,6 +98,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); diff --git a/ice40/chip.h b/ice40/chip.h index e1fc09a6..7d5c9fbf 100644 --- a/ice40/chip.h +++ b/ice40/chip.h @@ -432,6 +432,7 @@ struct ChipArgs struct Chip { ChipInfoPOD chip_info; + PackageInfoPOD *package_info; mutable std::unordered_map bel_by_name; mutable std::unordered_map wire_by_name; diff --git a/ice40/main.cc b/ice40/main.cc index 8c418cae..7a0d92be 100644 --- a/ice40/main.cc +++ b/ice40/main.cc @@ -83,7 +83,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(), + "set device package"); po::positional_options_description pos; pos.add("run", -1); @@ -127,41 +128,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 " @@ -170,6 +178,9 @@ int main(int argc, char *argv[]) } #endif + if (vm.count("package")) + chipArgs.package = vm["package"].as(); + Design design(chipArgs); init_python(argv[0]); python_export_global("design", design); -- cgit v1.2.3 From de0918c28758b09f638e02ffc04fad989321da1b Mon Sep 17 00:00:00 2001 From: David Shah Date: Wed, 13 Jun 2018 12:30:15 +0200 Subject: ice40: Add a PCF parser Signed-off-by: David Shah --- ice40/chip.cc | 14 ++++ ice40/chip.h | 2 + ice40/main.cc | 9 +++ ice40/pack_tests/io_wrapper.v | 169 ------------------------------------------ ice40/pack_tests/test.sh | 4 +- ice40/pcf.cc | 71 ++++++++++++++++++ ice40/pcf.h | 33 +++++++++ 7 files changed, 131 insertions(+), 171 deletions(-) delete mode 100644 ice40/pack_tests/io_wrapper.v create mode 100644 ice40/pcf.cc create mode 100644 ice40/pcf.h (limited to 'ice40') diff --git a/ice40/chip.cc b/ice40/chip.cc index 464b226c..267976eb 100644 --- a/ice40/chip.cc +++ b/ice40/chip.cc @@ -240,6 +240,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(); +} + +// ----------------------------------------------------------------------- + void Chip::getBelPosition(BelId bel, float &x, float &y) const { assert(bel != BelId()); diff --git a/ice40/chip.h b/ice40/chip.h index 7d5c9fbf..37cff038 100644 --- a/ice40/chip.h +++ b/ice40/chip.h @@ -693,6 +693,8 @@ struct Chip return range; } + BelId getPackagePinBel(const std::string &pin) const; + // ------------------------------------------------- void getBelPosition(BelId bel, float &x, float &y) const; diff --git a/ice40/main.cc b/ice40/main.cc index 7a0d92be..8ccec77b 100644 --- a/ice40/main.cc +++ b/ice40/main.cc @@ -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" @@ -74,6 +75,8 @@ int main(int argc, char *argv[]) "python file to execute"); options.add_options()("json", po::value(), "JSON design file to ingest"); + options.add_options()("pcf", po::value(), + "PCF constraints file to ingest"); options.add_options()("asc", po::value(), "asc bitstream file to write"); options.add_options()("version,v", "show version"); @@ -205,6 +208,12 @@ int main(int argc, char *argv[]) std::istream *f = new std::ifstream(filename); parse_json_file(f, filename, &design); + + if (vm.count("pcf")) { + std::ifstream pcf(vm["pcf"].as()); + apply_pcf(&design, pcf); + } + pack_design(&design); if (!vm.count("pack-only")) { place_design(&design); diff --git a/ice40/pack_tests/io_wrapper.v b/ice40/pack_tests/io_wrapper.v deleted file mode 100644 index e10ec419..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(outd_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 + * + * 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 +#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 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 + * + * 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 +#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 -- cgit v1.2.3