diff options
Diffstat (limited to 'ice40')
-rw-r--r-- | ice40/arch_place.cc | 89 | ||||
-rw-r--r-- | ice40/arch_place.h | 31 | ||||
-rw-r--r-- | ice40/blinky_nopack.ys | 3 | ||||
-rwxr-xr-x | ice40/blinky_noyspack.sh | 8 | ||||
-rw-r--r-- | ice40/cells.cc | 17 | ||||
-rw-r--r-- | ice40/cells.h | 5 | ||||
-rw-r--r-- | ice40/chip.cc | 20 | ||||
-rw-r--r-- | ice40/chip.h | 2 | ||||
-rw-r--r-- | ice40/icebreaker.ys | 8 | ||||
-rw-r--r-- | ice40/main.cc | 14 | ||||
-rw-r--r-- | ice40/pack.cc | 122 | ||||
-rw-r--r-- | ice40/pack.h | 27 | ||||
-rw-r--r-- | ice40/pack_tests/ffmodes.v | 39 | ||||
-rw-r--r-- | ice40/pack_tests/io_wrapper.v | 169 | ||||
-rw-r--r-- | ice40/pack_tests/test.pcf | 10 | ||||
-rwxr-xr-x | ice40/pack_tests/test.sh | 15 |
16 files changed, 569 insertions, 10 deletions
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 <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 "arch_place.h" + +static bool logicCellsCompatible(const std::vector<const CellInfo *> &cells) +{ + bool dffs_exist = false, dffs_neg = false; + const NetInfo *cen = nullptr, *clk = nullptr, *sr = nullptr; + std::unordered_set<const NetInfo *> 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<const CellInfo *> 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..8f8ce806 --- /dev/null +++ b/ice40/arch_place.h @@ -0,0 +1,31 @@ +/* + * 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 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(Design *design, CellInfo *cell, BelId bel); + +#endif diff --git a/ice40/blinky_nopack.ys b/ice40/blinky_nopack.ys new file mode 100644 index 00000000..aeaa518b --- /dev/null +++ b/ice40/blinky_nopack.ys @@ -0,0 +1,3 @@ +read_verilog blinky.v +synth_ice40 -nocarry -top blinky +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/cells.cc b/ice40/cells.cc index 1e9a012b..7abf83ff 100644 --- a/ice40/cells.cc +++ b/ice40/cells.cc @@ -38,6 +38,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"; @@ -62,10 +63,22 @@ 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; } +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"; @@ -109,6 +122,8 @@ 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"); } NEXTPNR_NAMESPACE_END diff --git a/ice40/cells.h b/ice40/cells.h index 1c2e0d0f..34a034cd 100644 --- a/ice40/cells.h +++ b/ice40/cells.h @@ -47,6 +47,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/chip.cc b/ice40/chip.cc index 29da5644..88fcc512 100644 --- a/ice40/chip.cc +++ b/ice40/chip.cc @@ -153,6 +153,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 9dc0498c..e48a4973 100644 --- a/ice40/chip.h +++ b/ice40/chip.h @@ -485,6 +485,8 @@ struct Chip return range; } + BelRange getBelsAtSameTile(BelId bel) const; + BelType getBelType(BelId bel) const { assert(bel != BelId()); 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/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<std::vector<std::string>>(), "python file to execute"); options.add_options()("json", po::value<std::string>(), @@ -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 new file mode 100644 index 00000000..ff421c17 --- /dev/null +++ b/ice40/pack.cc @@ -0,0 +1,122 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Clifford Wolf <clifford@clifford.at> + * Copyright (C) 2018 David Shah <dave@ds0.me> + * + * 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 <unordered_set> + +// Pack LUTs and LUT-FF pairs +static void pack_lut_lutffs(Design *design) +{ + std::unordered_set<IdString> packed_cells; + std::vector<CellInfo *> 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; + CellInfo *dff = net_only_drives(o, is_ff, "D", true); + 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); + } + } + } + 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<IdString> packed_cells; + std::vector<CellInfo *> 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; + } +} + +// 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); +} 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 <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 PACK_H +#define PACK_H + +#include "nextpnr.h" + +void pack_design(Design *design); + +#endif // ROUTE_H 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 |