From 2f61a9b98a621a35aa4763abaaf27ca12bfbbefa Mon Sep 17 00:00:00 2001 From: David Shah Date: Tue, 12 Jun 2018 12:13:11 +0200 Subject: ice40: Start working on a packer, currently not tested Signed-off-by: David Shah --- common/design_utils.h | 4 +++ ice40/cells.cc | 13 +++++++++ ice40/cells.h | 5 ++++ ice40/pack.cc | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++ ice40/pack.h | 27 ++++++++++++++++++ 5 files changed, 128 insertions(+) create mode 100644 ice40/pack.cc create mode 100644 ice40/pack.h diff --git a/common/design_utils.h b/common/design_utils.h index 43ff180b..9d027d58 100644 --- a/common/design_utils.h +++ b/common/design_utils.h @@ -37,6 +37,8 @@ template CellInfo *net_only_drives(NetInfo *net, F1 cell_pred, IdString port, bool exclusive = false) { + if (net == nullptr) + return nullptr; if (exclusive && (net->users.size() != 1)) { return nullptr; } else { @@ -54,6 +56,8 @@ CellInfo *net_only_drives(NetInfo *net, F1 cell_pred, IdString port, template CellInfo *net_driven_by(NetInfo *net, F1 cell_pred, IdString port) { + if (net == nullptr) + return nullptr; if (cell_pred(net->driver.cell) && net->driver.port == port) { return net->driver.cell; } else { diff --git a/ice40/cells.cc b/ice40/cells.cc index 328b5f2d..db13a55f 100644 --- a/ice40/cells.cc +++ b/ice40/cells.cc @@ -64,6 +64,19 @@ CellInfo *create_ice_cell(Design *design, IdString type, IdString name) return new_cell; } +void lut_to_lc(CellInfo *lut, CellInfo *lc, bool no_dff) +{ + lc->params["LUT_INIT"] = lut->params["LUT_INIT"]; + replace_port(lut, "I0", lc, "I0"); + replace_port(lut, "I1", lc, "I1"); + replace_port(lut, "I2", lc, "I2"); + replace_port(lut, "I3", lc, "I3"); + if (no_dff) { + replace_port(lut, "O", lc, "O"); + lc->params["DFF_ENABLE"] = "0"; + } +} + void dff_to_lc(CellInfo *dff, CellInfo *lc, bool pass_thru_lut) { lc->params["DFF_ENABLE"] = "1"; diff --git a/ice40/cells.h b/ice40/cells.h index 1fa85413..a2d45df6 100644 --- a/ice40/cells.h +++ b/ice40/cells.h @@ -45,6 +45,11 @@ inline bool is_ff(const CellInfo *cell) cell->type == "SB_DFFNESS" || cell->type == "SB_DFFNES"; } +// 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 +void lut_to_lc(CellInfo *lut, CellInfo *lc, bool no_dff = true); + // Convert a SB_DFFx primitive to (part of) an ICESTORM_LC, setting parameters // and reconnecting signals as necessary. If pass_thru_lut is True, the LUT will // be configured as pass through and D connected to I0, otherwise D will be diff --git a/ice40/pack.cc b/ice40/pack.cc new file mode 100644 index 00000000..692bfba2 --- /dev/null +++ b/ice40/pack.cc @@ -0,0 +1,79 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Clifford Wolf + * Copyright (C) 2018 David Shah + * + * 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 "pack.h" +#include "cells.h" +#include "design_utils.h" +#include "log.h" + +#include + +// Pack LUTs and LUT-FF pairs +static void pack_lut_lutffs(Design *design) +{ + std::unordered_set packed_cells; + for (auto cell : design->cells) { + CellInfo *ci = cell.second; + if (is_lut(ci)) { + CellInfo *packed = create_ice_cell(design, "ICESTORM_LC", + std::string(ci->name) + "_LC"); + packed_cells.insert(ci->name); + // See if we can pack into a DFF + // TODO: LUT cascade + NetInfo *o = ci->ports.at("O").net; + CellInfo *dff = net_only_drives(o, is_ff, "D", true); + if (dff) { + lut_to_lc(ci, packed, false); + dff_to_lc(dff, packed, false); + packed_cells.insert(dff->name); + } else { + lut_to_lc(ci, packed, true); + } + } + } + for (auto pcell : packed_cells) { + design->cells.erase(pcell); + } +} + +// Pack FFs not packed as LUTFFs +static void pack_nonlut_ffs(Design *design) +{ + std::unordered_set packed_cells; + for (auto cell : design->cells) { + CellInfo *ci = cell.second; + if (is_ff(ci)) { + CellInfo *packed = create_ice_cell(design, "ICESTORM_LC", + std::string(ci->name) + "_LC"); + packed_cells.insert(ci->name); + dff_to_lc(ci, packed, true); + } + } + for (auto pcell : packed_cells) { + design->cells.erase(pcell); + } +} + +// Main pack function +void pack_design(Design *design) +{ + pack_lut_lutffs(design); + pack_nonlut_ffs(design); +} diff --git a/ice40/pack.h b/ice40/pack.h new file mode 100644 index 00000000..87a390ff --- /dev/null +++ b/ice40/pack.h @@ -0,0 +1,27 @@ +/* + * 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 PACK_H +#define PACK_H + +#include "nextpnr.h" + +void pack_design(Design *design); + +#endif // ROUTE_H -- cgit v1.2.3 From f72807f790e8d3f3f2a630f461bfe086e8d0e108 Mon Sep 17 00:00:00 2001 From: David Shah Date: Tue, 12 Jun 2018 12:46:30 +0200 Subject: ice40: Debugging the packer Signed-off-by: David Shah --- ice40/blinky_nopack.ys | 3 +++ ice40/cells.cc | 4 +++- ice40/main.cc | 14 ++++++++++++-- ice40/pack.cc | 18 ++++++++++++++++++ python/dump_design.py | 2 +- 5 files changed, 37 insertions(+), 4 deletions(-) create mode 100644 ice40/blinky_nopack.ys diff --git a/ice40/blinky_nopack.ys b/ice40/blinky_nopack.ys new file mode 100644 index 00000000..2fea95bc --- /dev/null +++ b/ice40/blinky_nopack.ys @@ -0,0 +1,3 @@ +read_verilog blinky.v +synth_ice40 -nocarry -top blinky +write_json blinky.json diff --git a/ice40/cells.cc b/ice40/cells.cc index db13a55f..6ad9d136 100644 --- a/ice40/cells.cc +++ b/ice40/cells.cc @@ -36,6 +36,7 @@ CellInfo *create_ice_cell(Design *design, IdString type, IdString name) } else { new_cell->name = name; } + new_cell->type = type; if (type == "ICESTORM_LC") { new_cell->params["LUT_INIT"] = "0"; new_cell->params["NEG_CLK"] = "0"; @@ -60,7 +61,6 @@ CellInfo *create_ice_cell(Design *design, IdString type, IdString name) } else { log_error("unable to create iCE40 cell of type %s", type.c_str()); } - design->cells[new_cell->name] = new_cell; return new_cell; } @@ -120,4 +120,6 @@ void dff_to_lc(CellInfo *dff, CellInfo *lc, bool pass_thru_lut) lc->params["LUT_INIT"] = "2"; replace_port(dff, "D", lc, "I0"); } + + replace_port(dff, "Q", lc, "O"); } diff --git a/ice40/main.cc b/ice40/main.cc index cceb2b04..0e989819 100644 --- a/ice40/main.cc +++ b/ice40/main.cc @@ -29,6 +29,7 @@ #include "log.h" #include "mainwindow.h" #include "nextpnr.h" +#include "pack.h" #include "place.h" #include "pybindings.h" #include "route.h" @@ -67,6 +68,10 @@ int main(int argc, char *argv[]) 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"); + options.add_options()("run", po::value>(), "python file to execute"); options.add_options()("json", po::value(), @@ -251,8 +256,13 @@ int main(int argc, char *argv[]) std::istream *f = new std::ifstream(filename); parse_json_file(f, filename, &design); - place_design(&design); - route_design(&design); + if (vm.count("pack") || vm.count("pack-only")) { + pack_design(&design); + } + if (!vm.count("pack-only")) { + place_design(&design); + route_design(&design); + } } if (vm.count("asc")) { diff --git a/ice40/pack.cc b/ice40/pack.cc index 692bfba2..47e55b68 100644 --- a/ice40/pack.cc +++ b/ice40/pack.cc @@ -29,12 +29,18 @@ static void pack_lut_lutffs(Design *design) { std::unordered_set packed_cells; + std::vector new_cells; for (auto cell : design->cells) { CellInfo *ci = cell.second; + log_info("cell '%s' is of type '%s'\n", ci->name.c_str(), + ci->type.c_str()); if (is_lut(ci)) { CellInfo *packed = create_ice_cell(design, "ICESTORM_LC", std::string(ci->name) + "_LC"); packed_cells.insert(ci->name); + new_cells.push_back(packed); + log_info("packed cell %s into %s\n", ci->name.c_str(), + packed->name.c_str()); // See if we can pack into a DFF // TODO: LUT cascade NetInfo *o = ci->ports.at("O").net; @@ -42,7 +48,10 @@ static void pack_lut_lutffs(Design *design) if (dff) { lut_to_lc(ci, packed, false); dff_to_lc(dff, packed, false); + design->nets.erase(o->name); packed_cells.insert(dff->name); + log_info("packed cell %s into %s\n", dff->name.c_str(), + packed->name.c_str()); } else { lut_to_lc(ci, packed, true); } @@ -51,24 +60,33 @@ static void pack_lut_lutffs(Design *design) for (auto pcell : packed_cells) { design->cells.erase(pcell); } + for (auto ncell : new_cells) { + design->cells[ncell->name] = ncell; + } } // Pack FFs not packed as LUTFFs static void pack_nonlut_ffs(Design *design) { std::unordered_set packed_cells; + std::vector new_cells; + for (auto cell : design->cells) { CellInfo *ci = cell.second; if (is_ff(ci)) { CellInfo *packed = create_ice_cell(design, "ICESTORM_LC", std::string(ci->name) + "_LC"); packed_cells.insert(ci->name); + new_cells.push_back(packed); dff_to_lc(ci, packed, true); } } for (auto pcell : packed_cells) { design->cells.erase(pcell); } + for (auto ncell : new_cells) { + design->cells[ncell->name] = ncell; + } } // Main pack function diff --git a/python/dump_design.py b/python/dump_design.py index 3972f4dc..3408ef9d 100644 --- a/python/dump_design.py +++ b/python/dump_design.py @@ -20,6 +20,6 @@ for cell, cinfo in sorted(design.cells, key=lambda x: x.first): val = "{}'b{}".format(len(val), val) print("\t\t{}: {}".format(param, val)) - if cinfo.bel != -1: + if cinfo.bel.index != -1: print("\tBel: {}".format(chip.getBelName(cinfo.bel))) print() -- cgit v1.2.3 From 67a5cedbe30f681fd3c5c52ed8552abcc7583a45 Mon Sep 17 00:00:00 2001 From: David Shah Date: Tue, 12 Jun 2018 13:09:36 +0200 Subject: ice40: Pack constants to LCs Signed-off-by: David Shah --- ice40/blinky_nopack.ys | 2 +- ice40/blinky_noyspack.sh | 8 ++++++++ ice40/icebreaker.ys | 8 +------- ice40/pack.cc | 25 +++++++++++++++++++++++++ 4 files changed, 35 insertions(+), 8 deletions(-) create mode 100755 ice40/blinky_noyspack.sh diff --git a/ice40/blinky_nopack.ys b/ice40/blinky_nopack.ys index 2fea95bc..aeaa518b 100644 --- a/ice40/blinky_nopack.ys +++ b/ice40/blinky_nopack.ys @@ -1,3 +1,3 @@ read_verilog blinky.v synth_ice40 -nocarry -top blinky -write_json blinky.json +write_json blinky_nopack.json diff --git a/ice40/blinky_noyspack.sh b/ice40/blinky_noyspack.sh new file mode 100755 index 00000000..00824ae9 --- /dev/null +++ b/ice40/blinky_noyspack.sh @@ -0,0 +1,8 @@ +#!/bin/bash +set -ex +yosys blinky_nopack.ys +../nextpnr-ice40 --json blinky_nopack.json --asc blinky.asc --pack +icepack blinky.asc blinky.bin +icebox_vlog blinky.asc > blinky_chip.v +iverilog -o blinky_tb blinky_chip.v blinky_tb.v +vvp -N ./blinky_tb diff --git a/ice40/icebreaker.ys b/ice40/icebreaker.ys index 7933254d..878914aa 100644 --- a/ice40/icebreaker.ys +++ b/ice40/icebreaker.ys @@ -1,9 +1,3 @@ read_verilog icebreaker.v -read_verilog -lib +/ice40/cells_sim.v -synth -top icebreaker -abc -lut 4 -techmap -map blinky_map.v -splitnets -opt_clean -stat +synth_ice40 -nocarry -top icebreaker write_json icebreaker.json diff --git a/ice40/pack.cc b/ice40/pack.cc index 47e55b68..eb783f2f 100644 --- a/ice40/pack.cc +++ b/ice40/pack.cc @@ -89,9 +89,34 @@ static void pack_nonlut_ffs(Design *design) } } +// Pack constants (simple implementation) +static void pack_constants(Design *design) { + CellInfo *gnd_cell = create_ice_cell(design, "ICESTORM_LC", + "$PACKER_GND"); + gnd_cell->attrs["LUT_INIT"] = "0"; + + CellInfo *vcc_cell = create_ice_cell(design, "ICESTORM_LC", + "$PACKER_VCC"); + vcc_cell->attrs["LUT_INIT"] = "1"; + + for (auto net : design->nets) { + NetInfo *ni = net.second; + if (ni->driver.cell != nullptr && ni->driver.cell->type == "GND") { + ni->driver.cell = gnd_cell; + ni->driver.port = "O"; + design->cells[gnd_cell->name] = gnd_cell; + } else if (ni->driver.cell != nullptr && ni->driver.cell->type == "VCC") { + ni->driver.cell = vcc_cell; + ni->driver.port = "O"; + design->cells[vcc_cell->name] = vcc_cell; + } + } +} + // Main pack function void pack_design(Design *design) { + pack_constants(design); pack_lut_lutffs(design); pack_nonlut_ffs(design); } -- cgit v1.2.3 From 031d8e811f9ce00f0c72e697789f991834d1f8f2 Mon Sep 17 00:00:00 2001 From: David Shah Date: Tue, 12 Jun 2018 13:40:22 +0200 Subject: ice40: Adding a placement validity checker Signed-off-by: David Shah --- ice40/arch_place.cc | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++ ice40/arch_place.h | 31 +++++++++++++++++++ ice40/chip.cc | 20 ++++++++++++ ice40/chip.h | 2 ++ ice40/pack.cc | 12 ++++---- 5 files changed, 148 insertions(+), 6 deletions(-) create mode 100644 ice40/arch_place.cc create mode 100644 ice40/arch_place.h diff --git a/ice40/arch_place.cc b/ice40/arch_place.cc new file mode 100644 index 00000000..2367d981 --- /dev/null +++ b/ice40/arch_place.cc @@ -0,0 +1,89 @@ +/* + * 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 "arch_place.h" + +static bool logicCellsCompatible(const std::vector &cells) +{ + bool dffs_exist = false, dffs_neg = false; + const NetInfo *cen = nullptr, *clk = nullptr, *sr = nullptr; + std::unordered_set locals; + + for (auto cell : cells) { + if (std::stoi(cell->params.at("DFF_ENABLE"))) { + if (!dffs_exist) { + dffs_exist = true; + cen = cell->ports.at("CEN").net; + clk = cell->ports.at("CLK").net; + sr = cell->ports.at("SR").net; + + locals.insert(cen); + locals.insert(clk); + locals.insert(sr); + + if (std::stoi(cell->params.at("NEG_CLK"))) { + dffs_neg = true; + } + } else { + if (cen != cell->ports.at("CEN").net) + return false; + if (clk == cell->ports.at("CLK").net) + return false; + if (sr != cell->ports.at("SR").net) + return false; + if (dffs_neg != bool(std::stoi(cell->params.at("NEG_CLK")))) + return false; + } + } + + locals.insert(cell->ports.at("I0").net); + locals.insert(cell->ports.at("I1").net); + locals.insert(cell->ports.at("I2").net); + locals.insert(cell->ports.at("I3").net); + } + + locals.erase(nullptr); // disconnected signals don't use local tracks + + return locals.size() <= 32; +} + +bool isValidBelForCell(Design *design, CellInfo *cell, BelId bel) +{ + const Chip &chip = design->chip; + if (cell->type == "ICESTORM_LC") { + assert(chip.getBelType(bel) == TYPE_ICESTORM_LC); + + std::vector cells; + + for (auto bel_other : chip.getBelsAtSameTile(bel)) { + IdString cell_other = chip.getBelCell(bel_other, false); + if (cell_other != IdString()) { + const CellInfo *ci_other = design->cells[cell_other]; + cells.push_back(ci_other); + } + } + + cells.push_back(cell); + return logicCellsCompatible(cells); + + } else { + // TODO: IO cell clock checks + return true; + } +} diff --git a/ice40/arch_place.h b/ice40/arch_place.h new file mode 100644 index 00000000..19b0635f --- /dev/null +++ b/ice40/arch_place.h @@ -0,0 +1,31 @@ +/* + * 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 ICE40_ARCH_PLACE_H +#define ICE40_ARCH_PLACE_H + +#include "nextpnr.h" +// Architecure-specific placement functions + +// Whether or not a given cell can be placed at a given Bel +// This is not intended for Bel type checks, but finer-grained constraints +// such as conflicting set/reset signals, etc +bool isValidBelForCell(Chip *chip, CellInfo *cell, BelId bel); + +#endif diff --git a/ice40/chip.cc b/ice40/chip.cc index 42252fa0..21beb648 100644 --- a/ice40/chip.cc +++ b/ice40/chip.cc @@ -151,6 +151,26 @@ BelId Chip::getBelByName(IdString name) const return ret; } +BelRange Chip::getBelsAtSameTile(BelId bel) const +{ + BelRange br; + assert(bel != BelId()); + // This requires Bels at the same tile are consecutive + int x = chip_info.bel_data[bel.index].x; + int y = chip_info.bel_data[bel.index].y; + int start = bel.index, end = bel.index; + while (start >= 0 && chip_info.bel_data[start].x == x && + chip_info.bel_data[start].y == y) + start--; + start++; + br.b.cursor = start; + while (end < chip_info.num_bels && chip_info.bel_data[end].x == x && + chip_info.bel_data[end].y == y) + end++; + br.e.cursor = end; + return br; +} + WireId Chip::getWireBelPin(BelId bel, PortPin pin) const { WireId ret; diff --git a/ice40/chip.h b/ice40/chip.h index 451be9ce..097fb286 100644 --- a/ice40/chip.h +++ b/ice40/chip.h @@ -479,6 +479,8 @@ struct Chip return range; } + BelRange getBelsAtSameTile(BelId bel) const; + BelType getBelType(BelId bel) const { assert(bel != BelId()); diff --git a/ice40/pack.cc b/ice40/pack.cc index eb783f2f..ff421c17 100644 --- a/ice40/pack.cc +++ b/ice40/pack.cc @@ -90,13 +90,12 @@ static void pack_nonlut_ffs(Design *design) } // Pack constants (simple implementation) -static void pack_constants(Design *design) { - CellInfo *gnd_cell = create_ice_cell(design, "ICESTORM_LC", - "$PACKER_GND"); +static void pack_constants(Design *design) +{ + CellInfo *gnd_cell = create_ice_cell(design, "ICESTORM_LC", "$PACKER_GND"); gnd_cell->attrs["LUT_INIT"] = "0"; - CellInfo *vcc_cell = create_ice_cell(design, "ICESTORM_LC", - "$PACKER_VCC"); + CellInfo *vcc_cell = create_ice_cell(design, "ICESTORM_LC", "$PACKER_VCC"); vcc_cell->attrs["LUT_INIT"] = "1"; for (auto net : design->nets) { @@ -105,7 +104,8 @@ static void pack_constants(Design *design) { ni->driver.cell = gnd_cell; ni->driver.port = "O"; design->cells[gnd_cell->name] = gnd_cell; - } else if (ni->driver.cell != nullptr && ni->driver.cell->type == "VCC") { + } else if (ni->driver.cell != nullptr && + ni->driver.cell->type == "VCC") { ni->driver.cell = vcc_cell; ni->driver.port = "O"; design->cells[vcc_cell->name] = vcc_cell; -- cgit v1.2.3 From 47eeda40bce5b520f1c5aafb52f5b4c11b799d60 Mon Sep 17 00:00:00 2001 From: David Shah Date: Tue, 12 Jun 2018 13:45:59 +0200 Subject: Implement the placement validity checker Signed-off-by: David Shah --- common/place.cc | 4 +++- dummy/arch_place.cc | 25 +++++++++++++++++++++++++ dummy/arch_place.h | 32 ++++++++++++++++++++++++++++++++ ice40/arch_place.h | 2 +- 4 files changed, 61 insertions(+), 2 deletions(-) create mode 100644 dummy/arch_place.cc create mode 100644 dummy/arch_place.h diff --git a/common/place.cc b/common/place.cc index 0223c78f..b187b0f0 100644 --- a/common/place.cc +++ b/common/place.cc @@ -28,6 +28,7 @@ #include #include +#include "arch_place.h" #include "log.h" #include "place.h" @@ -102,7 +103,8 @@ void place_design(Design *design) while ((bi != blist.end()) && ((design->chip.getBelType(*bi) != bel_type || - !design->chip.checkBelAvail(*bi)))) + !design->chip.checkBelAvail(*bi)) || + !isValidBelForCell(design, cell, *bi))) bi++; if (bi == blist.end()) log_error("Too many \'%s\' used in design\n", diff --git a/dummy/arch_place.cc b/dummy/arch_place.cc new file mode 100644 index 00000000..e41b8cc3 --- /dev/null +++ b/dummy/arch_place.cc @@ -0,0 +1,25 @@ +/* + * 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 "arch_place.h" + +bool isValidBelForCell(Design *design, CellInfo *cell, BelId bel) +{ + return true; +} diff --git a/dummy/arch_place.h b/dummy/arch_place.h new file mode 100644 index 00000000..446396e9 --- /dev/null +++ b/dummy/arch_place.h @@ -0,0 +1,32 @@ +/* + * 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 DUMMY_ARCH_PLACE_H +#define DUMMY_ARCH_PLACE_H + +#include "nextpnr.h" + +// Architecure-specific placement functions + +// Whether or not a given cell can be placed at a given Bel +// This is not intended for Bel type checks, but finer-grained constraints +// such as conflicting set/reset signals, etc +bool isValidBelForCell(Design *design, CellInfo *cell, BelId bel); + +#endif diff --git a/ice40/arch_place.h b/ice40/arch_place.h index 19b0635f..8f8ce806 100644 --- a/ice40/arch_place.h +++ b/ice40/arch_place.h @@ -26,6 +26,6 @@ // Whether or not a given cell can be placed at a given Bel // This is not intended for Bel type checks, but finer-grained constraints // such as conflicting set/reset signals, etc -bool isValidBelForCell(Chip *chip, CellInfo *cell, BelId bel); +bool isValidBelForCell(Design *design, CellInfo *cell, BelId bel); #endif -- cgit v1.2.3 From 9ee6a6e1149e35bcca3c1781f6ce84b11dc80296 Mon Sep 17 00:00:00 2001 From: David Shah Date: Tue, 12 Jun 2018 14:19:26 +0200 Subject: ice40: Creating packer tests Signed-off-by: David Shah --- ice40/pack_tests/ffmodes.v | 39 ++++++++++ ice40/pack_tests/io_wrapper.v | 169 ++++++++++++++++++++++++++++++++++++++++++ ice40/pack_tests/test.pcf | 10 +++ ice40/pack_tests/test.sh | 15 ++++ 4 files changed, 233 insertions(+) create mode 100644 ice40/pack_tests/ffmodes.v create mode 100644 ice40/pack_tests/io_wrapper.v create mode 100644 ice40/pack_tests/test.pcf create mode 100755 ice40/pack_tests/test.sh diff --git a/ice40/pack_tests/ffmodes.v b/ice40/pack_tests/ffmodes.v new file mode 100644 index 00000000..6ff99bce --- /dev/null +++ b/ice40/pack_tests/ffmodes.v @@ -0,0 +1,39 @@ +module top(input clk, cen, rst, ina, inb, output reg outa, outb, outc, outd); + +reg temp0 = 1'b0, temp1 = 1'b0; + +always @(posedge clk) + if (cen) + if(rst) + temp0 <= 1'b0; + else + temp0 <= ina; + +always @(negedge clk) + if (ina) + if(rst) + temp1 <= 1'b1; + else + temp1 <= inb; + + +always @(posedge clk or negedge rst) + if(!rst) + outa <= 1'b0; + else + outa <= temp0; + +always @(posedge clk) + outb <= temp1; + +always @(negedge clk) + outc <= temp0; + +always @(negedge clk or posedge rst) + if (rst) + outd <= 1'b1; + else + outd <= temp1; + + +endmodule diff --git a/ice40/pack_tests/io_wrapper.v b/ice40/pack_tests/io_wrapper.v new file mode 100644 index 00000000..b58d6c0c --- /dev/null +++ b/ice40/pack_tests/io_wrapper.v @@ -0,0 +1,169 @@ +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.pcf b/ice40/pack_tests/test.pcf new file mode 100644 index 00000000..8cd488bf --- /dev/null +++ b/ice40/pack_tests/test.pcf @@ -0,0 +1,10 @@ +set_io clk 1 +set_io cen 2 +set_io rst 3 +set_io ina 4 +set_io inb 7 +set_io outa 8 +set_io outb 9 +set_io outc 10 +set_io outd 11 + diff --git a/ice40/pack_tests/test.sh b/ice40/pack_tests/test.sh new file mode 100755 index 00000000..24bb6549 --- /dev/null +++ b/ice40/pack_tests/test.sh @@ -0,0 +1,15 @@ +#!/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 +icebox_vlog -p test.pcf ${NAME}.asc > ${NAME}_out.v + +yosys -p "rename top gate\ + read_verilog $1\ + rename top gold\ + hierarchy\ + proc\ + clk2fflogic\ + miter -equiv -flatten -ignore_gold_x -make_outputs -make_outcmp gold gate miter\ + sat -dump_vcd equiv_${NAME}.vcd -verify-no-timeout -timeout 20 -seq 10 -prove trigger 0 -prove-skip 1 -show-inputs -show-outputs miter" ${NAME}_out.v -- cgit v1.2.3